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;
}