Rewrite ssl3_send_client_certificate.

The old logic was quite messy and grew a number of no-ops over the
years. It was also unreasonably fond of the variable name |i|.

The current logic wasn't even correct. It's overly fond of sending no
certificate, even when it pushes errors on the error queue for a fatal
error.

Change-Id: Ie5b2b38dd309f535af1d17fa261da7dc23185866
Reviewed-on: https://boringssl-review.googlesource.com/7418
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 201c036..b490826 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1875,21 +1875,17 @@
 }
 
 int ssl3_send_client_certificate(SSL *ssl) {
-  X509 *x509 = NULL;
-  EVP_PKEY *pkey = NULL;
-  int i;
-
   if (ssl->state == SSL3_ST_CW_CERT_A) {
-    /* Let cert callback update client certificates if required */
+    /* Call cert_cb to update the certificate. */
     if (ssl->cert->cert_cb) {
-      i = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
-      if (i < 0) {
+      int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+      if (ret < 0) {
         ssl->rwstate = SSL_X509_LOOKUP;
         return -1;
       }
-      if (i == 0) {
+      if (ret == 0) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        return 0;
+        return -1;
       }
       ssl->rwstate = SSL_NOTHING;
     }
@@ -1901,52 +1897,43 @@
     }
   }
 
-  /* We need to get a client cert */
   if (ssl->state == SSL3_ST_CW_CERT_B) {
-    /* If we get an error, we need to:
-     *   ssl->rwstate=SSL_X509_LOOKUP; return(-1);
-     * We then get retried later */
-    i = ssl_do_client_cert_cb(ssl, &x509, &pkey);
-    if (i < 0) {
+    /* Call client_cert_cb to update the certificate. */
+    X509 *x509 = NULL;
+    EVP_PKEY *pkey = NULL;
+    int ret = ssl_do_client_cert_cb(ssl, &x509, &pkey);
+    if (ret < 0) {
       ssl->rwstate = SSL_X509_LOOKUP;
       return -1;
     }
     ssl->rwstate = SSL_NOTHING;
-    if (i == 1 && pkey != NULL && x509 != NULL) {
-      ssl->state = SSL3_ST_CW_CERT_B;
-      if (!SSL_use_certificate(ssl, x509) || !SSL_use_PrivateKey(ssl, pkey)) {
-        i = 0;
-      }
-    } else if (i == 1) {
-      i = 0;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
-    }
 
+    int setup_error = ret == 1 && (!SSL_use_certificate(ssl, x509) ||
+                                   !SSL_use_PrivateKey(ssl, pkey));
     X509_free(x509);
     EVP_PKEY_free(pkey);
-    if (i && !ssl3_has_client_certificate(ssl)) {
-      i = 0;
-    }
-    if (i == 0) {
-      if (ssl->version == SSL3_VERSION) {
-        ssl->s3->tmp.cert_req = 0;
-        ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
-        return 1;
-      } else {
-        ssl->s3->tmp.cert_req = 2;
-        /* There is no client certificate, so the handshake buffer may be
-         * released. */
-        ssl3_free_handshake_buffer(ssl);
-      }
+    if (setup_error) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      return -1;
     }
 
-    /* Ok, we have a cert */
     ssl->state = SSL3_ST_CW_CERT_C;
   }
 
   if (ssl->state == SSL3_ST_CW_CERT_C) {
-    if (ssl->s3->tmp.cert_req == 2) {
-      /* Send an empty Certificate message. */
+    if (!ssl3_has_client_certificate(ssl)) {
+      /* Without a client certificate, the handshake buffer may be released. */
+      ssl3_free_handshake_buffer(ssl);
+
+      if (ssl->version == SSL3_VERSION) {
+        /* In SSL 3.0, send no certificate by skipping both messages. */
+        ssl->s3->tmp.cert_req = 0;
+        ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
+        return 1;
+      }
+
+      /* In TLS, send an empty Certificate message. */
+      ssl->s3->tmp.cert_req = 2;
       uint8_t *p = ssl_handshake_start(ssl);
       l2n3(0, p);
       if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) {
@@ -1958,7 +1945,7 @@
     ssl->state = SSL3_ST_CW_CERT_D;
   }
 
-  /* SSL3_ST_CW_CERT_D */
+  assert(ssl->state == SSL3_ST_CW_CERT_D);
   return ssl_do_write(ssl);
 }
 
@@ -2078,7 +2065,15 @@
   if (ssl->ctx->client_cert_cb == NULL) {
     return 0;
   }
-  return ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey);
+
+  int ret = ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey);
+  if (ret <= 0) {
+    return ret;
+  }
+
+  assert(*out_x509 != NULL);
+  assert(*out_pkey != NULL);
+  return 1;
 }
 
 int ssl3_verify_server_cert(SSL *ssl) {