SSL_CONFIG: new struct for sheddable handshake configuration.
|SSL_CONFIG| is a container for bits of configuration that are
unneeded after the handshake completes. By default it is retained for
the life of the |SSL|, but it may be shed at the caller's option by
calling SSL_set_shed_handshake_config(). This is incompatible with
renegotiation, and with SSL_clear().
|SSL_CONFIG| is reachable by |ssl->config| and by |hs->config|. The
latter is always non-NULL. To avoid null checks, I've changed the
signature of a number of functions from |SSL*| arguments to
|SSL_HANDSHAKE*| arguments.
When configuration has been shed, setters that touch |SSL_CONFIG|
return an error value if that is possible. Setters that return |void|
do nothing.
Getters that request |SSL_CONFIG| values will fail with an |assert| if
the configuration has been shed. When asserts are compiled out, they
will return an error value.
The aim of this commit is to simplify analysis of split-handshakes by
making it obvious that some bits of state have no effects beyond the
handshake. It also cuts down on memory usage.
Of note: |SSL_CTX| is still reachable after the configuration has been
shed, and a couple things need to be retained only for the sake of
post-handshake hooks. Perhaps these can be fixed in time.
Change-Id: Idf09642e0518945b81a1e9fcd7331cc9cf7cc2d6
Bug: 123
Reviewed-on: https://boringssl-review.googlesource.com/27644
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
index 272fc55..b992e9a 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -381,13 +381,13 @@
if (version >= TLS1_3_VERSION) {
// TLS 1.3 uses tickets as authenticators, so we are willing to use them for
// longer.
- session->timeout = ssl->session_ctx->session_psk_dhe_timeout;
+ session->timeout = hs->config->session_ctx->session_psk_dhe_timeout;
session->auth_timeout = SSL_DEFAULT_SESSION_AUTH_TIMEOUT;
} else {
// TLS 1.2 resumption does not incorporate new key material, so we use a
// much shorter timeout.
- session->timeout = ssl->session_ctx->session_timeout;
- session->auth_timeout = ssl->session_ctx->session_timeout;
+ session->timeout = hs->config->session_ctx->session_timeout;
+ session->auth_timeout = hs->config->session_ctx->session_timeout;
}
if (is_server) {
@@ -405,13 +405,13 @@
session->session_id_length = 0;
}
- if (ssl->cert->sid_ctx_length > sizeof(session->sid_ctx)) {
+ if (hs->config->cert->sid_ctx_length > sizeof(session->sid_ctx)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- OPENSSL_memcpy(session->sid_ctx, ssl->cert->sid_ctx,
- ssl->cert->sid_ctx_length);
- session->sid_ctx_length = ssl->cert->sid_ctx_length;
+ OPENSSL_memcpy(session->sid_ctx, hs->config->cert->sid_ctx,
+ hs->config->cert->sid_ctx_length);
+ session->sid_ctx_length = hs->config->cert->sid_ctx_length;
// The session is marked not resumable until it is completely filled in.
session->not_resumable = 1;
@@ -475,7 +475,7 @@
return 1;
}
-static int ssl_encrypt_ticket_with_cipher_ctx(SSL *ssl, CBB *out,
+static int ssl_encrypt_ticket_with_cipher_ctx(SSL_HANDSHAKE *hs, CBB *out,
const uint8_t *session_buf,
size_t session_len) {
ScopedEVP_CIPHER_CTX ctx;
@@ -493,11 +493,11 @@
// Initialize HMAC and cipher contexts. If callback present it does all the
// work otherwise use generated values from parent ctx.
- SSL_CTX *tctx = ssl->session_ctx;
+ SSL_CTX *tctx = hs->config->session_ctx;
uint8_t iv[EVP_MAX_IV_LENGTH];
uint8_t key_name[16];
if (tctx->tlsext_ticket_key_cb != NULL) {
- if (tctx->tlsext_ticket_key_cb(ssl, key_name, iv, ctx.get(), hctx.get(),
+ if (tctx->tlsext_ticket_key_cb(hs->ssl, key_name, iv, ctx.get(), hctx.get(),
1 /* encrypt */) < 0) {
return 0;
}
@@ -554,11 +554,12 @@
return 1;
}
-static int ssl_encrypt_ticket_with_method(SSL *ssl, CBB *out,
+static int ssl_encrypt_ticket_with_method(SSL_HANDSHAKE *hs, CBB *out,
const uint8_t *session_buf,
size_t session_len) {
- const SSL_TICKET_AEAD_METHOD *method = ssl->session_ctx->ticket_aead_method;
- const size_t max_overhead = method->max_overhead(ssl);
+ const SSL_TICKET_AEAD_METHOD *method =
+ hs->config->session_ctx->ticket_aead_method;
+ const size_t max_overhead = method->max_overhead(hs->ssl);
const size_t max_out = session_len + max_overhead;
if (max_out < max_overhead) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
@@ -571,7 +572,8 @@
}
size_t out_len;
- if (!method->seal(ssl, ptr, &out_len, max_out, session_buf, session_len)) {
+ if (!method->seal(hs->ssl, ptr, &out_len, max_out, session_buf,
+ session_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TICKET_ENCRYPTION_FAILED);
return 0;
}
@@ -583,7 +585,8 @@
return 1;
}
-int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) {
+int ssl_encrypt_ticket(SSL_HANDSHAKE *hs, CBB *out,
+ const SSL_SESSION *session) {
// Serialize the SSL_SESSION to be encoded into the ticket.
uint8_t *session_buf = NULL;
size_t session_len;
@@ -592,25 +595,25 @@
}
int ret = 0;
- if (ssl->session_ctx->ticket_aead_method) {
- ret = ssl_encrypt_ticket_with_method(ssl, out, session_buf, session_len);
+ if (hs->config->session_ctx->ticket_aead_method) {
+ ret = ssl_encrypt_ticket_with_method(hs, out, session_buf, session_len);
} else {
- ret =
- ssl_encrypt_ticket_with_cipher_ctx(ssl, out, session_buf, session_len);
+ ret = ssl_encrypt_ticket_with_cipher_ctx(hs, out, session_buf, session_len);
}
OPENSSL_free(session_buf);
return ret;
}
-int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session) {
+int ssl_session_is_context_valid(const SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session) {
if (session == NULL) {
return 0;
}
- return session->sid_ctx_length == ssl->cert->sid_ctx_length &&
- OPENSSL_memcmp(session->sid_ctx, ssl->cert->sid_ctx,
- ssl->cert->sid_ctx_length) == 0;
+ return session->sid_ctx_length == hs->config->cert->sid_ctx_length &&
+ OPENSSL_memcmp(session->sid_ctx, hs->config->cert->sid_ctx,
+ hs->config->cert->sid_ctx_length) == 0;
}
int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session) {
@@ -632,14 +635,14 @@
int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
const SSL_SESSION *session) {
const SSL *const ssl = hs->ssl;
- return ssl_session_is_context_valid(ssl, session) &&
+ return ssl_session_is_context_valid(hs, session) &&
// The session must have been created by the same type of end point as
// we're now using it with.
ssl->server == session->is_server &&
// The session must not be expired.
ssl_session_is_time_valid(ssl, session) &&
/* Only resume if the session's version matches the negotiated
- * version. */
+ * version. */
ssl->version == session->ssl_version &&
// Only resume if the session's cipher matches the negotiated one.
hs->new_cipher == session->cipher &&
@@ -649,14 +652,14 @@
((sk_CRYPTO_BUFFER_num(session->certs) == 0 &&
!session->peer_sha256_valid) ||
session->peer_sha256_valid ==
- ssl->retain_only_sha256_of_client_certs);
+ hs->config->retain_only_sha256_of_client_certs);
}
// ssl_lookup_session looks up |session_id| in the session cache and sets
// |*out_session| to an |SSL_SESSION| object if found.
static enum ssl_hs_wait_t ssl_lookup_session(
- SSL *ssl, UniquePtr<SSL_SESSION> *out_session, const uint8_t *session_id,
- size_t session_id_len) {
+ SSL_HANDSHAKE *hs, UniquePtr<SSL_SESSION> *out_session,
+ const uint8_t *session_id, size_t session_id_len) {
out_session->reset();
if (session_id_len == 0 || session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
@@ -665,15 +668,16 @@
UniquePtr<SSL_SESSION> session;
// Try the internal cache, if it exists.
- if (!(ssl->session_ctx->session_cache_mode &
+ if (!(hs->config->session_ctx->session_cache_mode &
SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) {
SSL_SESSION data;
- data.ssl_version = ssl->version;
+ data.ssl_version = hs->ssl->version;
data.session_id_length = session_id_len;
OPENSSL_memcpy(data.session_id, session_id, session_id_len);
- MutexReadLock lock(&ssl->session_ctx->lock);
- session.reset(lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &data));
+ MutexReadLock lock(&hs->config->session_ctx->lock);
+ session.reset(
+ lh_SSL_SESSION_retrieve(hs->config->session_ctx->sessions, &data));
if (session) {
// |lh_SSL_SESSION_retrieve| returns a non-owning pointer.
SSL_SESSION_up_ref(session.get());
@@ -682,10 +686,10 @@
}
// Fall back to the external cache, if it exists.
- if (!session && ssl->session_ctx->get_session_cb != nullptr) {
+ if (!session && hs->config->session_ctx->get_session_cb != nullptr) {
int copy = 1;
- session.reset(ssl->session_ctx->get_session_cb(ssl, session_id,
- session_id_len, ©));
+ session.reset(hs->config->session_ctx->get_session_cb(
+ hs->ssl, session_id, session_id_len, ©));
if (!session) {
return ssl_hs_ok;
}
@@ -704,15 +708,15 @@
}
// Add the externally cached session to the internal cache if necessary.
- if (!(ssl->session_ctx->session_cache_mode &
+ if (!(hs->config->session_ctx->session_cache_mode &
SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
- SSL_CTX_add_session(ssl->session_ctx, session.get());
+ SSL_CTX_add_session(hs->config->session_ctx, session.get());
}
}
- if (session && !ssl_session_is_time_valid(ssl, session.get())) {
+ if (session && !ssl_session_is_time_valid(hs->ssl, session.get())) {
// The session was from the cache, so remove it.
- SSL_CTX_remove_session(ssl->session_ctx, session.get());
+ SSL_CTX_remove_session(hs->config->session_ctx, session.get());
session.reset();
}
@@ -720,13 +724,13 @@
return ssl_hs_ok;
}
-enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl,
+enum ssl_hs_wait_t ssl_get_prev_session(SSL_HANDSHAKE *hs,
UniquePtr<SSL_SESSION> *out_session,
bool *out_tickets_supported,
bool *out_renew_ticket,
const SSL_CLIENT_HELLO *client_hello) {
// This is used only by servers.
- assert(ssl->server);
+ assert(hs->ssl->server);
UniquePtr<SSL_SESSION> session;
bool renew_ticket = false;
@@ -734,12 +738,12 @@
const uint8_t *ticket = NULL;
size_t ticket_len = 0;
const bool tickets_supported =
- !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) &&
- ssl->version > SSL3_VERSION &&
+ !(SSL_get_options(hs->ssl) & SSL_OP_NO_TICKET) &&
+ hs->ssl->version > SSL3_VERSION &&
SSL_early_callback_ctx_extension_get(
client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len);
if (tickets_supported && ticket_len > 0) {
- switch (ssl_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len,
+ switch (ssl_process_ticket(hs, &session, &renew_ticket, ticket, ticket_len,
client_hello->session_id,
client_hello->session_id_len)) {
case ssl_ticket_aead_success:
@@ -755,7 +759,7 @@
} else {
// The client didn't send a ticket, so the session ID is a real ID.
enum ssl_hs_wait_t lookup_ret = ssl_lookup_session(
- ssl, &session, client_hello->session_id, client_hello->session_id_len);
+ hs, &session, client_hello->session_id, client_hello->session_id_len);
if (lookup_ret != ssl_hs_ok) {
return lookup_ret;
}