Treat handshake_failure in response to ClientHello special.

Add a dedicated error code to the queue for a handshake_failure alert in
response to ClientHello. This matches NSS's client behavior and gives a better
error on a (probable) failure to negotiate initial parameters.

BUG=https://crbug.com/446505

Change-Id: I34368712085a6cbf0031902daf2c00393783d96d
Reviewed-on: https://boringssl-review.googlesource.com/2751
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 1a45805..fdcaf76 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -748,6 +748,18 @@
                                  SSL_GET_MESSAGE_HASH_MESSAGE, &ok);
 
   if (!ok) {
+    uint32_t err = ERR_peek_error();
+    if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
+        ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {
+      /* Add a dedicated error code to the queue for a handshake_failure alert
+       * in response to ClientHello. This matches NSS's client behavior and
+       * gives a better error on a (probable) failure to negotiate initial
+       * parameters. Note: this error code comes after the original one.
+       *
+       * See https://crbug.com/446505. */
+      OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello,
+                        SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
+    }
     return n;
   }
 
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
index f9be633..2f06460 100644
--- a/ssl/ssl_error.c
+++ b/ssl/ssl_error.c
@@ -314,6 +314,7 @@
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS), "GOT_CHANNEL_ID_BEFORE_A_CCS"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS), "GOT_NEXT_PROTO_BEFORE_A_CCS"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION), "GOT_NEXT_PROTO_WITHOUT_EXTENSION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO), "HANDSHAKE_FAILURE_ON_CLIENT_HELLO"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HANDSHAKE_RECORD_BEFORE_CCS), "HANDSHAKE_RECORD_BEFORE_CCS"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTPS_PROXY_REQUEST), "HTTPS_PROXY_REQUEST"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTP_REQUEST), "HTTP_REQUEST"},
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 8d6dabc..6faccb5 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -556,6 +556,14 @@
 		shouldFail:    true,
 		expectedError: ":WRONG_SSL_VERSION:",
 	},
+	{
+		name: "NoSharedCipher",
+		config: Config{
+			CipherSuites: []uint16{},
+		},
+		shouldFail:    true,
+		expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
+	},
 }
 
 func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {