Call cert_cb before resolving resumption.

This is in preparation for determining the cipher suite (which, in TLS
1.2, requires the certificate be known) before resumption.

Note this has caller-visible effects:

- cert_cb is now called whether resumption occurs or not. Our only
  consumer which uses this as a server is Node which will require a
  patch to fix up their mucking about with SSL_get_session. (But the
  patch should be quite upstreamable. More 1.1.0-compatible and
  generally saner.)

- cert_cb is now called before new_session_cb and dos_protection_cb.

BUG=116

Change-Id: I6cc745757f63281fad714d4548f23880570204b0
Reviewed-on: https://boringssl-review.googlesource.com/11846
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
David Benjamin 2016-11-16 19:07:53 +09:00 committed by CQ bot account: commit-bot@chromium.org
parent 4eb95ccfd6
commit 34202b93b6
2 changed files with 145 additions and 150 deletions

View File

@ -748,10 +748,29 @@ static int ssl3_get_client_hello(SSL *ssl) {
}
if (ssl->state == SSL3_ST_SR_CLNT_HELLO_D) {
/* Call |cert_cb| to update server certificates if required. */
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
if (rv == 0) {
al = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
goto f_err;
}
if (rv < 0) {
ssl->rwstate = SSL_X509_LOOKUP;
goto err;
}
}
ssl->state = SSL3_ST_SR_CLNT_HELLO_E;
}
assert(ssl->state == SSL3_ST_SR_CLNT_HELLO_E);
/* Determine whether we are doing session resumption. */
int tickets_supported = 0, renew_ticket = 0;
switch (ssl_get_prev_session(ssl, &session, &tickets_supported,
&renew_ticket, &client_hello)) {
switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket,
&client_hello)) {
case ssl_session_success:
break;
case ssl_session_error:
@ -808,13 +827,6 @@ static int ssl3_get_client_hello(SSL *ssl) {
goto f_err;
}
ssl->state = SSL3_ST_SR_CLNT_HELLO_E;
}
/* Determine the remaining connection parameters. This is a separate state so
* |cert_cb| does not cause earlier logic to run multiple times. */
assert(ssl->state == SSL3_ST_SR_CLNT_HELLO_E);
if (ssl->session != NULL) {
/* Check that the cipher is in the list. */
if (!ssl_client_cipher_list_contains_cipher(
@ -826,20 +838,6 @@ static int ssl3_get_client_hello(SSL *ssl) {
ssl->s3->tmp.new_cipher = ssl->session->cipher;
} else {
/* Call |cert_cb| to update server certificates if required. */
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
if (rv == 0) {
al = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
goto f_err;
}
if (rv < 0) {
ssl->rwstate = SSL_X509_LOOKUP;
goto err;
}
}
const SSL_CIPHER *c =
ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl));
if (c == NULL) {

View File

@ -123,6 +123,75 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
hs->state = state_select_parameters;
return ssl_hs_ok;
}
static const SSL_CIPHER *choose_tls13_cipher(
const SSL *ssl, const struct ssl_early_callback_ctx *client_hello) {
if (client_hello->cipher_suites_len % 2 != 0) {
return NULL;
}
CBS cipher_suites;
CBS_init(&cipher_suites, client_hello->cipher_suites,
client_hello->cipher_suites_len);
const int aes_is_fine = EVP_has_aes_hardware();
const SSL_CIPHER *best = NULL;
while (CBS_len(&cipher_suites) > 0) {
uint16_t cipher_suite;
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
return NULL;
}
const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite);
if (candidate == NULL || !ssl_is_valid_cipher(ssl, candidate)) {
continue;
}
/* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
* ChaCha20 if we do not have AES hardware. */
if (aes_is_fine) {
return candidate;
}
if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
return candidate;
}
if (best == NULL) {
best = candidate;
}
}
return best;
}
static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) {
/* Call |cert_cb| to update server certificates if required. */
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
if (rv == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
}
if (rv < 0) {
hs->state = state_select_parameters;
return ssl_hs_x509_lookup;
}
}
struct ssl_early_callback_ctx client_hello;
if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
ssl->init_num)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
SSL_SESSION *session = NULL;
CBS pre_shared_key, binders;
@ -182,77 +251,6 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
hs->state = state_select_parameters;
return ssl_hs_ok;
}
static const SSL_CIPHER *choose_tls13_cipher(
const SSL *ssl, const struct ssl_early_callback_ctx *client_hello) {
if (client_hello->cipher_suites_len % 2 != 0) {
return NULL;
}
CBS cipher_suites;
CBS_init(&cipher_suites, client_hello->cipher_suites,
client_hello->cipher_suites_len);
const int aes_is_fine = EVP_has_aes_hardware();
const SSL_CIPHER *best = NULL;
while (CBS_len(&cipher_suites) > 0) {
uint16_t cipher_suite;
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
return NULL;
}
const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite);
if (candidate == NULL || !ssl_is_valid_cipher(ssl, candidate)) {
continue;
}
/* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
* ChaCha20 if we do not have AES hardware. */
if (aes_is_fine) {
return candidate;
}
if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
return candidate;
}
if (best == NULL) {
best = candidate;
}
}
return best;
}
static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) {
if (!ssl->s3->session_reused) {
/* Call |cert_cb| to update server certificates if required. */
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
if (rv == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
}
if (rv < 0) {
hs->state = state_select_parameters;
return ssl_hs_x509_lookup;
}
}
}
struct ssl_early_callback_ctx client_hello;
if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
ssl->init_num)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
if (ssl->s3->session_reused) {
/* Clients may not offer sessions containing unsupported ciphers. */
if (!ssl_client_cipher_list_contains_cipher(
@ -287,7 +285,6 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) {
/* Resolve ALPN after the cipher suite is selected. HTTP/2 negotiation depends
* on the cipher suite. */
uint8_t alert;
if (!ssl_negotiate_alpn(ssl, &alert, &client_hello)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;