Use handshake parameters to decide if cert/key are available Whether the host has a valid certificate or private key may depend on the handshake parameters and not just its configuration. For example, negotiating the delegated credential extension (see https://tools.ietf.org/html/draft-ietf-tls-subcerts) requires an alternate private key for the handshake. Change-Id: I11cea1d11e731aa4018d980c010b8d8ebaa64c31 Reviewed-on: https://boringssl-review.googlesource.com/c/33664 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com>
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 0274dc2..4d57ae5 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc
@@ -1219,7 +1219,7 @@ } } - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { // Without a client certificate, the handshake buffer may be released. hs->transcript.FreeBuffer(); } @@ -1386,12 +1386,12 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - if (!hs->cert_request || !ssl_has_certificate(hs->config)) { + if (!hs->cert_request || !ssl_has_certificate(hs)) { hs->state = state_send_client_finished; return ssl_hs_ok; } - assert(ssl_has_private_key(hs->config)); + assert(ssl_has_private_key(hs)); ScopedCBB cbb; CBB body, child; if (!ssl->method->init_message(ssl, cbb.get(), &body,
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc index 1572096..15ba2b0 100644 --- a/ssl/handshake_server.cc +++ b/ssl/handshake_server.cc
@@ -303,7 +303,7 @@ uint32_t mask_k = 0; uint32_t mask_a = 0; - if (ssl_has_certificate(hs->config)) { + if (ssl_has_certificate(hs)) { mask_a |= ssl_cipher_auth_mask_for_key(hs->local_pubkey.get()); if (EVP_PKEY_id(hs->local_pubkey.get()) == EVP_PKEY_RSA) { mask_k |= SSL_kRSA; @@ -868,7 +868,7 @@ ScopedCBB cbb; if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); return ssl_hs_error; } @@ -974,7 +974,7 @@ // Add a signature. if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { - if (!ssl_has_private_key(hs->config)) { + if (!ssl_has_private_key(hs)) { ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; }
diff --git a/ssl/internal.h b/ssl/internal.h index bc45b50..9846966 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -919,8 +919,8 @@ // Private key operations. -// ssl_has_private_key returns whether |cfg| has a private key configured. -bool ssl_has_private_key(const SSL_CONFIG *cfg); +// ssl_has_private_key returns whether |hs| has a private key configured. +bool ssl_has_private_key(const SSL_HANDSHAKE *hs); // ssl_private_key_* perform the corresponding operation on // |SSL_PRIVATE_KEY_METHOD|. If there is a custom private key configured, they @@ -1173,7 +1173,7 @@ // ssl_has_certificate returns whether a certificate and private key are // configured. -bool ssl_has_certificate(const SSL_CONFIG *cfg); +bool ssl_has_certificate(const SSL_HANDSHAKE *hs); // ssl_parse_cert_chain parses a certificate list from |cbs| in the format used // by a TLS Certificate message. On success, it advances |cbs| and returns
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc index 37d6501..9551810 100644 --- a/ssl/ssl_cert.cc +++ b/ssl/ssl_cert.cc
@@ -324,10 +324,10 @@ return true; } -bool ssl_has_certificate(const SSL_CONFIG *cfg) { - return cfg->cert->chain != nullptr && - sk_CRYPTO_BUFFER_value(cfg->cert->chain.get(), 0) != nullptr && - ssl_has_private_key(cfg); +bool ssl_has_certificate(const SSL_HANDSHAKE *hs) { + return hs->config->cert->chain != nullptr && + sk_CRYPTO_BUFFER_value(hs->config->cert->chain.get(), 0) != nullptr && + ssl_has_private_key(hs); } bool ssl_parse_cert_chain(uint8_t *out_alert, @@ -395,7 +395,7 @@ } bool ssl_add_cert_chain(SSL_HANDSHAKE *hs, CBB *cbb) { - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { return CBB_add_u24(cbb, 0); } @@ -728,7 +728,7 @@ bool ssl_on_certificate_selected(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { // Nothing to do. return true; }
diff --git a/ssl/ssl_privkey.cc b/ssl/ssl_privkey.cc index e716c9a..16888b9 100644 --- a/ssl/ssl_privkey.cc +++ b/ssl/ssl_privkey.cc
@@ -133,8 +133,9 @@ return NULL; } -bool ssl_has_private_key(const SSL_CONFIG *cfg) { - return cfg->cert->privatekey != nullptr || cfg->cert->key_method != nullptr; +bool ssl_has_private_key(const SSL_HANDSHAKE *hs) { + return (hs->config->cert->privatekey != nullptr || + hs->config->cert->key_method != nullptr); } static bool pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc index eb3a38b..841482f 100644 --- a/ssl/ssl_x509.cc +++ b/ssl/ssl_x509.cc
@@ -448,7 +448,7 @@ // Only build a chain if there are no intermediates configured and the feature // isn't disabled. if ((hs->ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || - !ssl_has_certificate(hs->config) || hs->config->cert->chain == NULL || + !ssl_has_certificate(hs) || hs->config->cert->chain == NULL || sk_CRYPTO_BUFFER_num(hs->config->cert->chain.get()) > 1) { return 1; } @@ -1223,7 +1223,8 @@ assert(ssl->config); return -1; } - if (ssl_has_certificate(ssl->config.get()) || + + if (ssl_has_certificate(ssl->s3->hs.get()) || ssl->ctx->client_cert_cb == NULL) { return 1; }
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc index f6e359c..605942a 100644 --- a/ssl/tls13_both.cc +++ b/ssl/tls13_both.cc
@@ -441,7 +441,7 @@ return false; } - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { return ssl_add_message_cbb(ssl, cbb.get()); }
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc index 0ab4021..e7d6dae 100644 --- a/ssl/tls13_client.cc +++ b/ssl/tls13_client.cc
@@ -685,7 +685,7 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) { // Don't send CertificateVerify if there is no certificate. - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { hs->tls13_state = state_complete_second_flight; return ssl_hs_ok; }
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc index efdb602..562fecb 100644 --- a/ssl/tls13_server.cc +++ b/ssl/tls13_server.cc
@@ -662,7 +662,7 @@ // Send the server Certificate message, if necessary. if (!ssl->s3->session_reused) { - if (!ssl_has_certificate(hs->config)) { + if (!ssl_has_certificate(hs)) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); return ssl_hs_error; }