123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /*
- * 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 "utils/s2n_result.h"
- /* The state machine refers to the "master" secret as the "application" secret.
- * Let's use that terminology here to match.
- */
- #define S2N_APPLICATION_SECRET S2N_MASTER_SECRET
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A
- *# The notation "K_{send,recv} = foo" means "set
- *# the send/recv key to the given key".
- */
- #define K_send(conn, secret_type) RESULT_GUARD(s2n_set_key(conn, secret_type, (conn)->mode))
- #define K_recv(conn, secret_type) RESULT_GUARD(s2n_set_key(conn, secret_type, S2N_PEER_MODE((conn)->mode)))
- static const struct s2n_blob s2n_zero_length_context = { 0 };
- static S2N_RESULT s2n_zero_sequence_number(struct s2n_connection *conn, s2n_mode mode)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(conn->secure);
- struct s2n_blob sequence_number = { 0 };
- if (mode == S2N_CLIENT) {
- RESULT_GUARD_POSIX(s2n_blob_init(&sequence_number,
- conn->secure->client_sequence_number, sizeof(conn->secure->client_sequence_number)));
- } else {
- RESULT_GUARD_POSIX(s2n_blob_init(&sequence_number,
- conn->secure->server_sequence_number, sizeof(conn->secure->server_sequence_number)));
- }
- RESULT_GUARD_POSIX(s2n_blob_zero(&sequence_number));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_set_key(struct s2n_connection *conn, s2n_extract_secret_type_t secret_type, s2n_mode mode)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(conn->secure);
- RESULT_ENSURE_REF(conn->secure->cipher_suite);
- const struct s2n_cipher_suite *cipher_suite = conn->secure->cipher_suite;
- RESULT_ENSURE_REF(conn->secure->cipher_suite->record_alg);
- RESULT_ENSURE_REF(conn->secure->cipher_suite->record_alg->cipher);
- const struct s2n_cipher *cipher = conn->secure->cipher_suite->record_alg->cipher;
- uint8_t *implicit_iv_data = NULL;
- struct s2n_session_key *session_key = NULL;
- if (mode == S2N_CLIENT) {
- implicit_iv_data = conn->secure->client_implicit_iv;
- session_key = &conn->secure->client_key;
- conn->client = conn->secure;
- } else {
- implicit_iv_data = conn->secure->server_implicit_iv;
- session_key = &conn->secure->server_key;
- conn->server = conn->secure;
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.3
- *# The traffic keying material is generated from the following input
- *# values:
- *#
- *# - A secret value
- **/
- struct s2n_blob secret = { 0 };
- uint8_t secret_bytes[S2N_TLS13_SECRET_MAX_LEN] = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&secret, secret_bytes, S2N_TLS13_SECRET_MAX_LEN));
- RESULT_GUARD(s2n_tls13_secrets_get(conn, secret_type, mode, &secret));
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.3
- *#
- *# - A purpose value indicating the specific value being generated
- **/
- const struct s2n_blob *key_purpose = &s2n_tls13_label_traffic_secret_key;
- const struct s2n_blob *iv_purpose = &s2n_tls13_label_traffic_secret_iv;
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.3
- *#
- *# - The length of the key being generated
- **/
- const uint32_t key_size = cipher->key_material_size;
- const uint32_t iv_size = S2N_TLS13_FIXED_IV_LEN;
- /*
- * 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
- */
- s2n_hmac_algorithm hmac_alg = cipher_suite->prf_alg;
- DEFER_CLEANUP(struct s2n_hmac_state hmac = { 0 }, s2n_hmac_free);
- RESULT_GUARD_POSIX(s2n_hmac_new(&hmac));
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.3
- *#
- *# The traffic keying material is generated from an input traffic secret
- *# value using:
- *#
- *# [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
- **/
- struct s2n_blob key = { 0 };
- uint8_t key_bytes[S2N_TLS13_SECRET_MAX_LEN] = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&key, key_bytes, key_size));
- RESULT_GUARD_POSIX(s2n_hkdf_expand_label(&hmac, hmac_alg,
- &secret, key_purpose, &s2n_zero_length_context, &key));
- /**
- *= https://tools.ietf.org/rfc/rfc8446#section-7.3
- *# [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)
- **/
- struct s2n_blob iv = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&iv, implicit_iv_data, iv_size));
- RESULT_GUARD_POSIX(s2n_hkdf_expand_label(&hmac, hmac_alg,
- &secret, iv_purpose, &s2n_zero_length_context, &iv));
- bool is_sending_secret = (mode == conn->mode);
- if (is_sending_secret) {
- RESULT_GUARD_POSIX(cipher->set_encryption_key(session_key, &key));
- } else {
- RESULT_GUARD_POSIX(cipher->set_decryption_key(session_key, &key));
- }
- /**
- *= https://tools.ietf.org/rfc/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.
- */
- RESULT_GUARD(s2n_zero_sequence_number(conn, mode));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_client_key_schedule(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- message_type_t message_type = s2n_conn_get_current_message_type(conn);
- /**
- * How client keys are set varies depending on early data state.
- *
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A
- *# Actions which are taken only in certain circumstances
- *# are indicated in [].
- */
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.1
- *# START <----+
- *# Send ClientHello | | Recv HelloRetryRequest
- *# [K_send = early data] | |
- */
- if (message_type == CLIENT_HELLO
- && conn->early_data_state == S2N_EARLY_DATA_REQUESTED) {
- K_send(conn, S2N_EARLY_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.1
- *# v |
- *# / WAIT_SH ----+
- *# | | Recv ServerHello
- *# | | K_recv = handshake
- */
- if (message_type == SERVER_HELLO) {
- K_recv(conn, S2N_HANDSHAKE_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.1
- *# Can | V
- *# send | WAIT_EE
- *# early | | Recv EncryptedExtensions
- *# data | +--------+--------+
- *# | Using | | Using certificate
- *# | PSK | v
- *# | | WAIT_CERT_CR
- *# | | Recv | | Recv CertificateRequest
- *# | | Certificate | v
- *# | | | WAIT_CERT
- *# | | | | Recv Certificate
- *# | | v v
- *# | | WAIT_CV
- *# | | | Recv CertificateVerify
- *# | +> WAIT_FINISHED <+
- *# | | Recv Finished
- *# \ | [Send EndOfEarlyData]
- *# | K_send = handshake
- */
- if ((message_type == SERVER_FINISHED && !WITH_EARLY_DATA(conn))
- || (message_type == END_OF_EARLY_DATA)) {
- K_send(conn, S2N_HANDSHAKE_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.1
- *# | [Send Certificate [+ CertificateVerify]]
- *# Can send | Send Finished
- *# app data --> | K_send = K_recv = application
- */
- if (message_type == CLIENT_FINISHED) {
- K_send(conn, S2N_APPLICATION_SECRET);
- K_recv(conn, S2N_APPLICATION_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.1
- *# after here v
- *# CONNECTED
- */
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_server_key_schedule(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- message_type_t message_type = s2n_conn_get_current_message_type(conn);
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2
- *# START <-----+
- *# Recv ClientHello | | Send HelloRetryRequest
- *# v |
- *# RECVD_CH ----+
- *# | Select parameters
- *# v
- *# NEGOTIATED
- *# | Send ServerHello
- *# | K_send = handshake
- */
- if (message_type == SERVER_HELLO) {
- K_send(conn, S2N_HANDSHAKE_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2
- *# | Send EncryptedExtensions
- *# | [Send CertificateRequest]
- *# Can send | [Send Certificate + CertificateVerify]
- *# app data | Send Finished
- *# after --> | K_send = application
- */
- if (message_type == SERVER_FINISHED) {
- K_send(conn, S2N_APPLICATION_SECRET);
- /* clang-format off */
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2
- *# here +--------+--------+
- *# No 0-RTT | | 0-RTT
- *# | |
- *# K_recv = handshake | | K_recv = early data
- */
- /* clang-format on */
- if (WITH_EARLY_DATA(conn)) {
- K_recv(conn, S2N_EARLY_SECRET);
- } else {
- K_recv(conn, S2N_HANDSHAKE_SECRET);
- }
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2
- *# [Skip decrypt errors] | +------> WAIT_EOED -+
- *# | | Recv | | Recv EndOfEarlyData
- *# | | early data | | K_recv = handshake
- *# | +------------+ |
- */
- if (message_type == END_OF_EARLY_DATA) {
- K_recv(conn, S2N_HANDSHAKE_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2
- *# | |
- *# +> WAIT_FLIGHT2 <--------+
- *# |
- *# +--------+--------+
- *# No auth | | Client auth
- *# | |
- *# | v
- *# | WAIT_CERT
- *# | Recv | | Recv Certificate
- *# | empty | v
- *# | Certificate | WAIT_CV
- *# | | | Recv
- *# | v | CertificateVerify
- *# +-> WAIT_FINISHED <---+
- *# | Recv Finished
- *# | K_recv = application
- */
- if (message_type == CLIENT_FINISHED) {
- K_recv(conn, S2N_APPLICATION_SECRET);
- }
- /**
- *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2
- *# v
- *# CONNECTED
- */
- return S2N_RESULT_OK;
- }
- s2n_result (*key_schedules[])(struct s2n_connection *) = {
- [S2N_CLIENT] = &s2n_client_key_schedule,
- [S2N_SERVER] = &s2n_server_key_schedule,
- };
- S2N_RESULT s2n_tls13_key_schedule_update(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) {
- return S2N_RESULT_OK;
- }
- RESULT_ENSURE_REF(key_schedules[conn->mode]);
- RESULT_GUARD(key_schedules[conn->mode](conn));
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_tls13_key_schedule_reset(struct s2n_connection *conn)
- {
- RESULT_ENSURE_REF(conn);
- RESULT_ENSURE_REF(conn->initial);
- conn->client = conn->initial;
- conn->server = conn->initial;
- conn->secrets.extract_secret_type = S2N_NONE_SECRET;
- return S2N_RESULT_OK;
- }
|