Push an error if custom private keys fail.

The private key callback may not push one of its own (it's possible to
register a custom error library and whatnot, but this is tedious). If
the callback does not push any, we report SSL_ERROR_SYSCALL. This is not
completely wrong, as "syscall" really means "I don't know, something you
gave me, probably the BIO, failed so I assume you know what happened",
but most callers just check errno. And indeed cert_cb pushes its own
error, so this probably should as well.

Update-Note: Custom private key callbacks which push an error code on
    failure will report both that error followed by
    SSL_R_PRIVATE_KEY_OPERATION_FAILED. Callbacks which did not push any
    error will switch from SSL_ERROR_SYSCALL to SSL_ERROR_SSL with
    SSL_R_PRIVATE_KEY_OPERATION_FAILED.

Change-Id: I7e90cd327fe0cbcff395470381a3591364a82c74
Reviewed-on: https://boringssl-review.googlesource.com/25544
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index 4450958..7b63bc8 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -117,6 +117,7 @@
 SSL,192,PEER_DID_NOT_RETURN_A_CERTIFICATE
 SSL,193,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
 SSL,267,PRE_SHARED_KEY_MUST_BE_LAST
+SSL,287,PRIVATE_KEY_OPERATION_FAILED
 SSL,194,PROTOCOL_IS_SHUTDOWN
 SSL,271,PSK_IDENTITY_BINDER_COUNT_MISMATCH
 SSL,195,PSK_IDENTITY_NOT_FOUND
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index a1b6fa7..249fce1 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -4697,6 +4697,7 @@
 #define SSL_R_HANDSHAKE_NOT_COMPLETE 284
 #define SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI 285
 #define SSL_R_SERVER_ECHOED_INVALID_SESSION_ID 286
+#define SSL_R_PRIVATE_KEY_OPERATION_FAILED 287
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/ssl/ssl_privkey.cc b/ssl/ssl_privkey.cc
index 134ad56..33cc720 100644
--- a/ssl/ssl_privkey.cc
+++ b/ssl/ssl_privkey.cc
@@ -205,6 +205,9 @@
       ret = ssl->cert->key_method->sign(ssl, out, out_len, max_out, sigalg,
                                         in.data(), in.size());
     }
+    if (ret == ssl_private_key_failure) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PRIVATE_KEY_OPERATION_FAILED);
+    }
     hs->pending_private_key_op = ret == ssl_private_key_retry;
     return ret;
   }
@@ -241,6 +244,9 @@
       ret = ssl->cert->key_method->decrypt(ssl, out, out_len, max_out,
                                            in.data(), in.size());
     }
+    if (ret == ssl_private_key_failure) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_PRIVATE_KEY_OPERATION_FAILED);
+    }
     hs->pending_private_key_op = ret == ssl_private_key_retry;
     return ret;
   }