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>
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 1c61cdf..ff91697 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -748,84 +748,6 @@
}
if (ssl->state == SSL3_ST_SR_CLNT_HELLO_D) {
- /* 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)) {
- case ssl_session_success:
- break;
- case ssl_session_error:
- goto err;
- case ssl_session_retry:
- ssl->rwstate = SSL_PENDING_SESSION;
- goto err;
- }
-
- if (session != NULL) {
- if (session->extended_master_secret &&
- !ssl->s3->tmp.extended_master_secret) {
- /* A ClientHello without EMS that attempts to resume a session with EMS
- * is fatal to the connection. */
- al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
- goto f_err;
- }
-
- if (!ssl_session_is_resumable(ssl, session) ||
- /* If the client offers the EMS extension, but the previous session
- * didn't use it, then negotiate a new session. */
- ssl->s3->tmp.extended_master_secret !=
- session->extended_master_secret) {
- SSL_SESSION_free(session);
- session = NULL;
- }
- }
-
- if (session != NULL) {
- /* Use the old session. */
- ssl->s3->hs->ticket_expected = renew_ticket;
- ssl->session = session;
- session = NULL;
- ssl->s3->session_reused = 1;
- } else {
- ssl->s3->hs->ticket_expected = tickets_supported;
- ssl_set_session(ssl, NULL);
- if (!ssl_get_new_session(ssl, 1 /* server */)) {
- goto err;
- }
-
- /* Clear the session ID if we want the session to be single-use. */
- if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
- ssl->s3->new_session->session_id_length = 0;
- }
- }
-
- if (ssl->ctx->dos_protection_cb != NULL &&
- ssl->ctx->dos_protection_cb(&client_hello) == 0) {
- /* Connection rejected for DOS reasons. */
- al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
- 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(
- &client_hello, (uint16_t)ssl->session->cipher->id)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING);
- goto f_err;
- }
-
- 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);
@@ -840,6 +762,82 @@
}
}
+ 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)) {
+ case ssl_session_success:
+ break;
+ case ssl_session_error:
+ goto err;
+ case ssl_session_retry:
+ ssl->rwstate = SSL_PENDING_SESSION;
+ goto err;
+ }
+
+ if (session != NULL) {
+ if (session->extended_master_secret &&
+ !ssl->s3->tmp.extended_master_secret) {
+ /* A ClientHello without EMS that attempts to resume a session with EMS
+ * is fatal to the connection. */
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ goto f_err;
+ }
+
+ if (!ssl_session_is_resumable(ssl, session) ||
+ /* If the client offers the EMS extension, but the previous session
+ * didn't use it, then negotiate a new session. */
+ ssl->s3->tmp.extended_master_secret !=
+ session->extended_master_secret) {
+ SSL_SESSION_free(session);
+ session = NULL;
+ }
+ }
+
+ if (session != NULL) {
+ /* Use the old session. */
+ ssl->s3->hs->ticket_expected = renew_ticket;
+ ssl->session = session;
+ session = NULL;
+ ssl->s3->session_reused = 1;
+ } else {
+ ssl->s3->hs->ticket_expected = tickets_supported;
+ ssl_set_session(ssl, NULL);
+ if (!ssl_get_new_session(ssl, 1 /* server */)) {
+ goto err;
+ }
+
+ /* Clear the session ID if we want the session to be single-use. */
+ if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+ ssl->s3->new_session->session_id_length = 0;
+ }
+ }
+
+ if (ssl->ctx->dos_protection_cb != NULL &&
+ ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+ /* Connection rejected for DOS reasons. */
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+ goto f_err;
+ }
+
+ if (ssl->session != NULL) {
+ /* Check that the cipher is in the list. */
+ if (!ssl_client_cipher_list_contains_cipher(
+ &client_hello, (uint16_t)ssl->session->cipher->id)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING);
+ goto f_err;
+ }
+
+ ssl->s3->tmp.new_cipher = ssl->session->cipher;
+ } else {
const SSL_CIPHER *c =
ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl));
if (c == NULL) {