C++ the ticket keys a bit.
While I'm here, remove the silly "tlsext_" prefix. At this point it's no longer novel that a feature is encoded in an extension. Change-Id: Ib5fbd2121333a213bdda0332885a8c90036ebc4d Reviewed-on: https://boringssl-review.googlesource.com/29592 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
0ce090acd6
commit
7bb0fbf77b
@ -2032,17 +2032,17 @@ extern const SSL_X509_METHOD ssl_crypto_x509_method;
|
|||||||
// crypto/x509.
|
// crypto/x509.
|
||||||
extern const SSL_X509_METHOD ssl_noop_x509_method;
|
extern const SSL_X509_METHOD ssl_noop_x509_method;
|
||||||
|
|
||||||
struct tlsext_ticket_key {
|
struct TicketKey {
|
||||||
static constexpr bool kAllowUniquePtr = true;
|
static constexpr bool kAllowUniquePtr = true;
|
||||||
|
|
||||||
uint8_t name[SSL_TICKET_KEY_NAME_LEN];
|
uint8_t name[SSL_TICKET_KEY_NAME_LEN] = {0};
|
||||||
uint8_t hmac_key[16];
|
uint8_t hmac_key[16] = {0};
|
||||||
uint8_t aes_key[16];
|
uint8_t aes_key[16] = {0};
|
||||||
// next_rotation_tv_sec is the time (in seconds from the epoch) when the
|
// next_rotation_tv_sec is the time (in seconds from the epoch) when the
|
||||||
// current key should be superseded by a new key, or the time when a previous
|
// current key should be superseded by a new key, or the time when a previous
|
||||||
// key should be dropped. If zero, then the key should not be automatically
|
// key should be dropped. If zero, then the key should not be automatically
|
||||||
// rotated.
|
// rotated.
|
||||||
uint64_t next_rotation_tv_sec;
|
uint64_t next_rotation_tv_sec = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace bssl
|
} // namespace bssl
|
||||||
@ -2952,17 +2952,16 @@ struct ssl_ctx_st {
|
|||||||
int (*tlsext_servername_callback)(SSL *, int *, void *) = nullptr;
|
int (*tlsext_servername_callback)(SSL *, int *, void *) = nullptr;
|
||||||
void *tlsext_servername_arg = nullptr;
|
void *tlsext_servername_arg = nullptr;
|
||||||
|
|
||||||
// RFC 4507 session ticket keys. |tlsext_ticket_key_current| may be NULL
|
// RFC 4507 session ticket keys. |ticket_key_current| may be NULL before the
|
||||||
// before the first handshake and |tlsext_ticket_key_prev| may be NULL at any
|
// first handshake and |ticket_key_prev| may be NULL at any time.
|
||||||
// time. Automatically generated ticket keys are rotated as needed at
|
// Automatically generated ticket keys are rotated as needed at handshake
|
||||||
// handshake time. Hence, all access must be synchronized through |lock|.
|
// time. Hence, all access must be synchronized through |lock|.
|
||||||
bssl::tlsext_ticket_key *tlsext_ticket_key_current = nullptr;
|
bssl::UniquePtr<bssl::TicketKey> ticket_key_current;
|
||||||
bssl::tlsext_ticket_key *tlsext_ticket_key_prev = nullptr;
|
bssl::UniquePtr<bssl::TicketKey> ticket_key_prev;
|
||||||
|
|
||||||
// Callback to support customisation of ticket key setting
|
// Callback to support customisation of ticket key setting
|
||||||
int (*tlsext_ticket_key_cb)(SSL *ssl, uint8_t *name, uint8_t *iv,
|
int (*ticket_key_cb)(SSL *ssl, uint8_t *name, uint8_t *iv,
|
||||||
EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx,
|
EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc) = nullptr;
|
||||||
int enc) = nullptr;
|
|
||||||
|
|
||||||
// Server-only: psk_identity_hint is the default identity hint to send in
|
// Server-only: psk_identity_hint is the default identity hint to send in
|
||||||
// PSK-based key exchanges.
|
// PSK-based key exchanges.
|
||||||
|
@ -569,8 +569,6 @@ ssl_ctx_st::~ssl_ctx_st() {
|
|||||||
x509_method->ssl_ctx_free(this);
|
x509_method->ssl_ctx_free(this);
|
||||||
sk_CertCompressionAlg_pop_free(cert_compression_algs,
|
sk_CertCompressionAlg_pop_free(cert_compression_algs,
|
||||||
Delete<CertCompressionAlg>);
|
Delete<CertCompressionAlg>);
|
||||||
OPENSSL_free(tlsext_ticket_key_current);
|
|
||||||
OPENSSL_free(tlsext_ticket_key_prev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
|
SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
|
||||||
@ -1675,9 +1673,9 @@ int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, size_t len) {
|
|||||||
|
|
||||||
uint8_t *out_bytes = reinterpret_cast<uint8_t *>(out);
|
uint8_t *out_bytes = reinterpret_cast<uint8_t *>(out);
|
||||||
MutexReadLock lock(&ctx->lock);
|
MutexReadLock lock(&ctx->lock);
|
||||||
OPENSSL_memcpy(out_bytes, ctx->tlsext_ticket_key_current->name, 16);
|
OPENSSL_memcpy(out_bytes, ctx->ticket_key_current->name, 16);
|
||||||
OPENSSL_memcpy(out_bytes + 16, ctx->tlsext_ticket_key_current->hmac_key, 16);
|
OPENSSL_memcpy(out_bytes + 16, ctx->ticket_key_current->hmac_key, 16);
|
||||||
OPENSSL_memcpy(out_bytes + 32, ctx->tlsext_ticket_key_current->aes_key, 16);
|
OPENSSL_memcpy(out_bytes + 32, ctx->ticket_key_current->aes_key, 16);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1689,22 +1687,19 @@ int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, size_t len) {
|
|||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!ctx->tlsext_ticket_key_current) {
|
auto key = MakeUnique<TicketKey>();
|
||||||
ctx->tlsext_ticket_key_current =
|
if (!key) {
|
||||||
(tlsext_ticket_key *)OPENSSL_malloc(sizeof(tlsext_ticket_key));
|
|
||||||
if (!ctx->tlsext_ticket_key_current) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
OPENSSL_memset(ctx->tlsext_ticket_key_current, 0, sizeof(tlsext_ticket_key));
|
|
||||||
const uint8_t *in_bytes = reinterpret_cast<const uint8_t *>(in);
|
const uint8_t *in_bytes = reinterpret_cast<const uint8_t *>(in);
|
||||||
OPENSSL_memcpy(ctx->tlsext_ticket_key_current->name, in_bytes, 16);
|
OPENSSL_memcpy(key->name, in_bytes, 16);
|
||||||
OPENSSL_memcpy(ctx->tlsext_ticket_key_current->hmac_key, in_bytes + 16, 16);
|
OPENSSL_memcpy(key->hmac_key, in_bytes + 16, 16);
|
||||||
OPENSSL_memcpy(ctx->tlsext_ticket_key_current->aes_key, in_bytes + 32, 16);
|
OPENSSL_memcpy(key->aes_key, in_bytes + 32, 16);
|
||||||
OPENSSL_free(ctx->tlsext_ticket_key_prev);
|
// Disable automatic key rotation for manually-configured keys. This is now
|
||||||
ctx->tlsext_ticket_key_prev = nullptr;
|
// the caller's responsibility.
|
||||||
// Disable automatic key rotation.
|
key->next_rotation_tv_sec = 0;
|
||||||
ctx->tlsext_ticket_key_current->next_rotation_tv_sec = 0;
|
ctx->ticket_key_current = std::move(key);
|
||||||
|
ctx->ticket_key_prev.reset();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1712,7 +1707,7 @@ int SSL_CTX_set_tlsext_ticket_key_cb(
|
|||||||
SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv,
|
SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv,
|
||||||
EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
|
EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
|
||||||
int encrypt)) {
|
int encrypt)) {
|
||||||
ctx->tlsext_ticket_key_cb = callback;
|
ctx->ticket_key_cb = callback;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,47 +414,44 @@ int ssl_ctx_rotate_ticket_encryption_key(SSL_CTX *ctx) {
|
|||||||
// Avoid acquiring a write lock in the common case (i.e. a non-default key
|
// 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).
|
// is used or the default keys have not expired yet).
|
||||||
MutexReadLock lock(&ctx->lock);
|
MutexReadLock lock(&ctx->lock);
|
||||||
if (ctx->tlsext_ticket_key_current &&
|
if (ctx->ticket_key_current &&
|
||||||
(ctx->tlsext_ticket_key_current->next_rotation_tv_sec == 0 ||
|
(ctx->ticket_key_current->next_rotation_tv_sec == 0 ||
|
||||||
ctx->tlsext_ticket_key_current->next_rotation_tv_sec > now.tv_sec) &&
|
ctx->ticket_key_current->next_rotation_tv_sec > now.tv_sec) &&
|
||||||
(!ctx->tlsext_ticket_key_prev ||
|
(!ctx->ticket_key_prev ||
|
||||||
ctx->tlsext_ticket_key_prev->next_rotation_tv_sec > now.tv_sec)) {
|
ctx->ticket_key_prev->next_rotation_tv_sec > now.tv_sec)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexWriteLock lock(&ctx->lock);
|
MutexWriteLock lock(&ctx->lock);
|
||||||
if (!ctx->tlsext_ticket_key_current ||
|
if (!ctx->ticket_key_current ||
|
||||||
(ctx->tlsext_ticket_key_current->next_rotation_tv_sec != 0 &&
|
(ctx->ticket_key_current->next_rotation_tv_sec != 0 &&
|
||||||
ctx->tlsext_ticket_key_current->next_rotation_tv_sec <= now.tv_sec)) {
|
ctx->ticket_key_current->next_rotation_tv_sec <= now.tv_sec)) {
|
||||||
// The current key has not been initialized or it is expired.
|
// The current key has not been initialized or it is expired.
|
||||||
auto new_key = bssl::MakeUnique<struct tlsext_ticket_key>();
|
auto new_key = bssl::MakeUnique<TicketKey>();
|
||||||
if (!new_key) {
|
if (!new_key) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
OPENSSL_memset(new_key.get(), 0, sizeof(struct tlsext_ticket_key));
|
RAND_bytes(new_key->name, 16);
|
||||||
if (ctx->tlsext_ticket_key_current) {
|
RAND_bytes(new_key->hmac_key, 16);
|
||||||
|
RAND_bytes(new_key->aes_key, 16);
|
||||||
|
new_key->next_rotation_tv_sec =
|
||||||
|
now.tv_sec + SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL;
|
||||||
|
if (ctx->ticket_key_current) {
|
||||||
// The current key expired. Rotate it to prev and bump up its rotation
|
// 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
|
// timestamp. Note that even with the new rotation time it may still be
|
||||||
// expired and get droppped below.
|
// expired and get dropped below.
|
||||||
ctx->tlsext_ticket_key_current->next_rotation_tv_sec +=
|
ctx->ticket_key_current->next_rotation_tv_sec +=
|
||||||
SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL;
|
SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL;
|
||||||
OPENSSL_free(ctx->tlsext_ticket_key_prev);
|
ctx->ticket_key_prev = std::move(ctx->ticket_key_current);
|
||||||
ctx->tlsext_ticket_key_prev = ctx->tlsext_ticket_key_current;
|
|
||||||
}
|
}
|
||||||
ctx->tlsext_ticket_key_current = new_key.release();
|
ctx->ticket_key_current = std::move(new_key);
|
||||||
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.
|
// Drop an expired prev key.
|
||||||
if (ctx->tlsext_ticket_key_prev &&
|
if (ctx->ticket_key_prev &&
|
||||||
ctx->tlsext_ticket_key_prev->next_rotation_tv_sec <= now.tv_sec) {
|
ctx->ticket_key_prev->next_rotation_tv_sec <= now.tv_sec) {
|
||||||
OPENSSL_free(ctx->tlsext_ticket_key_prev);
|
ctx->ticket_key_prev.reset();
|
||||||
ctx->tlsext_ticket_key_prev = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -481,8 +478,8 @@ static int ssl_encrypt_ticket_with_cipher_ctx(SSL_HANDSHAKE *hs, CBB *out,
|
|||||||
SSL_CTX *tctx = hs->ssl->session_ctx.get();
|
SSL_CTX *tctx = hs->ssl->session_ctx.get();
|
||||||
uint8_t iv[EVP_MAX_IV_LENGTH];
|
uint8_t iv[EVP_MAX_IV_LENGTH];
|
||||||
uint8_t key_name[16];
|
uint8_t key_name[16];
|
||||||
if (tctx->tlsext_ticket_key_cb != NULL) {
|
if (tctx->ticket_key_cb != NULL) {
|
||||||
if (tctx->tlsext_ticket_key_cb(hs->ssl, key_name, iv, ctx.get(), hctx.get(),
|
if (tctx->ticket_key_cb(hs->ssl, key_name, iv, ctx.get(), hctx.get(),
|
||||||
1 /* encrypt */) < 0) {
|
1 /* encrypt */) < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -494,12 +491,12 @@ static int ssl_encrypt_ticket_with_cipher_ctx(SSL_HANDSHAKE *hs, CBB *out,
|
|||||||
MutexReadLock lock(&tctx->lock);
|
MutexReadLock lock(&tctx->lock);
|
||||||
if (!RAND_bytes(iv, 16) ||
|
if (!RAND_bytes(iv, 16) ||
|
||||||
!EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL,
|
!EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL,
|
||||||
tctx->tlsext_ticket_key_current->aes_key, iv) ||
|
tctx->ticket_key_current->aes_key, iv) ||
|
||||||
!HMAC_Init_ex(hctx.get(), tctx->tlsext_ticket_key_current->hmac_key, 16,
|
!HMAC_Init_ex(hctx.get(), tctx->ticket_key_current->hmac_key, 16,
|
||||||
tlsext_tick_md(), NULL)) {
|
tlsext_tick_md(), NULL)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
OPENSSL_memcpy(key_name, tctx->tlsext_ticket_key_current->name, 16);
|
OPENSSL_memcpy(key_name, tctx->ticket_key_current->name, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
@ -3490,7 +3490,7 @@ static enum ssl_ticket_aead_result_t ssl_decrypt_ticket_with_cb(
|
|||||||
ScopedEVP_CIPHER_CTX cipher_ctx;
|
ScopedEVP_CIPHER_CTX cipher_ctx;
|
||||||
ScopedHMAC_CTX hmac_ctx;
|
ScopedHMAC_CTX hmac_ctx;
|
||||||
const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN;
|
const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN;
|
||||||
int cb_ret = hs->ssl->session_ctx->tlsext_ticket_key_cb(
|
int cb_ret = hs->ssl->session_ctx->ticket_key_cb(
|
||||||
hs->ssl, (uint8_t *)ticket /* name */, (uint8_t *)iv, cipher_ctx.get(),
|
hs->ssl, (uint8_t *)ticket /* name */, (uint8_t *)iv, cipher_ctx.get(),
|
||||||
hmac_ctx.get(), 0 /* decrypt */);
|
hmac_ctx.get(), 0 /* decrypt */);
|
||||||
if (cb_ret < 0) {
|
if (cb_ret < 0) {
|
||||||
@ -3522,15 +3522,15 @@ static enum ssl_ticket_aead_result_t ssl_decrypt_ticket_with_ticket_keys(
|
|||||||
ScopedHMAC_CTX hmac_ctx;
|
ScopedHMAC_CTX hmac_ctx;
|
||||||
{
|
{
|
||||||
MutexReadLock lock(&ctx->lock);
|
MutexReadLock lock(&ctx->lock);
|
||||||
const tlsext_ticket_key *key;
|
const TicketKey *key;
|
||||||
if (ctx->tlsext_ticket_key_current &&
|
if (ctx->ticket_key_current &&
|
||||||
!OPENSSL_memcmp(ctx->tlsext_ticket_key_current->name, ticket,
|
!OPENSSL_memcmp(ctx->ticket_key_current->name, ticket,
|
||||||
SSL_TICKET_KEY_NAME_LEN)) {
|
SSL_TICKET_KEY_NAME_LEN)) {
|
||||||
key = ctx->tlsext_ticket_key_current;
|
key = ctx->ticket_key_current.get();
|
||||||
} else if (ctx->tlsext_ticket_key_prev &&
|
} else if (ctx->ticket_key_prev &&
|
||||||
!OPENSSL_memcmp(ctx->tlsext_ticket_key_prev->name, ticket,
|
!OPENSSL_memcmp(ctx->ticket_key_prev->name, ticket,
|
||||||
SSL_TICKET_KEY_NAME_LEN)) {
|
SSL_TICKET_KEY_NAME_LEN)) {
|
||||||
key = ctx->tlsext_ticket_key_prev;
|
key = ctx->ticket_key_prev.get();
|
||||||
} else {
|
} else {
|
||||||
return ssl_ticket_aead_ignore_ticket;
|
return ssl_ticket_aead_ignore_ticket;
|
||||||
}
|
}
|
||||||
@ -3589,14 +3589,14 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
|
|||||||
result = ssl_decrypt_ticket_with_method(
|
result = ssl_decrypt_ticket_with_method(
|
||||||
hs, &plaintext, &plaintext_len, out_renew_ticket, ticket, ticket_len);
|
hs, &plaintext, &plaintext_len, out_renew_ticket, ticket, ticket_len);
|
||||||
} else {
|
} else {
|
||||||
// Ensure there is room for the key name and the largest IV
|
// Ensure there is room for the key name and the largest IV |ticket_key_cb|
|
||||||
// |tlsext_ticket_key_cb| may try to consume. The real limit may be lower,
|
// may try to consume. The real limit may be lower, but the maximum IV
|
||||||
// but the maximum IV length should be well under the minimum size for the
|
// length should be well under the minimum size for the session material and
|
||||||
// session material and HMAC.
|
// HMAC.
|
||||||
if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) {
|
if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) {
|
||||||
return ssl_ticket_aead_ignore_ticket;
|
return ssl_ticket_aead_ignore_ticket;
|
||||||
}
|
}
|
||||||
if (hs->ssl->session_ctx->tlsext_ticket_key_cb != NULL) {
|
if (hs->ssl->session_ctx->ticket_key_cb != NULL) {
|
||||||
result = ssl_decrypt_ticket_with_cb(hs, &plaintext, &plaintext_len,
|
result = ssl_decrypt_ticket_with_cb(hs, &plaintext, &plaintext_len,
|
||||||
out_renew_ticket, ticket, ticket_len);
|
out_renew_ticket, ticket, ticket_len);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user