Rotate the default ticket encryption key.
The ticket encryption key is rotated automatically once every 24 hours,
unless a key has been configured manually (i.e. using
|SSL_CTX_set_tlsext_ticket_keys|) or one of the custom ticket encryption
methods is used.
Change-Id: I0dfff28b33e58e96b3bbf7f94dcd6d2642f37aec
Reviewed-on: https://boringssl-review.googlesource.com/18924
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/ssl_session.cc b/ssl/ssl_session.cc
index a1c21dc..dad0656 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -437,6 +437,59 @@
return 1;
}
+int ssl_ctx_rotate_ticket_encryption_key(SSL_CTX *ctx) {
+ OPENSSL_timeval now;
+ ssl_ctx_get_current_time(ctx, &now);
+ {
+ /* Avoid acquiring a write lock in the common case (i.e. a non-default key
+ * is used or the default keys have not expired yet). */
+ MutexReadLock lock(&ctx->lock);
+ if (ctx->tlsext_ticket_key_current &&
+ (ctx->tlsext_ticket_key_current->next_rotation_tv_sec == 0 ||
+ ctx->tlsext_ticket_key_current->next_rotation_tv_sec > now.tv_sec) &&
+ (!ctx->tlsext_ticket_key_prev ||
+ ctx->tlsext_ticket_key_prev->next_rotation_tv_sec > now.tv_sec)) {
+ return 1;
+ }
+ }
+
+ MutexWriteLock lock(&ctx->lock);
+ if (!ctx->tlsext_ticket_key_current ||
+ (ctx->tlsext_ticket_key_current->next_rotation_tv_sec != 0 &&
+ ctx->tlsext_ticket_key_current->next_rotation_tv_sec <= now.tv_sec)) {
+ /* The current key has not been initialized or it is expired. */
+ auto new_key = bssl::MakeUnique<struct tlsext_ticket_key>();
+ if (!new_key) {
+ return 0;
+ }
+ OPENSSL_memset(new_key.get(), 0, sizeof(struct tlsext_ticket_key));
+ if (ctx->tlsext_ticket_key_current) {
+ /* The current key expired. Rotate it to prev and bump up its rotation
+ * timestamp. Note that even with the new rotation time it may still be
+ * expired and get droppped below. */
+ ctx->tlsext_ticket_key_current->next_rotation_tv_sec +=
+ SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL;
+ OPENSSL_free(ctx->tlsext_ticket_key_prev);
+ ctx->tlsext_ticket_key_prev = ctx->tlsext_ticket_key_current;
+ }
+ ctx->tlsext_ticket_key_current = new_key.release();
+ RAND_bytes(ctx->tlsext_ticket_key_current->name, 16);
+ RAND_bytes(ctx->tlsext_ticket_key_current->hmac_key, 16);
+ RAND_bytes(ctx->tlsext_ticket_key_current->aes_key, 16);
+ ctx->tlsext_ticket_key_current->next_rotation_tv_sec =
+ now.tv_sec + SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL;
+ }
+
+ /* Drop an expired prev key. */
+ if (ctx->tlsext_ticket_key_prev &&
+ ctx->tlsext_ticket_key_prev->next_rotation_tv_sec <= now.tv_sec) {
+ OPENSSL_free(ctx->tlsext_ticket_key_prev);
+ ctx->tlsext_ticket_key_prev = nullptr;
+ }
+
+ return 1;
+}
+
static int ssl_encrypt_ticket_with_cipher_ctx(SSL *ssl, CBB *out,
const uint8_t *session_buf,
size_t session_len) {
@@ -464,14 +517,19 @@
return 0;
}
} else {
+ /* Rotate ticket key if necessary. */
+ if (!ssl_ctx_rotate_ticket_encryption_key(tctx)) {
+ return 0;
+ }
+ MutexReadLock lock(&tctx->lock);
if (!RAND_bytes(iv, 16) ||
!EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL,
- tctx->tlsext_tick_aes_key, iv) ||
- !HMAC_Init_ex(hctx.get(), tctx->tlsext_tick_hmac_key, 16,
+ tctx->tlsext_ticket_key_current->aes_key, iv) ||
+ !HMAC_Init_ex(hctx.get(), tctx->tlsext_ticket_key_current->hmac_key, 16,
tlsext_tick_md(), NULL)) {
return 0;
}
- OPENSSL_memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+ OPENSSL_memcpy(key_name, tctx->tlsext_ticket_key_current->name, 16);
}
uint8_t *ptr;