diff options
author | thegeorg <thegeorg@yandex-team.ru> | 2022-05-10 22:16:03 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.ru> | 2022-05-10 22:16:03 +0300 |
commit | 09c71d918d4d0b0ebf67e1ab41aa90ddf587a3f2 (patch) | |
tree | dd44d2cb68e2845c2d4c367b66893f3e043a6e8e /contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.c | |
parent | 5eb4a8a2d487411924e1d1b27c454223dcf35005 (diff) | |
download | ydb-09c71d918d4d0b0ebf67e1ab41aa90ddf587a3f2.tar.gz |
Update contrib/restricted/aws/s2n to 1.3.12
ref:f8279d764b4c00974a63543a1364c91e2b81b7a6
Diffstat (limited to 'contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.c')
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.c b/contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.c new file mode 100644 index 0000000000..16fd78c042 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.c @@ -0,0 +1,328 @@ +/* + * 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); + struct s2n_blob sequence_number; + 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.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) +{ + 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) +{ + 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); + /** + *= https://tools.ietf.org/rfc/rfc8446#appendix-A.2 + *# here +--------+--------+ + *# No 0-RTT | | 0-RTT + *# | | + *# K_recv = handshake | | K_recv = early data + */ + 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); + conn->client = &conn->initial; + conn->server = &conn->initial; + conn->secrets.tls13.extract_secret_type = S2N_NONE_SECRET; + return S2N_RESULT_OK; +} |