int s2n_config_add_ticket_crypto_key()

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;
}