diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c')
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c | 802 |
1 files changed, 401 insertions, 401 deletions
diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c b/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c index fe000814e7..b89c6f04fb 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c @@ -1,401 +1,401 @@ -/* - * 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_handshake.h" -#include "tls/s2n_cipher_suites.h" -#include "tls/s2n_security_policies.h" - -static int s2n_zero_sequence_number(struct s2n_connection *conn, s2n_mode mode) -{ - notnull_check(conn); - struct s2n_blob sequence_number; - if (mode == S2N_CLIENT) { - GUARD(s2n_blob_init(&sequence_number, conn->secure.client_sequence_number, sizeof(conn->secure.client_sequence_number))); - } else { - GUARD(s2n_blob_init(&sequence_number, conn->secure.server_sequence_number, sizeof(conn->secure.server_sequence_number))); - } - GUARD(s2n_blob_zero(&sequence_number)); - return S2N_SUCCESS; -} - -int s2n_tls13_mac_verify(struct s2n_tls13_keys *keys, struct s2n_blob *finished_verify, struct s2n_blob *wire_verify) -{ - notnull_check(wire_verify->data); - eq_check(wire_verify->size, keys->size); - - S2N_ERROR_IF(!s2n_constant_time_equals(finished_verify->data, wire_verify->data, keys->size), S2N_ERR_BAD_MESSAGE); - - return 0; -} - -/* - * Initializes the tls13_keys struct - */ -static int s2n_tls13_keys_init_with_ref(struct s2n_tls13_keys *handshake, s2n_hmac_algorithm alg, uint8_t * extract, uint8_t * derive) -{ - notnull_check(handshake); - - handshake->hmac_algorithm = alg; - GUARD(s2n_hmac_hash_alg(alg, &handshake->hash_algorithm)); - GUARD(s2n_hash_digest_size(handshake->hash_algorithm, &handshake->size)); - GUARD(s2n_blob_init(&handshake->extract_secret, extract, handshake->size)); - GUARD(s2n_blob_init(&handshake->derive_secret, derive, handshake->size)); - GUARD(s2n_hmac_new(&handshake->hmac)); - - return 0; -} - -int s2n_tls13_keys_from_conn(struct s2n_tls13_keys *keys, struct s2n_connection *conn) -{ - GUARD(s2n_tls13_keys_init_with_ref(keys, conn->secure.cipher_suite->prf_alg, conn->secure.rsa_premaster_secret, conn->secure.master_secret)); - - return 0; -} - -int s2n_tls13_compute_ecc_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) { - notnull_check(conn); - - const struct s2n_ecc_preferences *ecc_preferences = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_preferences)); - notnull_check(ecc_preferences); - - struct s2n_ecc_evp_params *server_key = &conn->secure.server_ecc_evp_params; - notnull_check(server_key); - notnull_check(server_key->negotiated_curve); - /* for now we do this tedious loop to find the matching client key selection. - * this can be simplified if we get an index or a pointer to a specific key */ - int selection = -1; - for (int i = 0; i < ecc_preferences->count; i++) { - if (server_key->negotiated_curve->iana_id == ecc_preferences->ecc_curves[i]->iana_id) { - selection = i; - break; - } - } - - S2N_ERROR_IF(selection < 0, S2N_ERR_BAD_KEY_SHARE); - struct s2n_ecc_evp_params *client_key = &conn->secure.client_ecc_evp_params[selection]; - notnull_check(client_key); - - if (conn->mode == S2N_CLIENT) { - GUARD(s2n_ecc_evp_compute_shared_secret_from_params(client_key, server_key, shared_secret)); - } else { - GUARD(s2n_ecc_evp_compute_shared_secret_from_params(server_key, client_key, shared_secret)); - } - - return 0; -} - -/* Computes the ECDHE+PQKEM hybrid shared secret as defined in - * https://tools.ietf.org/html/draft-stebila-tls-hybrid-design */ -int s2n_tls13_compute_pq_hybrid_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) { - notnull_check(conn); - notnull_check(shared_secret); - - /* conn->secure.server_ecc_evp_params should be set only during a classic/non-hybrid handshake */ - eq_check(NULL, conn->secure.server_ecc_evp_params.negotiated_curve); - eq_check(NULL, conn->secure.server_ecc_evp_params.evp_pkey); - - struct s2n_kem_group_params *server_kem_group_params = &conn->secure.server_kem_group_params; - notnull_check(server_kem_group_params); - struct s2n_ecc_evp_params *server_ecc_params = &server_kem_group_params->ecc_params; - notnull_check(server_ecc_params); - - struct s2n_kem_group_params *client_kem_group_params = conn->secure.chosen_client_kem_group_params; - notnull_check(client_kem_group_params); - struct s2n_ecc_evp_params *client_ecc_params = &client_kem_group_params->ecc_params; - notnull_check(client_ecc_params); - - DEFER_CLEANUP(struct s2n_blob ecdhe_shared_secret = { 0 }, s2n_blob_zeroize_free); - - /* Compute the ECDHE shared secret, and retrieve the PQ shared secret. */ - if (conn->mode == S2N_CLIENT) { - GUARD(s2n_ecc_evp_compute_shared_secret_from_params(client_ecc_params, server_ecc_params, &ecdhe_shared_secret)); - } else { - GUARD(s2n_ecc_evp_compute_shared_secret_from_params(server_ecc_params, client_ecc_params, &ecdhe_shared_secret)); - } - - struct s2n_blob *pq_shared_secret = &client_kem_group_params->kem_params.shared_secret; - notnull_check(pq_shared_secret); - notnull_check(pq_shared_secret->data); - - const struct s2n_kem_group *negotiated_kem_group = conn->secure.server_kem_group_params.kem_group; - notnull_check(negotiated_kem_group); - notnull_check(negotiated_kem_group->kem); - - eq_check(pq_shared_secret->size, negotiated_kem_group->kem->shared_secret_key_length); - - /* Construct the concatenated/hybrid shared secret */ - uint32_t hybrid_shared_secret_size = ecdhe_shared_secret.size + negotiated_kem_group->kem->shared_secret_key_length; - GUARD(s2n_alloc(shared_secret, hybrid_shared_secret_size)); - struct s2n_stuffer stuffer_combiner = { 0 }; - GUARD(s2n_stuffer_init(&stuffer_combiner, shared_secret)); - GUARD(s2n_stuffer_write(&stuffer_combiner, &ecdhe_shared_secret)); - GUARD(s2n_stuffer_write(&stuffer_combiner, pq_shared_secret)); - - /* No longer need PQ shared secret or ECC keys */ - GUARD(s2n_kem_group_free(server_kem_group_params)); - GUARD(s2n_kem_group_free(client_kem_group_params)); - - return S2N_SUCCESS; -} - -static int s2n_tls13_pq_hybrid_supported(struct s2n_connection *conn) { - return conn->secure.server_kem_group_params.kem_group != NULL; -} - -int s2n_tls13_compute_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) -{ - notnull_check(conn); - - if (s2n_tls13_pq_hybrid_supported(conn)) { - GUARD(s2n_tls13_compute_pq_hybrid_shared_secret(conn, shared_secret)); - } else { - GUARD(s2n_tls13_compute_ecc_shared_secret(conn, shared_secret)); - } - - return S2N_SUCCESS; -} - -/* - * This function executes after Server Hello is processed - * and handshake hashes are computed. It produces and configure - * the shared secret, handshake secrets, handshake traffic keys, - * and finished keys. - */ -int s2n_tls13_handle_handshake_secrets(struct s2n_connection *conn) -{ - notnull_check(conn); - const struct s2n_ecc_preferences *ecc_preferences = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_preferences)); - notnull_check(ecc_preferences); - - /* get tls13 key context */ - s2n_tls13_connection_keys(secrets, conn); - - /* get shared secret */ - DEFER_CLEANUP(struct s2n_blob shared_secret = { 0 }, s2n_free); - GUARD(s2n_tls13_compute_shared_secret(conn, &shared_secret)); - - /* derive early secrets */ - GUARD(s2n_tls13_derive_early_secrets(&secrets)); - - /* produce handshake secrets */ - s2n_stack_blob(client_hs_secret, secrets.size, S2N_TLS13_SECRET_MAX_LEN); - s2n_stack_blob(server_hs_secret, secrets.size, S2N_TLS13_SECRET_MAX_LEN); - - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, secrets.hash_algorithm, &hash_state)); - GUARD(s2n_tls13_derive_handshake_secrets(&secrets, &shared_secret, &hash_state, &client_hs_secret, &server_hs_secret)); - - /* trigger secret callbacks */ - if (conn->secret_cb && conn->config->quic_enabled) { - GUARD(conn->secret_cb(conn->secret_cb_context, conn, S2N_CLIENT_HANDSHAKE_TRAFFIC_SECRET, - client_hs_secret.data, client_hs_secret.size)); - GUARD(conn->secret_cb(conn->secret_cb_context, conn, S2N_SERVER_HANDSHAKE_TRAFFIC_SECRET, - server_hs_secret.data, server_hs_secret.size)); - } - - /* produce handshake traffic keys and configure record algorithm */ - s2n_tls13_key_blob(server_hs_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); - struct s2n_blob server_hs_iv = { .data = conn->secure.server_implicit_iv, .size = S2N_TLS13_FIXED_IV_LEN }; - GUARD(s2n_tls13_derive_traffic_keys(&secrets, &server_hs_secret, &server_hs_key, &server_hs_iv)); - - s2n_tls13_key_blob(client_hs_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); - struct s2n_blob client_hs_iv = { .data = conn->secure.client_implicit_iv, .size = S2N_TLS13_FIXED_IV_LEN }; - GUARD(s2n_tls13_derive_traffic_keys(&secrets, &client_hs_secret, &client_hs_key, &client_hs_iv)); - - GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.server_key)); - GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.client_key)); - - if (conn->mode == S2N_CLIENT) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.server_key, &server_hs_key)); - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.client_key, &client_hs_key)); - } else { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.server_key, &server_hs_key)); - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.client_key, &client_hs_key)); - } - - /* calculate server + client finished keys and store them in handshake struct */ - struct s2n_blob server_finished_key = { .data = conn->handshake.server_finished, .size = secrets.size }; - struct s2n_blob client_finished_key = { .data = conn->handshake.client_finished, .size = secrets.size }; - GUARD(s2n_tls13_derive_finished_key(&secrets, &server_hs_secret, &server_finished_key)); - GUARD(s2n_tls13_derive_finished_key(&secrets, &client_hs_secret, &client_finished_key)); - - /* since shared secret has been computed, clean up keys */ - GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); - for (int i = 0; i < ecc_preferences->count; i++) { - GUARD(s2n_ecc_evp_params_free(&conn->secure.client_ecc_evp_params[i])); - } - - /* According to https://tools.ietf.org/html/rfc8446#section-5.3: - * Each sequence number is set to zero at the beginning of a connection and - * whenever the key is changed - */ - GUARD(s2n_zero_sequence_number(conn, S2N_CLIENT)); - GUARD(s2n_zero_sequence_number(conn, S2N_SERVER)); - - return 0; -} - -static int s2n_tls13_handle_application_secret(struct s2n_connection *conn, s2n_mode mode) -{ - /* get tls13 key context */ - s2n_tls13_connection_keys(keys, conn); - bool is_sending_secret = (mode == conn->mode); - - uint8_t *app_secret_data, *implicit_iv_data; - struct s2n_session_key *session_key; - s2n_secret_type_t secret_type; - if (mode == S2N_CLIENT) { - app_secret_data = conn->secure.client_app_secret; - implicit_iv_data = conn->secure.client_implicit_iv; - session_key = &conn->secure.client_key; - secret_type = S2N_CLIENT_APPLICATION_TRAFFIC_SECRET; - } else { - app_secret_data = conn->secure.server_app_secret; - implicit_iv_data = conn->secure.server_implicit_iv; - session_key = &conn->secure.server_key; - secret_type = S2N_SERVER_APPLICATION_TRAFFIC_SECRET; - } - - /* use frozen hashes during the server finished state */ - struct s2n_hash_state *hash_state; - GUARD_NONNULL(hash_state = &conn->handshake.server_finished_copy); - - /* calculate secret */ - struct s2n_blob app_secret = { .data = app_secret_data, .size = keys.size }; - GUARD(s2n_tls13_derive_application_secret(&keys, hash_state, &app_secret, mode)); - - /* trigger secret callback */ - if (conn->secret_cb && conn->config->quic_enabled) { - GUARD(conn->secret_cb(conn->secret_cb_context, conn, secret_type, - app_secret.data, app_secret.size)); - } - - /* derive key from secret */ - s2n_tls13_key_blob(app_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); - struct s2n_blob app_iv = { .data = implicit_iv_data, .size = S2N_TLS13_FIXED_IV_LEN }; - GUARD(s2n_tls13_derive_traffic_keys(&keys, &app_secret, &app_key, &app_iv)); - - /* update record algorithm secrets */ - if (is_sending_secret) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(session_key, &app_key)); - } else { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(session_key, &app_key)); - } - - /* According to https://tools.ietf.org/html/rfc8446#section-5.3: - * Each sequence number is set to zero at the beginning of a connection and - * whenever the key is changed - */ - GUARD(s2n_zero_sequence_number(conn, mode)); - - return S2N_SUCCESS; -} - -/* The application secrets are derived from the master secret, so the - * master secret must be handled BEFORE the application secrets. - */ -static int s2n_tls13_handle_master_secret(struct s2n_connection *conn) -{ - s2n_tls13_connection_keys(keys, conn); - GUARD(s2n_tls13_extract_master_secret(&keys)); - return S2N_SUCCESS; -} - -int s2n_tls13_handle_secrets(struct s2n_connection *conn) -{ - notnull_check(conn); - if (conn->actual_protocol_version < S2N_TLS13) { - return S2N_SUCCESS; - } - - switch(s2n_conn_get_current_message_type(conn)) { - case SERVER_HELLO: - GUARD(s2n_tls13_handle_handshake_secrets(conn)); - /* Set negotiated crypto parameters for encryption */ - conn->server = &conn->secure; - conn->client = &conn->secure; - break; - case SERVER_FINISHED: - if (conn->mode == S2N_SERVER) { - GUARD(s2n_tls13_handle_master_secret(conn)); - GUARD(s2n_tls13_handle_application_secret(conn, S2N_SERVER)); - } - break; - case CLIENT_FINISHED: - if (conn->mode == S2N_CLIENT) { - GUARD(s2n_tls13_handle_master_secret(conn)); - GUARD(s2n_tls13_handle_application_secret(conn, S2N_SERVER)); - } - GUARD(s2n_tls13_handle_application_secret(conn, S2N_CLIENT)); - break; - default: - break; - } - return S2N_SUCCESS; -} - -int s2n_update_application_traffic_keys(struct s2n_connection *conn, s2n_mode mode, keyupdate_status status) -{ - notnull_check(conn); - - /* get tls13 key context */ - s2n_tls13_connection_keys(keys, conn); - - struct s2n_session_key *old_key; - struct s2n_blob old_app_secret; - struct s2n_blob app_iv; - - if (mode == S2N_CLIENT) { - old_key = &conn->secure.client_key; - GUARD(s2n_blob_init(&old_app_secret, conn->secure.client_app_secret, keys.size)); - GUARD(s2n_blob_init(&app_iv, conn->secure.client_implicit_iv, S2N_TLS13_FIXED_IV_LEN)); - } else { - old_key = &conn->secure.server_key; - GUARD(s2n_blob_init(&old_app_secret, conn->secure.server_app_secret, keys.size)); - GUARD(s2n_blob_init(&app_iv, conn->secure.server_implicit_iv, S2N_TLS13_FIXED_IV_LEN)); - } - - /* Produce new application secret */ - s2n_stack_blob(app_secret_update, keys.size, S2N_TLS13_SECRET_MAX_LEN); - - /* Derives next generation of traffic secret */ - GUARD(s2n_tls13_update_application_traffic_secret(&keys, &old_app_secret, &app_secret_update)); - - s2n_tls13_key_blob(app_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); - - /* Derives next generation of traffic key */ - GUARD(s2n_tls13_derive_traffic_keys(&keys, &app_secret_update, &app_key, &app_iv)); - if (status == RECEIVING) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(old_key, &app_key)); - } else { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(old_key, &app_key)); - } - - /* According to https://tools.ietf.org/html/rfc8446#section-5.3: - * Each sequence number is set to zero at the beginning of a connection and - * whenever the key is changed; the first record transmitted under a particular traffic key - * MUST use sequence number 0. - */ - GUARD(s2n_zero_sequence_number(conn, mode)); - - /* Save updated secret */ - struct s2n_stuffer old_secret_stuffer = {0}; - GUARD(s2n_stuffer_init(&old_secret_stuffer, &old_app_secret)); - GUARD(s2n_stuffer_write_bytes(&old_secret_stuffer, app_secret_update.data, keys.size)); - - return S2N_SUCCESS; -} +/* + * 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_handshake.h" +#include "tls/s2n_cipher_suites.h" +#include "tls/s2n_security_policies.h" + +static int s2n_zero_sequence_number(struct s2n_connection *conn, s2n_mode mode) +{ + notnull_check(conn); + struct s2n_blob sequence_number; + if (mode == S2N_CLIENT) { + GUARD(s2n_blob_init(&sequence_number, conn->secure.client_sequence_number, sizeof(conn->secure.client_sequence_number))); + } else { + GUARD(s2n_blob_init(&sequence_number, conn->secure.server_sequence_number, sizeof(conn->secure.server_sequence_number))); + } + GUARD(s2n_blob_zero(&sequence_number)); + return S2N_SUCCESS; +} + +int s2n_tls13_mac_verify(struct s2n_tls13_keys *keys, struct s2n_blob *finished_verify, struct s2n_blob *wire_verify) +{ + notnull_check(wire_verify->data); + eq_check(wire_verify->size, keys->size); + + S2N_ERROR_IF(!s2n_constant_time_equals(finished_verify->data, wire_verify->data, keys->size), S2N_ERR_BAD_MESSAGE); + + return 0; +} + +/* + * Initializes the tls13_keys struct + */ +static int s2n_tls13_keys_init_with_ref(struct s2n_tls13_keys *handshake, s2n_hmac_algorithm alg, uint8_t * extract, uint8_t * derive) +{ + notnull_check(handshake); + + handshake->hmac_algorithm = alg; + GUARD(s2n_hmac_hash_alg(alg, &handshake->hash_algorithm)); + GUARD(s2n_hash_digest_size(handshake->hash_algorithm, &handshake->size)); + GUARD(s2n_blob_init(&handshake->extract_secret, extract, handshake->size)); + GUARD(s2n_blob_init(&handshake->derive_secret, derive, handshake->size)); + GUARD(s2n_hmac_new(&handshake->hmac)); + + return 0; +} + +int s2n_tls13_keys_from_conn(struct s2n_tls13_keys *keys, struct s2n_connection *conn) +{ + GUARD(s2n_tls13_keys_init_with_ref(keys, conn->secure.cipher_suite->prf_alg, conn->secure.rsa_premaster_secret, conn->secure.master_secret)); + + return 0; +} + +int s2n_tls13_compute_ecc_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) { + notnull_check(conn); + + const struct s2n_ecc_preferences *ecc_preferences = NULL; + GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_preferences)); + notnull_check(ecc_preferences); + + struct s2n_ecc_evp_params *server_key = &conn->secure.server_ecc_evp_params; + notnull_check(server_key); + notnull_check(server_key->negotiated_curve); + /* for now we do this tedious loop to find the matching client key selection. + * this can be simplified if we get an index or a pointer to a specific key */ + int selection = -1; + for (int i = 0; i < ecc_preferences->count; i++) { + if (server_key->negotiated_curve->iana_id == ecc_preferences->ecc_curves[i]->iana_id) { + selection = i; + break; + } + } + + S2N_ERROR_IF(selection < 0, S2N_ERR_BAD_KEY_SHARE); + struct s2n_ecc_evp_params *client_key = &conn->secure.client_ecc_evp_params[selection]; + notnull_check(client_key); + + if (conn->mode == S2N_CLIENT) { + GUARD(s2n_ecc_evp_compute_shared_secret_from_params(client_key, server_key, shared_secret)); + } else { + GUARD(s2n_ecc_evp_compute_shared_secret_from_params(server_key, client_key, shared_secret)); + } + + return 0; +} + +/* Computes the ECDHE+PQKEM hybrid shared secret as defined in + * https://tools.ietf.org/html/draft-stebila-tls-hybrid-design */ +int s2n_tls13_compute_pq_hybrid_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) { + notnull_check(conn); + notnull_check(shared_secret); + + /* conn->secure.server_ecc_evp_params should be set only during a classic/non-hybrid handshake */ + eq_check(NULL, conn->secure.server_ecc_evp_params.negotiated_curve); + eq_check(NULL, conn->secure.server_ecc_evp_params.evp_pkey); + + struct s2n_kem_group_params *server_kem_group_params = &conn->secure.server_kem_group_params; + notnull_check(server_kem_group_params); + struct s2n_ecc_evp_params *server_ecc_params = &server_kem_group_params->ecc_params; + notnull_check(server_ecc_params); + + struct s2n_kem_group_params *client_kem_group_params = conn->secure.chosen_client_kem_group_params; + notnull_check(client_kem_group_params); + struct s2n_ecc_evp_params *client_ecc_params = &client_kem_group_params->ecc_params; + notnull_check(client_ecc_params); + + DEFER_CLEANUP(struct s2n_blob ecdhe_shared_secret = { 0 }, s2n_blob_zeroize_free); + + /* Compute the ECDHE shared secret, and retrieve the PQ shared secret. */ + if (conn->mode == S2N_CLIENT) { + GUARD(s2n_ecc_evp_compute_shared_secret_from_params(client_ecc_params, server_ecc_params, &ecdhe_shared_secret)); + } else { + GUARD(s2n_ecc_evp_compute_shared_secret_from_params(server_ecc_params, client_ecc_params, &ecdhe_shared_secret)); + } + + struct s2n_blob *pq_shared_secret = &client_kem_group_params->kem_params.shared_secret; + notnull_check(pq_shared_secret); + notnull_check(pq_shared_secret->data); + + const struct s2n_kem_group *negotiated_kem_group = conn->secure.server_kem_group_params.kem_group; + notnull_check(negotiated_kem_group); + notnull_check(negotiated_kem_group->kem); + + eq_check(pq_shared_secret->size, negotiated_kem_group->kem->shared_secret_key_length); + + /* Construct the concatenated/hybrid shared secret */ + uint32_t hybrid_shared_secret_size = ecdhe_shared_secret.size + negotiated_kem_group->kem->shared_secret_key_length; + GUARD(s2n_alloc(shared_secret, hybrid_shared_secret_size)); + struct s2n_stuffer stuffer_combiner = { 0 }; + GUARD(s2n_stuffer_init(&stuffer_combiner, shared_secret)); + GUARD(s2n_stuffer_write(&stuffer_combiner, &ecdhe_shared_secret)); + GUARD(s2n_stuffer_write(&stuffer_combiner, pq_shared_secret)); + + /* No longer need PQ shared secret or ECC keys */ + GUARD(s2n_kem_group_free(server_kem_group_params)); + GUARD(s2n_kem_group_free(client_kem_group_params)); + + return S2N_SUCCESS; +} + +static int s2n_tls13_pq_hybrid_supported(struct s2n_connection *conn) { + return conn->secure.server_kem_group_params.kem_group != NULL; +} + +int s2n_tls13_compute_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) +{ + notnull_check(conn); + + if (s2n_tls13_pq_hybrid_supported(conn)) { + GUARD(s2n_tls13_compute_pq_hybrid_shared_secret(conn, shared_secret)); + } else { + GUARD(s2n_tls13_compute_ecc_shared_secret(conn, shared_secret)); + } + + return S2N_SUCCESS; +} + +/* + * This function executes after Server Hello is processed + * and handshake hashes are computed. It produces and configure + * the shared secret, handshake secrets, handshake traffic keys, + * and finished keys. + */ +int s2n_tls13_handle_handshake_secrets(struct s2n_connection *conn) +{ + notnull_check(conn); + const struct s2n_ecc_preferences *ecc_preferences = NULL; + GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_preferences)); + notnull_check(ecc_preferences); + + /* get tls13 key context */ + s2n_tls13_connection_keys(secrets, conn); + + /* get shared secret */ + DEFER_CLEANUP(struct s2n_blob shared_secret = { 0 }, s2n_free); + GUARD(s2n_tls13_compute_shared_secret(conn, &shared_secret)); + + /* derive early secrets */ + GUARD(s2n_tls13_derive_early_secrets(&secrets)); + + /* produce handshake secrets */ + s2n_stack_blob(client_hs_secret, secrets.size, S2N_TLS13_SECRET_MAX_LEN); + s2n_stack_blob(server_hs_secret, secrets.size, S2N_TLS13_SECRET_MAX_LEN); + + struct s2n_hash_state hash_state = {0}; + GUARD(s2n_handshake_get_hash_state(conn, secrets.hash_algorithm, &hash_state)); + GUARD(s2n_tls13_derive_handshake_secrets(&secrets, &shared_secret, &hash_state, &client_hs_secret, &server_hs_secret)); + + /* trigger secret callbacks */ + if (conn->secret_cb && conn->config->quic_enabled) { + GUARD(conn->secret_cb(conn->secret_cb_context, conn, S2N_CLIENT_HANDSHAKE_TRAFFIC_SECRET, + client_hs_secret.data, client_hs_secret.size)); + GUARD(conn->secret_cb(conn->secret_cb_context, conn, S2N_SERVER_HANDSHAKE_TRAFFIC_SECRET, + server_hs_secret.data, server_hs_secret.size)); + } + + /* produce handshake traffic keys and configure record algorithm */ + s2n_tls13_key_blob(server_hs_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); + struct s2n_blob server_hs_iv = { .data = conn->secure.server_implicit_iv, .size = S2N_TLS13_FIXED_IV_LEN }; + GUARD(s2n_tls13_derive_traffic_keys(&secrets, &server_hs_secret, &server_hs_key, &server_hs_iv)); + + s2n_tls13_key_blob(client_hs_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); + struct s2n_blob client_hs_iv = { .data = conn->secure.client_implicit_iv, .size = S2N_TLS13_FIXED_IV_LEN }; + GUARD(s2n_tls13_derive_traffic_keys(&secrets, &client_hs_secret, &client_hs_key, &client_hs_iv)); + + GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.server_key)); + GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.client_key)); + + if (conn->mode == S2N_CLIENT) { + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.server_key, &server_hs_key)); + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.client_key, &client_hs_key)); + } else { + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.server_key, &server_hs_key)); + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.client_key, &client_hs_key)); + } + + /* calculate server + client finished keys and store them in handshake struct */ + struct s2n_blob server_finished_key = { .data = conn->handshake.server_finished, .size = secrets.size }; + struct s2n_blob client_finished_key = { .data = conn->handshake.client_finished, .size = secrets.size }; + GUARD(s2n_tls13_derive_finished_key(&secrets, &server_hs_secret, &server_finished_key)); + GUARD(s2n_tls13_derive_finished_key(&secrets, &client_hs_secret, &client_finished_key)); + + /* since shared secret has been computed, clean up keys */ + GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); + for (int i = 0; i < ecc_preferences->count; i++) { + GUARD(s2n_ecc_evp_params_free(&conn->secure.client_ecc_evp_params[i])); + } + + /* According to https://tools.ietf.org/html/rfc8446#section-5.3: + * Each sequence number is set to zero at the beginning of a connection and + * whenever the key is changed + */ + GUARD(s2n_zero_sequence_number(conn, S2N_CLIENT)); + GUARD(s2n_zero_sequence_number(conn, S2N_SERVER)); + + return 0; +} + +static int s2n_tls13_handle_application_secret(struct s2n_connection *conn, s2n_mode mode) +{ + /* get tls13 key context */ + s2n_tls13_connection_keys(keys, conn); + bool is_sending_secret = (mode == conn->mode); + + uint8_t *app_secret_data, *implicit_iv_data; + struct s2n_session_key *session_key; + s2n_secret_type_t secret_type; + if (mode == S2N_CLIENT) { + app_secret_data = conn->secure.client_app_secret; + implicit_iv_data = conn->secure.client_implicit_iv; + session_key = &conn->secure.client_key; + secret_type = S2N_CLIENT_APPLICATION_TRAFFIC_SECRET; + } else { + app_secret_data = conn->secure.server_app_secret; + implicit_iv_data = conn->secure.server_implicit_iv; + session_key = &conn->secure.server_key; + secret_type = S2N_SERVER_APPLICATION_TRAFFIC_SECRET; + } + + /* use frozen hashes during the server finished state */ + struct s2n_hash_state *hash_state; + GUARD_NONNULL(hash_state = &conn->handshake.server_finished_copy); + + /* calculate secret */ + struct s2n_blob app_secret = { .data = app_secret_data, .size = keys.size }; + GUARD(s2n_tls13_derive_application_secret(&keys, hash_state, &app_secret, mode)); + + /* trigger secret callback */ + if (conn->secret_cb && conn->config->quic_enabled) { + GUARD(conn->secret_cb(conn->secret_cb_context, conn, secret_type, + app_secret.data, app_secret.size)); + } + + /* derive key from secret */ + s2n_tls13_key_blob(app_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); + struct s2n_blob app_iv = { .data = implicit_iv_data, .size = S2N_TLS13_FIXED_IV_LEN }; + GUARD(s2n_tls13_derive_traffic_keys(&keys, &app_secret, &app_key, &app_iv)); + + /* update record algorithm secrets */ + if (is_sending_secret) { + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(session_key, &app_key)); + } else { + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(session_key, &app_key)); + } + + /* According to https://tools.ietf.org/html/rfc8446#section-5.3: + * Each sequence number is set to zero at the beginning of a connection and + * whenever the key is changed + */ + GUARD(s2n_zero_sequence_number(conn, mode)); + + return S2N_SUCCESS; +} + +/* The application secrets are derived from the master secret, so the + * master secret must be handled BEFORE the application secrets. + */ +static int s2n_tls13_handle_master_secret(struct s2n_connection *conn) +{ + s2n_tls13_connection_keys(keys, conn); + GUARD(s2n_tls13_extract_master_secret(&keys)); + return S2N_SUCCESS; +} + +int s2n_tls13_handle_secrets(struct s2n_connection *conn) +{ + notnull_check(conn); + if (conn->actual_protocol_version < S2N_TLS13) { + return S2N_SUCCESS; + } + + switch(s2n_conn_get_current_message_type(conn)) { + case SERVER_HELLO: + GUARD(s2n_tls13_handle_handshake_secrets(conn)); + /* Set negotiated crypto parameters for encryption */ + conn->server = &conn->secure; + conn->client = &conn->secure; + break; + case SERVER_FINISHED: + if (conn->mode == S2N_SERVER) { + GUARD(s2n_tls13_handle_master_secret(conn)); + GUARD(s2n_tls13_handle_application_secret(conn, S2N_SERVER)); + } + break; + case CLIENT_FINISHED: + if (conn->mode == S2N_CLIENT) { + GUARD(s2n_tls13_handle_master_secret(conn)); + GUARD(s2n_tls13_handle_application_secret(conn, S2N_SERVER)); + } + GUARD(s2n_tls13_handle_application_secret(conn, S2N_CLIENT)); + break; + default: + break; + } + return S2N_SUCCESS; +} + +int s2n_update_application_traffic_keys(struct s2n_connection *conn, s2n_mode mode, keyupdate_status status) +{ + notnull_check(conn); + + /* get tls13 key context */ + s2n_tls13_connection_keys(keys, conn); + + struct s2n_session_key *old_key; + struct s2n_blob old_app_secret; + struct s2n_blob app_iv; + + if (mode == S2N_CLIENT) { + old_key = &conn->secure.client_key; + GUARD(s2n_blob_init(&old_app_secret, conn->secure.client_app_secret, keys.size)); + GUARD(s2n_blob_init(&app_iv, conn->secure.client_implicit_iv, S2N_TLS13_FIXED_IV_LEN)); + } else { + old_key = &conn->secure.server_key; + GUARD(s2n_blob_init(&old_app_secret, conn->secure.server_app_secret, keys.size)); + GUARD(s2n_blob_init(&app_iv, conn->secure.server_implicit_iv, S2N_TLS13_FIXED_IV_LEN)); + } + + /* Produce new application secret */ + s2n_stack_blob(app_secret_update, keys.size, S2N_TLS13_SECRET_MAX_LEN); + + /* Derives next generation of traffic secret */ + GUARD(s2n_tls13_update_application_traffic_secret(&keys, &old_app_secret, &app_secret_update)); + + s2n_tls13_key_blob(app_key, conn->secure.cipher_suite->record_alg->cipher->key_material_size); + + /* Derives next generation of traffic key */ + GUARD(s2n_tls13_derive_traffic_keys(&keys, &app_secret_update, &app_key, &app_iv)); + if (status == RECEIVING) { + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(old_key, &app_key)); + } else { + GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(old_key, &app_key)); + } + + /* According to https://tools.ietf.org/html/rfc8446#section-5.3: + * Each sequence number is set to zero at the beginning of a connection and + * whenever the key is changed; the first record transmitted under a particular traffic key + * MUST use sequence number 0. + */ + GUARD(s2n_zero_sequence_number(conn, mode)); + + /* Save updated secret */ + struct s2n_stuffer old_secret_stuffer = {0}; + GUARD(s2n_stuffer_init(&old_secret_stuffer, &old_app_secret)); + GUARD(s2n_stuffer_write_bytes(&old_secret_stuffer, app_secret_update.data, keys.size)); + + return S2N_SUCCESS; +} |