123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 |
- /*
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
- #include "tls/s2n_tls13_secrets.h"
- #include "tls/s2n_connection.h"
- #include "tls/s2n_key_log.h"
- #include "tls/s2n_tls13_handshake.h"
- #include "utils/s2n_bitmap.h"
- #define S2N_MAX_HASHLEN SHA384_DIGEST_LENGTH
- #define CONN_HMAC_ALG(conn) ((conn)->secure->cipher_suite->prf_alg)
- #define CONN_SECRETS(conn) ((conn)->secrets.version.tls13)
- #define CONN_HASHES(conn) ((conn)->handshake.hashes)
- #define CONN_SECRET(conn, secret) ( \
- (struct s2n_blob){ .data = CONN_SECRETS(conn).secret, .size = s2n_get_hash_len(CONN_HMAC_ALG(conn)) })
- #define CONN_HASH(conn, hash) ( \
- (struct s2n_blob){ .data = CONN_HASHES(conn)->hash, .size = s2n_get_hash_len(CONN_HMAC_ALG(conn)) })
- #define CONN_FINISHED(conn, mode) ( \
- (struct s2n_blob){ .data = (conn)->handshake.mode##_finished, .size = s2n_get_hash_len(CONN_HMAC_ALG(conn)) })
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# If a given secret is not available, then the 0-value consisting of a
- *# string of Hash.length bytes set to zeros is used.
- */
- static uint8_t zero_value_bytes[S2N_MAX_HASHLEN] = { 0 };
- #define ZERO_VALUE(hmac_alg) ( \
- (const struct s2n_blob){ .data = zero_value_bytes, .size = s2n_get_hash_len(hmac_alg) })
- /**
- * When an operation doesn't need an actual transcript hash,
- * it uses an empty transcript hash as an input instead.
- *
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# Note that in some cases a zero-
- *# length Context (indicated by "") is passed to HKDF-Expand-Label
- */
- #define EMPTY_CONTEXT(hmac_alg) ( \
- (const struct s2n_blob){ .data = s2n_get_empty_context(hmac_alg), .size = s2n_get_hash_len(hmac_alg) })
- static uint8_t s2n_get_hash_len(s2n_hmac_algorithm hmac_alg)
- {
- uint8_t hash_size = 0;
- if (s2n_hmac_digest_size(hmac_alg, &hash_size) != S2N_SUCCESS) {
- return 0;
- }
- return hash_size;
- }
- static uint8_t *s2n_get_empty_context(s2n_hmac_algorithm hmac_alg)
- {
- static uint8_t sha256_empty_digest[S2N_MAX_HASHLEN] = { 0 };
- static uint8_t sha384_empty_digest[S2N_MAX_HASHLEN] = { 0 };
- switch (hmac_alg) {
- case S2N_HMAC_SHA256:
- return sha256_empty_digest;
- case S2N_HMAC_SHA384:
- return sha384_empty_digest;
- default:
- return NULL;
- }
- }
- static s2n_hmac_algorithm supported_hmacs[] = {
- S2N_HMAC_SHA256,
- S2N_HMAC_SHA384
- };
- S2N_RESULT s2n_tls13_empty_transcripts_init()
- {
- DEFER_CLEANUP(struct s2n_hash_state hash = { 0 }, s2n_hash_free);
- RESULT_GUARD_POSIX(s2n_hash_new(&hash));
- s2n_hash_algorithm hash_alg = S2N_HASH_NONE;
- for (size_t i = 0; i < s2n_array_len(supported_hmacs); i++) {
- s2n_hmac_algorithm hmac_alg = supported_hmacs[i];
- struct s2n_blob digest = EMPTY_CONTEXT(hmac_alg);
- RESULT_GUARD_POSIX(s2n_hmac_hash_alg(hmac_alg, &hash_alg));
- RESULT_GUARD_POSIX(s2n_hash_init(&hash, hash_alg));
- RESULT_GUARD_POSIX(s2n_hash_digest(&hash, digest.data, digest.size));
- }
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_calculate_transcript_digest(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(conn->handshake.hashes);
- s2n_hash_algorithm hash_algorithm = S2N_HASH_NONE;
- RESULT_GUARD_POSIX(s2n_hmac_hash_alg(CONN_HMAC_ALG(conn), &hash_algorithm));
- uint8_t digest_size = 0;
- RESULT_GUARD_POSIX(s2n_hash_digest_size(hash_algorithm, &digest_size));
- struct s2n_blob digest = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&digest, CONN_HASHES(conn)->transcript_hash_digest, digest_size));
- struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace;
- RESULT_GUARD(s2n_handshake_copy_hash_state(conn, hash_algorithm, hash_state));
- RESULT_GUARD_POSIX(s2n_hash_digest(hash_state, digest.data, digest.size));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_extract_secret(s2n_hmac_algorithm hmac_alg,
- const struct s2n_blob *previous_secret_material, const struct s2n_blob *new_secret_material,
- struct s2n_blob *output)
- {
- /*
- * TODO: We should be able to reuse the prf_work_space rather
- * than allocating a new HMAC every time.
- * https://github.com/aws/s2n-tls/issues/3206
- */
- DEFER_CLEANUP(struct s2n_hmac_state hmac_state = { 0 }, s2n_hmac_free);
- RESULT_GUARD_POSIX(s2n_hmac_new(&hmac_state));
- RESULT_GUARD_POSIX(s2n_hkdf_extract(&hmac_state, hmac_alg,
- previous_secret_material, new_secret_material, output));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# Derive-Secret(Secret, Label, Messages) =
- *# HKDF-Expand-Label(Secret, Label,
- *# Transcript-Hash(Messages), Hash.length)
- */
- static S2N_RESULT s2n_derive_secret(s2n_hmac_algorithm hmac_alg,
- const struct s2n_blob *previous_secret_material, const struct s2n_blob *label, const struct s2n_blob *context,
- struct s2n_blob *output)
- {
- /*
- * TODO: We should be able to reuse the prf_work_space rather
- * than allocating a new HMAC every time.
- * https://github.com/aws/s2n-tls/issues/3206
- */
- DEFER_CLEANUP(struct s2n_hmac_state hmac_state = { 0 }, s2n_hmac_free);
- RESULT_GUARD_POSIX(s2n_hmac_new(&hmac_state));
- output->size = s2n_get_hash_len(hmac_alg);
- RESULT_GUARD_POSIX(s2n_hkdf_expand_label(&hmac_state, hmac_alg,
- previous_secret_material, label, context, output));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_derive_secret_with_context(struct s2n_connection *conn,
- s2n_extract_secret_type_t input_secret_type, const struct s2n_blob *label, message_type_t transcript_end_msg,
- struct s2n_blob *output)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(label);
- RESULT_ENSURE_REF(output);
- RESULT_ENSURE(conn->secrets.extract_secret_type == input_secret_type, S2N_ERR_SECRET_SCHEDULE_STATE);
- RESULT_ENSURE(s2n_conn_get_current_message_type(conn) == transcript_end_msg, S2N_ERR_SECRET_SCHEDULE_STATE);
- RESULT_GUARD(s2n_derive_secret(CONN_HMAC_ALG(conn), &CONN_SECRET(conn, extract_secret),
- label, &CONN_HASH(conn, transcript_hash_digest), output));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_derive_secret_without_context(struct s2n_connection *conn,
- s2n_extract_secret_type_t input_secret_type, struct s2n_blob *output)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(output);
- RESULT_ENSURE(conn->secrets.extract_secret_type == input_secret_type, S2N_ERR_SECRET_SCHEDULE_STATE);
- RESULT_GUARD(s2n_derive_secret(CONN_HMAC_ALG(conn), &CONN_SECRET(conn, extract_secret),
- &s2n_tls13_label_derived_secret, &EMPTY_CONTEXT(CONN_HMAC_ALG(conn)), output));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-4.4.4
- *# The key used to compute the Finished message is computed from the
- *# Base Key defined in Section 4.4 using HKDF (see Section 7.1).
- *# Specifically:
- *#
- *# finished_key =
- *# HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
- **/
- static S2N_RESULT s2n_tls13_compute_finished_key(struct s2n_connection *conn,
- const struct s2n_blob *base_key, struct s2n_blob *output)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(base_key);
- RESULT_ENSURE_REF(output);
- RESULT_GUARD(s2n_handshake_set_finished_len(conn, output->size));
- /*
- * TODO: We should be able to reuse the prf_work_space rather
- * than allocating a new HMAC every time.
- */
- DEFER_CLEANUP(struct s2n_hmac_state hmac_state = { 0 }, s2n_hmac_free);
- RESULT_GUARD_POSIX(s2n_hmac_new(&hmac_state));
- RESULT_GUARD_POSIX(s2n_hkdf_expand_label(&hmac_state, CONN_HMAC_ALG(conn),
- base_key, &s2n_tls13_label_finished, &(struct s2n_blob){ 0 }, output));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_call_secret_callbacks(struct s2n_connection *conn,
- const struct s2n_blob *secret, s2n_secret_type_t secret_type)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(secret);
- if (conn->secret_cb && (s2n_connection_is_quic_enabled(conn) || s2n_in_unit_test())) {
- RESULT_GUARD_POSIX(conn->secret_cb(conn->secret_cb_context, conn, secret_type,
- secret->data, secret->size));
- }
- s2n_result_ignore(s2n_key_log_tls13_secret(conn, secret, secret_type));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_trigger_secret_callbacks(struct s2n_connection *conn,
- const struct s2n_blob *secret, s2n_extract_secret_type_t secret_type, s2n_mode mode)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(secret);
- static const s2n_secret_type_t conversions[][2] = {
- [S2N_EARLY_SECRET] = { S2N_CLIENT_EARLY_TRAFFIC_SECRET, S2N_CLIENT_EARLY_TRAFFIC_SECRET },
- [S2N_HANDSHAKE_SECRET] = { S2N_SERVER_HANDSHAKE_TRAFFIC_SECRET, S2N_CLIENT_HANDSHAKE_TRAFFIC_SECRET },
- [S2N_MASTER_SECRET] = { S2N_SERVER_APPLICATION_TRAFFIC_SECRET, S2N_CLIENT_APPLICATION_TRAFFIC_SECRET },
- };
- s2n_secret_type_t callback_secret_type = conversions[secret_type][mode];
- RESULT_GUARD(s2n_call_secret_callbacks(conn, secret, callback_secret_type));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# 0
- *# |
- *# v
- *# PSK -> HKDF-Extract = Early Secret
- *
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# There are multiple potential Early Secret values, depending on which
- *# PSK the server ultimately selects. The client will need to compute
- *# one for each potential PSK
- */
- S2N_RESULT s2n_extract_early_secret(struct s2n_psk *psk)
- {
- RESULT_ENSURE_REF(psk);
- RESULT_GUARD_POSIX(s2n_realloc(&psk->early_secret, s2n_get_hash_len(psk->hmac_alg)));
- RESULT_GUARD(s2n_extract_secret(psk->hmac_alg,
- &ZERO_VALUE(psk->hmac_alg),
- &psk->secret,
- &psk->early_secret));
- return S2N_RESULT_OK;
- }
- /*
- * When we require an early secret to derive other secrets,
- * either retrieve the early secret stored on the chosen / early data PSK
- * or calculate one using a "zero" PSK.
- */
- static S2N_RESULT s2n_extract_early_secret_for_schedule(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- struct s2n_psk *psk = conn->psk_params.chosen_psk;
- s2n_hmac_algorithm hmac_alg = CONN_HMAC_ALG(conn);
- /*
- * If the client is sending early data, then the PSK is always assumed
- * to be the first PSK offered.
- */
- if (conn->mode == S2N_CLIENT && conn->early_data_state == S2N_EARLY_DATA_REQUESTED) {
- RESULT_GUARD(s2n_array_get(&conn->psk_params.psk_list, 0, (void **) &psk));
- RESULT_ENSURE_REF(psk);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# if no PSK is selected, it will then need
- *# to compute the Early Secret corresponding to the zero PSK.
- */
- if (psk == NULL) {
- RESULT_GUARD(s2n_extract_secret(hmac_alg,
- &ZERO_VALUE(hmac_alg),
- &ZERO_VALUE(hmac_alg),
- &CONN_SECRET(conn, extract_secret)));
- return S2N_RESULT_OK;
- }
- /*
- * The early secret is required to generate or verify a PSK's binder,
- * so must have already been calculated if a valid PSK exists.
- * Use the early secret stored on the PSK.
- */
- RESULT_ENSURE_EQ(hmac_alg, psk->hmac_alg);
- RESULT_CHECKED_MEMCPY(CONN_SECRETS(conn).extract_secret, psk->early_secret.data, psk->early_secret.size);
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "ext binder" | "res binder", "")
- *# | = binder_key
- */
- S2N_RESULT s2n_derive_binder_key(struct s2n_psk *psk, struct s2n_blob *output)
- {
- RESULT_ENSURE_REF(psk);
- RESULT_ENSURE_REF(output);
- const struct s2n_blob *label = &s2n_tls13_label_resumption_psk_binder_key;
- if (psk->type == S2N_PSK_TYPE_EXTERNAL) {
- label = &s2n_tls13_label_external_psk_binder_key;
- }
- RESULT_GUARD(s2n_extract_early_secret(psk));
- RESULT_GUARD(s2n_derive_secret(psk->hmac_alg,
- &psk->early_secret,
- label,
- &EMPTY_CONTEXT(psk->hmac_alg),
- output));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "c e traffic", ClientHello)
- *# | = client_early_traffic_secret
- */
- static S2N_RESULT s2n_derive_client_early_traffic_secret(struct s2n_connection *conn, struct s2n_blob *output)
- {
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_EARLY_SECRET,
- &s2n_tls13_label_client_early_traffic_secret,
- CLIENT_HELLO,
- output));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# v
- *# Derive-Secret(., "derived", "")
- *# |
- *# v
- *# (EC)DHE -> HKDF-Extract = Handshake Secret
- */
- static S2N_RESULT s2n_extract_handshake_secret(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- struct s2n_blob derived_secret = { 0 };
- uint8_t derived_secret_bytes[S2N_TLS13_SECRET_MAX_LEN] = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&derived_secret, derived_secret_bytes, S2N_TLS13_SECRET_MAX_LEN));
- RESULT_GUARD(s2n_derive_secret_without_context(conn, S2N_EARLY_SECRET, &derived_secret));
- DEFER_CLEANUP(struct s2n_blob shared_secret = { 0 }, s2n_free_or_wipe);
- RESULT_GUARD_POSIX(s2n_tls13_compute_shared_secret(conn, &shared_secret));
- RESULT_GUARD(s2n_extract_secret(CONN_HMAC_ALG(conn),
- &derived_secret,
- &shared_secret,
- &CONN_SECRET(conn, extract_secret)));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "c hs traffic",
- *# | ClientHello...ServerHello)
- *# | = client_handshake_traffic_secret
- */
- static S2N_RESULT s2n_derive_client_handshake_traffic_secret(struct s2n_connection *conn, struct s2n_blob *output)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(output);
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_HANDSHAKE_SECRET,
- &s2n_tls13_label_client_handshake_traffic_secret,
- SERVER_HELLO,
- output));
- /*
- * The client finished key needs to be calculated using the
- * same connection state as the client handshake secret.
- *
- *= https://tools.ietf.org/rfc/rfc8446#section-4.4.4
- *# The key used to compute the Finished message is computed from the
- *# Base Key defined in Section 4.4 using HKDF (see Section 7.1).
- */
- RESULT_GUARD(s2n_tls13_compute_finished_key(conn,
- output, &CONN_FINISHED(conn, client)));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "s hs traffic",
- *# | ClientHello...ServerHello)
- *# | = server_handshake_traffic_secret
- */
- static S2N_RESULT s2n_derive_server_handshake_traffic_secret(struct s2n_connection *conn, struct s2n_blob *output)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(output);
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_HANDSHAKE_SECRET,
- &s2n_tls13_label_server_handshake_traffic_secret,
- SERVER_HELLO,
- output));
- /*
- * The server finished key needs to be calculated using the
- * same connection state as the server handshake secret.
- *
- *= https://tools.ietf.org/rfc/rfc8446#section-4.4.4
- *# The key used to compute the Finished message is computed from the
- *# Base Key defined in Section 4.4 using HKDF (see Section 7.1).
- */
- RESULT_GUARD(s2n_tls13_compute_finished_key(conn,
- output, &CONN_FINISHED(conn, server)));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# v
- *# Derive-Secret(., "derived", "")
- *# |
- *# v
- *# 0 -> HKDF-Extract = Master Secret
- */
- static S2N_RESULT s2n_extract_master_secret(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- struct s2n_blob derived_secret = { 0 };
- uint8_t derived_secret_bytes[S2N_TLS13_SECRET_MAX_LEN] = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&derived_secret, derived_secret_bytes, S2N_TLS13_SECRET_MAX_LEN));
- RESULT_GUARD(s2n_derive_secret_without_context(conn, S2N_HANDSHAKE_SECRET, &derived_secret));
- RESULT_GUARD(s2n_extract_secret(CONN_HMAC_ALG(conn),
- &derived_secret,
- &ZERO_VALUE(CONN_HMAC_ALG(conn)),
- &CONN_SECRET(conn, extract_secret)));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "c ap traffic",
- *# | ClientHello...server Finished)
- *# | = client_application_traffic_secret_0
- */
- static S2N_RESULT s2n_derive_client_application_traffic_secret(struct s2n_connection *conn, struct s2n_blob *output)
- {
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_MASTER_SECRET,
- &s2n_tls13_label_client_application_traffic_secret,
- SERVER_FINISHED,
- output));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "s ap traffic",
- *# | ClientHello...server Finished)
- *# | = server_application_traffic_secret_0
- */
- static S2N_RESULT s2n_derive_server_application_traffic_secret(struct s2n_connection *conn, struct s2n_blob *output)
- {
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_MASTER_SECRET,
- &s2n_tls13_label_server_application_traffic_secret,
- SERVER_FINISHED,
- output));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "res master",
- *# ClientHello...client Finished)
- *# = resumption_master_secret
- */
- S2N_RESULT s2n_derive_resumption_master_secret(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- /* Secret derivation requires these fields to be non-null. */
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_MASTER_SECRET,
- &s2n_tls13_label_resumption_master_secret,
- CLIENT_FINISHED,
- &CONN_SECRET(conn, resumption_master_secret)));
- return S2N_RESULT_OK;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.1
- *# |
- *# +-----> Derive-Secret(., "exp master",
- *# | ClientHello...server Finished)
- *# | = exporter_master_secret
- */
- S2N_RESULT s2n_derive_exporter_master_secret(struct s2n_connection *conn, struct s2n_blob *secret)
- {
- RESULT_ENSURE_REF(conn);
- /* Secret derivation requires these fields to be non-null. */
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- RESULT_GUARD(s2n_derive_secret_with_context(conn,
- S2N_MASTER_SECRET,
- &s2n_tls13_label_exporter_master_secret,
- SERVER_FINISHED,
- secret));
- RESULT_GUARD(s2n_call_secret_callbacks(conn, secret, S2N_EXPORTER_SECRET));
- return S2N_RESULT_OK;
- }
- static s2n_result (*extract_methods[])(struct s2n_connection *conn) = {
- [S2N_EARLY_SECRET] = &s2n_extract_early_secret_for_schedule,
- [S2N_HANDSHAKE_SECRET] = &s2n_extract_handshake_secret,
- [S2N_MASTER_SECRET] = &s2n_extract_master_secret,
- };
- S2N_RESULT s2n_tls13_extract_secret(struct s2n_connection *conn, s2n_extract_secret_type_t secret_type)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- RESULT_ENSURE_REF(conn->handshake.hashes);
- RESULT_ENSURE_NE(secret_type, S2N_NONE_SECRET);
- RESULT_ENSURE_GTE(secret_type, 0);
- RESULT_ENSURE_LT(secret_type, s2n_array_len(extract_methods));
- s2n_extract_secret_type_t next_secret_type = conn->secrets.extract_secret_type + 1;
- for (s2n_extract_secret_type_t i = next_secret_type; i <= secret_type; i++) {
- RESULT_ENSURE_REF(extract_methods[i]);
- RESULT_GUARD(extract_methods[i](conn));
- conn->secrets.extract_secret_type = i;
- }
- return S2N_RESULT_OK;
- }
- static s2n_result (*derive_methods[][2])(struct s2n_connection *conn, struct s2n_blob *secret) = {
- [S2N_EARLY_SECRET] = { &s2n_derive_client_early_traffic_secret, &s2n_derive_client_early_traffic_secret },
- [S2N_HANDSHAKE_SECRET] = { &s2n_derive_server_handshake_traffic_secret, &s2n_derive_client_handshake_traffic_secret },
- [S2N_MASTER_SECRET] = { &s2n_derive_server_application_traffic_secret, &s2n_derive_client_application_traffic_secret },
- };
- S2N_RESULT s2n_tls13_derive_secret(struct s2n_connection *conn, s2n_extract_secret_type_t secret_type,
- s2n_mode mode, struct s2n_blob *secret)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(secret);
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- RESULT_ENSURE_REF(conn->handshake.hashes);
- RESULT_ENSURE_NE(secret_type, S2N_NONE_SECRET);
- RESULT_GUARD(s2n_tls13_extract_secret(conn, secret_type));
- RESULT_ENSURE_GTE(secret_type, 0);
- RESULT_ENSURE_LT(secret_type, s2n_array_len(derive_methods));
- RESULT_ENSURE_REF(derive_methods[secret_type][mode]);
- RESULT_GUARD(derive_methods[secret_type][mode](conn, secret));
- RESULT_GUARD(s2n_trigger_secret_callbacks(conn, secret, secret_type, mode));
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_tls13_secrets_clean(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- /* Secret clean requires these fields to be non-null. */
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- if (conn->actual_protocol_version < S2N_TLS13) {
- return S2N_RESULT_OK;
- }
- /*
- * Wipe base secrets.
- * Not strictly necessary, but probably safer than leaving them.
- * A compromised secret additionally compromises all secrets derived from it,
- * so these are the most sensitive secrets.
- */
- RESULT_GUARD_POSIX(s2n_blob_zero(&CONN_SECRET(conn, extract_secret)));
- conn->secrets.extract_secret_type = S2N_NONE_SECRET;
- /* Wipe other secrets no longer needed */
- RESULT_GUARD_POSIX(s2n_blob_zero(&CONN_SECRET(conn, client_early_secret)));
- RESULT_GUARD_POSIX(s2n_blob_zero(&CONN_SECRET(conn, client_handshake_secret)));
- RESULT_GUARD_POSIX(s2n_blob_zero(&CONN_SECRET(conn, server_handshake_secret)));
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_tls13_secrets_update(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) {
- return S2N_RESULT_OK;
- }
- /* Secret update requires these fields to be non-null. */
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- message_type_t message_type = s2n_conn_get_current_message_type(conn);
- switch (message_type) {
- case CLIENT_HELLO:
- if (conn->early_data_state == S2N_EARLY_DATA_REQUESTED
- || conn->early_data_state == S2N_EARLY_DATA_ACCEPTED) {
- RESULT_GUARD(s2n_calculate_transcript_digest(conn));
- RESULT_GUARD(s2n_tls13_derive_secret(conn, S2N_EARLY_SECRET,
- S2N_CLIENT, &CONN_SECRET(conn, client_early_secret)));
- }
- break;
- case SERVER_HELLO:
- RESULT_GUARD(s2n_calculate_transcript_digest(conn));
- RESULT_GUARD(s2n_tls13_derive_secret(conn, S2N_HANDSHAKE_SECRET,
- S2N_CLIENT, &CONN_SECRET(conn, client_handshake_secret)));
- RESULT_GUARD(s2n_tls13_derive_secret(conn, S2N_HANDSHAKE_SECRET,
- S2N_SERVER, &CONN_SECRET(conn, server_handshake_secret)));
- break;
- case SERVER_FINISHED:
- RESULT_GUARD(s2n_calculate_transcript_digest(conn));
- RESULT_GUARD(s2n_tls13_derive_secret(conn, S2N_MASTER_SECRET,
- S2N_CLIENT, &CONN_SECRET(conn, client_app_secret)));
- RESULT_GUARD(s2n_tls13_derive_secret(conn, S2N_MASTER_SECRET,
- S2N_SERVER, &CONN_SECRET(conn, server_app_secret)));
- RESULT_GUARD(s2n_derive_exporter_master_secret(conn,
- &CONN_SECRET(conn, exporter_master_secret)));
- break;
- case CLIENT_FINISHED:
- RESULT_GUARD(s2n_calculate_transcript_digest(conn));
- RESULT_GUARD(s2n_derive_resumption_master_secret(conn));
- break;
- default:
- break;
- }
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_tls13_secrets_get(struct s2n_connection *conn, s2n_extract_secret_type_t secret_type,
- s2n_mode mode, struct s2n_blob *secret)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(secret);
- /* Getting secrets requires these fields to be non-null. */
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- uint8_t *secrets[][2] = {
- [S2N_EARLY_SECRET] = { NULL, CONN_SECRETS(conn).client_early_secret },
- [S2N_HANDSHAKE_SECRET] = { CONN_SECRETS(conn).server_handshake_secret, CONN_SECRETS(conn).client_handshake_secret },
- [S2N_MASTER_SECRET] = { CONN_SECRETS(conn).server_app_secret, CONN_SECRETS(conn).client_app_secret },
- };
- RESULT_ENSURE_GT(secret_type, S2N_NONE_SECRET);
- RESULT_ENSURE_LT(secret_type, s2n_array_len(secrets));
- RESULT_ENSURE_LTE(secret_type, conn->secrets.extract_secret_type);
- RESULT_ENSURE_REF(secrets[secret_type][mode]);
- secret->size = s2n_get_hash_len(CONN_HMAC_ALG(conn));
- RESULT_CHECKED_MEMCPY(secret->data, secrets[secret_type][mode], secret->size);
- RESULT_ENSURE_GT(secret->size, 0);
- return S2N_RESULT_OK;
- }
- /*
- *= https://www.rfc-editor.org/rfc/rfc8446#section-7.5
- *# The exporter value is computed as:
- *#
- *# TLS-Exporter(label, context_value, key_length) =
- *# HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
- *# "exporter", Hash(context_value), key_length)
- */
- int s2n_connection_tls_exporter(struct s2n_connection *conn,
- const uint8_t *label_in, uint32_t label_length,
- const uint8_t *context, uint32_t context_length,
- uint8_t *output_in, uint32_t output_length)
- {
- POSIX_ENSURE_REF(conn);
- POSIX_ENSURE_REF(output_in);
- POSIX_ENSURE_REF(label_in);
- POSIX_ENSURE_REF(context);
- POSIX_ENSURE(s2n_connection_get_protocol_version(conn) == S2N_TLS13, S2N_ERR_INVALID_STATE);
- POSIX_ENSURE(is_handshake_complete(conn), S2N_ERR_HANDSHAKE_NOT_COMPLETE);
- POSIX_ENSURE_REF(conn->secure);
- POSIX_ENSURE_REF(conn->secure->cipher_suite);
- s2n_hmac_algorithm hmac_alg = conn->secure->cipher_suite->prf_alg;
- uint8_t label_bytes[S2N_MAX_HKDF_EXPAND_LABEL_LENGTH] = { 0 };
- struct s2n_blob label = { 0 };
- POSIX_ENSURE_LTE(label_length, sizeof(label_bytes));
- POSIX_CHECKED_MEMCPY(label_bytes, label_in, label_length);
- POSIX_GUARD(s2n_blob_init(&label, label_bytes, label_length));
- uint8_t derived_secret_bytes[S2N_MAX_DIGEST_LEN] = { 0 };
- struct s2n_blob derived_secret = { 0 };
- POSIX_ENSURE_LTE(s2n_get_hash_len(CONN_HMAC_ALG(conn)), S2N_MAX_DIGEST_LEN);
- POSIX_GUARD(s2n_blob_init(&derived_secret,
- derived_secret_bytes, s2n_get_hash_len(CONN_HMAC_ALG(conn))));
- POSIX_GUARD_RESULT(s2n_derive_secret(hmac_alg, &CONN_SECRET(conn, exporter_master_secret),
- &label, &EMPTY_CONTEXT(hmac_alg), &derived_secret));
- DEFER_CLEANUP(struct s2n_hmac_state hmac_state = { 0 }, s2n_hmac_free);
- POSIX_GUARD(s2n_hmac_new(&hmac_state));
- DEFER_CLEANUP(struct s2n_hash_state hash = { 0 }, s2n_hash_free);
- POSIX_GUARD(s2n_hash_new(&hash));
- s2n_hash_algorithm hash_alg = { 0 };
- POSIX_GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg));
- uint8_t digest_bytes[S2N_MAX_DIGEST_LEN] = { 0 };
- struct s2n_blob digest = { 0 };
- POSIX_ENSURE_LTE(s2n_get_hash_len(CONN_HMAC_ALG(conn)), S2N_MAX_DIGEST_LEN);
- POSIX_GUARD(s2n_blob_init(&digest, digest_bytes, s2n_get_hash_len(CONN_HMAC_ALG(conn))));
- POSIX_GUARD(s2n_hash_init(&hash, hash_alg));
- POSIX_GUARD(s2n_hash_update(&hash, context, context_length));
- POSIX_GUARD(s2n_hash_digest(&hash, digest.data, digest.size));
- struct s2n_blob output = { 0 };
- POSIX_GUARD(s2n_blob_init(&output, output_in, output_length));
- POSIX_GUARD(s2n_hkdf_expand_label(&hmac_state, hmac_alg,
- &derived_secret, &s2n_tls13_label_exporter, &digest, &output));
- return S2N_SUCCESS;
- }
|