in tls/s2n_config.c [918:984]
int s2n_config_add_ticket_crypto_key(struct s2n_config *config,
const uint8_t *name, uint32_t name_len,
uint8_t *key, uint32_t key_len,
uint64_t intro_time_in_seconds_from_epoch)
{
POSIX_ENSURE_REF(config);
POSIX_ENSURE_REF(name);
POSIX_ENSURE_REF(key);
/* both session ticket and session cache encryption/decryption can use the same key mechanism */
if (!config->use_tickets && !config->use_session_cache) {
return 0;
}
POSIX_GUARD(s2n_config_wipe_expired_ticket_crypto_keys(config, -1));
POSIX_ENSURE(key_len != 0, S2N_ERR_INVALID_TICKET_KEY_LENGTH);
uint32_t ticket_keys_len = 0;
POSIX_GUARD_RESULT(s2n_array_num_elements(config->ticket_keys, &ticket_keys_len));
POSIX_ENSURE(ticket_keys_len < S2N_MAX_TICKET_KEYS, S2N_ERR_TICKET_KEY_LIMIT);
POSIX_ENSURE(name_len != 0, S2N_ERR_INVALID_TICKET_KEY_NAME_OR_NAME_LENGTH);
POSIX_ENSURE(name_len <= S2N_TICKET_KEY_NAME_LEN, S2N_ERR_INVALID_TICKET_KEY_NAME_OR_NAME_LENGTH);
/* Copy the name into a zero-padded array. */
/* This ensures that all ticket names are equal in length, as the serialized name is fixed length */
uint8_t name_data[S2N_TICKET_KEY_NAME_LEN] = { 0 };
POSIX_CHECKED_MEMCPY(name_data, name, name_len);
uint8_t output_pad[S2N_AES256_KEY_LEN + S2N_TICKET_AAD_IMPLICIT_LEN] = { 0 };
struct s2n_blob out_key = { 0 };
POSIX_GUARD(s2n_blob_init(&out_key, output_pad, s2n_array_len(output_pad)));
struct s2n_blob in_key = { 0 };
POSIX_GUARD(s2n_blob_init(&in_key, key, key_len));
struct s2n_blob salt = { 0 };
POSIX_GUARD(s2n_blob_init(&salt, NULL, 0));
struct s2n_blob info = { 0 };
POSIX_GUARD(s2n_blob_init(&info, NULL, 0));
struct s2n_ticket_key *session_ticket_key = { 0 };
DEFER_CLEANUP(struct s2n_blob allocator = { 0 }, s2n_free);
POSIX_GUARD(s2n_alloc(&allocator, sizeof(struct s2n_ticket_key)));
session_ticket_key = (struct s2n_ticket_key *) (void *) allocator.data;
DEFER_CLEANUP(struct s2n_hmac_state hmac = { 0 }, s2n_hmac_free);
POSIX_GUARD(s2n_hmac_new(&hmac));
POSIX_GUARD(s2n_hkdf(&hmac, S2N_HMAC_SHA256, &salt, &in_key, &info, &out_key));
POSIX_CHECKED_MEMCPY(session_ticket_key->key_name, name_data, s2n_array_len(name_data));
POSIX_CHECKED_MEMCPY(session_ticket_key->aes_key, out_key.data, S2N_AES256_KEY_LEN);
out_key.data = output_pad + S2N_AES256_KEY_LEN;
POSIX_CHECKED_MEMCPY(session_ticket_key->implicit_aad, out_key.data, S2N_TICKET_AAD_IMPLICIT_LEN);
if (intro_time_in_seconds_from_epoch == 0) {
uint64_t now = 0;
POSIX_GUARD_RESULT(s2n_config_wall_clock(config, &now));
session_ticket_key->intro_timestamp = now;
} else {
session_ticket_key->intro_timestamp = (intro_time_in_seconds_from_epoch * ONE_SEC_IN_NANOS);
}
POSIX_GUARD(s2n_config_store_ticket_key(config, session_ticket_key));
return 0;
}