Have |SSL_get_verify_result| return |X509_V_OK| when no client certificate is given.

9498e74 changed the default value of verify_result to an error. This
tripped up NGINX, which depends on a bug[1] in OpenSSL. netty-tcnative
also uses this behavior, though it currently isn't tripped up by 9498e74
because it calls |SSL_set_verify_result|. However, we would like to
remove |SSL_set_verify_result| and with two data points, it seems this
is behavior we must preserve.

This change sets |verify_result| to |X509_V_OK| when a) no client
certificate is requested or b) none is given and it's optional.

[1] See BUGS in https://www.openssl.org/docs/manmaster/ssl/SSL_get_verify_result.html

Change-Id: Ibd33660ae409bfe272963a8c39b7e9aa83c3d635
Reviewed-on: https://boringssl-review.googlesource.com/9067
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 4818fe5..f5c8b3c 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -809,6 +809,13 @@
     if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
       ssl->s3->tmp.cert_request = 0;
     }
+
+    if (!ssl->s3->tmp.cert_request) {
+      /* OpenSSL returns X509_V_OK when no certificates are requested. This is
+       * classed by them as a bug, but it's assumed by at least nginx. */
+      ssl->verify_result = X509_V_OK;
+      ssl->s3->new_session->verify_result = X509_V_OK;
+    }
   }
 
   /* Now that the cipher is known, initialize the handshake hash. */
@@ -1244,13 +1251,18 @@
   if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
     if (ssl->version == SSL3_VERSION &&
         ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
-      /* In SSL 3.0, the Certificate message is omitted to signal no certificate. */
+      /* In SSL 3.0, the Certificate message is omitted to signal no
+       * certificate. */
       if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
         return -1;
       }
 
+      /* OpenSSL returns X509_V_OK when no certificates are received. This is
+       * classed by them as a bug, but it's assumed by at least nginx. */
+      ssl->verify_result = X509_V_OK;
+      ssl->s3->new_session->verify_result = X509_V_OK;
       ssl->s3->tmp.reuse_message = 1;
       return 1;
     }
@@ -1297,6 +1309,10 @@
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
       goto err;
     }
+
+    /* OpenSSL returns X509_V_OK when no certificates are received. This is
+     * classed by them as a bug, but it's assumed by at least nginx. */
+    ssl->verify_result = X509_V_OK;
   } else {
     /* The hash would have been filled in. */
     if (ssl->ctx->retain_only_sha256_of_client_certs) {