Move tmp.extended_master_secret to SSL_HANDSHAKE.
The two non-trivial changes are:
1. The public API now queries it out of the session. There is a long
comment over the old field explaining why the state was separate, but
this predates EMS being forbidden from changing across resumption. It
is not possible for established_session and the socket to disagree on
EMS.
2. Since SSL_HANDSHAKE gets reset on each handshake, the check that EMS
does not change on renego looks different. I've reworked that function a
bit, but it should have the same effect.
Change-Id: If72e5291f79681381cf4d8ceab267f76618b7c3d
Reviewed-on: https://boringssl-review.googlesource.com/13910
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index e6b8c09..c4f5e8e 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -998,8 +998,7 @@
}
if (ssl->session != NULL &&
- ssl->s3->tmp.extended_master_secret !=
- ssl->session->extended_master_secret) {
+ hs->extended_master_secret != ssl->session->extended_master_secret) {
al = SSL_AD_HANDSHAKE_FAILURE;
if (ssl->session->extended_master_secret) {
OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
@@ -1649,7 +1648,7 @@
if (hs->new_session->master_key_length == 0) {
goto err;
}
- hs->new_session->extended_master_secret = ssl->s3->tmp.extended_master_secret;
+ hs->new_session->extended_master_secret = hs->extended_master_secret;
OPENSSL_cleanse(pms, pms_len);
OPENSSL_free(pms);
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index fdf78e4..51338e2 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -933,8 +933,7 @@
}
if (session != NULL) {
- if (session->extended_master_secret &&
- !ssl->s3->tmp.extended_master_secret) {
+ if (session->extended_master_secret && !hs->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;
@@ -945,8 +944,7 @@
if (!ssl_session_is_resumable(hs, 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) {
+ hs->extended_master_secret != session->extended_master_secret) {
SSL_SESSION_free(session);
session = NULL;
}
@@ -1743,7 +1741,7 @@
if (hs->new_session->master_key_length == 0) {
goto err;
}
- hs->new_session->extended_master_secret = ssl->s3->tmp.extended_master_secret;
+ hs->new_session->extended_master_secret = hs->extended_master_secret;
OPENSSL_cleanse(premaster_secret, premaster_secret_len);
OPENSSL_free(premaster_secret);
diff --git a/ssl/internal.h b/ssl/internal.h
index 040b6fd..b2c9fcd 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1107,6 +1107,10 @@
/* v2_clienthello is one if we received a V2ClientHello. */
unsigned v2_clienthello:1;
+ /* extended_master_secret is one if the extended master secret extension is
+ * negotiated in this handshake. */
+ unsigned extended_master_secret:1;
+
/* client_version is the value sent or received in the ClientHello version. */
uint16_t client_version;
} /* SSL_HANDSHAKE */;
@@ -1619,14 +1623,6 @@
uint8_t new_mac_secret_len;
uint8_t new_key_len;
uint8_t new_fixed_iv_len;
-
- /* extended_master_secret indicates whether the extended master secret
- * computation is used in this handshake. Note that this is different from
- * whether it was used for the current session. If this is a resumption
- * handshake then EMS might be negotiated in the client and server hello
- * messages, but it doesn't matter if the session that's being resumed
- * didn't use it to create the master secret initially. */
- char extended_master_secret;
} tmp;
/* established_session is the session established by the connection. This
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 517ddbb..d0151bb 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1224,11 +1224,26 @@
int SSL_get_verify_mode(const SSL *ssl) { return ssl->verify_mode; }
int SSL_get_extms_support(const SSL *ssl) {
+ /* TLS 1.3 does not require extended master secret and always reports as
+ * supporting it. */
if (!ssl->s3->have_version) {
return 0;
}
- return ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
- ssl->s3->tmp.extended_master_secret == 1;
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ return 1;
+ }
+
+ /* If the initial handshake completed, query the established session. */
+ if (ssl->s3->established_session != NULL) {
+ return ssl->s3->established_session->extended_master_secret;
+ }
+
+ /* Otherwise, query the in-progress handshake. */
+ if (ssl->s3->hs != NULL) {
+ return ssl->s3->hs->extended_master_secret;
+ }
+ assert(0);
+ return 0;
}
int SSL_CTX_get_read_ahead(const SSL_CTX *ctx) { return 0; }
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 909d6df..9f11e05 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -473,7 +473,7 @@
const uint8_t *premaster,
size_t premaster_len) {
const SSL *ssl = hs->ssl;
- if (ssl->s3->tmp.extended_master_secret) {
+ if (hs->extended_master_secret) {
uint8_t digests[EVP_MAX_MD_SIZE];
size_t digests_len;
if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) ||
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 7a9f83a..d6ef1ff 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -870,38 +870,32 @@
static int ext_ems_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
SSL *const ssl = hs->ssl;
- /* Whether EMS is negotiated may not change on renegotation. */
- if (ssl->s3->initial_handshake_complete) {
- if ((contents != NULL) != ssl->s3->tmp.extended_master_secret) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_EMS_MISMATCH);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+
+ if (contents != NULL) {
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ ssl->version == SSL3_VERSION ||
+ CBS_len(contents) != 0) {
return 0;
}
- return 1;
+ hs->extended_master_secret = 1;
}
- if (contents == NULL) {
- return 1;
- }
-
- if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
- ssl->version == SSL3_VERSION) {
+ /* Whether EMS is negotiated may not change on renegotiation. */
+ if (ssl->s3->established_session != NULL &&
+ hs->extended_master_secret !=
+ ssl->s3->established_session->extended_master_secret) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_EMS_MISMATCH);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
- if (CBS_len(contents) != 0) {
- return 0;
- }
-
- ssl->s3->tmp.extended_master_secret = 1;
return 1;
}
static int ext_ems_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
- SSL *const ssl = hs->ssl;
- uint16_t version = ssl3_protocol_version(ssl);
+ uint16_t version = ssl3_protocol_version(hs->ssl);
if (version >= TLS1_3_VERSION ||
version == SSL3_VERSION) {
return 1;
@@ -915,12 +909,12 @@
return 0;
}
- ssl->s3->tmp.extended_master_secret = 1;
+ hs->extended_master_secret = 1;
return 1;
}
static int ext_ems_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
- if (!hs->ssl->s3->tmp.extended_master_secret) {
+ if (!hs->extended_master_secret) {
return 1;
}