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 | |
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')
145 files changed, 11405 insertions, 4841 deletions
diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_alpn.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_alpn.c index e66b7c0478..b7fd2678ed 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_alpn.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_alpn.c @@ -19,6 +19,7 @@ #include "tls/extensions/s2n_client_alpn.h" #include "tls/extensions/s2n_extension_type.h" +#include "tls/s2n_protocol_preferences.h" #include "tls/s2n_tls.h" #include "tls/s2n_tls_parameters.h" @@ -48,11 +49,11 @@ static bool s2n_client_alpn_should_send(struct s2n_connection *conn) static int s2n_client_alpn_send(struct s2n_connection *conn, struct s2n_stuffer *out) { struct s2n_blob *client_app_protocols; - GUARD(s2n_connection_get_protocol_preferences(conn, &client_app_protocols)); - notnull_check(client_app_protocols); + POSIX_GUARD(s2n_connection_get_protocol_preferences(conn, &client_app_protocols)); + POSIX_ENSURE_REF(client_app_protocols); - GUARD(s2n_stuffer_write_uint16(out, client_app_protocols->size)); - GUARD(s2n_stuffer_write(out, client_app_protocols)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, client_app_protocols->size)); + POSIX_GUARD(s2n_stuffer_write(out, client_app_protocols)); return S2N_SUCCESS; } @@ -60,18 +61,17 @@ static int s2n_client_alpn_send(struct s2n_connection *conn, struct s2n_stuffer static int s2n_client_alpn_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint16_t size_of_all; - struct s2n_stuffer client_protos = {0}; struct s2n_stuffer server_protos = {0}; struct s2n_blob *server_app_protocols; - GUARD(s2n_connection_get_protocol_preferences(conn, &server_app_protocols)); + POSIX_GUARD(s2n_connection_get_protocol_preferences(conn, &server_app_protocols)); if (!server_app_protocols->size) { /* No protocols configured, nothing to do */ return S2N_SUCCESS; } - GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all < 3) { /* Malformed length, ignore the extension */ return S2N_SUCCESS; @@ -80,38 +80,26 @@ static int s2n_client_alpn_recv(struct s2n_connection *conn, struct s2n_stuffer struct s2n_blob client_app_protocols = { 0 }; client_app_protocols.size = size_of_all; client_app_protocols.data = s2n_stuffer_raw_read(extension, size_of_all); - notnull_check(client_app_protocols.data); + POSIX_ENSURE_REF(client_app_protocols.data); /* Find a matching protocol */ - GUARD(s2n_stuffer_init(&client_protos, &client_app_protocols)); - GUARD(s2n_stuffer_write(&client_protos, &client_app_protocols)); - GUARD(s2n_stuffer_init(&server_protos, server_app_protocols)); - GUARD(s2n_stuffer_write(&server_protos, server_app_protocols)); - - while (s2n_stuffer_data_available(&server_protos)) { - uint8_t length; - uint8_t server_protocol[255]; - GUARD(s2n_stuffer_read_uint8(&server_protos, &length)); - GUARD(s2n_stuffer_read_bytes(&server_protos, server_protocol, length)); - - while (s2n_stuffer_data_available(&client_protos)) { - uint8_t client_length; - GUARD(s2n_stuffer_read_uint8(&client_protos, &client_length)); - S2N_ERROR_IF(client_length > s2n_stuffer_data_available(&client_protos), S2N_ERR_BAD_MESSAGE); - if (client_length != length) { - GUARD(s2n_stuffer_skip_read(&client_protos, client_length)); - } else { - uint8_t client_protocol[255]; - GUARD(s2n_stuffer_read_bytes(&client_protos, client_protocol, client_length)); - if (memcmp(client_protocol, server_protocol, client_length) == 0) { - memcpy_check(conn->application_protocol, client_protocol, client_length); - conn->application_protocol[client_length] = '\0'; - return S2N_SUCCESS; - } - } + POSIX_GUARD(s2n_stuffer_init(&server_protos, server_app_protocols)); + POSIX_GUARD(s2n_stuffer_skip_write(&server_protos, server_app_protocols->size)); + + while (s2n_stuffer_data_available(&server_protos) > 0) { + struct s2n_blob server_protocol = { 0 }; + POSIX_ENSURE(s2n_result_is_ok(s2n_protocol_preferences_read(&server_protos, &server_protocol)), + S2N_ERR_BAD_MESSAGE); + + bool is_match = false; + POSIX_ENSURE(s2n_result_is_ok(s2n_protocol_preferences_contain(&client_app_protocols, &server_protocol, &is_match)), + S2N_ERR_BAD_MESSAGE); + + if (is_match) { + POSIX_CHECKED_MEMCPY(conn->application_protocol, server_protocol.data, server_protocol.size); + conn->application_protocol[server_protocol.size] = '\0'; + return S2N_SUCCESS; } - - GUARD(s2n_stuffer_reread(&client_protos)); } return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_early_data_indication.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_early_data_indication.c new file mode 100644 index 0000000000..3cfea591cd --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_early_data_indication.c @@ -0,0 +1,186 @@ +/* + * 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 "api/s2n.h" + +#include "tls/extensions/s2n_early_data_indication.h" + +#include "tls/extensions/s2n_client_psk.h" +#include "tls/s2n_cipher_suites.h" +#include "tls/s2n_early_data.h" +#include "tls/s2n_protocol_preferences.h" +#include "tls/s2n_tls13.h" +#include "utils/s2n_safety.h" + +/* S2N determines the handshake type after the ServerHello, but that will be + * too late to handle the early data + middlebox compatibility case: + * + *= https://tools.ietf.org/rfc/rfc8446#appendix-D.4 + *# - If not offering early data, the client sends a dummy + *# change_cipher_spec record (see the third paragraph of Section 5) + *# immediately before its second flight. This may either be before + *# its second ClientHello or before its encrypted handshake flight. + *# If offering early data, the record is placed immediately after the + *# first ClientHello. + * + * We need to set the handshake type flags in question during the ClientHello. + * This will require special [INITIAL | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] + * entries in the handshake arrays. + */ +static S2N_RESULT s2n_setup_middlebox_compat_for_early_data(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + if (s2n_is_middlebox_compat_enabled(conn)) { + RESULT_GUARD(s2n_handshake_type_set_tls13_flag(conn, MIDDLEBOX_COMPAT)); + RESULT_GUARD(s2n_handshake_type_set_tls13_flag(conn, EARLY_CLIENT_CCS)); + } + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_early_data_config_is_possible(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + struct s2n_psk *first_psk = NULL; + RESULT_GUARD(s2n_array_get(&conn->psk_params.psk_list, 0, (void**) &first_psk)); + RESULT_ENSURE_REF(first_psk); + + struct s2n_early_data_config *early_data_config = &first_psk->early_data_config; + + /* Must support early data */ + RESULT_ENSURE_GT(early_data_config->max_early_data_size, 0); + + /* Early data must require a protocol than we could negotiate */ + RESULT_ENSURE_GTE(s2n_connection_get_protocol_version(conn), early_data_config->protocol_version); + RESULT_ENSURE_GTE(s2n_connection_get_protocol_version(conn), S2N_TLS13); + + const struct s2n_cipher_preferences *cipher_preferences = NULL; + RESULT_GUARD_POSIX(s2n_connection_get_cipher_preferences(conn, &cipher_preferences)); + RESULT_ENSURE_REF(cipher_preferences); + + /* Early data must require a supported cipher */ + bool match = false; + for (uint8_t i = 0; i < cipher_preferences->count; i++) { + if (cipher_preferences->suites[i] == early_data_config->cipher_suite) { + match = true; + break; + } + } + RESULT_ENSURE_EQ(match, true); + + /* If early data specifies an application protocol, it must be supported by protocol preferences */ + if (early_data_config->application_protocol.size > 0) { + struct s2n_blob *application_protocols = NULL; + RESULT_GUARD_POSIX(s2n_connection_get_protocol_preferences(conn, &application_protocols)); + RESULT_ENSURE_REF(application_protocols); + + match = false; + RESULT_GUARD(s2n_protocol_preferences_contain(application_protocols, &early_data_config->application_protocol, &match)); + RESULT_ENSURE_EQ(match, true); + } + + return S2N_RESULT_OK; +} + +static bool s2n_client_early_data_indication_should_send(struct s2n_connection *conn) +{ + return s2n_result_is_ok(s2n_early_data_config_is_possible(conn)) + && conn && conn->early_data_expected + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# A client MUST NOT include the + *# "early_data" extension in its followup ClientHello. + **/ + && !s2n_is_hello_retry_handshake(conn) + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# When a PSK is used and early data is allowed for that PSK, the client + *# can send Application Data in its first flight of messages. If the + *# client opts to do so, it MUST supply both the "pre_shared_key" and + *# "early_data" extensions. + */ + && s2n_client_psk_extension.should_send(conn); +} + +static int s2n_client_early_data_indication_is_missing(struct s2n_connection *conn) +{ + if (conn->early_data_state != S2N_EARLY_DATA_REJECTED) { + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_NOT_REQUESTED)); + } + return S2N_SUCCESS; +} + +/** + * The client version of this extension is empty, so we don't read/write any data. + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# The "extension_data" field of this extension contains an + *# "EarlyDataIndication" value. + *# + *# struct {} Empty; + *# + *# struct { + *# select (Handshake.msg_type) { + ** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# case client_hello: Empty; + ** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# }; + *# } EarlyDataIndication; + **/ + +static int s2n_client_early_data_indication_send(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + POSIX_GUARD_RESULT(s2n_setup_middlebox_compat_for_early_data(conn)); + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REQUESTED)); + + /* Set the cipher suite for early data */ + struct s2n_psk *first_psk = NULL; + POSIX_GUARD_RESULT(s2n_array_get(&conn->psk_params.psk_list, 0, (void**) &first_psk)); + POSIX_ENSURE_REF(first_psk); + conn->secure.cipher_suite = first_psk->early_data_config.cipher_suite; + + return S2N_SUCCESS; +} + +static int s2n_client_early_data_indiction_recv(struct s2n_connection *conn, struct s2n_stuffer *in) +{ + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# A client MUST NOT include the + *# "early_data" extension in its followup ClientHello. + */ + POSIX_ENSURE(conn->handshake.message_number == 0, S2N_ERR_UNSUPPORTED_EXTENSION); + + /* Although technically we could NOT set the [MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] handshake type + * for the server because the server ignores the Client CCS message state, doing so would mean that + * the client and server state machines would be out of sync and potentially cause confusion. + */ + POSIX_GUARD_RESULT(s2n_setup_middlebox_compat_for_early_data(conn)); + + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REQUESTED)); + return S2N_SUCCESS; +} + +const s2n_extension_type s2n_client_early_data_indication_extension = { + .iana_value = TLS_EXTENSION_EARLY_DATA, + .is_response = false, + .send = s2n_client_early_data_indication_send, + .recv = s2n_client_early_data_indiction_recv, + .should_send = s2n_client_early_data_indication_should_send, + .if_missing = s2n_client_early_data_indication_is_missing, +}; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_ems.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_ems.c new file mode 100644 index 0000000000..36ec3d339f --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_ems.c @@ -0,0 +1,63 @@ +/* + * 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 <sys/param.h> +#include <stdint.h> + +#include "tls/s2n_tls.h" +#include "tls/extensions/s2n_ems.h" + +#include "utils/s2n_safety.h" + +static int s2n_client_ems_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); +static bool s2n_client_ems_should_send(struct s2n_connection *conn); + +/** + *= https://tools.ietf.org/rfc/rfc7627#section-5.1 + *# + *# This document defines a new TLS extension, "extended_master_secret" + *# (with extension type 0x0017), which is used to signal both client and + *# server to use the extended master secret computation. The + *# "extension_data" field of this extension is empty. Thus, the entire + *# encoding of the extension is 00 17 00 00 (in hexadecimal.) + **/ +const s2n_extension_type s2n_client_ems_extension = { + .iana_value = TLS_EXTENSION_EMS, + .is_response = false, + .send = s2n_extension_send_noop, + .recv = s2n_client_ems_recv, + .should_send = s2n_client_ems_should_send, + .if_missing = s2n_extension_noop_if_missing, +}; + +static int s2n_client_ems_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) +{ + POSIX_ENSURE_REF(conn); + + /* Read nothing. The extension just needs to exist. */ + conn->ems_negotiated = true; + + return S2N_SUCCESS; +} + +static bool s2n_client_ems_should_send(struct s2n_connection *conn) +{ + /* Don't send this extension if the previous session did not negotiate EMS */ + if (conn->set_session && !conn->ems_negotiated) { + return false; + } else { + return true; + } +} diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_key_share.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_key_share.c index 178f2e9c1d..6073263014 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_key_share.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_key_share.c @@ -24,8 +24,6 @@ #include "tls/s2n_tls13.h" #include "pq-crypto/s2n_pq.h" -#define S2N_IS_KEY_SHARE_LIST_EMPTY(preferred_key_shares) (preferred_key_shares & 1) -#define S2N_IS_KEY_SHARE_REQUESTED(preferred_key_shares, i) ((preferred_key_shares >> (i + 1)) & 1) /** * Specified in https://tools.ietf.org/html/rfc8446#section-4.2.8 * "The "key_share" extension contains the endpoint's cryptographic parameters." @@ -54,64 +52,57 @@ static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stu const s2n_extension_type s2n_client_key_share_extension = { .iana_value = TLS_EXTENSION_KEY_SHARE, + .minimum_version = S2N_TLS13, .is_response = false, .send = s2n_client_key_share_send, .recv = s2n_client_key_share_recv, - .should_send = s2n_extension_send_if_tls13_connection, + .should_send = s2n_extension_always_send, .if_missing = s2n_extension_noop_if_missing, }; -static int s2n_generate_preferred_ecc_key_shares(struct s2n_connection *conn, struct s2n_stuffer *out) +static int s2n_generate_default_ecc_key_share(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - uint8_t preferred_key_shares = conn->preferred_key_shares; - struct s2n_ecc_evp_params *ecc_evp_params = NULL; - + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); - /* If lsb is set, skip keyshare generation for all curve */ - if (S2N_IS_KEY_SHARE_LIST_EMPTY(preferred_key_shares)) { - return S2N_SUCCESS; - } + /* We only ever send a single EC key share: either the share requested by the server + * during a retry, or the most preferred share according to local preferences. + */ + struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params; + if (s2n_is_hello_retry_handshake(conn)) { + const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve; - for (size_t i = 0; i < ecc_pref->count; i++) { - /* If a bit in the bitmap (minus the lsb) is set, generate keyshare for the corresponding curve */ - if (S2N_IS_KEY_SHARE_REQUESTED(preferred_key_shares, i)) { - ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; - ecc_evp_params->negotiated_curve = ecc_pref->ecc_curves[i]; - GUARD(s2n_ecdhe_parameters_send(ecc_evp_params, out)); + /* If the server did not request a specific ECC keyshare, don't send one */ + if (!server_curve) { + return S2N_SUCCESS; } - } - return S2N_SUCCESS; -} - -static int s2n_generate_default_ecc_key_share(struct s2n_connection *conn, struct s2n_stuffer *out) -{ - notnull_check(conn); - const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + /* If the server requested a new ECC keyshare, free the old one */ + if (server_curve != client_params->negotiated_curve) { + POSIX_GUARD(s2n_ecc_evp_params_free(client_params)); + } - struct s2n_ecc_evp_params *ecc_evp_params = NULL; - ecc_evp_params = &conn->secure.client_ecc_evp_params[0]; - ecc_evp_params->negotiated_curve = ecc_pref->ecc_curves[0]; - GUARD(s2n_ecdhe_parameters_send(ecc_evp_params, out)); + client_params->negotiated_curve = server_curve; + } else { + client_params->negotiated_curve = ecc_pref->ecc_curves[0]; + } + POSIX_GUARD(s2n_ecdhe_parameters_send(client_params, out)); return S2N_SUCCESS; } -static int s2n_generate_pq_hybrid_key_share(struct s2n_stuffer *out, struct s2n_kem_group_params *kem_group_params) { - notnull_check(out); - notnull_check(kem_group_params); +static int s2n_generate_pq_hybrid_key_share(struct s2n_stuffer *out, struct s2n_kem_group_params *kem_group_params) +{ + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(kem_group_params); /* This function should never be called when PQ is disabled */ - ENSURE_POSIX(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); + POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); const struct s2n_kem_group *kem_group = kem_group_params->kem_group; - notnull_check(kem_group); + POSIX_ENSURE_REF(kem_group); /* The structure of the PQ share is: * IANA ID (2 bytes) @@ -120,29 +111,28 @@ static int s2n_generate_pq_hybrid_key_share(struct s2n_stuffer *out, struct s2n_ * || ECC key share (variable bytes) * || size of PQ key share (2 bytes) * || PQ key share (variable bytes) */ - GUARD(s2n_stuffer_write_uint16(out, kem_group->iana_id)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_group->iana_id)); struct s2n_stuffer_reservation total_share_size = {0}; - GUARD(s2n_stuffer_reserve_uint16(out, &total_share_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &total_share_size)); struct s2n_ecc_evp_params *ecc_params = &kem_group_params->ecc_params; ecc_params->negotiated_curve = kem_group->curve; - GUARD(s2n_stuffer_write_uint16(out, ecc_params->negotiated_curve->share_size)); - GUARD(s2n_ecc_evp_generate_ephemeral_key(ecc_params)); - GUARD(s2n_ecc_evp_write_params_point(ecc_params, out)); + POSIX_GUARD_RESULT(s2n_ecdhe_send_public_key(ecc_params, out)); struct s2n_kem_params *kem_params = &kem_group_params->kem_params; kem_params->kem = kem_group->kem; - GUARD(s2n_kem_send_public_key(out, kem_params)); + POSIX_GUARD(s2n_kem_send_public_key(out, kem_params)); - GUARD(s2n_stuffer_write_vector_size(&total_share_size)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&total_share_size)); return S2N_SUCCESS; } -static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - notnull_check(out); +static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(out); /* Client should skip sending PQ groups/key shares if PQ is disabled */ if (!s2n_pq_is_enabled()) { @@ -150,206 +140,113 @@ static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn, } const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); if (kem_pref->tls13_kem_group_count == 0) { return S2N_SUCCESS; } - /* We only send a single PQ key share - the highest preferred one */ - struct s2n_kem_group_params *kem_group_params = &conn->secure.client_kem_group_params[0]; - kem_group_params->kem_group = kem_pref->tls13_kem_groups[0]; - - GUARD(s2n_generate_pq_hybrid_key_share(out, kem_group_params)); - - return S2N_SUCCESS; -} - -static int s2n_wipe_all_client_keyshares(struct s2n_connection *conn) { - notnull_check(conn); - - const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); - - const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); - - for (size_t i = 0; i < ecc_pref->count; i++) { - GUARD(s2n_ecc_evp_params_free(&conn->secure.client_ecc_evp_params[i])); - conn->secure.client_ecc_evp_params[i].negotiated_curve = NULL; - } - - for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - GUARD(s2n_kem_group_free(&conn->secure.client_kem_group_params[i])); - conn->secure.client_kem_group_params[i].kem_group = NULL; - conn->secure.client_kem_group_params[i].kem_params.kem = NULL; - conn->secure.client_kem_group_params[i].ecc_params.negotiated_curve = NULL; - } - - return S2N_SUCCESS; -} - -static int s2n_send_hrr_ecc_keyshare(struct s2n_connection *conn, struct s2n_stuffer *out) -{ - notnull_check(conn); - const struct s2n_ecc_named_curve *server_negotiated_curve = NULL; - struct s2n_ecc_evp_params *ecc_evp_params = NULL; - - const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); - - server_negotiated_curve = conn->secure.server_ecc_evp_params.negotiated_curve; - ENSURE_POSIX(server_negotiated_curve != NULL, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(s2n_ecc_preferences_includes_curve(ecc_pref, server_negotiated_curve->iana_id), - S2N_ERR_INVALID_HELLO_RETRY); + /* We only ever send a single PQ key share: either the share requested by the server + * during a retry, or the most preferred share according to local preferences. + */ + struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params; + if (s2n_is_hello_retry_handshake(conn)) { + const struct s2n_kem_group *server_group = conn->kex_params.server_kem_group_params.kem_group; - for (size_t i = 0; i < ecc_pref->count; i++) { - if (ecc_pref->ecc_curves[i]->iana_id == server_negotiated_curve->iana_id) { - ecc_evp_params = &conn->secure.client_ecc_evp_params[i]; - ENSURE_POSIX(ecc_evp_params->evp_pkey == NULL, S2N_ERR_INVALID_HELLO_RETRY); + /* If the server did not request a specific PQ keyshare, don't send one */ + if (!server_group) { + return S2N_SUCCESS; } - } - - /* None of the previously generated keyshares were selected for negotiation, so wipe them */ - GUARD(s2n_wipe_all_client_keyshares(conn)); - /* Generate the keyshare for the server negotiated curve */ - ecc_evp_params->negotiated_curve = server_negotiated_curve; - GUARD(s2n_ecdhe_parameters_send(ecc_evp_params, out)); - - return S2N_SUCCESS; -} - -static int s2n_send_hrr_pq_hybrid_keyshare(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - notnull_check(out); - - /* If PQ is disabled, the client should not have sent any PQ IDs - * in the supported_groups list of the initial ClientHello */ - ENSURE_POSIX(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); - const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); - - const struct s2n_kem_group *server_negotiated_kem_group = conn->secure.server_kem_group_params.kem_group; - ENSURE_POSIX(server_negotiated_kem_group != NULL, S2N_ERR_INVALID_HELLO_RETRY); - ENSURE_POSIX(s2n_kem_preferences_includes_tls13_kem_group(kem_pref, server_negotiated_kem_group->iana_id), - S2N_ERR_INVALID_HELLO_RETRY); - struct s2n_kem_group_params *kem_group_params = NULL; - - for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - if (kem_pref->tls13_kem_groups[i]->iana_id == server_negotiated_kem_group->iana_id) { - kem_group_params = &conn->secure.client_kem_group_params[i]; - ENSURE_POSIX(kem_group_params->kem_group == NULL, S2N_ERR_INVALID_HELLO_RETRY); - ENSURE_POSIX(kem_group_params->ecc_params.evp_pkey == NULL, S2N_ERR_INVALID_HELLO_RETRY); - ENSURE_POSIX(kem_group_params->kem_params.private_key.data == NULL, S2N_ERR_INVALID_HELLO_RETRY); + /* If the server requested a new PQ keyshare, free the old one */ + if (client_params->kem_group != server_group) { + POSIX_GUARD(s2n_kem_group_free(client_params)); } - } - - /* None of the previously generated keyshares were selected for negotiation, so wipe them */ - GUARD(s2n_wipe_all_client_keyshares(conn)); - /* Generate the keyshare for the server negotiated KEM group */ - kem_group_params->kem_group = server_negotiated_kem_group; - GUARD(s2n_generate_pq_hybrid_key_share(out, kem_group_params)); - - return S2N_SUCCESS; -} -/* From https://tools.ietf.org/html/rfc8446#section-4.1.2 - * If a "key_share" extension was supplied in the HelloRetryRequest, - * replace the list of shares with a list containing a single - * KeyShareEntry from the indicated group.*/ -static int s2n_send_hrr_keyshare(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - notnull_check(out); - - if (conn->secure.server_kem_group_params.kem_group != NULL) { - GUARD(s2n_send_hrr_pq_hybrid_keyshare(conn, out)); + client_params->kem_group = server_group; } else { - GUARD(s2n_send_hrr_ecc_keyshare(conn, out)); + client_params->kem_group = kem_pref->tls13_kem_groups[0]; } + POSIX_GUARD(s2n_generate_pq_hybrid_key_share(out, client_params)); return S2N_SUCCESS; } -static int s2n_ecdhe_supported_curves_send(struct s2n_connection *conn, struct s2n_stuffer *out) -{ - if (!conn->preferred_key_shares) { - GUARD(s2n_generate_default_ecc_key_share(conn, out)); - return S2N_SUCCESS; - } - - GUARD(s2n_generate_preferred_ecc_key_shares(conn, out)); - return S2N_SUCCESS; -} - static int s2n_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out) { struct s2n_stuffer_reservation shares_size = {0}; - GUARD(s2n_stuffer_reserve_uint16(out, &shares_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &shares_size)); + POSIX_GUARD(s2n_generate_default_pq_hybrid_key_share(conn, out)); + POSIX_GUARD(s2n_generate_default_ecc_key_share(conn, out)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&shares_size)); - if (s2n_is_hello_retry_handshake(conn)) { - GUARD(s2n_send_hrr_keyshare(conn, out)); - } else { - GUARD(s2n_generate_default_pq_hybrid_key_share(conn, out)); - GUARD(s2n_ecdhe_supported_curves_send(conn, out)); - } - - GUARD(s2n_stuffer_write_vector_size(&shares_size)); + /* We must have written at least one share */ + POSIX_ENSURE(s2n_stuffer_data_available(out) > shares_size.length, S2N_ERR_BAD_KEY_SHARE); return S2N_SUCCESS; } static int s2n_client_key_share_parse_ecc(struct s2n_stuffer *key_share, const struct s2n_ecc_named_curve *curve, - struct s2n_ecc_evp_params *ecc_params) { - notnull_check(key_share); - notnull_check(curve); - notnull_check(ecc_params); + struct s2n_ecc_evp_params *ecc_params) +{ + POSIX_ENSURE_REF(key_share); + POSIX_ENSURE_REF(curve); + POSIX_ENSURE_REF(ecc_params); struct s2n_blob point_blob = { 0 }; - GUARD(s2n_ecc_evp_read_params_point(key_share, curve->share_size, &point_blob)); + POSIX_GUARD(s2n_ecc_evp_read_params_point(key_share, curve->share_size, &point_blob)); /* Ignore curves with points we can't parse */ ecc_params->negotiated_curve = curve; if (s2n_ecc_evp_parse_params_point(&point_blob, ecc_params) != S2N_SUCCESS) { ecc_params->negotiated_curve = NULL; - GUARD(s2n_ecc_evp_params_free(ecc_params)); + POSIX_GUARD(s2n_ecc_evp_params_free(ecc_params)); } return S2N_SUCCESS; } -static int s2n_client_key_share_recv_ecc(struct s2n_connection *conn, struct s2n_stuffer *key_share, - uint16_t curve_iana_id, bool *match) { - notnull_check(conn); - notnull_check(key_share); - notnull_check(match); +static int s2n_client_key_share_recv_ecc(struct s2n_connection *conn, struct s2n_stuffer *key_share, uint16_t curve_iana_id) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(key_share); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); + + struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params; const struct s2n_ecc_named_curve *curve = NULL; - struct s2n_ecc_evp_params *client_ecc_params = NULL; for (size_t i = 0; i < ecc_pref->count; i++) { - if (curve_iana_id == ecc_pref->ecc_curves[i]->iana_id) { - curve = ecc_pref->ecc_curves[i]; - client_ecc_params = &conn->secure.client_ecc_evp_params[i]; + const struct s2n_ecc_named_curve *supported_curve = ecc_pref->ecc_curves[i]; + POSIX_ENSURE_REF(supported_curve); + + /* Stop if we reach the current highest priority share. + * Any share of lower priority is discarded. + */ + if (client_params->negotiated_curve == supported_curve) { break; } - } - /* Ignore unsupported curves */ - if (!curve || !client_ecc_params) { - return S2N_SUCCESS; + /* Skip if not supported by the client. + * The client must not send shares it doesn't support, but the server + * is not required to error if they are encountered. + */ + if (!conn->kex_params.mutually_supported_curves[i]) { + continue; + } + + /* Stop if we find a match */ + if (curve_iana_id == supported_curve->iana_id) { + curve = supported_curve; + break; + } } - /* Ignore curves that we've already received material for */ - if (client_ecc_params->negotiated_curve) { + /* Ignore unsupported curves */ + if (!curve) { return S2N_SUCCESS; } @@ -358,47 +255,66 @@ static int s2n_client_key_share_recv_ecc(struct s2n_connection *conn, struct s2n return S2N_SUCCESS; } - GUARD(s2n_client_key_share_parse_ecc(key_share, curve, client_ecc_params)); - /* negotiated_curve will be non-NULL if the key share was parsed successfully */ - if (client_ecc_params->negotiated_curve) { - *match = true; + DEFER_CLEANUP(struct s2n_ecc_evp_params new_client_params = { 0 }, s2n_ecc_evp_params_free); + + POSIX_GUARD(s2n_client_key_share_parse_ecc(key_share, curve, &new_client_params)); + /* negotiated_curve will be NULL if the key share was not parsed successfully */ + if (!new_client_params.negotiated_curve) { + return S2N_SUCCESS; } + POSIX_GUARD(s2n_ecc_evp_params_free(client_params)); + *client_params = new_client_params; + + ZERO_TO_DISABLE_DEFER_CLEANUP(new_client_params); return S2N_SUCCESS; } -static int s2n_client_key_share_recv_pq_hybrid(struct s2n_connection *conn, struct s2n_stuffer *key_share, - uint16_t kem_group_iana_id, bool *match) { - notnull_check(conn); - notnull_check(key_share); - notnull_check(match); +static int s2n_client_key_share_recv_pq_hybrid(struct s2n_connection *conn, struct s2n_stuffer *key_share, uint16_t kem_group_iana_id) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(key_share); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); /* Ignore key share if PQ is not enabled */ if (!s2n_pq_is_enabled()) { return S2N_SUCCESS; } + struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params; + const struct s2n_kem_group *kem_group = NULL; - struct s2n_kem_group_params *client_kem_group_params = NULL; for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - if (kem_group_iana_id == kem_pref->tls13_kem_groups[i]->iana_id) { - kem_group = kem_pref->tls13_kem_groups[i]; - client_kem_group_params = &conn->secure.client_kem_group_params[i]; + const struct s2n_kem_group *supported_group = kem_pref->tls13_kem_groups[i]; + POSIX_ENSURE_REF(supported_group); + + /* Stop if we reach the current highest priority share. + * Any share of lower priority is discarded. + */ + if (client_params->kem_group == supported_group) { break; } - } - /* Ignore unsupported KEM groups */ - if (!kem_group || !client_kem_group_params) { - return S2N_SUCCESS; + /* Skip if not supported by the client. + * The client must not send shares it doesn't support, but the server + * is not required to error if they are encountered. + */ + if (!conn->kex_params.mutually_supported_kem_groups[i]) { + continue; + } + + /* Stop if we find a match */ + if (kem_group_iana_id == supported_group->iana_id) { + kem_group = supported_group; + break; + } } - /* Ignore KEM groups that we've already received material for */ - if (client_kem_group_params->kem_group) { + /* Ignore unsupported KEM groups */ + if (!kem_group) { return S2N_SUCCESS; } @@ -407,85 +323,86 @@ static int s2n_client_key_share_recv_pq_hybrid(struct s2n_connection *conn, stru return S2N_SUCCESS; } - uint16_t ec_share_size = 0; - GUARD(s2n_stuffer_read_uint16(key_share, &ec_share_size)); /* Ignore KEM groups with unexpected ECC share sizes */ + uint16_t ec_share_size = 0; + POSIX_GUARD(s2n_stuffer_read_uint16(key_share, &ec_share_size)); if (ec_share_size != kem_group->curve->share_size) { return S2N_SUCCESS; } - GUARD(s2n_client_key_share_parse_ecc(key_share, kem_group->curve, &client_kem_group_params->ecc_params)); + DEFER_CLEANUP(struct s2n_kem_group_params new_client_params = { 0 }, s2n_kem_group_free); + new_client_params.kem_group = kem_group; + + POSIX_GUARD(s2n_client_key_share_parse_ecc(key_share, kem_group->curve, &new_client_params.ecc_params)); /* If we were unable to parse the EC portion of the share, negotiated_curve * will be NULL, and we should ignore the entire key share. */ - if (!client_kem_group_params->ecc_params.negotiated_curve) { + if (!new_client_params.ecc_params.negotiated_curve) { return S2N_SUCCESS; } /* Note: the PQ share size is validated in s2n_kem_recv_public_key() */ /* Ignore groups with PQ public keys we can't parse */ - client_kem_group_params->kem_params.kem = kem_group->kem; - if (s2n_kem_recv_public_key(key_share, &client_kem_group_params->kem_params) != S2N_SUCCESS) { - client_kem_group_params->kem_group = NULL; - client_kem_group_params->kem_params.kem = NULL; - client_kem_group_params->ecc_params.negotiated_curve = NULL; - /* s2n_kem_group_free() will free both the ECC and KEM params */ - GUARD(s2n_kem_group_free(client_kem_group_params)); + new_client_params.kem_params.kem = kem_group->kem; + if (s2n_kem_recv_public_key(key_share, &new_client_params.kem_params) != S2N_SUCCESS) { return S2N_SUCCESS; } - client_kem_group_params->kem_group = kem_group; - *match = true; + POSIX_GUARD(s2n_kem_group_free(client_params)); + *client_params = new_client_params; + + ZERO_TO_DISABLE_DEFER_CLEANUP(new_client_params); return S2N_SUCCESS; } -static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - notnull_check(extension); - - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return S2N_SUCCESS; - } - - const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); - - const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); +/* + * We chose our most preferred group of the mutually supported groups while processing the + * supported_groups extension. However, our true most preferred group is always the + * group that we already have a key share for, since retries are expensive. + * + * This method modifies our group selection based on what keyshares are available. + * It then stores the client keyshare for the selected group, or initiates a retry + * if no valid keyshares are available. + */ +static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(extension); uint16_t key_shares_size; - GUARD(s2n_stuffer_read_uint16(extension, &key_shares_size)); - ENSURE_POSIX(s2n_stuffer_data_available(extension) >= key_shares_size, S2N_ERR_BAD_MESSAGE); - - uint16_t named_group, share_size; - bool match_found = false; - /* bytes_processed is declared as a uint32_t to avoid integer overflow in later calculations */ - uint32_t bytes_processed = 0; + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &key_shares_size)); + POSIX_ENSURE(s2n_stuffer_data_available(extension) == key_shares_size, S2N_ERR_BAD_MESSAGE); - while (bytes_processed < key_shares_size) { - GUARD(s2n_stuffer_read_uint16(extension, &named_group)); - GUARD(s2n_stuffer_read_uint16(extension, &share_size)); + uint16_t named_group = 0, share_size = 0; + struct s2n_blob key_share_blob = { 0 }; + struct s2n_stuffer key_share = { 0 }; - ENSURE_POSIX(s2n_stuffer_data_available(extension) >= share_size, S2N_ERR_BAD_MESSAGE); - bytes_processed += share_size + S2N_SIZE_OF_NAMED_GROUP + S2N_SIZE_OF_KEY_SHARE_SIZE; + uint16_t keyshare_count = 0; + while(s2n_stuffer_data_available(extension) > 0) { + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &named_group)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &share_size)); + POSIX_ENSURE(s2n_stuffer_data_available(extension) >= share_size, S2N_ERR_BAD_MESSAGE); - struct s2n_blob key_share_blob = { .size = share_size, .data = s2n_stuffer_raw_read(extension, share_size) }; - notnull_check(key_share_blob.data); - struct s2n_stuffer key_share = { 0 }; - GUARD(s2n_stuffer_init(&key_share, &key_share_blob)); - GUARD(s2n_stuffer_skip_write(&key_share, share_size)); + POSIX_GUARD(s2n_blob_init(&key_share_blob, + s2n_stuffer_raw_read(extension, share_size), share_size)); + POSIX_GUARD(s2n_stuffer_init(&key_share, &key_share_blob)); + POSIX_GUARD(s2n_stuffer_skip_write(&key_share, share_size)); + keyshare_count++; /* Try to parse the share as ECC, then as PQ/hybrid; will ignore * shares for unrecognized groups. */ - GUARD(s2n_client_key_share_recv_ecc(conn, &key_share, named_group, &match_found)); - GUARD(s2n_client_key_share_recv_pq_hybrid(conn, &key_share, named_group, &match_found)); + POSIX_GUARD(s2n_client_key_share_recv_ecc(conn, &key_share, named_group)); + POSIX_GUARD(s2n_client_key_share_recv_pq_hybrid(conn, &key_share, named_group)); } + /* During a retry, the client should only have sent one keyshare */ + POSIX_ENSURE(!s2n_is_hello_retry_handshake(conn) || keyshare_count == 1, S2N_ERR_BAD_MESSAGE); + /* If there were no matching key shares, then we received an empty key share extension * or we didn't match a key share with a supported group. We should send a retry. */ - if (!match_found) { - GUARD(s2n_set_hello_retry_required(conn)); + struct s2n_ecc_evp_params *client_ecc_params = &conn->kex_params.client_ecc_evp_params; + struct s2n_kem_group_params *client_pq_params = &conn->kex_params.client_kem_group_params; + if (!client_pq_params->kem_group && !client_ecc_params->negotiated_curve) { + POSIX_GUARD(s2n_set_hello_retry_required(conn)); } return S2N_SUCCESS; @@ -495,11 +412,11 @@ static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stu uint32_t s2n_extensions_client_key_share_size(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); uint32_t s2n_client_key_share_extension_size = S2N_SIZE_OF_EXTENSION_TYPE + S2N_SIZE_OF_EXTENSION_DATA_SIZE diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_max_frag_len.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_max_frag_len.c index 880193a1a1..df5d2e5088 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_max_frag_len.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_max_frag_len.c @@ -52,13 +52,29 @@ static int s2n_client_max_frag_len_recv(struct s2n_connection *conn, struct s2n_ } uint8_t mfl_code; - GUARD(s2n_stuffer_read_uint8(extension, &mfl_code)); - if (mfl_code > S2N_TLS_MAX_FRAG_LEN_4096 || mfl_code_to_length[mfl_code] > S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) { + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &mfl_code)); + + /* + *= https://tools.ietf.org/rfc/rfc6066#section-4 + *= type=exception + *= reason=For compatibility, we choose to ignore malformed extensions if they are optional + *# If a server receives a maximum fragment length negotiation request + *# for a value other than the allowed values, it MUST abort the + *# handshake with an "illegal_parameter" alert. + */ + if (mfl_code >= s2n_array_len(mfl_code_to_length) || mfl_code_to_length[mfl_code] > S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) { return S2N_SUCCESS; } - conn->mfl_code = mfl_code; - conn->max_outgoing_fragment_length = mfl_code_to_length[mfl_code]; + /* + *= https://tools.ietf.org/rfc/rfc6066#section-4 + *# Once a maximum fragment length other than 2^14 has been successfully + *# negotiated, the client and server MUST immediately begin fragmenting + *# messages (including handshake messages) to ensure that no fragment + *# larger than the negotiated length is sent. + */ + conn->negotiated_mfl_code = mfl_code; + POSIX_GUARD_RESULT(s2n_connection_set_max_fragment_length(conn, mfl_code_to_length[mfl_code])); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_pq_kem.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_pq_kem.c index 83c4c8f1d0..aae1fe8256 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_pq_kem.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_pq_kem.c @@ -49,12 +49,12 @@ static bool s2n_client_pq_kem_should_send(struct s2n_connection *conn) static int s2n_client_pq_kem_send(struct s2n_connection *conn, struct s2n_stuffer *out) { const struct s2n_kem_preferences *kem_preferences = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_preferences)); - notnull_check(kem_preferences); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_preferences)); + POSIX_ENSURE_REF(kem_preferences); - GUARD(s2n_stuffer_write_uint16(out, kem_preferences->kem_count * sizeof(kem_extension_size))); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_preferences->kem_count * sizeof(kem_extension_size))); for (int i = 0; i < kem_preferences->kem_count; i++) { - GUARD(s2n_stuffer_write_uint16(out, kem_preferences->kems[i]->kem_extension_id)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_preferences->kems[i]->kem_extension_id)); } return S2N_SUCCESS; @@ -63,14 +63,14 @@ static int s2n_client_pq_kem_send(struct s2n_connection *conn, struct s2n_stuffe static int s2n_client_pq_kem_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint16_t size_of_all; - struct s2n_blob *proposed_kems = &conn->secure.client_pq_kem_extension; + struct s2n_blob *proposed_kems = &conn->kex_params.client_pq_kem_extension; /* Ignore extension if PQ is disabled */ if (!s2n_pq_is_enabled()) { return S2N_SUCCESS; } - GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all % sizeof(kem_extension_size)) { /* Malformed length, ignore the extension */ return S2N_SUCCESS; @@ -78,7 +78,7 @@ static int s2n_client_pq_kem_recv(struct s2n_connection *conn, struct s2n_stuffe proposed_kems->size = size_of_all; proposed_kems->data = s2n_stuffer_raw_read(extension, proposed_kems->size); - notnull_check(proposed_kems->data); + POSIX_ENSURE_REF(proposed_kems->data); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_psk.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_psk.c index d457829022..f8278f36b4 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_psk.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_psk.c @@ -27,30 +27,49 @@ #define SIZE_OF_BINDER_SIZE sizeof(uint8_t) #define SIZE_OF_BINDER_LIST_SIZE sizeof(uint16_t) -#define MAX_NUM_OF_PSK_IDENTITIES 100 + +/* To avoid a DoS attack triggered by decrypting too many session tickets, + * set a limit on the number of tickets we will attempt to decrypt before giving up. + * We may want to make this configurable someday, but just set a reasonable maximum for now. */ +#define MAX_REJECTED_TICKETS 3 static int s2n_client_psk_send(struct s2n_connection *conn, struct s2n_stuffer *out); static int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); +static int s2n_client_psk_is_missing(struct s2n_connection *conn); const s2n_extension_type s2n_client_psk_extension = { .iana_value = TLS_EXTENSION_PRE_SHARED_KEY, + .minimum_version = S2N_TLS13, .is_response = false, .send = s2n_client_psk_send, .recv = s2n_client_psk_recv, .should_send = s2n_client_psk_should_send, - .if_missing = s2n_extension_noop_if_missing, + .if_missing = s2n_client_psk_is_missing, }; +int s2n_client_psk_is_missing(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + + /* If the PSK extension is missing, we must not have received + * a request for early data. + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# When a PSK is used and early data is allowed for that PSK, the client + *# can send Application Data in its first flight of messages. If the + *# client opts to do so, it MUST supply both the "pre_shared_key" and + *# "early_data" extensions. + */ + POSIX_ENSURE(conn->early_data_state != S2N_EARLY_DATA_REQUESTED, S2N_ERR_UNSUPPORTED_EXTENSION); + return S2N_SUCCESS; +} + bool s2n_client_psk_should_send(struct s2n_connection *conn) { if (conn == NULL) { return false; } - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return false; - } - /* If this is NOT the second ClientHello after a retry, then all PSKs are viable. * Send the extension if any PSKs are configured. */ @@ -72,22 +91,62 @@ bool s2n_client_psk_should_send(struct s2n_connection *conn) return false; } +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11.1 + *# The "obfuscated_ticket_age" + *# field of each PskIdentity contains an obfuscated version of the + *# ticket age formed by taking the age in milliseconds and adding the + *# "ticket_age_add" value that was included with the ticket (see + *# Section 4.6.1), modulo 2^32. +*/ +static S2N_RESULT s2n_generate_obfuscated_ticket_age(struct s2n_psk *psk, uint64_t current_time, uint32_t *output) +{ + RESULT_ENSURE_REF(psk); + RESULT_ENSURE_MUT(output); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11 + *# For identities + *# established externally, an obfuscated_ticket_age of 0 SHOULD be + *# used, + **/ + if (psk->type == S2N_PSK_TYPE_EXTERNAL) { + *output = 0; + return S2N_RESULT_OK; + } + + RESULT_ENSURE(current_time >= psk->ticket_issue_time, S2N_ERR_SAFETY); + + /* Calculate ticket age */ + uint64_t ticket_age_in_nanos = current_time - psk->ticket_issue_time; + + /* Convert ticket age to milliseconds */ + uint64_t ticket_age_in_millis = ticket_age_in_nanos / ONE_MILLISEC_IN_NANOS; + RESULT_ENSURE(ticket_age_in_millis <= UINT32_MAX, S2N_ERR_SAFETY); + + /* Add the ticket_age_add value to the ticket age in milliseconds. The resulting uint32_t value + * may wrap, resulting in the modulo 2^32 operation. */ + *output = ticket_age_in_millis + psk->ticket_age_add; + + return S2N_RESULT_OK; +} + static int s2n_client_psk_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_psk_parameters *psk_params = &conn->psk_params; struct s2n_array *psk_list = &psk_params->psk_list; struct s2n_stuffer_reservation identity_list_size; - GUARD(s2n_stuffer_reserve_uint16(out, &identity_list_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &identity_list_size)); uint16_t binder_list_size = SIZE_OF_BINDER_LIST_SIZE; for (size_t i = 0; i < psk_list->len; i++) { struct s2n_psk *psk = NULL; - GUARD_AS_POSIX(s2n_array_get(psk_list, i, (void**) &psk)); - notnull_check(psk); + POSIX_GUARD_RESULT(s2n_array_get(psk_list, i, (void**) &psk)); + POSIX_ENSURE_REF(psk); /** *= https://tools.ietf.org/rfc/rfc8446#section-4.1.4 @@ -100,17 +159,23 @@ static int s2n_client_psk_send(struct s2n_connection *conn, struct s2n_stuffer * } /* Write the identity */ - GUARD(s2n_stuffer_write_uint16(out, psk->identity.size)); - GUARD(s2n_stuffer_write(out, &psk->identity)); - GUARD(s2n_stuffer_write_uint32(out, 0)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, psk->identity.size)); + POSIX_GUARD(s2n_stuffer_write(out, &psk->identity)); + + /* Write obfuscated ticket age */ + uint32_t obfuscated_ticket_age = 0; + uint64_t current_time = 0; + POSIX_GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_time)); + POSIX_GUARD_RESULT(s2n_generate_obfuscated_ticket_age(psk, current_time, &obfuscated_ticket_age)); + POSIX_GUARD(s2n_stuffer_write_uint32(out, obfuscated_ticket_age)); /* Calculate binder size */ uint8_t hash_size = 0; - GUARD(s2n_hmac_digest_size(psk->hmac_alg, &hash_size)); + POSIX_GUARD(s2n_hmac_digest_size(psk->hmac_alg, &hash_size)); binder_list_size += hash_size + SIZE_OF_BINDER_SIZE; } - GUARD(s2n_stuffer_write_vector_size(&identity_list_size)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&identity_list_size)); /* Calculating the binders requires a complete ClientHello, and at this point * the extension size, extension list size, and message size are all blank. @@ -118,231 +183,177 @@ static int s2n_client_psk_send(struct s2n_connection *conn, struct s2n_stuffer * * We'll write placeholder data to ensure the extension and extension list sizes * are calculated correctly, then rewrite the binders with real data later. */ psk_params->binder_list_size = binder_list_size; - GUARD(s2n_stuffer_skip_write(out, binder_list_size)); + POSIX_GUARD(s2n_stuffer_skip_write(out, binder_list_size)); return S2N_SUCCESS; } -/* Match a PSK identity received from the client against the server's known PSK identities. +/* Find the first of the server's PSK identities that matches the client's identities. + * This method compares all server identities to all client identities. * - * While both the client's offered identities and whether a match was found are public, we should make an attempt - * to keep the server's known identities a secret. We will make comparisons to the server's identities constant + * While both the client's identities and whether a match was found are public, we should make an attempt + * to keep the server's identities a secret. We will make comparisons to the server's identities constant * time (to hide partial matches) and not end the search early when a match is found (to hide the ordering). * * Keeping these comparisons constant time is not high priority. There's no known attack using these timings, * and an attacker could probably guess the server's known identities just by observing the public identities * sent by clients. */ -static S2N_RESULT s2n_match_psk_identity(struct s2n_array *known_psks, const struct s2n_blob *wire_identity, - struct s2n_psk **match) +static S2N_RESULT s2n_select_external_psk(struct s2n_connection *conn, struct s2n_offered_psk_list *client_identity_list) { - ENSURE_REF(match); - ENSURE_REF(wire_identity); - ENSURE_REF(known_psks); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(client_identity_list); - *match = NULL; - - for (size_t i = 0; i < known_psks->len; i++) { - struct s2n_psk *psk = NULL; - GUARD_RESULT(s2n_array_get(known_psks, i, (void**)&psk)); - ENSURE_REF(psk); - - ENSURE_REF(psk->identity.data); - ENSURE_REF(wire_identity->data); + struct s2n_array *server_psks = &conn->psk_params.psk_list; + conn->psk_params.chosen_psk = NULL; - uint32_t compare_size = MIN(wire_identity->size, psk->identity.size); - if (s2n_constant_time_equals(psk->identity.data, wire_identity->data, compare_size) - & (psk->identity.size == wire_identity->size) & (!*match)) { - *match = psk; - } + for (size_t i = 0; i < server_psks->len; i++) { + struct s2n_psk *server_psk = NULL; + RESULT_GUARD(s2n_array_get(server_psks, i, (void**) &server_psk)); + RESULT_ENSURE_REF(server_psk); + + struct s2n_offered_psk client_psk = { 0 }; + uint16_t wire_index = 0; + + RESULT_GUARD_POSIX(s2n_offered_psk_list_reread(client_identity_list)); + while(s2n_offered_psk_list_has_next(client_identity_list)) { + RESULT_GUARD_POSIX(s2n_offered_psk_list_next(client_identity_list, &client_psk)); + uint16_t compare_size = MIN(client_psk.identity.size, server_psk->identity.size); + if (s2n_constant_time_equals(client_psk.identity.data, server_psk->identity.data, compare_size) + & (client_psk.identity.size == server_psk->identity.size) + & (conn->psk_params.chosen_psk == NULL)) { + conn->psk_params.chosen_psk = server_psk; + conn->psk_params.chosen_psk_wire_index = wire_index; + } + wire_index++; + }; } + RESULT_ENSURE_REF(conn->psk_params.chosen_psk); return S2N_RESULT_OK; } -static S2N_RESULT s2n_select_psk_identity(struct s2n_connection *conn, struct s2n_psk_identity *identities, size_t identities_length) -{ - ENSURE_REF(conn); - ENSURE_REF(identities); +static S2N_RESULT s2n_select_resumption_psk(struct s2n_connection *conn, struct s2n_offered_psk_list *client_identity_list) { + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(client_identity_list); - struct s2n_array *known_psks = &conn->psk_params.psk_list; + struct s2n_offered_psk client_psk = { 0 }; conn->psk_params.chosen_psk = NULL; - for (size_t i = 0; i < identities_length; i++) { - struct s2n_blob wire_identity = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&wire_identity, identities[i].data, identities[i].length)); - - struct s2n_psk *local_match = NULL; - GUARD_RESULT(s2n_match_psk_identity(known_psks, &wire_identity, &local_match)); - - /* When a local match is found we do not end this loop early in an attempt - * to keep the server's known identities a secret and hide its ordering. - */ - if (local_match != NULL && conn->psk_params.chosen_psk == NULL) { - conn->psk_params.chosen_psk_wire_index = i; - conn->psk_params.chosen_psk = local_match; + uint8_t rejected_count = 0; + while (s2n_offered_psk_list_has_next(client_identity_list) && (rejected_count < MAX_REJECTED_TICKETS)) { + RESULT_GUARD_POSIX(s2n_offered_psk_list_next(client_identity_list, &client_psk)); + /* Select the first resumption PSK that can be decrypted */ + if (s2n_offered_psk_list_choose_psk(client_identity_list, &client_psk) == S2N_SUCCESS) { + return S2N_RESULT_OK; } + rejected_count++; } - return S2N_RESULT_OK; -} - -static S2N_RESULT s2n_count_psk_identities(struct s2n_stuffer *input, uint16_t *identity_count) -{ - ENSURE_REF(input); - ENSURE_REF(identity_count); - - const size_t obfuscated_ticket_age_size = sizeof(uint32_t); - - *identity_count = 0; - while (s2n_stuffer_data_available(input) > 0) { - uint16_t identity_size = 0; - GUARD_AS_RESULT(s2n_stuffer_read_uint16(input, &identity_size)); - GUARD_AS_RESULT(s2n_stuffer_skip_read(input, identity_size)); - GUARD_AS_RESULT(s2n_stuffer_skip_read(input, obfuscated_ticket_age_size)); - (*identity_count)++; - } - GUARD_AS_RESULT(s2n_stuffer_reread(input)); - return S2N_RESULT_OK; + RESULT_BAIL(S2N_ERR_INVALID_SESSION_TICKET); } static S2N_RESULT s2n_client_psk_recv_identity_list(struct s2n_connection *conn, struct s2n_stuffer *wire_identities_in) { - ENSURE_REF(conn); - ENSURE_REF(wire_identities_in); - - uint16_t identities_count = 0; - GUARD_RESULT(s2n_count_psk_identities(wire_identities_in, &identities_count)); - ENSURE_GT(identities_count, 0); - ENSURE_LTE(identities_count, MAX_NUM_OF_PSK_IDENTITIES); - - DEFER_CLEANUP(struct s2n_blob wire_identities_blob = { 0 }, s2n_free); - GUARD_AS_RESULT(s2n_alloc(&wire_identities_blob, identities_count * sizeof(struct s2n_psk_identity))); - struct s2n_psk_identity *wire_identities = (struct s2n_psk_identity*)(void*) wire_identities_blob.data; - - uint16_t wire_index = 0; - while (s2n_stuffer_data_available(wire_identities_in) > 0) { - uint16_t identity_size = 0; - GUARD_AS_RESULT(s2n_stuffer_read_uint16(wire_identities_in, &identity_size)); - ENSURE_GT(identity_size, 0); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->config); + RESULT_ENSURE_REF(wire_identities_in); - uint8_t *identity_data = s2n_stuffer_raw_read(wire_identities_in, identity_size); - ENSURE_REF(identity_data); - - wire_identities[wire_index].data = identity_data; - wire_identities[wire_index].length = identity_size; - - /** - *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11 - *# For identities established externally, an obfuscated_ticket_age of 0 SHOULD be - *# used, and servers MUST ignore the value. - */ - uint32_t obfuscated_ticket_age = 0; - GUARD_AS_RESULT(s2n_stuffer_read_uint32(wire_identities_in, &obfuscated_ticket_age)); - - wire_index++; - } + struct s2n_offered_psk_list identity_list = { + .conn = conn, + .wire_data = *wire_identities_in, + }; if (conn->config->psk_selection_cb) { - GUARD_AS_RESULT(conn->config->psk_selection_cb(conn, wire_identities, identities_count, - &conn->psk_params.chosen_psk_wire_index)); - struct s2n_blob chosen_wire_identity = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&chosen_wire_identity, - wire_identities[conn->psk_params.chosen_psk_wire_index].data, - wire_identities[conn->psk_params.chosen_psk_wire_index].length)); - GUARD_RESULT(s2n_match_psk_identity(&conn->psk_params.psk_list, &chosen_wire_identity, &conn->psk_params.chosen_psk)); - } else { - GUARD_RESULT(s2n_select_psk_identity(conn, wire_identities, identities_count)); + RESULT_GUARD_POSIX(conn->config->psk_selection_cb(conn, conn->config->psk_selection_ctx, &identity_list)); + } else if(conn->psk_params.type == S2N_PSK_TYPE_EXTERNAL) { + RESULT_GUARD(s2n_select_external_psk(conn, &identity_list)); + } else if(conn->psk_params.type == S2N_PSK_TYPE_RESUMPTION) { + RESULT_GUARD(s2n_select_resumption_psk(conn, &identity_list)); } - ENSURE_LT(conn->psk_params.chosen_psk_wire_index, identities_count); - ENSURE_REF(conn->psk_params.chosen_psk); - + RESULT_ENSURE_REF(conn->psk_params.chosen_psk); return S2N_RESULT_OK; } static S2N_RESULT s2n_client_psk_recv_binder_list(struct s2n_connection *conn, struct s2n_blob *partial_client_hello, struct s2n_stuffer *wire_binders_in) { - ENSURE_REF(conn); - ENSURE_REF(wire_binders_in); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(wire_binders_in); uint16_t wire_index = 0; while (s2n_stuffer_data_available(wire_binders_in) > 0) { uint8_t wire_binder_size = 0; - GUARD_AS_RESULT(s2n_stuffer_read_uint8(wire_binders_in, &wire_binder_size)); + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(wire_binders_in, &wire_binder_size)); uint8_t *wire_binder_data; - ENSURE_REF(wire_binder_data = s2n_stuffer_raw_read(wire_binders_in, wire_binder_size)); + RESULT_ENSURE_REF(wire_binder_data = s2n_stuffer_raw_read(wire_binders_in, wire_binder_size)); struct s2n_blob wire_binder = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&wire_binder, wire_binder_data, wire_binder_size)); + RESULT_GUARD_POSIX(s2n_blob_init(&wire_binder, wire_binder_data, wire_binder_size)); if (wire_index == conn->psk_params.chosen_psk_wire_index) { - GUARD_AS_RESULT(s2n_psk_verify_binder(conn, conn->psk_params.chosen_psk, + RESULT_GUARD_POSIX(s2n_psk_verify_binder(conn, conn->psk_params.chosen_psk, partial_client_hello, &wire_binder)); return S2N_RESULT_OK; } wire_index++; } - BAIL(S2N_ERR_BAD_MESSAGE); + RESULT_BAIL(S2N_ERR_BAD_MESSAGE); } static S2N_RESULT s2n_client_psk_recv_identities(struct s2n_connection *conn, struct s2n_stuffer *extension) { - ENSURE_REF(conn); + RESULT_ENSURE_REF(conn); uint16_t identity_list_size = 0; - GUARD_AS_RESULT(s2n_stuffer_read_uint16(extension, &identity_list_size)); + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(extension, &identity_list_size)); uint8_t *identity_list_data; - ENSURE_REF(identity_list_data = s2n_stuffer_raw_read(extension, identity_list_size)); + RESULT_ENSURE_REF(identity_list_data = s2n_stuffer_raw_read(extension, identity_list_size)); struct s2n_blob identity_list_blob = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&identity_list_blob, identity_list_data, identity_list_size)); + RESULT_GUARD_POSIX(s2n_blob_init(&identity_list_blob, identity_list_data, identity_list_size)); struct s2n_stuffer identity_list = { 0 }; - GUARD_AS_RESULT(s2n_stuffer_init(&identity_list, &identity_list_blob)); - GUARD_AS_RESULT(s2n_stuffer_skip_write(&identity_list, identity_list_blob.size)); + RESULT_GUARD_POSIX(s2n_stuffer_init(&identity_list, &identity_list_blob)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&identity_list, identity_list_blob.size)); return s2n_client_psk_recv_identity_list(conn, &identity_list); } static S2N_RESULT s2n_client_psk_recv_binders(struct s2n_connection *conn, struct s2n_stuffer *extension) { - ENSURE_REF(conn); + RESULT_ENSURE_REF(conn); uint16_t binder_list_size = 0; - GUARD_AS_RESULT(s2n_stuffer_read_uint16(extension, &binder_list_size)); + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(extension, &binder_list_size)); uint8_t *binder_list_data; - ENSURE_REF(binder_list_data = s2n_stuffer_raw_read(extension, binder_list_size)); + RESULT_ENSURE_REF(binder_list_data = s2n_stuffer_raw_read(extension, binder_list_size)); struct s2n_blob binder_list_blob = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&binder_list_blob, binder_list_data, binder_list_size)); + RESULT_GUARD_POSIX(s2n_blob_init(&binder_list_blob, binder_list_data, binder_list_size)); struct s2n_stuffer binder_list = { 0 }; - GUARD_AS_RESULT(s2n_stuffer_init(&binder_list, &binder_list_blob)); - GUARD_AS_RESULT(s2n_stuffer_skip_write(&binder_list, binder_list_blob.size)); + RESULT_GUARD_POSIX(s2n_stuffer_init(&binder_list, &binder_list_blob)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&binder_list, binder_list_blob.size)); /* Record the ClientHello message up to but not including the binder list. * This is required to calculate the binder for the chosen PSK. */ struct s2n_blob partial_client_hello = { 0 }; const struct s2n_stuffer *client_hello = &conn->handshake.io; uint32_t binders_size = binder_list_blob.size + SIZE_OF_BINDER_LIST_SIZE; - ENSURE_GTE(client_hello->write_cursor, binders_size); + RESULT_ENSURE_GTE(client_hello->write_cursor, binders_size); uint16_t partial_client_hello_size = client_hello->write_cursor - binders_size; - GUARD_AS_RESULT(s2n_blob_slice(&client_hello->blob, &partial_client_hello, 0, partial_client_hello_size)); + RESULT_GUARD_POSIX(s2n_blob_slice(&client_hello->blob, &partial_client_hello, 0, partial_client_hello_size)); return s2n_client_psk_recv_binder_list(conn, &partial_client_hello, &binder_list); } int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return S2N_SUCCESS; - } + POSIX_ENSURE_REF(conn); /** *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11 @@ -352,11 +363,11 @@ int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extensi *# the handshake with an "illegal_parameter" alert. */ s2n_extension_type_id psk_ext_id; - GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_PRE_SHARED_KEY, &psk_ext_id)); - ne_check(conn->client_hello.extensions.count, 0); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_PRE_SHARED_KEY, &psk_ext_id)); + POSIX_ENSURE_NE(conn->client_hello.extensions.count, 0); uint16_t last_wire_index = conn->client_hello.extensions.count - 1; uint16_t extension_wire_index = conn->client_hello.extensions.parsed_extensions[psk_ext_id].wire_index; - ENSURE_POSIX(extension_wire_index == last_wire_index, S2N_ERR_UNSUPPORTED_EXTENSION); + POSIX_ENSURE(extension_wire_index == last_wire_index, S2N_ERR_UNSUPPORTED_EXTENSION); /** *= https://tools.ietf.org/rfc/rfc8446#section-4.2.9 @@ -367,16 +378,16 @@ int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extensi * required to be the last extension sent in the list. */ s2n_extension_type_id psk_ke_mode_ext_id; - GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_PSK_KEY_EXCHANGE_MODES, &psk_ke_mode_ext_id)); - ENSURE_POSIX(S2N_CBIT_TEST(conn->extension_requests_received, psk_ke_mode_ext_id), S2N_ERR_MISSING_EXTENSION); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_PSK_KEY_EXCHANGE_MODES, &psk_ke_mode_ext_id)); + POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_requests_received, psk_ke_mode_ext_id), S2N_ERR_MISSING_EXTENSION); if (conn->psk_params.psk_ke_mode == S2N_PSK_DHE_KE) { s2n_extension_type_id key_share_ext_id; - GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_KEY_SHARE, &key_share_ext_id)); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_KEY_SHARE, &key_share_ext_id)); /* A key_share extension must have been received in order to use a pre-shared key * in (EC)DHE key exchange mode. */ - ENSURE_POSIX(S2N_CBIT_TEST(conn->extension_requests_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION); + POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_requests_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION); } else { /* s2n currently only supports pre-shared keys in (EC)DHE key exchange mode. If we receive keys with any other * exchange mode we fall back to a full handshake. @@ -401,7 +412,7 @@ int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extensi *# value is not present or does not validate, the server MUST abort the *# handshake. */ - GUARD_AS_POSIX(s2n_client_psk_recv_binders(conn, extension)); + POSIX_GUARD_RESULT(s2n_client_psk_recv_binders(conn, extension)); } /* At this point, we have either chosen a PSK or fallen back to a full handshake. */ diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_renegotiation_info.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_renegotiation_info.c index 3a012f47d1..772712fda4 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_renegotiation_info.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_renegotiation_info.c @@ -36,7 +36,7 @@ static int s2n_client_renegotiation_recv(struct s2n_connection *conn, struct s2n { /* RFC5746 Section 3.2: The renegotiated_connection field is of zero length for the initial handshake. */ uint8_t renegotiated_connection_len; - GUARD(s2n_stuffer_read_uint8(extension, &renegotiated_connection_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &renegotiated_connection_len)); S2N_ERROR_IF(s2n_stuffer_data_available(extension) || renegotiated_connection_len, S2N_ERR_NON_EMPTY_RENEGOTIATION_INFO); conn->secure_renegotiation = 1; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_server_name.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_server_name.c index 904976e4cc..0e69283a2c 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_server_name.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_server_name.c @@ -39,47 +39,50 @@ const s2n_extension_type s2n_client_server_name_extension = { static bool s2n_client_server_name_should_send(struct s2n_connection *conn) { - return conn && strlen(conn->server_name) > 0; + return conn && conn->server_name[0] != '\0'; } static int s2n_client_server_name_send(struct s2n_connection *conn, struct s2n_stuffer *out) { struct s2n_stuffer_reservation server_name_list_size = {0}; - GUARD(s2n_stuffer_reserve_uint16(out, &server_name_list_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &server_name_list_size)); /* NameType, as described by RFC6066. * host_name is currently the only possible NameType defined. */ - GUARD(s2n_stuffer_write_uint8(out, S2N_NAME_TYPE_HOST_NAME)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, S2N_NAME_TYPE_HOST_NAME)); - GUARD(s2n_stuffer_write_uint16(out, strlen(conn->server_name))); - GUARD(s2n_stuffer_write_bytes(out, (const uint8_t *) conn->server_name, strlen(conn->server_name))); + POSIX_GUARD(s2n_stuffer_write_uint16(out, strlen(conn->server_name))); + POSIX_GUARD(s2n_stuffer_write_bytes(out, (const uint8_t *) conn->server_name, strlen(conn->server_name))); - GUARD(s2n_stuffer_write_vector_size(&server_name_list_size)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&server_name_list_size)); return S2N_SUCCESS; } +/* Read the extension up to the first item in ServerNameList. Store the first entry's length in server_name_len. + * For now s2n ignores all subsequent items in ServerNameList. + */ static int s2n_client_server_name_check(struct s2n_connection *conn, struct s2n_stuffer *extension, uint16_t *server_name_len) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); uint16_t size_of_all; - GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); - lte_check(size_of_all, s2n_stuffer_data_available(extension)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); + POSIX_ENSURE_LTE(size_of_all, s2n_stuffer_data_available(extension)); uint8_t server_name_type; - GUARD(s2n_stuffer_read_uint8(extension, &server_name_type)); - eq_check(server_name_type, S2N_NAME_TYPE_HOST_NAME); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &server_name_type)); + POSIX_ENSURE_EQ(server_name_type, S2N_NAME_TYPE_HOST_NAME); - GUARD(s2n_stuffer_read_uint16(extension, server_name_len)); - lt_check(*server_name_len, sizeof(conn->server_name)); - lte_check(*server_name_len, s2n_stuffer_data_available(extension)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, server_name_len)); + POSIX_ENSURE_LT(*server_name_len, sizeof(conn->server_name)); + POSIX_ENSURE_LTE(*server_name_len, s2n_stuffer_data_available(extension)); return S2N_SUCCESS; } static int s2n_client_server_name_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); /* Exit early if we've already parsed the server name */ if (conn->server_name[0]) { @@ -93,8 +96,8 @@ static int s2n_client_server_name_recv(struct s2n_connection *conn, struct s2n_s } uint8_t *server_name; - notnull_check(server_name = s2n_stuffer_raw_read(extension, server_name_len)); - memcpy_check(conn->server_name, server_name, server_name_len); + POSIX_ENSURE_REF(server_name = s2n_stuffer_raw_read(extension, server_name_len)); + POSIX_CHECKED_MEMCPY(conn->server_name, server_name, server_name_len); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_session_ticket.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_session_ticket.c index 96ef1b7308..ca9c5e96e7 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_session_ticket.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_session_ticket.c @@ -17,6 +17,8 @@ #include <stdint.h> #include "tls/extensions/s2n_client_session_ticket.h" + +#include "tls/extensions/s2n_client_psk.h" #include "tls/s2n_tls.h" #include "tls/s2n_tls_parameters.h" #include "tls/s2n_resume.h" @@ -38,18 +40,18 @@ const s2n_extension_type s2n_client_session_ticket_extension = { static bool s2n_client_session_ticket_should_send(struct s2n_connection *conn) { - return conn->config->use_tickets; + return conn->config->use_tickets && !s2n_client_psk_should_send(conn); } static int s2n_client_session_ticket_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - GUARD(s2n_stuffer_write(out, &conn->client_ticket)); + POSIX_GUARD(s2n_stuffer_write(out, &conn->client_ticket)); return S2N_SUCCESS; } static int s2n_client_session_ticket_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - if (conn->config->use_tickets != 1) { + if (conn->config->use_tickets != 1 || conn->actual_protocol_version > S2N_TLS12) { /* Ignore the extension. */ return S2N_SUCCESS; } @@ -59,9 +61,9 @@ static int s2n_client_session_ticket_recv(struct s2n_connection *conn, struct s2 return S2N_SUCCESS; } - if (s2n_stuffer_data_available(extension) == S2N_TICKET_SIZE_IN_BYTES) { + if (s2n_stuffer_data_available(extension) == S2N_TLS12_TICKET_SIZE_IN_BYTES) { conn->session_ticket_status = S2N_DECRYPT_TICKET; - GUARD(s2n_stuffer_copy(extension, &conn->client_ticket_to_decrypt, S2N_TICKET_SIZE_IN_BYTES)); + POSIX_GUARD(s2n_stuffer_copy(extension, &conn->client_ticket_to_decrypt, S2N_TLS12_TICKET_SIZE_IN_BYTES)); } else if (s2n_config_is_encrypt_decrypt_key_available(conn->config) == 1) { conn->session_ticket_status = S2N_NEW_TICKET; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_status_request.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_status_request.c index e5144fba8b..608e8d0a55 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_status_request.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_status_request.c @@ -42,20 +42,20 @@ static bool s2n_client_status_request_should_send(struct s2n_connection *conn) static int s2n_client_status_request_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - GUARD(s2n_stuffer_write_uint8(out, (uint8_t) conn->config->status_request_type)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, (uint8_t) conn->config->status_request_type)); /* responder_id_list * * From https://tools.ietf.org/html/rfc6066#section-8: * A zero-length "responder_id_list" sequence has the special meaning that the responders are implicitly * known to the server, e.g., by prior arrangement */ - GUARD(s2n_stuffer_write_uint16(out, 0)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, 0)); /* request_extensions * * From https://tools.ietf.org/html/rfc6066#section-8: * A zero-length "request_extensions" value means that there are no extensions. */ - GUARD(s2n_stuffer_write_uint16(out, 0)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, 0)); return S2N_SUCCESS; } @@ -68,7 +68,7 @@ static int s2n_client_status_request_recv(struct s2n_connection *conn, struct s2 } uint8_t type; - GUARD(s2n_stuffer_read_uint8(extension, &type)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &type)); if (type != (uint8_t) S2N_STATUS_REQUEST_OCSP) { /* We only support OCSP (type 1), ignore the extension */ return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_groups.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_groups.c index 4cb2f9e3c5..1b8ead056d 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_groups.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_groups.c @@ -48,33 +48,33 @@ bool s2n_extension_should_send_if_ecc_enabled(struct s2n_connection *conn) static int s2n_client_supported_groups_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); /* Group list len */ struct s2n_stuffer_reservation group_list_len = { 0 }; - GUARD(s2n_stuffer_reserve_uint16(out, &group_list_len)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &group_list_len)); /* Send KEM groups list first */ if (s2n_connection_get_protocol_version(conn) >= S2N_TLS13 && s2n_pq_is_enabled()) { for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - GUARD(s2n_stuffer_write_uint16(out, kem_pref->tls13_kem_groups[i]->iana_id)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_pref->tls13_kem_groups[i]->iana_id)); } } /* Then send curve list */ for (size_t i = 0; i < ecc_pref->count; i++) { - GUARD(s2n_stuffer_write_uint16(out, ecc_pref->ecc_curves[i]->iana_id)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_pref->ecc_curves[i]->iana_id)); } - GUARD(s2n_stuffer_write_vector_size(&group_list_len)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&group_list_len)); return S2N_SUCCESS; } @@ -83,16 +83,16 @@ static int s2n_client_supported_groups_send(struct s2n_connection *conn, struct * mutually_supported_kem_groups array based on the received IANA ID. Will * ignore unrecognized IANA IDs (and return success). */ static int s2n_client_supported_groups_recv_iana_id(struct s2n_connection *conn, uint16_t iana_id) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); for (size_t i = 0; i < ecc_pref->count; i++) { const struct s2n_ecc_named_curve *supported_curve = ecc_pref->ecc_curves[i]; if (iana_id == supported_curve->iana_id) { - conn->secure.mutually_supported_curves[i] = supported_curve; + conn->kex_params.mutually_supported_curves[i] = supported_curve; return S2N_SUCCESS; } } @@ -103,13 +103,13 @@ static int s2n_client_supported_groups_recv_iana_id(struct s2n_connection *conn, } const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { const struct s2n_kem_group *supported_kem_group = kem_pref->tls13_kem_groups[i]; if (iana_id == supported_kem_group->iana_id) { - conn->secure.mutually_supported_kem_groups[i] = supported_kem_group; + conn->kex_params.mutually_supported_kem_groups[i] = supported_kem_group; return S2N_SUCCESS; } } @@ -118,40 +118,40 @@ static int s2n_client_supported_groups_recv_iana_id(struct s2n_connection *conn, } static int s2n_choose_supported_group(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); /* Ensure that only the intended group will be non-NULL (if no group is chosen, everything * should be NULL). */ - conn->secure.server_kem_group_params.kem_group = NULL; - conn->secure.server_kem_group_params.ecc_params.negotiated_curve = NULL; - conn->secure.server_kem_group_params.kem_params.kem = NULL; - conn->secure.server_ecc_evp_params.negotiated_curve = NULL; + conn->kex_params.server_kem_group_params.kem_group = NULL; + conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve = NULL; + conn->kex_params.server_kem_group_params.kem_params.kem = NULL; + conn->kex_params.server_ecc_evp_params.negotiated_curve = NULL; /* Prefer to negotiate hybrid PQ over ECC. If PQ is disabled, we will never choose a * PQ group because the mutually_supported_kem_groups array will not have been * populated with anything. */ for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - const struct s2n_kem_group *candidate_kem_group = conn->secure.mutually_supported_kem_groups[i]; + const struct s2n_kem_group *candidate_kem_group = conn->kex_params.mutually_supported_kem_groups[i]; if (candidate_kem_group != NULL) { - conn->secure.server_kem_group_params.kem_group = candidate_kem_group; - conn->secure.server_kem_group_params.ecc_params.negotiated_curve = candidate_kem_group->curve; - conn->secure.server_kem_group_params.kem_params.kem = candidate_kem_group->kem; + conn->kex_params.server_kem_group_params.kem_group = candidate_kem_group; + conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve = candidate_kem_group->curve; + conn->kex_params.server_kem_group_params.kem_params.kem = candidate_kem_group->kem; return S2N_SUCCESS; } } for (size_t i = 0; i < ecc_pref->count; i++) { - const struct s2n_ecc_named_curve *candidate_curve = conn->secure.mutually_supported_curves[i]; + const struct s2n_ecc_named_curve *candidate_curve = conn->kex_params.mutually_supported_curves[i]; if (candidate_curve != NULL) { - conn->secure.server_ecc_evp_params.negotiated_curve = candidate_curve; + conn->kex_params.server_ecc_evp_params.negotiated_curve = candidate_curve; return S2N_SUCCESS; } } @@ -160,11 +160,11 @@ static int s2n_choose_supported_group(struct s2n_connection *conn) { } static int s2n_client_supported_groups_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - notnull_check(extension); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(extension); uint16_t size_of_all; - GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || (size_of_all % sizeof(uint16_t))) { /* Malformed length, ignore the extension */ return S2N_SUCCESS; @@ -172,11 +172,11 @@ static int s2n_client_supported_groups_recv(struct s2n_connection *conn, struct for (size_t i = 0; i < (size_of_all / sizeof(uint16_t)); i++) { uint16_t iana_id; - GUARD(s2n_stuffer_read_uint16(extension, &iana_id)); - GUARD(s2n_client_supported_groups_recv_iana_id(conn, iana_id)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &iana_id)); + POSIX_GUARD(s2n_client_supported_groups_recv_iana_id(conn, iana_id)); } - GUARD(s2n_choose_supported_group(conn)); + POSIX_GUARD(s2n_choose_supported_group(conn)); return S2N_SUCCESS; } @@ -185,12 +185,12 @@ static int s2n_client_supported_groups_recv(struct s2n_connection *conn, struct int s2n_extensions_client_supported_groups_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - GUARD(s2n_extension_send(&s2n_client_supported_groups_extension, conn, out)); + POSIX_GUARD(s2n_extension_send(&s2n_client_supported_groups_extension, conn, out)); /* The original send method also sent ec point formats. To avoid breaking * anything, I'm going to let it continue writing point formats. */ - GUARD(s2n_extension_send(&s2n_client_ec_point_format_extension, conn, out)); + POSIX_GUARD(s2n_extension_send(&s2n_client_ec_point_format_extension, conn, out)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c index d0ec8cb329..bbc37e475a 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c @@ -59,15 +59,16 @@ const s2n_extension_type s2n_client_supported_versions_extension = { static int s2n_client_supported_versions_send(struct s2n_connection *conn, struct s2n_stuffer *out) { uint8_t highest_supported_version = conn->client_protocol_version; - uint8_t minimum_supported_version; - GUARD(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); + uint8_t minimum_supported_version = s2n_unknown_protocol_version; + POSIX_GUARD_RESULT(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); + POSIX_ENSURE(highest_supported_version >= minimum_supported_version, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); uint8_t version_list_length = highest_supported_version - minimum_supported_version + 1; - GUARD(s2n_stuffer_write_uint8(out, version_list_length * S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, version_list_length * S2N_TLS_PROTOCOL_VERSION_LEN)); for (uint8_t i = highest_supported_version; i >= minimum_supported_version; i--) { - GUARD(s2n_stuffer_write_uint8(out, i / 10)); - GUARD(s2n_stuffer_write_uint8(out, i % 10)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, i / 10)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, i % 10)); } return S2N_SUCCESS; @@ -75,11 +76,11 @@ static int s2n_client_supported_versions_send(struct s2n_connection *conn, struc static int s2n_extensions_client_supported_versions_process(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint8_t highest_supported_version = conn->server_protocol_version; - uint8_t minimum_supported_version; - GUARD(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); + uint8_t minimum_supported_version = s2n_unknown_protocol_version; + POSIX_GUARD_RESULT(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); uint8_t size_of_version_list; - GUARD(s2n_stuffer_read_uint8(extension, &size_of_version_list)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &size_of_version_list)); S2N_ERROR_IF(size_of_version_list != s2n_stuffer_data_available(extension), S2N_ERR_BAD_MESSAGE); S2N_ERROR_IF(size_of_version_list % S2N_TLS_PROTOCOL_VERSION_LEN != 0, S2N_ERR_BAD_MESSAGE); @@ -88,7 +89,7 @@ static int s2n_extensions_client_supported_versions_process(struct s2n_connectio for (int i = 0; i < size_of_version_list; i += S2N_TLS_PROTOCOL_VERSION_LEN) { uint8_t client_version_parts[S2N_TLS_PROTOCOL_VERSION_LEN]; - GUARD(s2n_stuffer_read_bytes(extension, client_version_parts, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(extension, client_version_parts, S2N_TLS_PROTOCOL_VERSION_LEN)); /* If the client version is outside of our supported versions, then ignore the value. * S2N does not support SSLv2 except for upgrading connections. Since this extension is @@ -127,7 +128,7 @@ static int s2n_client_supported_versions_recv(struct s2n_connection *conn, struc if (s2n_extensions_client_supported_versions_process(conn, in) < 0) { s2n_queue_reader_unsupported_protocol_version_alert(conn); - S2N_ERROR(S2N_ERR_BAD_MESSAGE); + POSIX_BAIL(S2N_ERR_BAD_MESSAGE); } return S2N_SUCCESS; } @@ -135,8 +136,8 @@ static int s2n_client_supported_versions_recv(struct s2n_connection *conn, struc /* Old-style extension functions -- remove after extensions refactor is complete */ int s2n_extensions_client_supported_versions_size(struct s2n_connection *conn) { - uint8_t minimum_supported_version; - GUARD(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); + uint8_t minimum_supported_version = s2n_unknown_protocol_version; + POSIX_GUARD_RESULT(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); uint8_t highest_supported_version = conn->client_protocol_version; uint8_t version_list_length = highest_supported_version - minimum_supported_version + 1; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_cookie.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_cookie.c index 7e8885bc0b..18940d7191 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_cookie.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_cookie.c @@ -22,6 +22,7 @@ const s2n_extension_type s2n_client_cookie_extension = { .iana_value = TLS_EXTENSION_COOKIE, + .minimum_version = S2N_TLS13, .is_response = true, .send = s2n_extension_send_noop, .recv = s2n_extension_recv_noop, @@ -35,6 +36,7 @@ static int s2n_cookie_recv(struct s2n_connection *conn, struct s2n_stuffer *exte const s2n_extension_type s2n_server_cookie_extension = { .iana_value = TLS_EXTENSION_COOKIE, + .minimum_version = S2N_TLS13, .is_response = false, .send = s2n_cookie_send, .recv = s2n_cookie_recv, @@ -44,33 +46,29 @@ const s2n_extension_type s2n_server_cookie_extension = { static bool s2n_cookie_should_send(struct s2n_connection *conn) { - return s2n_extension_send_if_tls13_connection(conn) - && conn && s2n_stuffer_data_available(&conn->cookie_stuffer) > 0; + return conn && s2n_stuffer_data_available(&conn->cookie_stuffer) > 0; } static int s2n_cookie_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); uint16_t cookie_size = s2n_stuffer_data_available(&conn->cookie_stuffer); - GUARD(s2n_stuffer_write_uint16(out, cookie_size)); - GUARD(s2n_stuffer_copy(&conn->cookie_stuffer, out, cookie_size)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, cookie_size)); + POSIX_GUARD(s2n_stuffer_copy(&conn->cookie_stuffer, out, cookie_size)); return S2N_SUCCESS; } static int s2n_cookie_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return S2N_SUCCESS; - } + POSIX_ENSURE_REF(conn); uint16_t cookie_len; - GUARD(s2n_stuffer_read_uint16(extension, &cookie_len)); - ENSURE_POSIX(s2n_stuffer_data_available(extension) == cookie_len, S2N_ERR_BAD_MESSAGE); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &cookie_len)); + POSIX_ENSURE(s2n_stuffer_data_available(extension) == cookie_len, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_wipe(&conn->cookie_stuffer)); - GUARD(s2n_stuffer_resize(&conn->cookie_stuffer, cookie_len)); - GUARD(s2n_stuffer_copy(extension, &conn->cookie_stuffer, cookie_len)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->cookie_stuffer)); + POSIX_GUARD(s2n_stuffer_resize(&conn->cookie_stuffer, cookie_len)); + POSIX_GUARD(s2n_stuffer_copy(extension, &conn->cookie_stuffer, cookie_len)); return S2N_SUCCESS; } @@ -78,7 +76,7 @@ static int s2n_cookie_recv(struct s2n_connection *conn, struct s2n_stuffer *exte int s2n_extensions_cookie_size(struct s2n_connection *conn) { - GUARD(s2n_stuffer_reread(&conn->cookie_stuffer)); + POSIX_GUARD(s2n_stuffer_reread(&conn->cookie_stuffer)); if (s2n_stuffer_data_available(&conn->cookie_stuffer) == 0) { return 0; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_early_data_indication.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_early_data_indication.h new file mode 100644 index 0000000000..8e78c11cba --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_early_data_indication.h @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#pragma once + +#include "tls/extensions/s2n_extension_type.h" + +extern const s2n_extension_type s2n_client_early_data_indication_extension; +extern const s2n_extension_type s2n_server_early_data_indication_extension; +extern const s2n_extension_type s2n_nst_early_data_indication_extension; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_ec_point_format.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_ec_point_format.c index cb720581a6..00d0a240f9 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_ec_point_format.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_ec_point_format.c @@ -54,10 +54,10 @@ static bool s2n_server_ec_point_format_should_send(struct s2n_connection *conn) static int s2n_ec_point_format_send(struct s2n_connection *conn, struct s2n_stuffer *out) { /* Point format list len. We only support one. */ - GUARD(s2n_stuffer_write_uint8(out, 1)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, 1)); /* Only allow uncompressed format */ - GUARD(s2n_stuffer_write_uint8(out, TLS_EC_POINT_FORMAT_UNCOMPRESSED)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_EC_POINT_FORMAT_UNCOMPRESSED)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_ems.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_ems.h new file mode 100644 index 0000000000..7478332c34 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_ems.h @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#pragma once + +#include "tls/extensions/s2n_extension_type.h" + +extern const s2n_extension_type s2n_client_ems_extension; +extern const s2n_extension_type s2n_server_ems_extension; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c index 5188535bf4..25000e56a9 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c @@ -17,7 +17,7 @@ #include "s2n_extension_type.h" #include "s2n_extension_type_lists.h" -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" #include "utils/s2n_safety.h" @@ -29,46 +29,46 @@ static const s2n_parsed_extension empty_parsed_extensions[S2N_PARSED_EXTENSIONS_ int s2n_extension_list_send(s2n_extension_list_id list_type, struct s2n_connection *conn, struct s2n_stuffer *out) { s2n_extension_type_list *extension_type_list; - GUARD(s2n_extension_type_list_get(list_type, &extension_type_list)); + POSIX_GUARD(s2n_extension_type_list_get(list_type, &extension_type_list)); struct s2n_stuffer_reservation total_extensions_size = {0}; - GUARD(s2n_stuffer_reserve_uint16(out, &total_extensions_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &total_extensions_size)); for (int i = 0; i < extension_type_list->count; i++) { - GUARD(s2n_extension_send(extension_type_list->extension_types[i], conn, out)); + POSIX_GUARD(s2n_extension_send(extension_type_list->extension_types[i], conn, out)); } - GUARD(s2n_stuffer_write_vector_size(&total_extensions_size)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&total_extensions_size)); return S2N_SUCCESS; } int s2n_extension_list_recv(s2n_extension_list_id list_type, struct s2n_connection *conn, struct s2n_stuffer *in) { s2n_parsed_extensions_list parsed_extension_list = { 0 }; - GUARD(s2n_extension_list_parse(in, &parsed_extension_list)); - GUARD(s2n_extension_list_process(list_type, conn, &parsed_extension_list)); + POSIX_GUARD(s2n_extension_list_parse(in, &parsed_extension_list)); + POSIX_GUARD(s2n_extension_list_process(list_type, conn, &parsed_extension_list)); return S2N_SUCCESS; } static int s2n_extension_process_impl(const s2n_extension_type *extension_type, s2n_extension_type_id extension_id, struct s2n_connection *conn, s2n_parsed_extension *parsed_extensions) { - notnull_check(extension_type); - notnull_check(parsed_extensions); + POSIX_ENSURE_REF(extension_type); + POSIX_ENSURE_REF(parsed_extensions); if (s2n_parsed_extension_is_empty(&parsed_extensions[extension_id])) { - GUARD(s2n_extension_is_missing(extension_type, conn)); + POSIX_GUARD(s2n_extension_is_missing(extension_type, conn)); return S2N_SUCCESS; } - ENSURE_POSIX(parsed_extensions[extension_id].extension_type == extension_type->iana_value, + POSIX_ENSURE(parsed_extensions[extension_id].extension_type == extension_type->iana_value, S2N_ERR_INVALID_PARSED_EXTENSIONS); struct s2n_stuffer extension_stuffer; - GUARD(s2n_stuffer_init(&extension_stuffer, &parsed_extensions[extension_id].extension)); - GUARD(s2n_stuffer_skip_write(&extension_stuffer, parsed_extensions[extension_id].extension.size)); + POSIX_GUARD(s2n_stuffer_init(&extension_stuffer, &parsed_extensions[extension_id].extension)); + POSIX_GUARD(s2n_stuffer_skip_write(&extension_stuffer, parsed_extensions[extension_id].extension.size)); - GUARD(s2n_extension_recv(extension_type, conn, &extension_stuffer)); + POSIX_GUARD(s2n_extension_recv(extension_type, conn, &extension_stuffer)); return S2N_SUCCESS; } @@ -76,11 +76,11 @@ static int s2n_extension_process_impl(const s2n_extension_type *extension_type, int s2n_extension_process(const s2n_extension_type *extension_type, struct s2n_connection *conn, s2n_parsed_extensions_list *parsed_extension_list) { - notnull_check(parsed_extension_list); - notnull_check(extension_type); + POSIX_ENSURE_REF(parsed_extension_list); + POSIX_ENSURE_REF(extension_type); s2n_extension_type_id extension_id; - GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); int result = s2n_extension_process_impl(extension_type, extension_id, conn, parsed_extension_list->parsed_extensions); @@ -94,13 +94,13 @@ int s2n_extension_process(const s2n_extension_type *extension_type, struct s2n_c int s2n_extension_list_process(s2n_extension_list_id list_type, struct s2n_connection *conn, s2n_parsed_extensions_list *parsed_extension_list) { - notnull_check(parsed_extension_list); + POSIX_ENSURE_REF(parsed_extension_list); s2n_extension_type_list *extension_type_list; - GUARD(s2n_extension_type_list_get(list_type, &extension_type_list)); + POSIX_GUARD(s2n_extension_type_list_get(list_type, &extension_type_list)); for (int i = 0; i < extension_type_list->count; i++) { - GUARD(s2n_extension_process(extension_type_list->extension_types[i], + POSIX_GUARD(s2n_extension_process(extension_type_list->extension_types[i], conn, parsed_extension_list)); } @@ -122,19 +122,19 @@ int s2n_extension_list_process(s2n_extension_list_id list_type, struct s2n_conne static int s2n_extension_parse(struct s2n_stuffer *in, s2n_parsed_extension *parsed_extensions, uint16_t *wire_index) { - notnull_check(parsed_extensions); - notnull_check(wire_index); + POSIX_ENSURE_REF(parsed_extensions); + POSIX_ENSURE_REF(wire_index); uint16_t extension_type; - ENSURE_POSIX(s2n_stuffer_read_uint16(in, &extension_type) == S2N_SUCCESS, + POSIX_ENSURE(s2n_stuffer_read_uint16(in, &extension_type) == S2N_SUCCESS, S2N_ERR_BAD_MESSAGE); uint16_t extension_size; - ENSURE_POSIX(s2n_stuffer_read_uint16(in, &extension_size) == S2N_SUCCESS, + POSIX_ENSURE(s2n_stuffer_read_uint16(in, &extension_size) == S2N_SUCCESS, S2N_ERR_BAD_MESSAGE); uint8_t *extension_data = s2n_stuffer_raw_read(in, extension_size); - ENSURE_POSIX(extension_data != NULL, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(extension_data != NULL, S2N_ERR_BAD_MESSAGE); s2n_extension_type_id extension_id; if (s2n_extension_supported_iana_value_to_id(extension_type, &extension_id) != S2N_SUCCESS) { @@ -145,13 +145,13 @@ static int s2n_extension_parse(struct s2n_stuffer *in, s2n_parsed_extension *par s2n_parsed_extension *parsed_extension = &parsed_extensions[extension_id]; /* Error if extension is a duplicate */ - ENSURE_POSIX(s2n_parsed_extension_is_empty(parsed_extension), + POSIX_ENSURE(s2n_parsed_extension_is_empty(parsed_extension), S2N_ERR_DUPLICATE_EXTENSION); /* Fill in parsed extension */ parsed_extension->extension_type = extension_type; parsed_extension->wire_index = *wire_index; - GUARD(s2n_blob_init(&parsed_extension->extension, extension_data, extension_size)); + POSIX_GUARD(s2n_blob_init(&parsed_extension->extension, extension_data, extension_size)); (*wire_index)++; return S2N_SUCCESS; @@ -159,10 +159,10 @@ static int s2n_extension_parse(struct s2n_stuffer *in, s2n_parsed_extension *par int s2n_extension_list_parse(struct s2n_stuffer *in, s2n_parsed_extensions_list *parsed_extension_list) { - notnull_check(in); - notnull_check(parsed_extension_list); + POSIX_ENSURE_REF(in); + POSIX_ENSURE_REF(parsed_extension_list); - memset_check((s2n_parsed_extension*) parsed_extension_list->parsed_extensions, + POSIX_CHECKED_MEMSET((s2n_parsed_extension*) parsed_extension_list->parsed_extensions, 0, sizeof(parsed_extension_list->parsed_extensions)); uint16_t total_extensions_size; @@ -171,17 +171,17 @@ int s2n_extension_list_parse(struct s2n_stuffer *in, s2n_parsed_extensions_list } uint8_t *extensions_data = s2n_stuffer_raw_read(in, total_extensions_size); - ENSURE_POSIX(extensions_data != NULL, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(extensions_data != NULL, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_blob_init(&parsed_extension_list->raw, extensions_data, total_extensions_size)); + POSIX_GUARD(s2n_blob_init(&parsed_extension_list->raw, extensions_data, total_extensions_size)); struct s2n_stuffer extensions_stuffer; - GUARD(s2n_stuffer_init(&extensions_stuffer, &parsed_extension_list->raw)); - GUARD(s2n_stuffer_skip_write(&extensions_stuffer, total_extensions_size)); + POSIX_GUARD(s2n_stuffer_init(&extensions_stuffer, &parsed_extension_list->raw)); + POSIX_GUARD(s2n_stuffer_skip_write(&extensions_stuffer, total_extensions_size)); uint16_t wire_index = 0; while (s2n_stuffer_data_available(&extensions_stuffer)) { - GUARD(s2n_extension_parse(&extensions_stuffer, parsed_extension_list->parsed_extensions, &wire_index)); + POSIX_GUARD(s2n_extension_parse(&extensions_stuffer, parsed_extension_list->parsed_extensions, &wire_index)); } parsed_extension_list->count = wire_index; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h index dcf7c9da9b..a26eb3a89c 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h @@ -34,11 +34,13 @@ typedef struct { typedef enum { S2N_EXTENSION_LIST_CLIENT_HELLO = 0, + S2N_EXTENSION_LIST_HELLO_RETRY_REQUEST, S2N_EXTENSION_LIST_SERVER_HELLO_DEFAULT, S2N_EXTENSION_LIST_SERVER_HELLO_TLS13, S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS, S2N_EXTENSION_LIST_CERT_REQ, S2N_EXTENSION_LIST_CERTIFICATE, + S2N_EXTENSION_LIST_NST, S2N_EXTENSION_LIST_EMPTY, S2N_EXTENSION_LIST_IDS_COUNT, } s2n_extension_list_id; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c index 040c57a16c..1c808f1d8c 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" #include "tls/extensions/s2n_extension_type.h" @@ -72,7 +72,7 @@ s2n_extension_type_id s2n_extension_iana_value_to_id(const uint16_t iana_value) int s2n_extension_supported_iana_value_to_id(const uint16_t iana_value, s2n_extension_type_id *internal_id) { - notnull_check(internal_id); + POSIX_ENSURE_REF(internal_id); *internal_id = s2n_extension_iana_value_to_id(iana_value); S2N_ERROR_IF(*internal_id == s2n_unsupported_extension, S2N_ERR_UNRECOGNIZED_EXTENSION); @@ -81,13 +81,13 @@ int s2n_extension_supported_iana_value_to_id(const uint16_t iana_value, s2n_exte int s2n_extension_send(const s2n_extension_type *extension_type, struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(extension_type); - notnull_check(extension_type->should_send); - notnull_check(extension_type->send); - notnull_check(conn); + POSIX_ENSURE_REF(extension_type); + POSIX_ENSURE_REF(extension_type->should_send); + POSIX_ENSURE_REF(extension_type->send); + POSIX_ENSURE_REF(conn); s2n_extension_type_id extension_id; - GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); /* Do not send response if request not received. */ if (extension_type->is_response && @@ -95,23 +95,28 @@ int s2n_extension_send(const s2n_extension_type *extension_type, struct s2n_conn return S2N_SUCCESS; } + /* Do not send an extension that is not valid for the protocol version */ + if (extension_type->minimum_version > conn->actual_protocol_version) { + return S2N_SUCCESS; + } + /* Check if we need to send. Some extensions are only sent if specific conditions are met. */ if (!extension_type->should_send(conn)) { return S2N_SUCCESS; } /* Write extension type */ - GUARD(s2n_stuffer_write_uint16(out, extension_type->iana_value)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, extension_type->iana_value)); /* Reserve space for extension size */ struct s2n_stuffer_reservation extension_size_bytes = {0}; - GUARD(s2n_stuffer_reserve_uint16(out, &extension_size_bytes)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &extension_size_bytes)); /* Write extension data */ - GUARD(extension_type->send(conn, out)); + POSIX_GUARD(extension_type->send(conn, out)); /* Record extension size */ - GUARD(s2n_stuffer_write_vector_size(&extension_size_bytes)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&extension_size_bytes)); /* Set request bit flag */ if (!extension_type->is_response) { @@ -123,20 +128,37 @@ int s2n_extension_send(const s2n_extension_type *extension_type, struct s2n_conn int s2n_extension_recv(const s2n_extension_type *extension_type, struct s2n_connection *conn, struct s2n_stuffer *in) { - notnull_check(extension_type); - notnull_check(extension_type->recv); - notnull_check(conn); + POSIX_ENSURE_REF(extension_type); + POSIX_ENSURE_REF(extension_type->recv); + POSIX_ENSURE_REF(conn); s2n_extension_type_id extension_id; - GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); - - /* Do not accept a response if we did not send a request */ - if(extension_type->is_response && + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2 + *# Implementations MUST NOT send extension responses if the remote + *# endpoint did not send the corresponding extension requests, with the + *# exception of the "cookie" extension in the HelloRetryRequest. Upon + *# receiving such an extension, an endpoint MUST abort the handshake + *# with an "unsupported_extension" alert. + * + *= https://tools.ietf.org/rfc/rfc7627#section-5.3 + *# If the original session did not use the "extended_master_secret" + *# extension but the new ServerHello contains the extension, the + *# client MUST abort the handshake. + **/ + if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_sent, extension_id)) { - S2N_ERROR(S2N_ERR_UNSUPPORTED_EXTENSION); + POSIX_BAIL(S2N_ERR_UNSUPPORTED_EXTENSION); } - GUARD(extension_type->recv(conn, in)); + /* Do not process an extension not valid for the protocol version */ + if (extension_type->minimum_version > conn->actual_protocol_version) { + return S2N_SUCCESS; + } + + POSIX_GUARD(extension_type->recv(conn, in)); /* Set request bit flag */ if (!extension_type->is_response) { @@ -148,12 +170,12 @@ int s2n_extension_recv(const s2n_extension_type *extension_type, struct s2n_conn int s2n_extension_is_missing(const s2n_extension_type *extension_type, struct s2n_connection *conn) { - notnull_check(extension_type); - notnull_check(extension_type->if_missing); - notnull_check(conn); + POSIX_ENSURE_REF(extension_type); + POSIX_ENSURE_REF(extension_type->if_missing); + POSIX_ENSURE_REF(conn); s2n_extension_type_id extension_id; - GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id)); /* Do not consider an extension missing if we did not send a request */ if(extension_type->is_response && @@ -161,19 +183,24 @@ int s2n_extension_is_missing(const s2n_extension_type *extension_type, struct s2 return S2N_SUCCESS; } - GUARD(extension_type->if_missing(conn)); + /* Do not consider an extension missing if it is not valid for the protocol version */ + if (extension_type->minimum_version > conn->actual_protocol_version) { + return S2N_SUCCESS; + } + + POSIX_GUARD(extension_type->if_missing(conn)); return S2N_SUCCESS; } int s2n_extension_send_unimplemented(struct s2n_connection *conn, struct s2n_stuffer *out) { - S2N_ERROR(S2N_ERR_UNIMPLEMENTED); + POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } int s2n_extension_recv_unimplemented(struct s2n_connection *conn, struct s2n_stuffer *in) { - S2N_ERROR(S2N_ERR_UNIMPLEMENTED); + POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } int s2n_extension_send_noop(struct s2n_connection *conn, struct s2n_stuffer *out) @@ -203,7 +230,7 @@ bool s2n_extension_send_if_tls13_connection(struct s2n_connection *conn) int s2n_extension_error_if_missing(struct s2n_connection *conn) { - S2N_ERROR(S2N_ERR_MISSING_EXTENSION); + POSIX_BAIL(S2N_ERR_MISSING_EXTENSION); } int s2n_extension_noop_if_missing(struct s2n_connection *conn) diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h index 3c95af639f..f3ccf58730 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h @@ -22,6 +22,7 @@ #define S2N_EXTENSION_TYPE_FIELD_LENGTH 2 #define S2N_EXTENSION_LENGTH_FIELD_LENGTH 2 +#define S2N_EXTENSION_HEADER_LENGTH (S2N_EXTENSION_TYPE_FIELD_LENGTH + S2N_EXTENSION_LENGTH_FIELD_LENGTH) /* The number of extensions supported by S2N */ #define S2N_SUPPORTED_EXTENSIONS_COUNT (sizeof(s2n_supported_extensions) / sizeof(s2n_supported_extensions[0])) @@ -34,6 +35,7 @@ struct s2n_connection; typedef struct { uint16_t iana_value; unsigned is_response:1; + uint16_t minimum_version; int (*send) (struct s2n_connection *conn, struct s2n_stuffer *out); int (*recv) (struct s2n_connection *conn, struct s2n_stuffer *in); @@ -63,6 +65,8 @@ static const uint16_t s2n_supported_extensions[] = { TLS_QUIC_TRANSPORT_PARAMETERS, TLS_EXTENSION_PSK_KEY_EXCHANGE_MODES, TLS_EXTENSION_PRE_SHARED_KEY, + TLS_EXTENSION_EARLY_DATA, + TLS_EXTENSION_EMS, }; typedef char s2n_extension_bitfield[S2N_SUPPORTED_EXTENSIONS_BITFIELD_LEN]; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type_lists.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type_lists.c index 5395366a6c..ba749a4e87 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type_lists.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type_lists.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "tls/extensions/s2n_extension_type_lists.h" #include "tls/s2n_connection.h" @@ -31,6 +31,8 @@ #include "tls/extensions/s2n_client_supported_groups.h" #include "tls/extensions/s2n_client_pq_kem.h" #include "tls/extensions/s2n_client_psk.h" +#include "tls/extensions/s2n_ems.h" +#include "tls/extensions/s2n_early_data_indication.h" #include "tls/extensions/s2n_psk_key_exchange_modes.h" #include "tls/extensions/s2n_client_renegotiation_info.h" #include "tls/extensions/s2n_ec_point_format.h" @@ -50,7 +52,13 @@ static const s2n_extension_type *const client_hello_extensions[] = { &s2n_client_supported_versions_extension, + + /* We MUST process key_share after supported_groups, + * because we need to choose the keyshare based on the + * mutually supported groups. */ + &s2n_client_supported_groups_extension, &s2n_client_key_share_extension, + &s2n_client_signature_algorithms_extension, &s2n_client_server_name_extension, &s2n_client_alpn_extension, @@ -58,13 +66,14 @@ static const s2n_extension_type *const client_hello_extensions[] = { &s2n_client_sct_list_extension, &s2n_client_max_frag_len_extension, &s2n_client_session_ticket_extension, - &s2n_client_supported_groups_extension, &s2n_client_ec_point_format_extension, &s2n_client_pq_kem_extension, &s2n_client_renegotiation_info_extension, &s2n_client_cookie_extension, &s2n_quic_transport_parameters_extension, &s2n_psk_key_exchange_modes_extension, + &s2n_client_early_data_indication_extension, + &s2n_client_ems_extension, &s2n_client_psk_extension /* MUST be last */ }; @@ -78,6 +87,24 @@ static const s2n_extension_type *const tls12_server_hello_extensions[] = { &s2n_server_sct_list_extension, &s2n_server_max_fragment_length_extension, &s2n_server_session_ticket_extension, + &s2n_server_ems_extension, +}; + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.1.4 + *# The + *# HelloRetryRequest extensions defined in this specification are: + *# + *# - supported_versions (see Section 4.2.1) + *# + *# - cookie (see Section 4.2.2) + *# + *# - key_share (see Section 4.2.8) + */ +static const s2n_extension_type *const hello_retry_request_extensions[] = { + &s2n_server_supported_versions_extension, + &s2n_server_cookie_extension, + &s2n_server_key_share_extension, }; static const s2n_extension_type *const tls13_server_hello_extensions[] = { @@ -92,6 +119,7 @@ static const s2n_extension_type *const encrypted_extensions[] = { &s2n_server_max_fragment_length_extension, &s2n_server_alpn_extension, &s2n_quic_transport_parameters_extension, + &s2n_server_early_data_indication_extension, }; static const s2n_extension_type *const cert_req_extensions[] = { @@ -103,22 +131,28 @@ static const s2n_extension_type *const certificate_extensions[] = { &s2n_server_sct_list_extension, }; +static const s2n_extension_type *const nst_extensions[] = { + &s2n_nst_early_data_indication_extension, +}; + #define S2N_EXTENSION_LIST(list) { .extension_types = (list), .count = s2n_array_len(list) } static s2n_extension_type_list extension_lists[] = { [S2N_EXTENSION_LIST_CLIENT_HELLO] = S2N_EXTENSION_LIST(client_hello_extensions), + [S2N_EXTENSION_LIST_HELLO_RETRY_REQUEST] = S2N_EXTENSION_LIST(hello_retry_request_extensions), [S2N_EXTENSION_LIST_SERVER_HELLO_DEFAULT] = S2N_EXTENSION_LIST(tls12_server_hello_extensions), [S2N_EXTENSION_LIST_SERVER_HELLO_TLS13] = S2N_EXTENSION_LIST(tls13_server_hello_extensions), [S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS] = S2N_EXTENSION_LIST(encrypted_extensions), [S2N_EXTENSION_LIST_CERT_REQ] = S2N_EXTENSION_LIST(cert_req_extensions), [S2N_EXTENSION_LIST_CERTIFICATE] = S2N_EXTENSION_LIST(certificate_extensions), + [S2N_EXTENSION_LIST_NST] = S2N_EXTENSION_LIST(nst_extensions), [S2N_EXTENSION_LIST_EMPTY] = { .extension_types = NULL, .count = 0 }, }; int s2n_extension_type_list_get(s2n_extension_list_id list_type, s2n_extension_type_list **extension_list) { - notnull_check(extension_list); - lt_check(list_type, s2n_array_len(extension_lists)); + POSIX_ENSURE_REF(extension_list); + POSIX_ENSURE_LT(list_type, s2n_array_len(extension_lists)); *extension_list = &extension_lists[list_type]; return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.c index a91dbfd30b..6b3f144b3a 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.c @@ -17,17 +17,33 @@ #include "tls/s2n_tls.h" #include "utils/s2n_safety.h" -int s2n_ecdhe_parameters_send(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out) +/* Generate and write an ecc point. + * This is used to write the ecc portion of PQ hybrid keyshares, which does NOT include the curve id. + */ +S2N_RESULT s2n_ecdhe_send_public_key(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out) { - notnull_check(out); - notnull_check(ecc_evp_params); - notnull_check(ecc_evp_params->negotiated_curve); + RESULT_ENSURE_REF(ecc_evp_params); + RESULT_ENSURE_REF(ecc_evp_params->negotiated_curve); + + RESULT_GUARD_POSIX(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->share_size)); + if (ecc_evp_params->evp_pkey == NULL) { + RESULT_GUARD_POSIX(s2n_ecc_evp_generate_ephemeral_key(ecc_evp_params)); + } + RESULT_GUARD_POSIX(s2n_ecc_evp_write_params_point(ecc_evp_params, out)); + + return S2N_RESULT_OK; +} - GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id)); - GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->share_size)); +/* Generate and write an ecc point and its corresponding curve id. + * This is used to write ecc keyshares for the client and server key_share extensions. + */ +int s2n_ecdhe_parameters_send(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out) +{ + POSIX_ENSURE_REF(ecc_evp_params); + POSIX_ENSURE_REF(ecc_evp_params->negotiated_curve); - GUARD(s2n_ecc_evp_generate_ephemeral_key(ecc_evp_params)); - GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id)); + POSIX_GUARD_RESULT(s2n_ecdhe_send_public_key(ecc_evp_params, out)); - return 0; + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.h index f621d76b52..daa464c2bd 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_key_share.h @@ -25,4 +25,5 @@ #define S2N_SIZE_OF_NAMED_GROUP 2 #define S2N_SIZE_OF_KEY_SHARE_SIZE 2 -extern int s2n_ecdhe_parameters_send(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out); +S2N_RESULT s2n_ecdhe_send_public_key(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out); +int s2n_ecdhe_parameters_send(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out); diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_nst_early_data_indication.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_nst_early_data_indication.c new file mode 100644 index 0000000000..0f149ec2fe --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_nst_early_data_indication.c @@ -0,0 +1,80 @@ +/* + * 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 "api/s2n.h" + +#include "tls/extensions/s2n_early_data_indication.h" + +#include "stuffer/s2n_stuffer.h" +#include "tls/s2n_connection.h" +#include "tls/s2n_early_data.h" +#include "utils/s2n_safety.h" + +static bool s2n_nst_early_data_indication_should_send(struct s2n_connection *conn) +{ + uint32_t server_max_early_data = 0; + return s2n_result_is_ok(s2n_early_data_get_server_max_size(conn, &server_max_early_data)) + && server_max_early_data > 0; +} + +/** + * The client version of this extension is empty, so we don't read/write any data. + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# The "extension_data" field of this extension contains an + *# "EarlyDataIndication" value. + *# + *# struct {} Empty; + *# + *# struct { + *# select (Handshake.msg_type) { + *# case new_session_ticket: uint32 max_early_data_size; + ** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# }; + *# } EarlyDataIndication; + **/ + +static int s2n_nst_early_data_indication_send(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + uint32_t server_max_early_data = 0; + POSIX_GUARD_RESULT(s2n_early_data_get_server_max_size(conn, &server_max_early_data)); + POSIX_GUARD(s2n_stuffer_write_uint32(out, server_max_early_data)); + return S2N_SUCCESS; +} + +static int s2n_nst_early_data_indiction_recv(struct s2n_connection *conn, struct s2n_stuffer *in) +{ + POSIX_ENSURE_REF(conn); + uint32_t server_max_early_data = 0; + POSIX_GUARD(s2n_stuffer_read_uint32(in, &server_max_early_data)); + POSIX_GUARD(s2n_connection_set_server_max_early_data_size(conn, server_max_early_data)); + return S2N_SUCCESS; +} + +static int s2n_nst_early_data_indication_missing(struct s2n_connection *conn) +{ + POSIX_GUARD(s2n_connection_set_server_max_early_data_size(conn, 0)); + return S2N_SUCCESS; +} + +const s2n_extension_type s2n_nst_early_data_indication_extension = { + .iana_value = TLS_EXTENSION_EARLY_DATA, + .is_response = false, + .send = s2n_nst_early_data_indication_send, + .recv = s2n_nst_early_data_indiction_recv, + .should_send = s2n_nst_early_data_indication_should_send, + .if_missing = s2n_nst_early_data_indication_missing, +}; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.c index 67b1904b6b..e66a552772 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.c @@ -18,16 +18,16 @@ #include "tls/s2n_tls_parameters.h" #include "tls/extensions/s2n_client_psk.h" +#include "tls/extensions/s2n_psk_key_exchange_modes.h" #include "utils/s2n_safety.h" -#define PSK_KEY_EXCHANGE_MODE_SIZE sizeof(uint8_t) - static bool s2n_psk_key_exchange_modes_should_send(struct s2n_connection *conn); static int s2n_psk_key_exchange_modes_send(struct s2n_connection *conn, struct s2n_stuffer *out); static int s2n_psk_key_exchange_modes_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); const s2n_extension_type s2n_psk_key_exchange_modes_extension = { .iana_value = TLS_EXTENSION_PSK_KEY_EXCHANGE_MODES, + .minimum_version = S2N_TLS13, .is_response = false, .send = s2n_psk_key_exchange_modes_send, .recv = s2n_psk_key_exchange_modes_recv, @@ -43,26 +43,22 @@ static bool s2n_psk_key_exchange_modes_should_send(struct s2n_connection *conn) static int s2n_psk_key_exchange_modes_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - GUARD(s2n_stuffer_write_uint8(out, PSK_KEY_EXCHANGE_MODE_SIZE)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, PSK_KEY_EXCHANGE_MODE_SIZE)); /* s2n currently only supports pre-shared keys with (EC)DHE key establishment */ - GUARD(s2n_stuffer_write_uint8(out, TLS_PSK_DHE_KE_MODE)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_PSK_DHE_KE_MODE)); return S2N_SUCCESS; } static int s2n_psk_key_exchange_modes_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return S2N_SUCCESS; - } + POSIX_ENSURE_REF(conn); uint8_t psk_ke_mode_list_len; - GUARD(s2n_stuffer_read_uint8(extension, &psk_ke_mode_list_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &psk_ke_mode_list_len)); if (psk_ke_mode_list_len > s2n_stuffer_data_available(extension)) { /* Malformed length, ignore the extension */ return S2N_SUCCESS; @@ -70,7 +66,7 @@ static int s2n_psk_key_exchange_modes_recv(struct s2n_connection *conn, struct s for (size_t i = 0; i < psk_ke_mode_list_len; i++) { uint8_t wire_psk_ke_mode; - GUARD(s2n_stuffer_read_uint8(extension, &wire_psk_ke_mode)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &wire_psk_ke_mode)); /* s2n currently only supports pre-shared keys with (EC)DHE key establishment */ if (wire_psk_ke_mode == TLS_PSK_DHE_KE_MODE) { diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.h index 3c64f64489..74c1fe9797 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_psk_key_exchange_modes.h @@ -19,4 +19,6 @@ #include "tls/s2n_connection.h" #include "stuffer/s2n_stuffer.h" +#define PSK_KEY_EXCHANGE_MODE_SIZE sizeof(uint8_t) + extern const s2n_extension_type s2n_psk_key_exchange_modes_extension; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_quic_transport_params.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_quic_transport_params.c index 56f17abc3b..ab84388e7a 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_quic_transport_params.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_quic_transport_params.c @@ -31,44 +31,45 @@ static bool s2n_quic_transport_params_should_send(struct s2n_connection *conn) { - return conn && conn->config && conn->config->quic_enabled; + return s2n_connection_is_quic_enabled(conn); } static int s2n_quic_transport_params_if_missing(struct s2n_connection *conn) { - notnull_check(conn); - notnull_check(conn->config); - ENSURE_POSIX(!conn->config->quic_enabled, S2N_ERR_MISSING_EXTENSION); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_MISSING_EXTENSION); return S2N_SUCCESS; } static int s2n_quic_transport_params_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - notnull_check(out); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(out); if (conn->our_quic_transport_parameters.size) { - GUARD(s2n_stuffer_write(out, &conn->our_quic_transport_parameters)); + POSIX_GUARD(s2n_stuffer_write(out, &conn->our_quic_transport_parameters)); } return S2N_SUCCESS; } static int s2n_quic_transport_params_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - notnull_check(extension); - notnull_check(conn->config); - ENSURE_POSIX(conn->config->quic_enabled, S2N_ERR_UNSUPPORTED_EXTENSION); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(extension); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE(s2n_connection_is_quic_enabled(conn), S2N_ERR_UNSUPPORTED_EXTENSION); if (s2n_stuffer_data_available(extension)) { - GUARD(s2n_alloc(&conn->peer_quic_transport_parameters, s2n_stuffer_data_available(extension))); - GUARD(s2n_stuffer_read(extension, &conn->peer_quic_transport_parameters)); + POSIX_GUARD(s2n_alloc(&conn->peer_quic_transport_parameters, s2n_stuffer_data_available(extension))); + POSIX_GUARD(s2n_stuffer_read(extension, &conn->peer_quic_transport_parameters)); } return S2N_SUCCESS; } const s2n_extension_type s2n_quic_transport_parameters_extension = { .iana_value = TLS_QUIC_TRANSPORT_PARAMETERS, + .minimum_version = S2N_TLS13, .is_response = false, .send = s2n_quic_transport_params_send, .recv = s2n_quic_transport_params_recv, diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_alpn.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_alpn.c index a1f5ac17cf..9e6dee2136 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_alpn.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_alpn.c @@ -42,39 +42,39 @@ static bool s2n_alpn_should_send(struct s2n_connection *conn) static int s2n_alpn_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const uint8_t application_protocol_len = strlen(conn->application_protocol); /* Size of protocol name list */ - GUARD(s2n_stuffer_write_uint16(out, application_protocol_len + sizeof(uint8_t))); + POSIX_GUARD(s2n_stuffer_write_uint16(out, application_protocol_len + sizeof(uint8_t))); /* Single entry in protocol name list */ - GUARD(s2n_stuffer_write_uint8(out, application_protocol_len)); - GUARD(s2n_stuffer_write_bytes(out, (uint8_t *) conn->application_protocol, application_protocol_len)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, application_protocol_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, (uint8_t *) conn->application_protocol, application_protocol_len)); return S2N_SUCCESS; } static int s2n_alpn_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); uint16_t size_of_all; - GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &size_of_all)); if (size_of_all > s2n_stuffer_data_available(extension) || size_of_all < 3) { /* ignore invalid extension size */ return S2N_SUCCESS; } uint8_t protocol_len; - GUARD(s2n_stuffer_read_uint8(extension, &protocol_len)); - lt_check(protocol_len, s2n_array_len(conn->application_protocol)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &protocol_len)); + POSIX_ENSURE_LT(protocol_len, s2n_array_len(conn->application_protocol)); uint8_t *protocol = s2n_stuffer_raw_read(extension, protocol_len); - notnull_check(protocol); + POSIX_ENSURE_REF(protocol); /* copy the first protocol name */ - memcpy_check(conn->application_protocol, protocol, protocol_len); + POSIX_CHECKED_MEMCPY(conn->application_protocol, protocol, protocol_len); conn->application_protocol[protocol_len] = '\0'; return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_certificate_status.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_certificate_status.c index 486835689c..05063011c7 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_certificate_status.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_certificate_status.c @@ -44,37 +44,53 @@ static bool s2n_tls13_server_status_request_should_send(struct s2n_connection *c int s2n_server_certificate_status_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_blob *ocsp_status = &conn->handshake_params.our_chain_and_key->ocsp_status; - notnull_check(ocsp_status); + POSIX_ENSURE_REF(ocsp_status); - GUARD(s2n_stuffer_write_uint8(out, (uint8_t) S2N_STATUS_REQUEST_OCSP)); - GUARD(s2n_stuffer_write_uint24(out, ocsp_status->size)); - GUARD(s2n_stuffer_write(out, ocsp_status)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, (uint8_t) S2N_STATUS_REQUEST_OCSP)); + POSIX_GUARD(s2n_stuffer_write_uint24(out, ocsp_status->size)); + POSIX_GUARD(s2n_stuffer_write(out, ocsp_status)); return S2N_SUCCESS; } int s2n_server_certificate_status_recv(struct s2n_connection *conn, struct s2n_stuffer *in) { - notnull_check(conn); - + POSIX_ENSURE_REF(conn); + /** + *= https://tools.ietf.org/rfc/rfc6066#section-8 + *# struct { + *# CertificateStatusType status_type; + *# select (status_type) { + *# case ocsp: OCSPResponse; + *# } response; + *# } CertificateStatus; + *# + *# opaque OCSPResponse<1..2^24-1>; + *# + *# An "ocsp_response" contains a complete, DER-encoded OCSP response + *# (using the ASN.1 type OCSPResponse defined in [RFC2560]). Only one + *# OCSP response may be sent. + **/ uint8_t type; - GUARD(s2n_stuffer_read_uint8(in, &type)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &type)); if (type != S2N_STATUS_REQUEST_OCSP) { /* We only support OCSP */ return S2N_SUCCESS; } + conn->status_type = S2N_STATUS_REQUEST_OCSP; uint32_t status_size; - GUARD(s2n_stuffer_read_uint24(in, &status_size)); - lte_check(status_size, s2n_stuffer_data_available(in)); + POSIX_GUARD(s2n_stuffer_read_uint24(in, &status_size)); + POSIX_ENSURE_LTE(status_size, s2n_stuffer_data_available(in)); - GUARD(s2n_realloc(&conn->status_response, status_size)); - GUARD(s2n_stuffer_read_bytes(in, conn->status_response.data, status_size)); + POSIX_GUARD(s2n_realloc(&conn->status_response, status_size)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, conn->status_response.data, status_size)); - GUARD(s2n_x509_validator_validate_cert_stapled_ocsp_response( - &conn->x509_validator, conn, conn->status_response.data, conn->status_response.size)); + POSIX_ENSURE(s2n_x509_validator_validate_cert_stapled_ocsp_response( + &conn->x509_validator, conn, conn->status_response.data, conn->status_response.size) == S2N_CERT_OK, + S2N_ERR_CERT_UNTRUSTED); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_early_data_indication.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_early_data_indication.c new file mode 100644 index 0000000000..80a8143a81 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_early_data_indication.c @@ -0,0 +1,106 @@ +/* + * 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 "api/s2n.h" + +#include "tls/extensions/s2n_early_data_indication.h" + +#include "tls/s2n_connection.h" +#include "tls/s2n_early_data.h" +#include "tls/s2n_handshake.h" +#include "utils/s2n_safety.h" + +static bool s2n_server_early_data_indication_should_send(struct s2n_connection *conn) +{ + return conn && conn->early_data_state == S2N_EARLY_DATA_ACCEPTED; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# A server which receives an "early_data" extension MUST behave in one + *# of three ways: + *# + *# - Ignore the extension and return a regular 1-RTT response. + **/ +static int s2n_server_early_data_indication_is_missing(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + if (conn->early_data_state == S2N_EARLY_DATA_REQUESTED) { + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REJECTED)); + } + return S2N_SUCCESS; +} + +/** + * The server version of this extension is empty, so we don't read/write any data. + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# The "extension_data" field of this extension contains an + *# "EarlyDataIndication" value. + *# + *# struct {} Empty; + *# + *# struct { + *# select (Handshake.msg_type) { + ** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# case encrypted_extensions: Empty; + *# }; + *# } EarlyDataIndication; + **/ + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# A server which receives an "early_data" extension MUST behave in one + *# of three ways: + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# - Return its own "early_data" extension in EncryptedExtensions, + *# indicating that it intends to process the early data. + **/ + +static int s2n_server_early_data_indication_send(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + return S2N_SUCCESS; +} + +static int s2n_server_early_data_indication_recv(struct s2n_connection *conn, struct s2n_stuffer *in) +{ + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# If any of these checks fail, the server MUST NOT respond with the + *# extension + **/ + POSIX_ENSURE(s2n_early_data_is_valid_for_connection(conn), S2N_ERR_EARLY_DATA_NOT_ALLOWED); + + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_ACCEPTED)); + + /* The client does not know for sure whether the server accepted early data until it receives + * this extension as part of the EncryptedExtensions message, after the handshake type has + * already been calculated. We'll need to manually update the handshake type. + */ + conn->handshake.handshake_type |= WITH_EARLY_DATA; + + return S2N_SUCCESS; +} + +const s2n_extension_type s2n_server_early_data_indication_extension = { + .iana_value = TLS_EXTENSION_EARLY_DATA, + .is_response = true, + .send = s2n_server_early_data_indication_send, + .recv = s2n_server_early_data_indication_recv, + .should_send = s2n_server_early_data_indication_should_send, + .if_missing = s2n_server_early_data_indication_is_missing, +}; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_ems.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_ems.c new file mode 100644 index 0000000000..06f0474d8d --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_ems.c @@ -0,0 +1,74 @@ +/* + * 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 <sys/param.h> +#include <stdint.h> + +#include "tls/s2n_tls.h" +#include "tls/extensions/s2n_ems.h" + +#include "utils/s2n_safety.h" + +static int s2n_server_ems_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); +static bool s2n_server_ems_should_send(struct s2n_connection *conn); +static int s2n_server_ems_if_missing(struct s2n_connection *conn); + +/** + *= https://tools.ietf.org/rfc/rfc7627#section-5.1 + *# + *# This document defines a new TLS extension, "extended_master_secret" + *# (with extension type 0x0017), which is used to signal both client and + *# server to use the extended master secret computation. The + *# "extension_data" field of this extension is empty. Thus, the entire + *# encoding of the extension is 00 17 00 00 (in hexadecimal.) + **/ +const s2n_extension_type s2n_server_ems_extension = { + .iana_value = TLS_EXTENSION_EMS, + .is_response = true, + .send = s2n_extension_send_noop, + .recv = s2n_server_ems_recv, + .should_send = s2n_server_ems_should_send, + .if_missing = s2n_server_ems_if_missing, +}; + +static int s2n_server_ems_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) +{ + POSIX_ENSURE_REF(conn); + + /* Read nothing. The extension just needs to exist. */ + conn->ems_negotiated = true; + + return S2N_SUCCESS; +} + +static bool s2n_server_ems_should_send(struct s2n_connection *conn) +{ + return conn && conn->actual_protocol_version < S2N_TLS13; +} + +static int s2n_server_ems_if_missing(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + + /** + *= https://tools.ietf.org/rfc/rfc7627#section-5.3 + *# If the original session used the extension but the new ServerHello + *# does not contain the extension, the client MUST abort the + *# handshake. + **/ + POSIX_ENSURE(!conn->ems_negotiated, S2N_ERR_MISSING_EXTENSION); + + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c index eb0ead255a..46f5deb1d5 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c @@ -27,115 +27,105 @@ static int s2n_server_key_share_recv(struct s2n_connection *conn, struct s2n_stu const s2n_extension_type s2n_server_key_share_extension = { .iana_value = TLS_EXTENSION_KEY_SHARE, + .minimum_version = S2N_TLS13, .is_response = false, .send = s2n_server_key_share_send, .recv = s2n_server_key_share_recv, - .should_send = s2n_extension_send_if_tls13_connection, + .should_send = s2n_extension_always_send, .if_missing = s2n_extension_noop_if_missing, }; static int s2n_server_key_share_generate_pq_hybrid(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(out); - notnull_check(conn); + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(conn); - ENSURE_POSIX(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); + POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); - struct s2n_kem_group_params *server_kem_group_params = &conn->secure.server_kem_group_params; + struct s2n_kem_group_params *server_kem_group_params = &conn->kex_params.server_kem_group_params; - notnull_check(server_kem_group_params->kem_group); - GUARD(s2n_stuffer_write_uint16(out, server_kem_group_params->kem_group->iana_id)); + POSIX_ENSURE_REF(server_kem_group_params->kem_group); + POSIX_GUARD(s2n_stuffer_write_uint16(out, server_kem_group_params->kem_group->iana_id)); struct s2n_stuffer_reservation total_share_size = { 0 }; - GUARD(s2n_stuffer_reserve_uint16(out, &total_share_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &total_share_size)); struct s2n_ecc_evp_params *server_ecc_params = &server_kem_group_params->ecc_params; - notnull_check(server_ecc_params->negotiated_curve); - GUARD(s2n_stuffer_write_uint16(out, server_ecc_params->negotiated_curve->share_size)); - GUARD(s2n_ecc_evp_generate_ephemeral_key(server_ecc_params)); - GUARD(s2n_ecc_evp_write_params_point(server_ecc_params, out)); - - notnull_check(conn->secure.chosen_client_kem_group_params); - struct s2n_kem_params *client_kem_params = &conn->secure.chosen_client_kem_group_params->kem_params; - notnull_check(client_kem_params->public_key.data); + POSIX_ENSURE_REF(server_ecc_params->negotiated_curve); + POSIX_GUARD(s2n_stuffer_write_uint16(out, server_ecc_params->negotiated_curve->share_size)); + POSIX_GUARD(s2n_ecc_evp_generate_ephemeral_key(server_ecc_params)); + POSIX_GUARD(s2n_ecc_evp_write_params_point(server_ecc_params, out)); + + struct s2n_kem_params *client_kem_params = &conn->kex_params.client_kem_group_params.kem_params; + POSIX_ENSURE_REF(client_kem_params->public_key.data); /* s2n_kem_send_ciphertext() will generate the PQ shared secret and use * the client's public key to encapsulate; the PQ shared secret will be * stored in client_kem_params, and will be used during the hybrid shared * secret derivation. */ - GUARD(s2n_kem_send_ciphertext(out, client_kem_params)); + POSIX_GUARD(s2n_kem_send_ciphertext(out, client_kem_params)); - GUARD(s2n_stuffer_write_vector_size(&total_share_size)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&total_share_size)); return S2N_SUCCESS; } /* Check that client has sent a corresponding key share for the server's KEM group */ int s2n_server_key_share_send_check_pq_hybrid(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - ENSURE_POSIX(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); + POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); - notnull_check(conn->secure.server_kem_group_params.kem_group); - notnull_check(conn->secure.server_kem_group_params.kem_params.kem); - notnull_check(conn->secure.server_kem_group_params.ecc_params.negotiated_curve); + POSIX_ENSURE_REF(conn->kex_params.server_kem_group_params.kem_group); + POSIX_ENSURE_REF(conn->kex_params.server_kem_group_params.kem_params.kem); + POSIX_ENSURE_REF(conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve); - const struct s2n_kem_group *server_kem_group = conn->secure.server_kem_group_params.kem_group; + const struct s2n_kem_group *server_kem_group = conn->kex_params.server_kem_group_params.kem_group; const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); - ENSURE_POSIX(s2n_kem_preferences_includes_tls13_kem_group(kem_pref, server_kem_group->iana_id), + POSIX_ENSURE(s2n_kem_preferences_includes_tls13_kem_group(kem_pref, server_kem_group->iana_id), S2N_ERR_KEM_UNSUPPORTED_PARAMS); - struct s2n_kem_group_params *client_params = conn->secure.chosen_client_kem_group_params; - notnull_check(client_params); - - ENSURE_POSIX(client_params->kem_group == server_kem_group, S2N_ERR_BAD_KEY_SHARE); + struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params; + POSIX_ENSURE(client_params->kem_group == server_kem_group, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(client_params->ecc_params.negotiated_curve == server_kem_group->curve, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(client_params->ecc_params.evp_pkey != NULL, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_params->ecc_params.negotiated_curve == server_kem_group->curve, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_params->ecc_params.evp_pkey != NULL, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(client_params->kem_params.kem == server_kem_group->kem, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(client_params->kem_params.public_key.size == server_kem_group->kem->public_key_length, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(client_params->kem_params.public_key.data != NULL, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_params->kem_params.kem == server_kem_group->kem, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_params->kem_params.public_key.size == server_kem_group->kem->public_key_length, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_params->kem_params.public_key.data != NULL, S2N_ERR_BAD_KEY_SHARE); return S2N_SUCCESS; } /* Check that client has sent a corresponding key share for the server's EC curve */ int s2n_server_key_share_send_check_ecdhe(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); - const struct s2n_ecc_named_curve *server_curve = conn->secure.server_ecc_evp_params.negotiated_curve; - notnull_check(server_curve); + const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve; + POSIX_ENSURE_REF(server_curve); - struct s2n_ecc_evp_params *client_params = NULL; - for (size_t i = 0; i < ecc_pref->count; i++) { - if (server_curve == ecc_pref->ecc_curves[i]) { - client_params = &conn->secure.client_ecc_evp_params[i]; - break; - } - } - - notnull_check(client_params); - ENSURE_POSIX(client_params->negotiated_curve == server_curve, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(client_params->evp_pkey != NULL, S2N_ERR_BAD_KEY_SHARE); + struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params; + POSIX_ENSURE(client_params->negotiated_curve == server_curve, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_params->evp_pkey != NULL, S2N_ERR_BAD_KEY_SHARE); return S2N_SUCCESS; } static int s2n_server_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - notnull_check(out); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(out); - const struct s2n_ecc_named_curve *curve = conn->secure.server_ecc_evp_params.negotiated_curve; - const struct s2n_kem_group *kem_group = conn->secure.server_kem_group_params.kem_group; + const struct s2n_ecc_named_curve *curve = conn->kex_params.server_ecc_evp_params.negotiated_curve; + const struct s2n_kem_group *kem_group = conn->kex_params.server_kem_group_params.kem_group; /* Boolean XOR: exactly one of {server_curve, server_kem_group} should be non-null. */ - ENSURE_POSIX((curve == NULL) != (kem_group == NULL), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + POSIX_ENSURE((curve == NULL) != (kem_group == NULL), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); /* Retry requests only require the selected named group, not an actual share. * https://tools.ietf.org/html/rfc8446#section-4.2.8 */ @@ -147,16 +137,16 @@ static int s2n_server_key_share_send(struct s2n_connection *conn, struct s2n_stu named_group_id = kem_group->iana_id; } - GUARD(s2n_stuffer_write_uint16(out, named_group_id)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, named_group_id)); return S2N_SUCCESS; } if (curve != NULL) { - GUARD(s2n_server_key_share_send_check_ecdhe(conn)); - GUARD(s2n_ecdhe_parameters_send(&conn->secure.server_ecc_evp_params, out)); + POSIX_GUARD(s2n_server_key_share_send_check_ecdhe(conn)); + POSIX_GUARD(s2n_ecdhe_parameters_send(&conn->kex_params.server_ecc_evp_params, out)); } else { - GUARD(s2n_server_key_share_send_check_pq_hybrid(conn)); - GUARD(s2n_server_key_share_generate_pq_hybrid(conn, out)); + POSIX_GUARD(s2n_server_key_share_send_check_pq_hybrid(conn)); + POSIX_GUARD(s2n_server_key_share_generate_pq_hybrid(conn, out)); } return S2N_SUCCESS; @@ -164,20 +154,20 @@ static int s2n_server_key_share_send(struct s2n_connection *conn, struct s2n_stu static int s2n_server_key_share_recv_pq_hybrid(struct s2n_connection *conn, uint16_t named_group_iana, struct s2n_stuffer *extension) { - notnull_check(conn); - notnull_check(extension); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(extension); /* If PQ is disabled, the client should not have sent any PQ IDs * in the supported_groups list of the initial ClientHello */ - ENSURE_POSIX(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); + POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); /* This check should have been done higher up, but including it here as well for extra defense. * Uses S2N_ERR_ECDHE_UNSUPPORTED_CURVE for backward compatibility. */ - ENSURE_POSIX(s2n_kem_preferences_includes_tls13_kem_group(kem_pref, named_group_iana), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + POSIX_ENSURE(s2n_kem_preferences_includes_tls13_kem_group(kem_pref, named_group_iana), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); size_t kem_group_index = 0; for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { @@ -187,7 +177,7 @@ static int s2n_server_key_share_recv_pq_hybrid(struct s2n_connection *conn, uint } } - struct s2n_kem_group_params *server_kem_group_params = &conn->secure.server_kem_group_params; + struct s2n_kem_group_params *server_kem_group_params = &conn->kex_params.server_kem_group_params; server_kem_group_params->kem_group = kem_pref->tls13_kem_groups[kem_group_index]; server_kem_group_params->kem_params.kem = kem_pref->tls13_kem_groups[kem_group_index]->kem; server_kem_group_params->ecc_params.negotiated_curve = kem_pref->tls13_kem_groups[kem_group_index]->curve; @@ -200,29 +190,26 @@ static int s2n_server_key_share_recv_pq_hybrid(struct s2n_connection *conn, uint } /* Ensure that the server's key share corresponds with a key share previously sent by the client */ - ENSURE_POSIX(conn->secure.client_kem_group_params[kem_group_index].kem_params.private_key.data != NULL, - S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(conn->secure.client_kem_group_params[kem_group_index].ecc_params.evp_pkey != NULL, - S2N_ERR_BAD_KEY_SHARE); - notnull_check(conn->secure.client_kem_group_params[kem_group_index].kem_group); - eq_check(conn->secure.client_kem_group_params[kem_group_index].kem_group->iana_id, named_group_iana); - conn->secure.chosen_client_kem_group_params = &conn->secure.client_kem_group_params[kem_group_index]; + struct s2n_kem_group_params *client_kem_group_params = &conn->kex_params.client_kem_group_params; + POSIX_ENSURE(client_kem_group_params->kem_params.private_key.data, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_kem_group_params->ecc_params.evp_pkey, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_kem_group_params->kem_group == server_kem_group_params->kem_group, S2N_ERR_BAD_KEY_SHARE); uint16_t received_total_share_size; - GUARD(s2n_stuffer_read_uint16(extension, &received_total_share_size)); - ENSURE_POSIX(received_total_share_size == server_kem_group_params->kem_group->server_share_size, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(s2n_stuffer_data_available(extension) == received_total_share_size, S2N_ERR_BAD_KEY_SHARE); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &received_total_share_size)); + POSIX_ENSURE(received_total_share_size == server_kem_group_params->kem_group->server_share_size, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(s2n_stuffer_data_available(extension) == received_total_share_size, S2N_ERR_BAD_KEY_SHARE); /* Parse ECC key share */ uint16_t ecc_share_size; struct s2n_blob point_blob; - GUARD(s2n_stuffer_read_uint16(extension, &ecc_share_size)); - ENSURE_POSIX(s2n_ecc_evp_read_params_point(extension, ecc_share_size, &point_blob) == S2N_SUCCESS, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(s2n_ecc_evp_parse_params_point(&point_blob, &server_kem_group_params->ecc_params) == S2N_SUCCESS, S2N_ERR_BAD_KEY_SHARE); - ENSURE_POSIX(server_kem_group_params->ecc_params.evp_pkey != NULL, S2N_ERR_BAD_KEY_SHARE); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &ecc_share_size)); + POSIX_ENSURE(s2n_ecc_evp_read_params_point(extension, ecc_share_size, &point_blob) == S2N_SUCCESS, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(s2n_ecc_evp_parse_params_point(&point_blob, &server_kem_group_params->ecc_params) == S2N_SUCCESS, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(server_kem_group_params->ecc_params.evp_pkey != NULL, S2N_ERR_BAD_KEY_SHARE); /* Parse the PQ KEM key share */ - ENSURE_POSIX(s2n_kem_recv_ciphertext(extension, &conn->secure.chosen_client_kem_group_params->kem_params) == S2N_SUCCESS, + POSIX_ENSURE(s2n_kem_recv_ciphertext(extension, &conn->kex_params.client_kem_group_params.kem_params) == S2N_SUCCESS, S2N_ERR_BAD_KEY_SHARE); return S2N_SUCCESS; @@ -230,15 +217,15 @@ static int s2n_server_key_share_recv_pq_hybrid(struct s2n_connection *conn, uint static int s2n_server_key_share_recv_ecc(struct s2n_connection *conn, uint16_t named_group_iana, struct s2n_stuffer *extension) { - notnull_check(conn); - notnull_check(extension); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(extension); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); /* This check should have been done higher up, but including it here as well for extra defense. */ - ENSURE_POSIX(s2n_ecc_preferences_includes_curve(ecc_pref, named_group_iana), + POSIX_ENSURE(s2n_ecc_preferences_includes_curve(ecc_pref, named_group_iana), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); size_t supported_curve_index = 0; @@ -250,7 +237,7 @@ static int s2n_server_key_share_recv_ecc(struct s2n_connection *conn, uint16_t n } } - struct s2n_ecc_evp_params *server_ecc_evp_params = &conn->secure.server_ecc_evp_params; + struct s2n_ecc_evp_params *server_ecc_evp_params = &conn->kex_params.server_ecc_evp_params; server_ecc_evp_params->negotiated_curve = ecc_pref->ecc_curves[supported_curve_index]; /* If this is a HelloRetryRequest, we won't have a key share. We just have the selected group. @@ -259,12 +246,14 @@ static int s2n_server_key_share_recv_ecc(struct s2n_connection *conn, uint16_t n return S2N_SUCCESS; } - /* Key share not sent by client */ - S2N_ERROR_IF(conn->secure.client_ecc_evp_params[supported_curve_index].evp_pkey == NULL, S2N_ERR_BAD_KEY_SHARE); + /* Verify key share sent by client */ + struct s2n_ecc_evp_params *client_ecc_evp_params = &conn->kex_params.client_ecc_evp_params; + POSIX_ENSURE(client_ecc_evp_params->negotiated_curve == server_ecc_evp_params->negotiated_curve, S2N_ERR_BAD_KEY_SHARE); + POSIX_ENSURE(client_ecc_evp_params->evp_pkey, S2N_ERR_BAD_KEY_SHARE); uint16_t share_size; S2N_ERROR_IF(s2n_stuffer_data_available(extension) < sizeof(share_size), S2N_ERR_BAD_KEY_SHARE); - GUARD(s2n_stuffer_read_uint16(extension, &share_size)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &share_size)); S2N_ERROR_IF(s2n_stuffer_data_available(extension) < share_size, S2N_ERR_BAD_KEY_SHARE); /* Proceed to parse share */ @@ -286,31 +275,27 @@ static int s2n_server_key_share_recv_ecc(struct s2n_connection *conn, uint16_t n */ static int s2n_server_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return S2N_SUCCESS; - } - - notnull_check(conn); - notnull_check(extension); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(extension); uint16_t negotiated_named_group_iana = 0; S2N_ERROR_IF(s2n_stuffer_data_available(extension) < sizeof(negotiated_named_group_iana), S2N_ERR_BAD_KEY_SHARE); - GUARD(s2n_stuffer_read_uint16(extension, &negotiated_named_group_iana)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &negotiated_named_group_iana)); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); if (s2n_ecc_preferences_includes_curve(ecc_pref, negotiated_named_group_iana)) { - GUARD(s2n_server_key_share_recv_ecc(conn, negotiated_named_group_iana, extension)); + POSIX_GUARD(s2n_server_key_share_recv_ecc(conn, negotiated_named_group_iana, extension)); } else if (s2n_kem_preferences_includes_tls13_kem_group(kem_pref, negotiated_named_group_iana)) { - GUARD(s2n_server_key_share_recv_pq_hybrid(conn, negotiated_named_group_iana, extension)); + POSIX_GUARD(s2n_server_key_share_recv_pq_hybrid(conn, negotiated_named_group_iana, extension)); } else { - S2N_ERROR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); } return S2N_SUCCESS; @@ -318,15 +303,15 @@ static int s2n_server_key_share_recv(struct s2n_connection *conn, struct s2n_stu /* Selects highest priority mutually supported key share, or indicates need for HRR */ int s2n_extensions_server_key_share_select(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); /* Boolean XOR check. When receiving the supported_groups extension, s2n server * should (exclusively) set either server_curve or server_kem_group based on the @@ -335,44 +320,38 @@ int s2n_extensions_server_key_share_select(struct s2n_connection *conn) { * groups; key negotiation is not possible and the handshake should be aborted * without sending HRR. (The case of both being non-NULL should never occur, and * is an error.) */ - const struct s2n_ecc_named_curve *server_curve = conn->secure.server_ecc_evp_params.negotiated_curve; - const struct s2n_kem_group *server_kem_group = conn->secure.server_kem_group_params.kem_group; - ENSURE_POSIX((server_curve == NULL) != (server_kem_group == NULL), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve; + const struct s2n_kem_group *server_kem_group = conn->kex_params.server_kem_group_params.kem_group; + POSIX_ENSURE((server_curve == NULL) != (server_kem_group == NULL), S2N_ERR_ECDHE_UNSUPPORTED_CURVE); /* To avoid extra round trips, we prefer to negotiate a group for which we have already * received a key share (even if it is different than the group previously chosen). In * general, we prefer to negotiate PQ over ECDHE; however, if both client and server * support PQ, but the client sent only EC key shares, then we will negotiate ECHDE. */ - for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - if (conn->secure.mutually_supported_kem_groups[i] && conn->secure.client_kem_group_params[i].kem_group) { - notnull_check(conn->secure.client_kem_group_params[i].ecc_params.negotiated_curve); - notnull_check(conn->secure.client_kem_group_params[i].kem_params.kem); + if (conn->kex_params.client_kem_group_params.kem_group) { + POSIX_ENSURE_REF(conn->kex_params.client_kem_group_params.ecc_params.negotiated_curve); + POSIX_ENSURE_REF(conn->kex_params.client_kem_group_params.kem_params.kem); - conn->secure.server_kem_group_params.kem_group = conn->secure.client_kem_group_params[i].kem_group; - conn->secure.server_kem_group_params.ecc_params.negotiated_curve = conn->secure.client_kem_group_params[i].ecc_params.negotiated_curve; - conn->secure.server_kem_group_params.kem_params.kem = conn->secure.client_kem_group_params[i].kem_params.kem; - conn->secure.chosen_client_kem_group_params = &conn->secure.client_kem_group_params[i]; + conn->kex_params.server_kem_group_params.kem_group = conn->kex_params.client_kem_group_params.kem_group; + conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve = conn->kex_params.client_kem_group_params.ecc_params.negotiated_curve; + conn->kex_params.server_kem_group_params.kem_params.kem = conn->kex_params.client_kem_group_params.kem_params.kem; - conn->secure.server_ecc_evp_params.negotiated_curve = NULL; - return S2N_SUCCESS; - } + conn->kex_params.server_ecc_evp_params.negotiated_curve = NULL; + return S2N_SUCCESS; } - for (size_t i = 0; i < ecc_pref->count; i++) { - if (conn->secure.mutually_supported_curves[i] && conn->secure.client_ecc_evp_params[i].negotiated_curve) { - conn->secure.server_ecc_evp_params.negotiated_curve = conn->secure.client_ecc_evp_params[i].negotiated_curve; - - conn->secure.server_kem_group_params.kem_group = NULL; - conn->secure.server_kem_group_params.ecc_params.negotiated_curve = NULL; - conn->secure.server_kem_group_params.kem_params.kem = NULL; - conn->secure.chosen_client_kem_group_params = NULL; - return S2N_SUCCESS; - } + if (conn->kex_params.client_ecc_evp_params.negotiated_curve) { + conn->kex_params.server_ecc_evp_params.negotiated_curve = conn->kex_params.client_ecc_evp_params.negotiated_curve; + + conn->kex_params.server_kem_group_params.kem_group = NULL; + conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve = NULL; + conn->kex_params.server_kem_group_params.kem_params.kem = NULL; + return S2N_SUCCESS; } /* Server and client have mutually supported groups, but the client did not send key * shares for any of them. Send HRR indicating the server's preference. */ - GUARD(s2n_set_hello_retry_required(conn)); + POSIX_GUARD(s2n_set_hello_retry_required(conn)); return S2N_SUCCESS; } @@ -389,7 +368,7 @@ int s2n_extensions_server_key_share_select(struct s2n_connection *conn) { */ int s2n_extensions_server_key_share_send_size(struct s2n_connection *conn) { - const struct s2n_ecc_named_curve* curve = conn->secure.server_ecc_evp_params.negotiated_curve; + const struct s2n_ecc_named_curve* curve = conn->kex_params.server_ecc_evp_params.negotiated_curve; int key_share_size = S2N_SIZE_OF_EXTENSION_TYPE + S2N_SIZE_OF_EXTENSION_DATA_SIZE + S2N_SIZE_OF_NAMED_GROUP; @@ -422,7 +401,7 @@ int s2n_extensions_server_key_share_send(struct s2n_connection *conn, struct s2n /* * Client receives a Server Hello key share. * - * If the curve is supported, conn->secure.server_ecc_evp_params will be set. + * If the curve is supported, conn->kex_params.server_ecc_evp_params will be set. */ int s2n_extensions_server_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_max_fragment_length.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_max_fragment_length.c index 69b1530e54..e55e3f21e5 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_max_fragment_length.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_max_fragment_length.c @@ -13,12 +13,15 @@ * permissions and limitations under the License. */ +#include <sys/param.h> + #include "error/s2n_errno.h" #include "stuffer/s2n_stuffer.h" #include "utils/s2n_safety.h" +#include "tls/s2n_tls.h" #include "tls/s2n_tls_parameters.h" #include "tls/s2n_connection.h" @@ -39,23 +42,42 @@ const s2n_extension_type s2n_server_max_fragment_length_extension = { static bool s2n_max_fragment_length_should_send(struct s2n_connection *conn) { - return conn && conn->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE; + return conn && conn->negotiated_mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE; } static int s2n_max_fragment_length_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); - GUARD(s2n_stuffer_write_uint8(out, conn->mfl_code)); + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_stuffer_write_uint8(out, conn->negotiated_mfl_code)); return S2N_SUCCESS; } static int s2n_max_fragment_length_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - notnull_check(conn->config); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); uint8_t mfl_code; - GUARD(s2n_stuffer_read_uint8(extension, &mfl_code)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &mfl_code)); + + /* + *= https://tools.ietf.org/rfc/rfc6066#section-4 + *# Similarly, if a client + *# receives a maximum fragment length negotiation response that differs + *# from the length it requested, it MUST also abort the handshake with + *# an "illegal_parameter" alert. + */ S2N_ERROR_IF(mfl_code != conn->config->mfl_code, S2N_ERR_MAX_FRAG_LEN_MISMATCH); + + /* + *= https://tools.ietf.org/rfc/rfc6066#section-4 + *# Once a maximum fragment length other than 2^14 has been successfully + *# negotiated, the client and server MUST immediately begin fragmenting + *# messages (including handshake messages) to ensure that no fragment + *# larger than the negotiated length is sent. + */ + conn->negotiated_mfl_code = mfl_code; + POSIX_GUARD_RESULT(s2n_connection_set_max_fragment_length(conn, conn->max_outgoing_fragment_length)); + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c index cb930b17a4..9a36caff9f 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c @@ -28,6 +28,7 @@ static int s2n_server_psk_recv(struct s2n_connection *conn, struct s2n_stuffer * const s2n_extension_type s2n_server_psk_extension = { .iana_value = TLS_EXTENSION_PRE_SHARED_KEY, + .minimum_version = S2N_TLS13, .is_response = true, .send = s2n_server_psk_send, .recv = s2n_server_psk_recv, @@ -38,35 +39,30 @@ const s2n_extension_type s2n_server_psk_extension = { static bool s2n_server_psk_should_send(struct s2n_connection *conn) { /* Only send a server pre_shared_key extension if a chosen PSK is set on the connection */ - return conn && s2n_connection_get_protocol_version(conn) >= S2N_TLS13 - && conn->psk_params.chosen_psk; + return conn && conn->psk_params.chosen_psk; } static int s2n_server_psk_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); /* Send the index of the chosen PSK that is stored on the connection. */ - GUARD(s2n_stuffer_write_uint16(out, conn->psk_params.chosen_psk_wire_index)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, conn->psk_params.chosen_psk_wire_index)); return S2N_SUCCESS; } static int s2n_server_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); - - if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { - return S2N_SUCCESS; - } + POSIX_ENSURE_REF(conn); /* Currently in s2n, only (EC)DHE key exchange mode is supported. * Any other mode selected by the server is invalid because it was not offered by the client. * A key_share extension MUST have been received in order to use a pre-shared key in (EC)DHE key exchange mode. */ s2n_extension_type_id key_share_ext_id; - GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_KEY_SHARE, &key_share_ext_id)); - ENSURE_POSIX(S2N_CBIT_TEST(conn->extension_requests_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_KEY_SHARE, &key_share_ext_id)); + POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_requests_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION); /* From RFC section: https://tools.ietf.org/html/rfc8446#section-4.2.8.1 * Any future values that are allocated must ensure that the transmitted protocol messages @@ -76,16 +72,16 @@ static int s2n_server_psk_recv(struct s2n_connection *conn, struct s2n_stuffer * conn->psk_params.psk_ke_mode = S2N_PSK_DHE_KE; uint16_t chosen_psk_wire_index = 0; - GUARD(s2n_stuffer_read_uint16(extension, &chosen_psk_wire_index)); + POSIX_GUARD(s2n_stuffer_read_uint16(extension, &chosen_psk_wire_index)); /* From RFC section: https://tools.ietf.org/html/rfc8446#section-4.2.11 * Clients MUST verify that the server's selected_identity is within the * range supplied by the client. */ - ENSURE_POSIX(chosen_psk_wire_index < conn->psk_params.psk_list.len, S2N_ERR_INVALID_ARGUMENT); + POSIX_ENSURE(chosen_psk_wire_index < conn->psk_params.psk_list.len, S2N_ERR_INVALID_ARGUMENT); conn->psk_params.chosen_psk_wire_index = chosen_psk_wire_index; - GUARD_AS_POSIX(s2n_array_get(&conn->psk_params.psk_list, conn->psk_params.chosen_psk_wire_index, + POSIX_GUARD_RESULT(s2n_array_get(&conn->psk_params.psk_list, conn->psk_params.chosen_psk_wire_index, (void **)&conn->psk_params.chosen_psk)); return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_renegotiation_info.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_renegotiation_info.c index aac791c43c..6da5481ec9 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_renegotiation_info.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_renegotiation_info.c @@ -45,7 +45,7 @@ static bool s2n_renegotiation_info_should_send(struct s2n_connection *conn) static int s2n_renegotiation_info_send(struct s2n_connection *conn, struct s2n_stuffer *out) { /* renegotiated_connection length. Zero since we don't support renegotiation. */ - GUARD(s2n_stuffer_write_uint8(out, 0)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, 0)); return S2N_SUCCESS; } @@ -55,11 +55,11 @@ static int s2n_renegotiation_info_recv(struct s2n_connection *conn, struct s2n_s * the "renegotiated_connection" field is zero, and if it is not, MUST * abort the handshake. */ uint8_t renegotiated_connection_len; - GUARD(s2n_stuffer_read_uint8(extension, &renegotiated_connection_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &renegotiated_connection_len)); S2N_ERROR_IF(s2n_stuffer_data_available(extension), S2N_ERR_NON_EMPTY_RENEGOTIATION_INFO); S2N_ERROR_IF(renegotiated_connection_len, S2N_ERR_NON_EMPTY_RENEGOTIATION_INFO); - notnull_check(conn); + POSIX_ENSURE_REF(conn); conn->secure_renegotiation = 1; return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_sct_list.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_sct_list.c index 8a8158aecf..cf28bef52b 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_sct_list.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_sct_list.c @@ -41,27 +41,27 @@ static bool s2n_server_sct_list_should_send(struct s2n_connection *conn) int s2n_server_sct_list_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_blob *sct_list = &conn->handshake_params.our_chain_and_key->sct_list; - notnull_check(sct_list); - GUARD(s2n_stuffer_write(out, sct_list)); + POSIX_ENSURE_REF(sct_list); + POSIX_GUARD(s2n_stuffer_write(out, sct_list)); return S2N_SUCCESS; } int s2n_server_sct_list_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_blob sct_list; size_t data_available = s2n_stuffer_data_available(extension); - GUARD(s2n_blob_init(&sct_list, + POSIX_GUARD(s2n_blob_init(&sct_list, s2n_stuffer_raw_read(extension, data_available), data_available)); - notnull_check(sct_list.data); + POSIX_ENSURE_REF(sct_list.data); - GUARD(s2n_dup(&sct_list, &conn->ct_response)); + POSIX_GUARD(s2n_dup(&sct_list, &conn->ct_response)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_server_name.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_server_name.c index 158a9eae6c..239c84f1fb 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_server_name.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_server_name.c @@ -33,7 +33,7 @@ const s2n_extension_type s2n_server_server_name_extension = { static bool s2n_server_name_should_send(struct s2n_connection *conn) { - return conn && conn->server_name_used && !s2n_connection_is_session_resumed(conn); + return conn && conn->server_name_used && !IS_RESUMPTION_HANDSHAKE(conn); } static int s2n_server_name_send(struct s2n_connection *conn, struct s2n_stuffer *out) @@ -44,7 +44,7 @@ static int s2n_server_name_send(struct s2n_connection *conn, struct s2n_stuffer static int s2n_server_name_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); /* Read nothing. The extension just needs to exist. */ conn->server_name_used = 1; return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_session_ticket.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_session_ticket.c index 74875f05a6..d4c9bf019f 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_session_ticket.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_session_ticket.c @@ -40,7 +40,7 @@ static bool s2n_session_ticket_should_send(struct s2n_connection *conn) static int s2n_session_ticket_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { /* Read nothing. The extension just needs to exist. */ - notnull_check(conn); + POSIX_ENSURE_REF(conn); conn->session_ticket_status = S2N_NEW_TICKET; return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_status_request.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_status_request.c index 7003bf46ba..c73b5c32a4 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_status_request.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_status_request.c @@ -39,7 +39,7 @@ static bool s2n_server_status_request_should_send(struct s2n_connection *conn) int s2n_server_status_request_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { /* Read nothing. The extension just needs to exist. */ - notnull_check(conn); + POSIX_ENSURE_REF(conn); conn->status_type = S2N_STATUS_REQUEST_OCSP; return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c index cd0fb015dc..53e387d8cc 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c @@ -52,8 +52,8 @@ const s2n_extension_type s2n_server_supported_versions_extension = { static int s2n_server_supported_versions_send(struct s2n_connection *conn, struct s2n_stuffer *out) { - GUARD(s2n_stuffer_write_uint8(out, conn->server_protocol_version / 10)); - GUARD(s2n_stuffer_write_uint8(out, conn->server_protocol_version % 10)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, conn->server_protocol_version / 10)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, conn->server_protocol_version % 10)); return S2N_SUCCESS; } @@ -61,17 +61,18 @@ static int s2n_server_supported_versions_send(struct s2n_connection *conn, struc static int s2n_extensions_server_supported_versions_process(struct s2n_connection *conn, struct s2n_stuffer *extension) { uint8_t highest_supported_version = conn->client_protocol_version; - uint8_t minimum_supported_version; - GUARD(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); + uint8_t minimum_supported_version = s2n_unknown_protocol_version; + POSIX_GUARD_RESULT(s2n_connection_get_minimum_supported_version(conn, &minimum_supported_version)); + POSIX_ENSURE(highest_supported_version >= minimum_supported_version, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); uint8_t server_version_parts[S2N_TLS_PROTOCOL_VERSION_LEN]; - GUARD(s2n_stuffer_read_bytes(extension, server_version_parts, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(extension, server_version_parts, S2N_TLS_PROTOCOL_VERSION_LEN)); uint16_t server_version = (server_version_parts[0] * 10) + server_version_parts[1]; - gte_check(server_version, S2N_TLS13); - lte_check(server_version, highest_supported_version); - gte_check(server_version, minimum_supported_version); + POSIX_ENSURE_GTE(server_version, S2N_TLS13); + POSIX_ENSURE_LTE(server_version, highest_supported_version); + POSIX_ENSURE_GTE(server_version, minimum_supported_version); conn->server_protocol_version = server_version; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.c index d02b3f920d..3f77789e31 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.c @@ -21,11 +21,19 @@ #include "utils/s2n_safety.h" -int s2n_connection_get_minimum_supported_version(struct s2n_connection *conn, uint8_t *min_version) +S2N_RESULT s2n_connection_get_minimum_supported_version(struct s2n_connection *conn, uint8_t *min_version) { - const struct s2n_security_policy *security_policy; - GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + RESULT_ENSURE_REF(min_version); + + const struct s2n_security_policy *security_policy = NULL; + RESULT_GUARD_POSIX(s2n_connection_get_security_policy(conn, &security_policy)); + RESULT_ENSURE_REF(security_policy); *min_version = security_policy->minimum_protocol_version; - return 0; + /* QUIC requires >= TLS1.3 */ + if (s2n_connection_is_quic_enabled(conn)) { + *min_version = MAX(*min_version, S2N_TLS13); + } + + return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.h index 613830c347..6c1fdcea76 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_supported_versions.h @@ -18,4 +18,4 @@ #include "tls/s2n_connection.h" #include "stuffer/s2n_stuffer.h" -extern int s2n_connection_get_minimum_supported_version(struct s2n_connection *conn, uint8_t *min_version); +S2N_RESULT s2n_connection_get_minimum_supported_version(struct s2n_connection *conn, uint8_t *min_version); diff --git a/contrib/restricted/aws/s2n/tls/s2n_aead.c b/contrib/restricted/aws/s2n/tls/s2n_aead.c index b7a0b23160..16bbee133b 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_aead.c +++ b/contrib/restricted/aws/s2n/tls/s2n_aead.c @@ -18,61 +18,88 @@ #include "utils/s2n_safety.h" #include "utils/s2n_mem.h" +#include "tls/s2n_connection.h" #include "tls/s2n_record.h" /* Derive the AAD for an AEAD mode cipher suite from the connection state, per * RFC 5246 section 6.2.3.3 */ -S2N_RESULT s2n_aead_aad_init(const struct s2n_connection *conn, uint8_t * sequence_number, uint8_t content_type, uint16_t record_length, struct s2n_stuffer *ad) +S2N_RESULT s2n_aead_aad_init(const struct s2n_connection *conn, uint8_t * sequence_number, uint8_t content_type, uint16_t record_length, struct s2n_blob *ad) { + RESULT_ENSURE_REF(ad); + RESULT_ENSURE_GTE(ad->size, S2N_TLS_MAX_AAD_LEN); + + uint8_t *data = ad->data; + RESULT_GUARD_PTR(data); + /* ad = seq_num || record_type || version || length */ - GUARD_AS_RESULT(s2n_stuffer_write_bytes(ad, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); - GUARD_AS_RESULT(s2n_stuffer_write_uint8(ad, content_type)); - GUARD_AS_RESULT(s2n_stuffer_write_uint8(ad, conn->actual_protocol_version / 10)); - GUARD_AS_RESULT(s2n_stuffer_write_uint8(ad, conn->actual_protocol_version % 10)); - GUARD_AS_RESULT(s2n_stuffer_write_uint16(ad, record_length)); + size_t idx = 0; + for(; idx < S2N_TLS_SEQUENCE_NUM_LEN; idx++) { + data[idx] = sequence_number[idx]; + } + + data[idx++] = content_type; + data[idx++] = conn->actual_protocol_version / 10; + data[idx++] = conn->actual_protocol_version % 10; + data[idx++] = record_length >> 8; + data[idx++] = record_length & UINT8_MAX; + + /* Double check no overflow */ + RESULT_ENSURE_LTE(idx, ad->size); return S2N_RESULT_OK; } /* Prepares an AAD (additional authentication data) for a TLS 1.3 AEAD record */ -S2N_RESULT s2n_tls13_aead_aad_init(uint16_t record_length, uint8_t tag_length, struct s2n_stuffer *additional_data) +S2N_RESULT s2n_tls13_aead_aad_init(uint16_t record_length, uint8_t tag_length, struct s2n_blob *additional_data) { - ENSURE_GT(tag_length, 0); - ENSURE_REF(additional_data); - - /* - * tls1.3 additional_data = opaque_type || legacy_record_version || length - * - * https://tools.ietf.org/html/rfc8446#section-5.2 - * - * opaque_type: The outer opaque_type field of a TLSCiphertext record - * is always set to the value 23 (application_data) for outward - * compatibility with middleboxes accustomed to parsing previous - * versions of TLS. The actual content type of the record is found - * in TLSInnerPlaintext.type after decryption. - * legacy_record_version: The legacy_record_version field is always - * 0x0303. TLS 1.3 TLSCiphertexts are not generated until after - * TLS 1.3 has been negotiated, so there are no historical - * compatibility concerns where other values might be received. Note - * that the handshake protocol, including the ClientHello and - * ServerHello messages, authenticates the protocol version, so this - * value is redundant. - * length: The length (in bytes) of the following - * TLSCiphertext.encrypted_record, which is the sum of the lengths of - * the content and the padding, plus one for the inner content type, - * plus any expansion added by the AEAD algorithm. The length - * MUST NOT exceed 2^14 + 256 bytes. An endpoint that receives a - * record that exceeds this length MUST terminate the connection with - * a "record_overflow" alert. + RESULT_ENSURE_GT(tag_length, 0); + RESULT_ENSURE_REF(additional_data); + RESULT_ENSURE_GTE(additional_data->size, S2N_TLS13_AAD_LEN); + + uint8_t *data = additional_data->data; + RESULT_GUARD_PTR(data); + + size_t idx = 0; + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-5.2 + *# opaque_type: The outer opaque_type field of a TLSCiphertext record + *# is always set to the value 23 (application_data) for outward + *# compatibility with middleboxes accustomed to parsing previous + *# versions of TLS. The actual content type of the record is found + *# in TLSInnerPlaintext.type after decryption. + **/ + data[idx++] = TLS_APPLICATION_DATA; + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-5.2 + *# legacy_record_version: The legacy_record_version field is always + *# 0x0303. TLS 1.3 TLSCiphertexts are not generated until after + *# TLS 1.3 has been negotiated, so there are no historical + *# compatibility concerns where other values might be received. Note + *# that the handshake protocol, including the ClientHello and + *# ServerHello messages, authenticates the protocol version, so this + *# value is redundant. */ + data[idx++] = 0x03; + data[idx++] = 0x03; + /** + *= https://tools.ietf.org/rfc/rfc8446#section-5.2 + *# length: The length (in bytes) of the following + *# TLSCiphertext.encrypted_record, which is the sum of the lengths of + *# the content and the padding, plus one for the inner content type, + *# plus any expansion added by the AEAD algorithm. The length + *# MUST NOT exceed 2^14 + 256 bytes. An endpoint that receives a + *# record that exceeds this length MUST terminate the connection with + *# a "record_overflow" alert. + */ uint16_t length = record_length + tag_length; - ENSURE(length <= (1 << 14) + 256, S2N_ERR_RECORD_LIMIT); - - GUARD_AS_RESULT(s2n_stuffer_write_uint8(additional_data, TLS_APPLICATION_DATA)); /* fixed to 0x17 */ - GUARD_AS_RESULT(s2n_stuffer_write_uint8(additional_data, 3)); /* TLS record layer */ - GUARD_AS_RESULT(s2n_stuffer_write_uint8(additional_data, 3)); /* version fixed at 1.2 (0x0303) */ - GUARD_AS_RESULT(s2n_stuffer_write_uint16(additional_data, length)); + RESULT_ENSURE(length <= (1 << 14) + 256, S2N_ERR_RECORD_LIMIT); + data[idx++] = length >> 8; + data[idx++] = length & UINT8_MAX; + /* Double check no overflow */ + RESULT_ENSURE_LTE(idx, additional_data->size); return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_alerts.c b/contrib/restricted/aws/s2n/tls/s2n_alerts.c index 79f14f3214..c745a0d193 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_alerts.c +++ b/contrib/restricted/aws/s2n/tls/s2n_alerts.c @@ -27,40 +27,101 @@ #include "utils/s2n_safety.h" #include "utils/s2n_blob.h" -#define S2N_TLS_ALERT_CLOSE_NOTIFY 0 -#define S2N_TLS_ALERT_UNEXPECTED_MSG 10 -#define S2N_TLS_ALERT_BAD_RECORD_MAC 20 -#define S2N_TLS_ALERT_DECRYPT_FAILED 21 -#define S2N_TLS_ALERT_RECORD_OVERFLOW 22 -#define S2N_TLS_ALERT_DECOMP_FAILED 30 -#define S2N_TLS_ALERT_HANDSHAKE_FAILURE 40 -#define S2N_TLS_ALERT_NO_CERTIFICATE 41 -#define S2N_TLS_ALERT_BAD_CERTIFICATE 42 -#define S2N_TLS_ALERT_UNSUPPORTED_CERT 43 -#define S2N_TLS_ALERT_CERT_REVOKED 44 -#define S2N_TLS_ALERT_CERT_EXPIRED 45 -#define S2N_TLS_ALERT_CERT_UNKNOWN 46 -#define S2N_TLS_ALERT_ILLEGAL_PARAMETER 47 -#define S2N_TLS_ALERT_UNKNOWN_CA 48 -#define S2N_TLS_ALERT_ACCESS_DENIED 49 -#define S2N_TLS_ALERT_DECODE_ERROR 50 -#define S2N_TLS_ALERT_DECRYPT_ERROR 51 -#define S2N_TLS_ALERT_EXPORT_RESTRICTED 60 -#define S2N_TLS_ALERT_PROTOCOL_VERSION 70 -#define S2N_TLS_ALERT_INSUFFICIENT_SECURITY 71 -#define S2N_TLS_ALERT_INTERNAL_ERROR 80 -#define S2N_TLS_ALERT_USER_CANCELED 90 -#define S2N_TLS_ALERT_NO_RENEGOTIATION 100 -#define S2N_TLS_ALERT_UNSUPPORTED_EXTENSION 110 - #define S2N_TLS_ALERT_LEVEL_WARNING 1 #define S2N_TLS_ALERT_LEVEL_FATAL 2 +#define S2N_ALERT_CASE(error, alert_code) \ + case (error): \ + *alert = (alert_code); \ + return S2N_RESULT_OK + +#define S2N_NO_ALERT(error) \ + case (error): \ + RESULT_BAIL(S2N_ERR_NO_ALERT) + +static S2N_RESULT s2n_translate_protocol_error_to_alert(int error_code, uint8_t *alert) +{ + RESULT_ENSURE_REF(alert); + + switch(error_code) { + S2N_ALERT_CASE(S2N_ERR_MISSING_EXTENSION, S2N_TLS_ALERT_MISSING_EXTENSION); + + /* TODO: The ERR_BAD_MESSAGE -> ALERT_UNEXPECTED_MESSAGE mapping + * isn't always correct. Sometimes s2n-tls uses ERR_BAD_MESSAGE + * to indicate S2N_TLS_ALERT_ILLEGAL_PARAMETER instead. + * We'll want to add a new error to distinguish between the two usages: + * our errors should be equally or more specific than alerts, not less. + */ + S2N_ALERT_CASE(S2N_ERR_BAD_MESSAGE, S2N_TLS_ALERT_UNEXPECTED_MESSAGE); + + /* TODO: Add mappings for other protocol errors. + */ + S2N_NO_ALERT(S2N_ERR_ENCRYPT); + S2N_NO_ALERT(S2N_ERR_DECRYPT); + S2N_NO_ALERT(S2N_ERR_KEY_INIT); + S2N_NO_ALERT(S2N_ERR_KEY_DESTROY); + S2N_NO_ALERT(S2N_ERR_DH_SERIALIZING); + S2N_NO_ALERT(S2N_ERR_DH_SHARED_SECRET); + S2N_NO_ALERT(S2N_ERR_DH_WRITING_PUBLIC_KEY); + S2N_NO_ALERT(S2N_ERR_DH_FAILED_SIGNING); + S2N_NO_ALERT(S2N_ERR_DH_COPYING_PARAMETERS); + S2N_NO_ALERT(S2N_ERR_DH_GENERATING_PARAMETERS); + S2N_NO_ALERT(S2N_ERR_CIPHER_NOT_SUPPORTED); + S2N_NO_ALERT(S2N_ERR_NO_APPLICATION_PROTOCOL); + S2N_NO_ALERT(S2N_ERR_FALLBACK_DETECTED); + S2N_NO_ALERT(S2N_ERR_HASH_DIGEST_FAILED); + S2N_NO_ALERT(S2N_ERR_HASH_INIT_FAILED); + S2N_NO_ALERT(S2N_ERR_HASH_UPDATE_FAILED); + S2N_NO_ALERT(S2N_ERR_HASH_COPY_FAILED); + S2N_NO_ALERT(S2N_ERR_HASH_WIPE_FAILED); + S2N_NO_ALERT(S2N_ERR_HASH_NOT_READY); + S2N_NO_ALERT(S2N_ERR_ALLOW_MD5_FOR_FIPS_FAILED); + S2N_NO_ALERT(S2N_ERR_DECODE_CERTIFICATE); + S2N_NO_ALERT(S2N_ERR_DECODE_PRIVATE_KEY); + S2N_NO_ALERT(S2N_ERR_INVALID_HELLO_RETRY); + S2N_NO_ALERT(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + S2N_NO_ALERT(S2N_ERR_INVALID_SIGNATURE_SCHEME); + S2N_NO_ALERT(S2N_ERR_CBC_VERIFY); + S2N_NO_ALERT(S2N_ERR_DH_COPYING_PUBLIC_KEY); + S2N_NO_ALERT(S2N_ERR_SIGN); + S2N_NO_ALERT(S2N_ERR_VERIFY_SIGNATURE); + S2N_NO_ALERT(S2N_ERR_ECDHE_GEN_KEY); + S2N_NO_ALERT(S2N_ERR_ECDHE_SHARED_SECRET); + S2N_NO_ALERT(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + S2N_NO_ALERT(S2N_ERR_ECDSA_UNSUPPORTED_CURVE); + S2N_NO_ALERT(S2N_ERR_ECDHE_SERIALIZING); + S2N_NO_ALERT(S2N_ERR_KEM_UNSUPPORTED_PARAMS); + S2N_NO_ALERT(S2N_ERR_SHUTDOWN_RECORD_TYPE); + S2N_NO_ALERT(S2N_ERR_SHUTDOWN_CLOSED); + S2N_NO_ALERT(S2N_ERR_NON_EMPTY_RENEGOTIATION_INFO); + S2N_NO_ALERT(S2N_ERR_RECORD_LIMIT); + S2N_NO_ALERT(S2N_ERR_CERT_UNTRUSTED); + S2N_NO_ALERT(S2N_ERR_CERT_TYPE_UNSUPPORTED); + S2N_NO_ALERT(S2N_ERR_INVALID_MAX_FRAG_LEN); + S2N_NO_ALERT(S2N_ERR_MAX_FRAG_LEN_MISMATCH); + S2N_NO_ALERT(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + S2N_NO_ALERT(S2N_ERR_BAD_KEY_SHARE); + S2N_NO_ALERT(S2N_ERR_CANCELLED); + S2N_NO_ALERT(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); + S2N_NO_ALERT(S2N_ERR_MAX_INNER_PLAINTEXT_SIZE); + S2N_NO_ALERT(S2N_ERR_RECORD_STUFFER_SIZE); + S2N_NO_ALERT(S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE); + S2N_NO_ALERT(S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); + S2N_NO_ALERT(S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING); + S2N_NO_ALERT(S2N_ERR_UNSUPPORTED_EXTENSION); + S2N_NO_ALERT(S2N_ERR_DUPLICATE_EXTENSION); + S2N_NO_ALERT(S2N_ERR_MAX_EARLY_DATA_SIZE); + S2N_NO_ALERT(S2N_ERR_EARLY_DATA_TRIAL_DECRYPT); + } + + RESULT_BAIL(S2N_ERR_UNIMPLEMENTED); +} + static bool s2n_alerts_supported(struct s2n_connection *conn) { /* If running in QUIC mode, QUIC handles alerting. * S2N should not send or receive alerts. */ - return conn && conn->config && !conn->config->quic_enabled; + return !s2n_connection_is_quic_enabled(conn); } static bool s2n_handle_as_warning(struct s2n_connection *conn, uint8_t level, uint8_t type) @@ -78,12 +139,38 @@ static bool s2n_handle_as_warning(struct s2n_connection *conn, uint8_t level, ui return type == S2N_TLS_ALERT_USER_CANCELED; } +int s2n_error_get_alert(int error, uint8_t *alert) +{ + int error_type = s2n_error_get_type(error); + + POSIX_ENSURE_REF(alert); + + switch(error_type) { + case S2N_ERR_T_OK: + case S2N_ERR_T_CLOSED: + case S2N_ERR_T_BLOCKED: + case S2N_ERR_T_USAGE: + case S2N_ERR_T_ALERT: + POSIX_BAIL(S2N_ERR_NO_ALERT); + break; + case S2N_ERR_T_PROTO: + POSIX_GUARD_RESULT(s2n_translate_protocol_error_to_alert(error, alert)); + break; + case S2N_ERR_T_IO: + case S2N_ERR_T_INTERNAL: + *alert = S2N_TLS_ALERT_INTERNAL_ERROR; + break; + } + + return S2N_SUCCESS; +} + int s2n_process_alert_fragment(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); S2N_ERROR_IF(s2n_stuffer_data_available(&conn->in) == 0, S2N_ERR_BAD_MESSAGE); S2N_ERROR_IF(s2n_stuffer_data_available(&conn->alert_in) == 2, S2N_ERR_ALERT_PRESENT); - ENSURE_POSIX(s2n_alerts_supported(conn), S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(s2n_alerts_supported(conn), S2N_ERR_BAD_MESSAGE); while (s2n_stuffer_data_available(&conn->in)) { uint8_t bytes_required = 2; @@ -95,19 +182,20 @@ int s2n_process_alert_fragment(struct s2n_connection *conn) int bytes_to_read = MIN(bytes_required, s2n_stuffer_data_available(&conn->in)); - GUARD(s2n_stuffer_copy(&conn->in, &conn->alert_in, bytes_to_read)); + POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->alert_in, bytes_to_read)); if (s2n_stuffer_data_available(&conn->alert_in) == 2) { /* Close notifications are handled as shutdowns */ if (conn->alert_in_data[1] == S2N_TLS_ALERT_CLOSE_NOTIFY) { conn->closed = 1; + conn->close_notify_received = true; return 0; } /* Ignore warning-level alerts if we're in warning-tolerant mode */ if (s2n_handle_as_warning(conn, conn->alert_in_data[0], conn->alert_in_data[1])) { - GUARD(s2n_stuffer_wipe(&conn->alert_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->alert_in)); return 0; } @@ -118,7 +206,7 @@ int s2n_process_alert_fragment(struct s2n_connection *conn) /* All other alerts are treated as fatal errors */ conn->closed = 1; - S2N_ERROR(S2N_ERR_ALERT); + POSIX_BAIL(S2N_ERR_ALERT); } } @@ -127,7 +215,7 @@ int s2n_process_alert_fragment(struct s2n_connection *conn) int s2n_queue_writer_close_alert_warning(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); uint8_t alert[2]; alert[0] = S2N_TLS_ALERT_LEVEL_WARNING; @@ -144,7 +232,7 @@ int s2n_queue_writer_close_alert_warning(struct s2n_connection *conn) return S2N_SUCCESS; } - GUARD(s2n_stuffer_write(&conn->writer_alert_out, &out)); + POSIX_GUARD(s2n_stuffer_write(&conn->writer_alert_out, &out)); conn->close_notify_queued = 1; return S2N_SUCCESS; @@ -152,7 +240,7 @@ int s2n_queue_writer_close_alert_warning(struct s2n_connection *conn) static int s2n_queue_reader_alert(struct s2n_connection *conn, uint8_t level, uint8_t error_code) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); uint8_t alert[2]; alert[0] = level; @@ -169,7 +257,7 @@ static int s2n_queue_reader_alert(struct s2n_connection *conn, uint8_t level, ui return S2N_SUCCESS; } - GUARD(s2n_stuffer_write(&conn->reader_alert_out, &out)); + POSIX_GUARD(s2n_stuffer_write(&conn->reader_alert_out, &out)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_alerts.h b/contrib/restricted/aws/s2n/tls/s2n_alerts.h index 694c64068c..da735db9d8 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_alerts.h +++ b/contrib/restricted/aws/s2n/tls/s2n_alerts.h @@ -19,6 +19,84 @@ #include "tls/s2n_connection.h" +typedef enum { + /* + *= https://tools.ietf.org/rfc/rfc8446#section-6 + *# enum { + *# close_notify(0), + *# unexpected_message(10), + *# bad_record_mac(20), + *# record_overflow(22), + *# handshake_failure(40), + */ + S2N_TLS_ALERT_CLOSE_NOTIFY = 0, + S2N_TLS_ALERT_UNEXPECTED_MESSAGE = 10, + S2N_TLS_ALERT_BAD_RECORD_MAC = 20, + S2N_TLS_ALERT_RECORD_OVERFLOW = 22, + S2N_TLS_ALERT_HANDSHAKE_FAILURE = 40, + /* + *= https://tools.ietf.org/rfc/rfc8446#section-6 + *# bad_certificate(42), + *# unsupported_certificate(43), + *# certificate_revoked(44), + *# certificate_expired(45), + *# certificate_unknown(46), + */ + S2N_TLS_ALERT_BAD_CERTIFICATE = 42, + S2N_TLS_ALERT_UNSUPPORTED_CERTIFICATE = 43, + S2N_TLS_ALERT_CERTIFICATE_REVOKED = 44, + S2N_TLS_ALERT_CERTIFICATE_EXPIRED = 45, + S2N_TLS_ALERT_CERTIFICATE_UNKNOWN = 46, + /* + *= https://tools.ietf.org/rfc/rfc8446#section-6 + *# illegal_parameter(47), + *# unknown_ca(48), + *# access_denied(49), + *# decode_error(50), + *# decrypt_error(51), + */ + S2N_TLS_ALERT_ILLEGAL_PARAMETER = 47, + S2N_TLS_ALERT_UNKNOWN_CA = 48, + S2N_TLS_ALERT_ACCESS_DENIED = 49, + S2N_TLS_ALERT_DECODE_ERROR = 50, + S2N_TLS_ALERT_DECRYPT_ERROR = 51, + /* + *= https://tools.ietf.org/rfc/rfc8446#section-6 + *# protocol_version(70), + *# insufficient_security(71), + *# internal_error(80), + *# inappropriate_fallback(86), + *# user_canceled(90), + */ + S2N_TLS_ALERT_PROTOCOL_VERSION = 70, + S2N_TLS_ALERT_INSUFFICIENT_SECURITY = 71, + S2N_TLS_ALERT_INTERNAL_ERROR = 80, + S2N_TLS_ALERT_INAPPROPRIATE_FALLBACK = 86, + S2N_TLS_ALERT_USER_CANCELED = 90, + /* + *= https://tools.ietf.org/rfc/rfc8446#section-6 + *# missing_extension(109), + *# unsupported_extension(110), + *# unrecognized_name(112), + *# bad_certificate_status_response(113), + *# unknown_psk_identity(115), + */ + S2N_TLS_ALERT_MISSING_EXTENSION = 109, + S2N_TLS_ALERT_UNSUPPORTED_EXTENSION = 110, + S2N_TLS_ALERT_UNRECOGNIZED_NAME = 112, + S2N_TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE = 113, + S2N_TLS_ALERT_UNKNOWN_PSK_IDENTITY = 115, + /* + *= https://tools.ietf.org/rfc/rfc8446#section-6 + *# certificate_required(116), + *# no_application_protocol(120), + *# (255) + *# } AlertDescription; + */ + S2N_TLS_ALERT_CERTIFICATE_REQUIRED = 116, + S2N_TLS_ALERT_NO_APPLICATION_PROTOCOL = 120, +} s2n_tls_alert_code; + extern int s2n_process_alert_fragment(struct s2n_connection *conn); extern int s2n_queue_writer_close_alert_warning(struct s2n_connection *conn); extern int s2n_queue_reader_unsupported_protocol_version_alert(struct s2n_connection *conn); diff --git a/contrib/restricted/aws/s2n/tls/s2n_async_pkey.c b/contrib/restricted/aws/s2n/tls/s2n_async_pkey.c index d1960eac69..062324db57 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_async_pkey.c +++ b/contrib/restricted/aws/s2n/tls/s2n_async_pkey.c @@ -17,7 +17,7 @@ #include "crypto/s2n_hash.h" #include "crypto/s2n_signature.h" #include "error/s2n_errno.h" -#include "s2n.h" +#include "api/s2n.h" #include "tls/s2n_connection.h" #include "tls/s2n_handshake.h" #include "utils/s2n_blob.h" @@ -25,8 +25,6 @@ #include "utils/s2n_result.h" #include "utils/s2n_safety.h" -typedef enum { S2N_ASYNC_DECRYPT, S2N_ASYNC_SIGN } s2n_async_pkey_op_type; - struct s2n_async_pkey_decrypt_data { s2n_async_pkey_decrypt_complete on_complete; struct s2n_blob encrypted; @@ -44,6 +42,7 @@ struct s2n_async_pkey_sign_data { struct s2n_async_pkey_op { s2n_async_pkey_op_type type; struct s2n_connection *conn; + s2n_async_pkey_validation_mode validation_mode; unsigned complete : 1; unsigned applied : 1; union { @@ -55,6 +54,9 @@ struct s2n_async_pkey_op { struct s2n_async_pkey_op_actions { S2N_RESULT (*perform)(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey); S2N_RESULT (*apply)(struct s2n_async_pkey_op *op, struct s2n_connection *conn); + S2N_RESULT (*get_input_size)(struct s2n_async_pkey_op *op, uint32_t *data_len); + S2N_RESULT (*get_input)(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len); + S2N_RESULT (*set_output)(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len); S2N_RESULT (*free)(struct s2n_async_pkey_op *op); }; @@ -76,25 +78,37 @@ static S2N_RESULT s2n_async_pkey_decrypt_sync(struct s2n_connection *conn, struc static S2N_RESULT s2n_async_pkey_decrypt_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey); static S2N_RESULT s2n_async_pkey_decrypt_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn); +static S2N_RESULT s2n_async_pkey_get_input_size_decrypt(struct s2n_async_pkey_op *op, uint32_t *data_len); +static S2N_RESULT s2n_async_pkey_get_input_decrypt(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len); +static S2N_RESULT s2n_async_pkey_op_set_output_decrypt(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len); static S2N_RESULT s2n_async_pkey_decrypt_free(struct s2n_async_pkey_op *op); static S2N_RESULT s2n_async_pkey_sign_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey); static S2N_RESULT s2n_async_pkey_sign_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn); +static S2N_RESULT s2n_async_pkey_get_input_size_sign(struct s2n_async_pkey_op *op, uint32_t *data_len); +static S2N_RESULT s2n_async_pkey_get_input_sign(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len); +static S2N_RESULT s2n_async_pkey_op_set_output_sign(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len); static S2N_RESULT s2n_async_pkey_sign_free(struct s2n_async_pkey_op *op); static const struct s2n_async_pkey_op_actions s2n_async_pkey_decrypt_op = { .perform = &s2n_async_pkey_decrypt_perform, .apply = &s2n_async_pkey_decrypt_apply, + .get_input_size = &s2n_async_pkey_get_input_size_decrypt, + .get_input = &s2n_async_pkey_get_input_decrypt, + .set_output = &s2n_async_pkey_op_set_output_decrypt, .free = &s2n_async_pkey_decrypt_free }; static const struct s2n_async_pkey_op_actions s2n_async_pkey_sign_op = { .perform = &s2n_async_pkey_sign_perform, .apply = &s2n_async_pkey_sign_apply, + .get_input_size = &s2n_async_pkey_get_input_size_sign, + .get_input = &s2n_async_pkey_get_input_sign, + .set_output = &s2n_async_pkey_op_set_output_sign, .free = &s2n_async_pkey_sign_free }; DEFINE_POINTER_CLEANUP_FUNC(struct s2n_async_pkey_op *, s2n_async_pkey_op_free); static S2N_RESULT s2n_async_get_actions(s2n_async_pkey_op_type type, const struct s2n_async_pkey_op_actions **actions) { - ENSURE_REF(actions); + RESULT_ENSURE_REF(actions); switch (type) { case S2N_ASYNC_DECRYPT: @@ -111,13 +125,13 @@ static S2N_RESULT s2n_async_get_actions(s2n_async_pkey_op_type type, const struc static S2N_RESULT s2n_async_pkey_op_allocate(struct s2n_async_pkey_op **op) { - ENSURE_REF(op); - ENSURE(*op == NULL, S2N_ERR_SAFETY); + RESULT_ENSURE_REF(op); + RESULT_ENSURE(*op == NULL, S2N_ERR_SAFETY); /* allocate memory */ DEFER_CLEANUP(struct s2n_blob mem = {0}, s2n_free); - GUARD_AS_RESULT(s2n_alloc(&mem, sizeof(struct s2n_async_pkey_op))); - GUARD_AS_RESULT(s2n_blob_zero(&mem)); + RESULT_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_async_pkey_op))); + RESULT_GUARD_POSIX(s2n_blob_zero(&mem)); *op = (void *) mem.data; if (s2n_blob_init(&mem, NULL, 0) != S2N_SUCCESS) { @@ -130,70 +144,82 @@ static S2N_RESULT s2n_async_pkey_op_allocate(struct s2n_async_pkey_op **op) S2N_RESULT s2n_async_pkey_decrypt(struct s2n_connection *conn, struct s2n_blob *encrypted, struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete) { - ENSURE_REF(conn); - ENSURE_REF(encrypted); - ENSURE_REF(init_decrypted); - ENSURE_REF(on_complete); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(encrypted); + RESULT_ENSURE_REF(init_decrypted); + RESULT_ENSURE_REF(on_complete); if (conn->config->async_pkey_cb) { - GUARD_RESULT(s2n_async_pkey_decrypt_async(conn, encrypted, init_decrypted, on_complete)); + RESULT_GUARD(s2n_async_pkey_decrypt_async(conn, encrypted, init_decrypted, on_complete)); } else { - GUARD_RESULT(s2n_async_pkey_decrypt_sync(conn, encrypted, init_decrypted, on_complete)); + RESULT_GUARD(s2n_async_pkey_decrypt_sync(conn, encrypted, init_decrypted, on_complete)); } return S2N_RESULT_OK; } +S2N_RESULT s2n_async_cb_execute(struct s2n_connection *conn, struct s2n_async_pkey_op **owned_op) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(owned_op); + RESULT_ENSURE(conn->handshake.async_state == S2N_ASYNC_NOT_INVOKED, S2N_ERR_ASYNC_MORE_THAN_ONE); + + /* The callback now owns the operation, meaning we can't free it. + * Wipe our version and pass a copy to the callback. + */ + struct s2n_async_pkey_op *unowned_op = *owned_op; + ZERO_TO_DISABLE_DEFER_CLEANUP(*owned_op); + + conn->handshake.async_state = S2N_ASYNC_INVOKED; + RESULT_ENSURE(conn->config->async_pkey_cb(conn, unowned_op) == S2N_SUCCESS, S2N_ERR_ASYNC_CALLBACK_FAILED); + + /* + * If the callback already completed the operation, continue. + * Otherwise, we need to block s2n_negotiate and wait for the operation to complete. + */ + if (conn->handshake.async_state == S2N_ASYNC_COMPLETE) { + return S2N_RESULT_OK; + } + RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED); +} + S2N_RESULT s2n_async_pkey_decrypt_async(struct s2n_connection *conn, struct s2n_blob *encrypted, struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete) { - ENSURE_REF(conn); - ENSURE_REF(encrypted); - ENSURE_REF(init_decrypted); - ENSURE_REF(on_complete); - ENSURE(conn->handshake.async_state == S2N_ASYNC_NOT_INVOKED, S2N_ERR_ASYNC_MORE_THAN_ONE); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(encrypted); + RESULT_ENSURE_REF(init_decrypted); + RESULT_ENSURE_REF(on_complete); DEFER_CLEANUP(struct s2n_async_pkey_op *op = NULL, s2n_async_pkey_op_free_pointer); - GUARD_RESULT(s2n_async_pkey_op_allocate(&op)); + RESULT_GUARD(s2n_async_pkey_op_allocate(&op)); op->type = S2N_ASYNC_DECRYPT; op->conn = conn; + op->validation_mode = conn->config->async_pkey_validation_mode; struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; decrypt->on_complete = on_complete; - GUARD_AS_RESULT(s2n_dup(encrypted, &decrypt->encrypted)); - GUARD_AS_RESULT(s2n_dup(init_decrypted, &decrypt->decrypted)); - - /* Block the handshake and set async state to invoking to block async states */ - GUARD_AS_RESULT(s2n_conn_set_handshake_read_block(conn)); - conn->handshake.async_state = S2N_ASYNC_INVOKING_CALLBACK; - - /* Move op to tmp to avoid DEFER_CLEANUP freeing the op, as it will be owned by callback */ - struct s2n_async_pkey_op *tmp_op = op; - op = NULL; - - ENSURE(conn->config->async_pkey_cb(conn, tmp_op) == S2N_SUCCESS, S2N_ERR_ASYNC_CALLBACK_FAILED); + RESULT_GUARD_POSIX(s2n_dup(encrypted, &decrypt->encrypted)); + RESULT_GUARD_POSIX(s2n_dup(init_decrypted, &decrypt->decrypted)); - /* Set state to waiting to allow op to be consumed by connection */ - conn->handshake.async_state = S2N_ASYNC_INVOKED_WAITING; - - /* Return an async blocked error to drop out of s2n_negotiate loop */ - BAIL(S2N_ERR_ASYNC_BLOCKED); + RESULT_GUARD(s2n_async_cb_execute(conn, &op)); + return S2N_RESULT_OK; } S2N_RESULT s2n_async_pkey_decrypt_sync(struct s2n_connection *conn, struct s2n_blob *encrypted, struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete) { - ENSURE_REF(conn); - ENSURE_REF(encrypted); - ENSURE_REF(init_decrypted); - ENSURE_REF(on_complete); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(encrypted); + RESULT_ENSURE_REF(init_decrypted); + RESULT_ENSURE_REF(on_complete); const struct s2n_pkey *pkey = conn->handshake_params.our_chain_and_key->private_key; bool rsa_failed = s2n_pkey_decrypt(pkey, encrypted, init_decrypted) != S2N_SUCCESS; - GUARD_AS_RESULT(on_complete(conn, rsa_failed, init_decrypted)); + RESULT_GUARD_POSIX(on_complete(conn, rsa_failed, init_decrypted)); return S2N_RESULT_OK; } @@ -201,14 +227,14 @@ S2N_RESULT s2n_async_pkey_decrypt_sync(struct s2n_connection *conn, struct s2n_b S2N_RESULT s2n_async_pkey_sign(struct s2n_connection *conn, s2n_signature_algorithm sig_alg, struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete) { - ENSURE_REF(conn); - ENSURE_REF(digest); - ENSURE_REF(on_complete); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(digest); + RESULT_ENSURE_REF(on_complete); if (conn->config->async_pkey_cb) { - GUARD_RESULT(s2n_async_pkey_sign_async(conn, sig_alg, digest, on_complete)); + RESULT_GUARD(s2n_async_pkey_sign_async(conn, sig_alg, digest, on_complete)); } else { - GUARD_RESULT(s2n_async_pkey_sign_sync(conn, sig_alg, digest, on_complete)); + RESULT_GUARD(s2n_async_pkey_sign_sync(conn, sig_alg, digest, on_complete)); } return S2N_RESULT_OK; @@ -217,73 +243,60 @@ S2N_RESULT s2n_async_pkey_sign(struct s2n_connection *conn, s2n_signature_algori S2N_RESULT s2n_async_pkey_sign_async(struct s2n_connection *conn, s2n_signature_algorithm sig_alg, struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete) { - ENSURE_REF(conn); - ENSURE_REF(digest); - ENSURE_REF(on_complete); - ENSURE(conn->handshake.async_state == S2N_ASYNC_NOT_INVOKED, S2N_ERR_ASYNC_MORE_THAN_ONE); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(digest); + RESULT_ENSURE_REF(on_complete); DEFER_CLEANUP(struct s2n_async_pkey_op *op = NULL, s2n_async_pkey_op_free_pointer); - GUARD_RESULT(s2n_async_pkey_op_allocate(&op)); + RESULT_GUARD(s2n_async_pkey_op_allocate(&op)); op->type = S2N_ASYNC_SIGN; op->conn = conn; + op->validation_mode = conn->config->async_pkey_validation_mode; struct s2n_async_pkey_sign_data *sign = &op->op.sign; sign->on_complete = on_complete; sign->sig_alg = sig_alg; - GUARD_AS_RESULT(s2n_hash_new(&sign->digest)); - GUARD_AS_RESULT(s2n_hash_copy(&sign->digest, digest)); - - /* Block the handshake and set async state to invoking to block async states */ - GUARD_AS_RESULT(s2n_conn_set_handshake_read_block(conn)); - conn->handshake.async_state = S2N_ASYNC_INVOKING_CALLBACK; - - /* Move op to tmp to avoid DEFER_CLEANUP freeing the op, as it will be owned by callback */ - struct s2n_async_pkey_op *tmp_op = op; - op = NULL; + RESULT_GUARD_POSIX(s2n_hash_new(&sign->digest)); + RESULT_GUARD_POSIX(s2n_hash_copy(&sign->digest, digest)); - ENSURE(conn->config->async_pkey_cb(conn, tmp_op) == S2N_SUCCESS, S2N_ERR_ASYNC_CALLBACK_FAILED); - - /* Set state to waiting to allow op to be consumed by connection */ - conn->handshake.async_state = S2N_ASYNC_INVOKED_WAITING; - - /* Return an async blocked error to drop out of s2n_negotiate loop */ - BAIL(S2N_ERR_ASYNC_BLOCKED); + RESULT_GUARD(s2n_async_cb_execute(conn, &op)); + return S2N_RESULT_OK; } S2N_RESULT s2n_async_pkey_sign_sync(struct s2n_connection *conn, s2n_signature_algorithm sig_alg, struct s2n_hash_state *digest, s2n_async_pkey_sign_complete on_complete) { - ENSURE_REF(conn); - ENSURE_REF(digest); - ENSURE_REF(on_complete); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(digest); + RESULT_ENSURE_REF(on_complete); const struct s2n_pkey *pkey = conn->handshake_params.our_chain_and_key->private_key; DEFER_CLEANUP(struct s2n_blob signed_content = { 0 }, s2n_free); uint32_t maximum_signature_length = 0; - GUARD_RESULT(s2n_pkey_size(pkey, &maximum_signature_length)); - GUARD_AS_RESULT(s2n_alloc(&signed_content, maximum_signature_length)); + RESULT_GUARD(s2n_pkey_size(pkey, &maximum_signature_length)); + RESULT_GUARD_POSIX(s2n_alloc(&signed_content, maximum_signature_length)); - GUARD_AS_RESULT(s2n_pkey_sign(pkey, sig_alg, digest, &signed_content)); + RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sig_alg, digest, &signed_content)); - GUARD_AS_RESULT(on_complete(conn, &signed_content)); + RESULT_GUARD_POSIX(on_complete(conn, &signed_content)); return S2N_RESULT_OK; } int s2n_async_pkey_op_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *key) { - ENSURE_POSIX_REF(op); - ENSURE_POSIX_REF(key); - ENSURE_POSIX(!op->complete, S2N_ERR_ASYNC_ALREADY_PERFORMED); + POSIX_ENSURE_REF(op); + POSIX_ENSURE_REF(key); + POSIX_ENSURE(!op->complete, S2N_ERR_ASYNC_ALREADY_PERFORMED); const struct s2n_async_pkey_op_actions *actions = NULL; - GUARD_AS_POSIX(s2n_async_get_actions(op->type, &actions)); - notnull_check(actions); + POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions)); + POSIX_ENSURE_REF(actions); - GUARD_AS_POSIX(actions->perform(op, key)); + POSIX_GUARD_RESULT(actions->perform(op, key)); op->complete = true; @@ -292,52 +305,51 @@ int s2n_async_pkey_op_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key int s2n_async_pkey_op_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn) { - ENSURE_POSIX_REF(op); - ENSURE_POSIX_REF(conn); - ENSURE_POSIX(op->complete, S2N_ERR_ASYNC_NOT_PERFORMED); - ENSURE_POSIX(!op->applied, S2N_ERR_ASYNC_ALREADY_APPLIED); + POSIX_ENSURE_REF(op); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(op->complete, S2N_ERR_ASYNC_NOT_PERFORMED); + POSIX_ENSURE(!op->applied, S2N_ERR_ASYNC_ALREADY_APPLIED); /* We could have just used op->conn and removed a conn argument, but we want caller * to be explicit about connection it wants to resume. Plus this gives more * protections in cases if caller frees connection object and then tries to resume * the connection. */ - ENSURE_POSIX(op->conn == conn, S2N_ERR_ASYNC_WRONG_CONNECTION); - ENSURE_POSIX(conn->handshake.async_state != S2N_ASYNC_INVOKING_CALLBACK, S2N_ERR_ASYNC_APPLY_WHILE_INVOKING); - ENSURE_POSIX(conn->handshake.async_state == S2N_ASYNC_INVOKED_WAITING, S2N_ERR_ASYNC_WRONG_CONNECTION); + POSIX_ENSURE(op->conn == conn, S2N_ERR_ASYNC_WRONG_CONNECTION); + POSIX_ENSURE(conn->handshake.async_state == S2N_ASYNC_INVOKED, S2N_ERR_ASYNC_WRONG_CONNECTION); const struct s2n_async_pkey_op_actions *actions = NULL; - GUARD_AS_POSIX(s2n_async_get_actions(op->type, &actions)); - notnull_check(actions); + POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions)); + POSIX_ENSURE_REF(actions); - GUARD_AS_POSIX(actions->apply(op, conn)); + POSIX_GUARD_RESULT(actions->apply(op, conn)); op->applied = true; - conn->handshake.async_state = S2N_ASYNC_INVOKED_COMPLETE; + conn->handshake.async_state = S2N_ASYNC_COMPLETE; /* Free up the decrypt/sign structs to avoid storing secrets for too long */ - GUARD_AS_POSIX(actions->free(op)); + POSIX_GUARD_RESULT(actions->free(op)); return S2N_SUCCESS; } int s2n_async_pkey_op_free(struct s2n_async_pkey_op *op) { - ENSURE_POSIX_REF(op); + POSIX_ENSURE_REF(op); const struct s2n_async_pkey_op_actions *actions = NULL; - GUARD_AS_POSIX(s2n_async_get_actions(op->type, &actions)); - notnull_check(actions); + POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions)); + POSIX_ENSURE_REF(actions); /* If applied the decrypt/sign structs were released in apply call */ - if (!op->applied) { GUARD_AS_POSIX(actions->free(op)); } + if (!op->applied) { POSIX_GUARD_RESULT(actions->free(op)); } - GUARD_POSIX(s2n_free_object(( uint8_t ** )&op, sizeof(struct s2n_async_pkey_op))); + POSIX_GUARD(s2n_free_object(( uint8_t ** )&op, sizeof(struct s2n_async_pkey_op))); return S2N_SUCCESS; } S2N_RESULT s2n_async_pkey_decrypt_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey) { - ENSURE_REF(op); - ENSURE_REF(pkey); + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(pkey); struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; @@ -348,66 +360,259 @@ S2N_RESULT s2n_async_pkey_decrypt_perform(struct s2n_async_pkey_op *op, s2n_cert S2N_RESULT s2n_async_pkey_decrypt_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn) { - ENSURE_REF(op); - ENSURE_REF(conn); + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(conn); struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; - GUARD_AS_RESULT(decrypt->on_complete(conn, decrypt->rsa_failed, &decrypt->decrypted)); + RESULT_GUARD_POSIX(decrypt->on_complete(conn, decrypt->rsa_failed, &decrypt->decrypted)); return S2N_RESULT_OK; } S2N_RESULT s2n_async_pkey_decrypt_free(struct s2n_async_pkey_op *op) { - ENSURE_REF(op); + RESULT_ENSURE_REF(op); struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; - GUARD_AS_RESULT(s2n_blob_zero(&decrypt->decrypted)); - GUARD_AS_RESULT(s2n_blob_zero(&decrypt->encrypted)); - GUARD_AS_RESULT(s2n_free(&decrypt->decrypted)); - GUARD_AS_RESULT(s2n_free(&decrypt->encrypted)); + RESULT_GUARD_POSIX(s2n_blob_zero(&decrypt->decrypted)); + RESULT_GUARD_POSIX(s2n_blob_zero(&decrypt->encrypted)); + RESULT_GUARD_POSIX(s2n_free(&decrypt->decrypted)); + RESULT_GUARD_POSIX(s2n_free(&decrypt->encrypted)); return S2N_RESULT_OK; } S2N_RESULT s2n_async_pkey_sign_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *pkey) { - ENSURE_REF(op); - ENSURE_REF(pkey); + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(op->conn); + RESULT_ENSURE_REF(op->conn->config); + RESULT_ENSURE_REF(pkey); struct s2n_async_pkey_sign_data *sign = &op->op.sign; uint32_t maximum_signature_length = 0; - GUARD_RESULT(s2n_pkey_size(pkey, &maximum_signature_length)); - GUARD_AS_RESULT(s2n_alloc(&sign->signature, maximum_signature_length)); + RESULT_GUARD(s2n_pkey_size(pkey, &maximum_signature_length)); + RESULT_GUARD_POSIX(s2n_alloc(&sign->signature, maximum_signature_length)); - GUARD_AS_RESULT(s2n_pkey_sign(pkey, sign->sig_alg, &sign->digest, &sign->signature)); + /* If validation mode is S2N_ASYNC_PKEY_VALIDATION_STRICT + * then use local hash copy to sign the signature */ + if (op->validation_mode == S2N_ASYNC_PKEY_VALIDATION_STRICT) { + DEFER_CLEANUP(struct s2n_hash_state hash_state_copy, s2n_hash_free); + RESULT_GUARD_POSIX(s2n_hash_new(&hash_state_copy)); + RESULT_GUARD_POSIX(s2n_hash_copy(&hash_state_copy, &sign->digest)); + + RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sign->sig_alg, &hash_state_copy, &sign->signature)); + } else { + RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sign->sig_alg, &sign->digest, &sign->signature)); + } return S2N_RESULT_OK; } S2N_RESULT s2n_async_pkey_sign_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn) { - ENSURE_REF(op); - ENSURE_REF(conn); + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(conn); struct s2n_async_pkey_sign_data *sign = &op->op.sign; - GUARD_AS_RESULT(sign->on_complete(conn, &sign->signature)); + /* Perform signature validation only if validation feature is opt in */ + if (op->validation_mode == S2N_ASYNC_PKEY_VALIDATION_STRICT) { + RESULT_GUARD(s2n_async_pkey_verify_signature(conn, sign->sig_alg, &sign->digest, &sign->signature)); + } + + RESULT_GUARD_POSIX(sign->on_complete(conn, &sign->signature)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_async_pkey_verify_signature(struct s2n_connection *conn, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) { + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->handshake_params.our_chain_and_key); + RESULT_ENSURE_REF(digest); + RESULT_ENSURE_REF(signature); + + /* Parse public key for the cert */ + DEFER_CLEANUP(struct s2n_pkey public_key = {0}, s2n_pkey_free); + s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN; + RESULT_GUARD_POSIX(s2n_asn1der_to_public_key_and_type(&public_key, &pkey_type, + &conn->handshake_params.our_chain_and_key->cert_chain->head->raw)); + RESULT_ENSURE(s2n_pkey_verify(&public_key, sig_alg, digest, signature) == S2N_SUCCESS, S2N_ERR_VERIFY_SIGNATURE); return S2N_RESULT_OK; } S2N_RESULT s2n_async_pkey_sign_free(struct s2n_async_pkey_op *op) { - ENSURE_REF(op); + RESULT_ENSURE_REF(op); + + struct s2n_async_pkey_sign_data *sign = &op->op.sign; + + RESULT_GUARD_POSIX(s2n_hash_free(&sign->digest)); + RESULT_GUARD_POSIX(s2n_free(&sign->signature)); + + return S2N_RESULT_OK; +} + +int s2n_async_pkey_op_set_validation_mode(struct s2n_async_pkey_op *op, s2n_async_pkey_validation_mode mode) +{ + POSIX_ENSURE_REF(op); + + switch(mode) { + case S2N_ASYNC_PKEY_VALIDATION_FAST: + case S2N_ASYNC_PKEY_VALIDATION_STRICT: + op->validation_mode = mode; + return S2N_SUCCESS; + } + + POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT); +} + +int s2n_async_pkey_op_get_op_type(struct s2n_async_pkey_op *op, s2n_async_pkey_op_type *type) +{ + POSIX_ENSURE_REF(op); + POSIX_ENSURE_REF(type); + + *type = op->type; + + return S2N_SUCCESS; +} + +int s2n_async_pkey_op_get_input_size(struct s2n_async_pkey_op *op, uint32_t *data_len) +{ + POSIX_ENSURE_REF(op); + POSIX_ENSURE_REF(data_len); + + const struct s2n_async_pkey_op_actions *actions = NULL; + POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions)); + POSIX_ENSURE_REF(actions); + + POSIX_GUARD_RESULT(actions->get_input_size(op, data_len)); + + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_async_pkey_get_input_size_decrypt(struct s2n_async_pkey_op *op, uint32_t *data_len) +{ + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(data_len); + + struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; + struct s2n_blob *in = &decrypt->encrypted; + + *data_len = in->size; + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_async_pkey_get_input_size_sign(struct s2n_async_pkey_op *op, uint32_t *data_len) +{ + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(data_len); + + struct s2n_async_pkey_sign_data *sign = &op->op.sign; + struct s2n_hash_state *digest = &sign->digest; + + uint8_t digest_length = 0; + RESULT_GUARD_POSIX(s2n_hash_digest_size(digest->alg, &digest_length)); + + *data_len = digest_length; + + return S2N_RESULT_OK; +} + +int s2n_async_pkey_op_get_input(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len) +{ + POSIX_ENSURE_REF(op); + POSIX_ENSURE_REF(data); + + const struct s2n_async_pkey_op_actions *actions = NULL; + POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions)); + POSIX_ENSURE_REF(actions); + + POSIX_GUARD_RESULT(actions->get_input(op, data, data_len)); + + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_async_pkey_get_input_decrypt(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len) +{ + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(data); + + struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; + struct s2n_blob *in = &decrypt->encrypted; + + RESULT_ENSURE_LTE(in->size, data_len); + + RESULT_CHECKED_MEMCPY(data, in->data, in->size); + + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_async_pkey_get_input_sign(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len) +{ + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(data); + + struct s2n_async_pkey_sign_data *sign = &op->op.sign; + + DEFER_CLEANUP(struct s2n_hash_state digest_copy = { 0 }, s2n_hash_free); + RESULT_GUARD_POSIX(s2n_hash_new(&digest_copy)); + RESULT_GUARD_POSIX(s2n_hash_copy(&digest_copy, &sign->digest)); + + uint8_t digest_length = 0; + + RESULT_GUARD_POSIX(s2n_hash_digest_size(digest_copy.alg, &digest_length)); + + RESULT_ENSURE_LTE(digest_length, data_len); + RESULT_GUARD_POSIX(s2n_hash_digest(&digest_copy, data, digest_length)); + + return S2N_RESULT_OK; +} + +int s2n_async_pkey_op_set_output(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len) +{ + POSIX_ENSURE_REF(op); + POSIX_ENSURE_REF(data); + + const struct s2n_async_pkey_op_actions *actions = NULL; + POSIX_GUARD_RESULT(s2n_async_get_actions(op->type, &actions)); + POSIX_ENSURE_REF(actions); + + POSIX_GUARD_RESULT(actions->set_output(op, data, data_len)); + op->complete = true; + + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_async_pkey_op_set_output_decrypt(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len) +{ + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(data); + + struct s2n_async_pkey_decrypt_data *decrypt = &op->op.decrypt; + struct s2n_blob *out = &decrypt->decrypted; + + RESULT_GUARD_POSIX(s2n_realloc(out, data_len)); + RESULT_CHECKED_MEMCPY(out->data, data, data_len); + + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_async_pkey_op_set_output_sign(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len) +{ + RESULT_ENSURE_REF(op); + RESULT_ENSURE_REF(data); struct s2n_async_pkey_sign_data *sign = &op->op.sign; + struct s2n_blob *sigcopy = &sign->signature; - GUARD_AS_RESULT(s2n_hash_free(&sign->digest)); - GUARD_AS_RESULT(s2n_free(&sign->signature)); + RESULT_GUARD_POSIX(s2n_realloc(sigcopy, data_len)); + RESULT_CHECKED_MEMCPY(sigcopy->data, data, data_len); return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_async_pkey.h b/contrib/restricted/aws/s2n/tls/s2n_async_pkey.h index 2ef8386d2f..631a186a9a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_async_pkey.h +++ b/contrib/restricted/aws/s2n/tls/s2n_async_pkey.h @@ -32,19 +32,17 @@ struct s2n_async_pkey_op; #define S2N_ASYNC_PKEY_GUARD(conn) \ do { \ __typeof(conn) __tmp_conn = (conn); \ - GUARD_NONNULL(__tmp_conn); \ + POSIX_GUARD_PTR(__tmp_conn); \ switch (conn->handshake.async_state) { \ case S2N_ASYNC_NOT_INVOKED: \ break; \ \ - case S2N_ASYNC_INVOKING_CALLBACK: \ - case S2N_ASYNC_INVOKED_WAITING: \ - BAIL_POSIX(S2N_ERR_ASYNC_BLOCKED); \ + case S2N_ASYNC_INVOKED: \ + POSIX_BAIL(S2N_ERR_ASYNC_BLOCKED); \ \ - case S2N_ASYNC_INVOKED_COMPLETE: \ + case S2N_ASYNC_COMPLETE: \ /* clean up state and return a success from handler */ \ __tmp_conn->handshake.async_state = S2N_ASYNC_NOT_INVOKED; \ - GUARD(s2n_conn_clear_handshake_read_block(__tmp_conn)); \ return S2N_SUCCESS; \ } \ } while (0) @@ -56,15 +54,23 @@ struct s2n_async_pkey_op; * call, we use a macro which directly returns the result of s2n_async* operation forcing compiler to error out on * unreachable code and forcing developer to use on_complete function instead */ #define S2N_ASYNC_PKEY_DECRYPT(conn, encrypted, init_decrypted, on_complete) \ - return S2N_RESULT_TO_POSIX(s2n_async_pkey_decrypt(conn, encrypted, init_decrypted, on_complete)); + return s2n_result_is_ok(s2n_async_pkey_decrypt(conn, encrypted, init_decrypted, on_complete)) ? S2N_SUCCESS : S2N_FAILURE; #define S2N_ASYNC_PKEY_SIGN(conn, sig_alg, digest, on_complete) \ - return S2N_RESULT_TO_POSIX(s2n_async_pkey_sign(conn, sig_alg, digest, on_complete)); + return s2n_result_is_ok(s2n_async_pkey_sign(conn, sig_alg, digest, on_complete)) ? S2N_SUCCESS : S2N_FAILURE; int s2n_async_pkey_op_perform(struct s2n_async_pkey_op *op, s2n_cert_private_key *key); int s2n_async_pkey_op_apply(struct s2n_async_pkey_op *op, struct s2n_connection *conn); int s2n_async_pkey_op_free(struct s2n_async_pkey_op *op); +int s2n_async_pkey_op_get_op_type(struct s2n_async_pkey_op *op, s2n_async_pkey_op_type *type); +int s2n_async_pkey_op_get_input_size(struct s2n_async_pkey_op *op, uint32_t *data_len); +int s2n_async_pkey_op_get_input(struct s2n_async_pkey_op *op, uint8_t *data, uint32_t data_len); +int s2n_async_pkey_op_set_output(struct s2n_async_pkey_op *op, const uint8_t *data, uint32_t data_len); +int s2n_async_pkey_op_set_validation_mode(struct s2n_async_pkey_op *op, s2n_async_pkey_validation_mode mode); + +S2N_RESULT s2n_async_pkey_verify_signature(struct s2n_connection *conn, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature); S2N_RESULT s2n_async_pkey_decrypt(struct s2n_connection *conn, struct s2n_blob *encrypted, struct s2n_blob *init_decrypted, s2n_async_pkey_decrypt_complete on_complete); S2N_RESULT s2n_async_pkey_sign(struct s2n_connection *conn, s2n_signature_algorithm sig_alg, struct s2n_hash_state *digest, diff --git a/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c b/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c index 33404c811b..eb132cc642 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c +++ b/contrib/restricted/aws/s2n/tls/s2n_auth_selection.c @@ -40,7 +40,7 @@ * TLS1.2 cipher suites. */ -static int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authentication_method *auth_method) +int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authentication_method *auth_method) { switch(cert_type) { case S2N_PKEY_TYPE_RSA: @@ -52,9 +52,9 @@ static int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authen return S2N_SUCCESS; case S2N_PKEY_TYPE_UNKNOWN: case S2N_PKEY_TYPE_SENTINEL: - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); + POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); } - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); + POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); } static int s2n_get_cert_type_for_sig_alg(s2n_signature_algorithm sig_alg, s2n_pkey_type *cert_type) @@ -71,17 +71,17 @@ static int s2n_get_cert_type_for_sig_alg(s2n_signature_algorithm sig_alg, s2n_pk *cert_type = S2N_PKEY_TYPE_RSA_PSS; return S2N_SUCCESS; case S2N_SIGNATURE_ANONYMOUS: - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + POSIX_BAIL(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); } - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + POSIX_BAIL(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); } static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg, struct s2n_cipher_suite *cipher_suite) { - notnull_check(cipher_suite); + POSIX_ENSURE_REF(cipher_suite); s2n_pkey_type cert_type_for_sig_alg; - GUARD(s2n_get_cert_type_for_sig_alg(sig_alg, &cert_type_for_sig_alg)); + POSIX_GUARD(s2n_get_cert_type_for_sig_alg(sig_alg, &cert_type_for_sig_alg)); /* Non-ephemeral key exchange methods require encryption, and RSA-PSS certificates * do not support encryption. @@ -90,7 +90,7 @@ static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg * algorithm that requires RSA-PSS certificates is not valid. */ if (cipher_suite->key_exchange_alg != NULL && !cipher_suite->key_exchange_alg->is_ephemeral) { - ne_check(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); + POSIX_ENSURE_NE(cert_type_for_sig_alg, S2N_PKEY_TYPE_RSA_PSS); } /* If a cipher suite includes an auth method, then the signature algorithm @@ -98,8 +98,8 @@ static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg */ if (cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { s2n_authentication_method auth_method_for_sig_alg; - GUARD(s2n_get_auth_method_for_cert_type(cert_type_for_sig_alg, &auth_method_for_sig_alg)); - eq_check(cipher_suite->auth_method, auth_method_for_sig_alg); + POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type_for_sig_alg, &auth_method_for_sig_alg)); + POSIX_ENSURE_EQ(cipher_suite->auth_method, auth_method_for_sig_alg); } return S2N_SUCCESS; @@ -107,22 +107,22 @@ static int s2n_is_sig_alg_valid_for_cipher_suite(s2n_signature_algorithm sig_alg static int s2n_certs_exist_for_sig_scheme(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) { - notnull_check(sig_scheme); + POSIX_ENSURE_REF(sig_scheme); s2n_pkey_type cert_type; - GUARD(s2n_get_cert_type_for_sig_alg(sig_scheme->sig_alg, &cert_type)); + POSIX_GUARD(s2n_get_cert_type_for_sig_alg(sig_scheme->sig_alg, &cert_type)); /* A valid cert must exist for the authentication method. */ struct s2n_cert_chain_and_key *cert = s2n_get_compatible_cert_chain_and_key(conn, cert_type); - notnull_check(cert); + POSIX_ENSURE_REF(cert); /* For sig_algs that include a curve, the group must also match. */ if (sig_scheme->signature_curve != NULL) { - notnull_check(cert->private_key); - notnull_check(cert->cert_chain); - notnull_check(cert->cert_chain->head); - eq_check(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_ECDSA); - GUARD(s2n_ecdsa_pkey_matches_curve(&cert->private_key->key.ecdsa_key, sig_scheme->signature_curve)); + POSIX_ENSURE_REF(cert->private_key); + POSIX_ENSURE_REF(cert->cert_chain); + POSIX_ENSURE_REF(cert->cert_chain->head); + POSIX_ENSURE_EQ(cert->cert_chain->head->pkey_type, S2N_PKEY_TYPE_ECDSA); + POSIX_ENSURE_EQ(cert->cert_chain->head->ec_curve_nid, sig_scheme->signature_curve->libcrypto_nid); } return S2N_SUCCESS; @@ -136,7 +136,7 @@ static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_auth s2n_authentication_method auth_method_for_cert_type; for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { - GUARD(s2n_get_auth_method_for_cert_type(i, &auth_method_for_cert_type)); + POSIX_GUARD(s2n_get_auth_method_for_cert_type(i, &auth_method_for_cert_type)); if (auth_method != auth_method_for_cert_type) { continue; @@ -146,7 +146,7 @@ static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_auth return S2N_SUCCESS; } } - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); + POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); } /* TLS1.3 ciphers are always valid, as they don't include an auth method. @@ -158,9 +158,9 @@ static int s2n_certs_exist_for_auth_method(struct s2n_connection *conn, s2n_auth */ int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_cipher_suite *cipher_suite) { - notnull_check(cipher_suite); + POSIX_ENSURE_REF(cipher_suite); - GUARD(s2n_certs_exist_for_auth_method(conn, cipher_suite->auth_method)); + POSIX_GUARD(s2n_certs_exist_for_auth_method(conn, cipher_suite->auth_method)); return S2N_SUCCESS; } @@ -174,17 +174,17 @@ int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_c */ int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme) { - notnull_check(conn); - notnull_check(sig_scheme); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(sig_scheme); struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite; - notnull_check(cipher_suite); + POSIX_ENSURE_REF(cipher_suite); - GUARD(s2n_certs_exist_for_sig_scheme(conn, sig_scheme)); + POSIX_GUARD(s2n_certs_exist_for_sig_scheme(conn, sig_scheme)); /* For the client side, signature algorithm does not need to match the cipher suite. */ if (conn->mode == S2N_SERVER) { - GUARD(s2n_is_sig_alg_valid_for_cipher_suite(sig_scheme->sig_alg, cipher_suite)); + POSIX_GUARD(s2n_is_sig_alg_valid_for_cipher_suite(sig_scheme->sig_alg, cipher_suite)); } return S2N_SUCCESS; } @@ -200,11 +200,11 @@ int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s */ int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type cert_type) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); s2n_authentication_method auth_method; - GUARD(s2n_get_auth_method_for_cert_type(cert_type, &auth_method)); + POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type, &auth_method)); if (conn->secure.cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) { S2N_ERROR_IF(auth_method != conn->secure.cipher_suite->auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED); @@ -219,10 +219,10 @@ int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type c */ int s2n_select_certs_for_server_auth(struct s2n_connection *conn, struct s2n_cert_chain_and_key **chosen_certs) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); s2n_pkey_type cert_type; - GUARD(s2n_get_cert_type_for_sig_alg(conn->secure.conn_sig_scheme.sig_alg, &cert_type)); + POSIX_GUARD(s2n_get_cert_type_for_sig_alg(conn->handshake_params.conn_sig_scheme.sig_alg, &cert_type)); *chosen_certs = s2n_get_compatible_cert_chain_and_key(conn, cert_type); S2N_ERROR_IF(*chosen_certs == NULL, S2N_ERR_CERT_TYPE_UNSUPPORTED); diff --git a/contrib/restricted/aws/s2n/tls/s2n_auth_selection.h b/contrib/restricted/aws/s2n/tls/s2n_auth_selection.h index 370f00c4f8..b52736d7f6 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_auth_selection.h +++ b/contrib/restricted/aws/s2n/tls/s2n_auth_selection.h @@ -20,6 +20,7 @@ #include "crypto/s2n_certificate.h" #include "crypto/s2n_signature.h" +int s2n_get_auth_method_for_cert_type(s2n_pkey_type cert_type, s2n_authentication_method *auth_method); int s2n_is_cipher_suite_valid_for_auth(struct s2n_connection *conn, struct s2n_cipher_suite *cipher_suite); int s2n_is_sig_scheme_valid_for_auth(struct s2n_connection *conn, const struct s2n_signature_scheme *sig_scheme); int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type cert_type); diff --git a/contrib/restricted/aws/s2n/tls/s2n_cbc.c b/contrib/restricted/aws/s2n/tls/s2n_cbc.c index b2ae713e8e..401ab76072 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cbc.c +++ b/contrib/restricted/aws/s2n/tls/s2n_cbc.c @@ -23,6 +23,7 @@ #include "crypto/s2n_hmac.h" +#include "tls/s2n_connection.h" #include "tls/s2n_record.h" /* A TLS CBC record looks like .. @@ -47,18 +48,12 @@ */ int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted) { - /* Set up MAC copy workspace */ - struct s2n_hmac_state *copy = &conn->client->record_mac_copy_workspace; - if (conn->mode == S2N_CLIENT) { - copy = &conn->server->record_mac_copy_workspace; - } - uint8_t mac_digest_size; - GUARD(s2n_hmac_digest_size(hmac->alg, &mac_digest_size)); + POSIX_GUARD(s2n_hmac_digest_size(hmac->alg, &mac_digest_size)); /* The record has to be at least big enough to contain the MAC, * plus the padding length byte */ - gt_check(decrypted->size, mac_digest_size); + POSIX_ENSURE_GT(decrypted->size, mac_digest_size); int payload_and_padding_size = decrypted->size - mac_digest_size; @@ -68,18 +63,22 @@ int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, str int payload_length = MAX(payload_and_padding_size - padding_length - 1, 0); /* Update the MAC */ - GUARD(s2n_hmac_update(hmac, decrypted->data, payload_length)); - GUARD(s2n_hmac_copy(copy, hmac)); + POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data, payload_length)); + int currently_in_hash_block = hmac->currently_in_hash_block; /* Check the MAC */ uint8_t check_digest[S2N_MAX_DIGEST_LEN]; - lte_check(mac_digest_size, sizeof(check_digest)); - GUARD(s2n_hmac_digest_two_compression_rounds(hmac, check_digest, mac_digest_size)); + POSIX_ENSURE_LTE(mac_digest_size, sizeof(check_digest)); + POSIX_GUARD(s2n_hmac_digest_two_compression_rounds(hmac, check_digest, mac_digest_size)); int mismatches = s2n_constant_time_equals(decrypted->data + payload_length, check_digest, mac_digest_size) ^ 1; - /* Compute a MAC on the rest of the data so that we perform the same number of hash operations */ - GUARD(s2n_hmac_update(copy, decrypted->data + payload_length + mac_digest_size, decrypted->size - payload_length - mac_digest_size - 1)); + /* Compute a MAC on the rest of the data so that we perform the same number of hash operations. + * Include the partial hash block from the first MAC to ensure we use the same number of blocks. + */ + POSIX_GUARD(s2n_hmac_reset(hmac)); + POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data, currently_in_hash_block)); + POSIX_GUARD(s2n_hmac_update(hmac, decrypted->data + payload_length + mac_digest_size, decrypted->size - payload_length - mac_digest_size - 1)); /* SSLv3 doesn't specify what the padding should actually be */ if (conn->actual_protocol_version == S2N_SSLv3) { @@ -90,13 +89,11 @@ int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, str int check = MIN(255, (payload_and_padding_size - 1)); int cutoff = check - padding_length; - for (int i = 0, j = decrypted->size - 1 - check; i < check && j < decrypted->size; i++, j++) { + for (uint32_t i = 0, j = decrypted->size - 1 - check; i < check && j < decrypted->size; i++, j++) { uint8_t mask = ~(0xff << ((i >= cutoff) * 8)); mismatches |= (decrypted->data[j] ^ padding_length) & mask; } - GUARD(s2n_hmac_reset(copy)); - S2N_ERROR_IF(mismatches, S2N_ERR_CBC_VERIFY); return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_change_cipher_spec.c b/contrib/restricted/aws/s2n/tls/s2n_change_cipher_spec.c index 19caaa96a1..99dfdfb22a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_change_cipher_spec.c +++ b/contrib/restricted/aws/s2n/tls/s2n_change_cipher_spec.c @@ -32,7 +32,7 @@ int s2n_basic_ccs_recv(struct s2n_connection *conn) { uint8_t type; - GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type)); + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type)); S2N_ERROR_IF(type != CHANGE_CIPHER_SPEC_TYPE, S2N_ERR_BAD_MESSAGE); return 0; @@ -40,14 +40,14 @@ int s2n_basic_ccs_recv(struct s2n_connection *conn) int s2n_client_ccs_recv(struct s2n_connection *conn) { - GUARD(s2n_basic_ccs_recv(conn)); + POSIX_GUARD(s2n_basic_ccs_recv(conn)); /* Zero the sequence number */ struct s2n_blob seq = {.data = conn->secure.client_sequence_number,.size = sizeof(conn->secure.client_sequence_number) }; - GUARD(s2n_blob_zero(&seq)); + POSIX_GUARD(s2n_blob_zero(&seq)); /* Compute the finished message */ - GUARD(s2n_prf_client_finished(conn)); + POSIX_GUARD(s2n_prf_client_finished(conn)); /* Update the client to use the cipher-suite */ conn->client = &conn->secure; @@ -55,21 +55,21 @@ int s2n_client_ccs_recv(struct s2n_connection *conn) /* Flush any partial alert messages that were pending. * If we don't do this, an attacker can inject a 1-byte alert message into the handshake * and cause later, valid alerts to be processed incorrectly. */ - GUARD(s2n_stuffer_wipe(&conn->alert_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->alert_in)); return 0; } int s2n_server_ccs_recv(struct s2n_connection *conn) { - GUARD(s2n_basic_ccs_recv(conn)); + POSIX_GUARD(s2n_basic_ccs_recv(conn)); /* Zero the sequence number */ struct s2n_blob seq = {.data = conn->secure.server_sequence_number,.size = sizeof(conn->secure.server_sequence_number) }; - GUARD(s2n_blob_zero(&seq)); + POSIX_GUARD(s2n_blob_zero(&seq)); /* Compute the finished message */ - GUARD(s2n_prf_server_finished(conn)); + POSIX_GUARD(s2n_prf_server_finished(conn)); /* Update the secure state to active, and point the client at the active state */ conn->server = &conn->secure; @@ -77,14 +77,14 @@ int s2n_server_ccs_recv(struct s2n_connection *conn) /* Flush any partial alert messages that were pending. * If we don't do this, an attacker can inject a 1-byte alert message into the handshake * and cause later, valid alerts to be processed incorrectly. */ - GUARD(s2n_stuffer_wipe(&conn->alert_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->alert_in)); return 0; } int s2n_ccs_send(struct s2n_connection *conn) { - GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, CHANGE_CIPHER_SPEC_TYPE)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, CHANGE_CIPHER_SPEC_TYPE)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c index 67893009b1..10407f487a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c @@ -14,7 +14,7 @@ */ #include "tls/s2n_cipher_preferences.h" -#include <s2n.h> +#include "api/s2n.h" #include <stdint.h> #include <strings.h> #include "tls/s2n_config.h" @@ -57,6 +57,31 @@ const struct s2n_cipher_preferences cipher_preferences_20190801 = { .suites = cipher_suites_20190801, }; +/* Same as 20190801, but with ECDSA for TLS 1.2 added */ +struct s2n_cipher_suite *cipher_suites_20210831[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256, + &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha +}; + +const struct s2n_cipher_preferences cipher_preferences_20210831 = { + .count = s2n_array_len(cipher_suites_20210831), + .suites = cipher_suites_20210831, +}; + /* s2n's list of cipher suites, in order of preference, as of 2014-06-01 */ struct s2n_cipher_suite *cipher_suites_20140601[] = { &s2n_dhe_rsa_with_aes_128_cbc_sha256, @@ -311,6 +336,110 @@ const struct s2n_cipher_preferences cipher_preferences_20190214 = { .suites = cipher_suites_20190214, }; +/* 20190214 with aes-gcm prioritized above aes-cbc */ +struct s2n_cipher_suite *cipher_suites_20190214_gcm[] = { + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_20190214_gcm = { + .count = s2n_array_len(cipher_suites_20190214_gcm), + .suites = cipher_suites_20190214_gcm, +}; + +/* Same as cipher_suites_20190214, but with TLS 1.3 Ciphers */ +struct s2n_cipher_suite *cipher_suites_20210825[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_20210825 = { + .count = s2n_array_len(cipher_suites_20210825), + .suites = cipher_suites_20210825, +}; + +/* Same as cipher_suites_20190214_gcm, but with TLS 1.3 Ciphers */ +struct s2n_cipher_suite *cipher_suites_20210825_gcm[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_20210825_gcm = { + .count = s2n_array_len(cipher_suites_20210825_gcm), + .suites = cipher_suites_20210825_gcm, +}; + struct s2n_cipher_suite *cipher_suites_null[] = { &s2n_null_cipher_suite }; @@ -348,6 +477,34 @@ const struct s2n_cipher_preferences cipher_preferences_20170328 = { .suites = cipher_suites_20170328, }; +/* Equivalent to cipher_suites_20170328 with aes-gcm prioritized above aes-cbc */ +struct s2n_cipher_suite *cipher_suites_20170328_gcm[] = { + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_20170328_gcm = { + .count = s2n_array_len(cipher_suites_20170328_gcm), + .suites = cipher_suites_20170328_gcm, +}; + /* Preferences optimized for FIPS compatibility. */ struct s2n_cipher_suite *cipher_suites_20170405[] = { &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, @@ -368,6 +525,26 @@ const struct s2n_cipher_preferences cipher_preferences_20170405 = { .suites = cipher_suites_20170405, }; +/* Preferences optimized for FIPS compatibility with GCM prioritized */ +struct s2n_cipher_suite *cipher_suites_20170405_gcm[] = { + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_20170405_gcm = { + .count = s2n_array_len(cipher_suites_20170405_gcm), + .suites = cipher_suites_20170405_gcm, +}; + /* Equivalent to cipher_suite_20160411 with 3DES removed. * Make a CBC cipher #1 to avoid negotiating GCM with buggy Java clients. */ struct s2n_cipher_suite *cipher_suites_20170718[] = { @@ -390,6 +567,27 @@ const struct s2n_cipher_preferences cipher_preferences_20170718 = { .suites = cipher_suites_20170718, }; +/* Equivalent to cipher_suites_20170718 with aes-gcm prioritized above aes-cbc */ +struct s2n_cipher_suite *cipher_suites_20170718_gcm[] = { + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_20170718_gcm = { + .count = s2n_array_len(cipher_suites_20170718_gcm), + .suites = cipher_suites_20170718_gcm, +}; + struct s2n_cipher_suite *cipher_suites_elb_security_policy_2015_04[] = { &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, @@ -1004,6 +1202,79 @@ const struct s2n_cipher_preferences cipher_preferences_cloudfront_tls_1_2_2021 = .suites = cipher_suites_cloudfront_tls_1_2_2021, }; +/* Based on cipher_preferences_cloudfront_tls_1_0_2016, but with ordering changed and AES256-SHA256, DES-CBC3-SHA, and + * RC4-MD5 added for compatibility. */ +struct s2n_cipher_suite *cipher_suites_aws_crt_sdk_ssl_v3[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256, + &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_rsa_with_rc4_128_md5 +}; + +const struct s2n_cipher_preferences cipher_preferences_aws_crt_sdk_ssl_v3 = { + .count = s2n_array_len(cipher_suites_aws_crt_sdk_ssl_v3), + .suites = cipher_suites_aws_crt_sdk_ssl_v3, +}; + +/* Based on cipher_preferences_cloudfront_tls_1_0_2016, but with ordering changed and AES256-SHA256 added for + * compatibility. */ +struct s2n_cipher_suite *cipher_suites_aws_crt_sdk_default[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256, + &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_aws_crt_sdk_default = { + .count = s2n_array_len(cipher_suites_aws_crt_sdk_default), + .suites = cipher_suites_aws_crt_sdk_default, +}; + +struct s2n_cipher_suite *cipher_suites_aws_crt_sdk_tls_13[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716 +}; + +const struct s2n_cipher_preferences cipher_preferences_aws_crt_sdk_tls_13 = { + .count = s2n_array_len(cipher_suites_aws_crt_sdk_tls_13), + .suites = cipher_suites_aws_crt_sdk_tls_13, +}; + struct s2n_cipher_suite *cipher_suites_kms_tls_1_0_2018_10[] = { &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, @@ -1022,6 +1293,26 @@ const struct s2n_cipher_preferences cipher_preferences_kms_tls_1_0_2018_10 = { .suites = cipher_suites_kms_tls_1_0_2018_10, }; + +struct s2n_cipher_suite *cipher_suites_kms_tls_1_0_2021_08[] = { + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_kms_tls_1_0_2021_08 = { + .count = s2n_array_len(cipher_suites_kms_tls_1_0_2021_08), + .suites = cipher_suites_kms_tls_1_0_2021_08, +}; + struct s2n_cipher_suite *cipher_suites_kms_pq_tls_1_0_2019_06[] = { &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, @@ -1077,7 +1368,7 @@ const struct s2n_cipher_preferences cipher_preferences_pq_sike_test_tls_1_0_2020 .suites = cipher_suites_pq_sike_test_tls_1_0_2019_11, }; -/* Includes Both Round 2 and Round 1 PQ Ciphers */ +/* Includes Kyber, BIKE, and SIKE PQ Ciphers */ struct s2n_cipher_suite *cipher_suites_kms_pq_tls_1_0_2020_07[] = { &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, @@ -1121,6 +1412,306 @@ const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2020_12 = { .suites = cipher_suites_pq_tls_1_0_2020_12, }; +/* Same as ELBSecurityPolicy-TLS-1-1-2017-01, but with PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_1_2021_05_17[] = { + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_1_2021_05_17 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_1_2021_05_17), + .suites = cipher_suites_pq_tls_1_1_2021_05_17, +}; + +/* Same as cipher_preferences_20190214, but with PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_18[] = { + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_18 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_18), + .suites = cipher_suites_pq_tls_1_0_2021_05_18, +}; + +/* Same as ELBSecurityPolicy-2016-08, but with PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_19[] = { + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_19 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_19), + .suites = cipher_suites_pq_tls_1_0_2021_05_19, +}; + +/* Same as ELBSecurityPolicy-TLS-1-1-2017-01, but with TLS 1.3 and PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_1_2021_05_21[] = { + /* TLS 1.3 Ciphers don't specify their Key exchange method, allowing for Hybrid PQ KEMs to be negotiated separately */ + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_1_2021_05_21 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_1_2021_05_21), + .suites = cipher_suites_pq_tls_1_1_2021_05_21, +}; + +/* Same as cipher_preferences_20190214, but with TLS 1.3 and PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_22[] = { + /* TLS 1.3 Ciphers don't specify their Key exchange method, allowing for Hybrid PQ KEMs to be negotiated separately */ + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_22 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_22), + .suites = cipher_suites_pq_tls_1_0_2021_05_22, +}; + +/* Same as ELBSecurityPolicy-2016-08, but with TLS 1.3 and PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_23[] = { + /* TLS 1.3 Ciphers don't specify their Key exchange method, allowing for Hybrid PQ KEMs to be negotiated separately */ + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_23 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_23), + .suites = cipher_suites_pq_tls_1_0_2021_05_23, +}; + +/* Same as cipher_preferences_kms_pq_tls_1_0_2020_07, but with TLS 1.3 appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_24[] = { + /* TLS 1.3 Ciphers don't specify their Key exchange method, allowing for Hybrid PQ KEMs to be negotiated separately */ + S2N_TLS13_CIPHER_SUITES_20190801, + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_24 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_24), + .suites = cipher_suites_pq_tls_1_0_2021_05_24, +}; + +/* Same as 20190214_gcm, but with PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_25[] = { + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_25 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_25), + .suites = cipher_suites_pq_tls_1_0_2021_05_25, +}; + +/* Same as 20190214_gcm, but with TLS 1.3 and PQ Ciphers appended to top of preference list */ +struct s2n_cipher_suite *cipher_suites_pq_tls_1_0_2021_05_26[] = { + /* TLS 1.3 Ciphers don't specify their Key exchange method, allowing for Hybrid PQ KEMs to be negotiated separately */ + S2N_TLS13_CLOUDFRONT_CIPHER_SUITES_20200716, + &s2n_ecdhe_kyber_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_bike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_sike_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_rsa_with_aes_128_gcm_sha256, + &s2n_rsa_with_aes_256_gcm_sha384, + &s2n_rsa_with_aes_128_cbc_sha, + &s2n_rsa_with_aes_128_cbc_sha256, + &s2n_rsa_with_aes_256_cbc_sha, + &s2n_rsa_with_aes_256_cbc_sha256, + &s2n_rsa_with_3des_ede_cbc_sha, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_26 = { + .count = s2n_array_len(cipher_suites_pq_tls_1_0_2021_05_26), + .suites = cipher_suites_pq_tls_1_0_2021_05_26, +}; + struct s2n_cipher_suite *cipher_suites_kms_fips_tls_1_2_2018_10[] = { &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, @@ -1135,4 +1726,44 @@ const struct s2n_cipher_preferences cipher_preferences_kms_fips_tls_1_2_2018_10 .suites = cipher_suites_kms_fips_tls_1_2_2018_10, }; +struct s2n_cipher_suite *cipher_suites_kms_fips_tls_1_2_2021_08[] = { + &s2n_tls13_aes_128_gcm_sha256, + &s2n_tls13_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, +}; + +const struct s2n_cipher_preferences cipher_preferences_kms_fips_tls_1_2_2021_08 = { + .count = s2n_array_len(cipher_suites_kms_fips_tls_1_2_2021_08), + .suites = cipher_suites_kms_fips_tls_1_2_2021_08, +}; + +struct s2n_cipher_suite *cipher_suites_20210816[] = { + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, +}; + +const struct s2n_cipher_preferences cipher_preferences_20210816 = { + .count = s2n_array_len(cipher_suites_20210816), + .suites = cipher_suites_20210816, +}; + +struct s2n_cipher_suite *cipher_suites_20210816_gcm[] = { + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, +}; + +const struct s2n_cipher_preferences cipher_preferences_20210816_gcm = { + .count = s2n_array_len(cipher_suites_20210816_gcm), + .suites = cipher_suites_20210816_gcm, +}; + /* clang-format on */ diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h index 8dabb707ff..7156c68185 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h @@ -35,13 +35,23 @@ extern const struct s2n_cipher_preferences cipher_preferences_20160804; extern const struct s2n_cipher_preferences cipher_preferences_20160824; extern const struct s2n_cipher_preferences cipher_preferences_20170210; extern const struct s2n_cipher_preferences cipher_preferences_20170328; +extern const struct s2n_cipher_preferences cipher_preferences_20170328_gcm; extern const struct s2n_cipher_preferences cipher_preferences_20170405; +extern const struct s2n_cipher_preferences cipher_preferences_20170405_gcm; extern const struct s2n_cipher_preferences cipher_preferences_20170718; +extern const struct s2n_cipher_preferences cipher_preferences_20170718_gcm; extern const struct s2n_cipher_preferences cipher_preferences_20190214; +extern const struct s2n_cipher_preferences cipher_preferences_20190214_gcm; extern const struct s2n_cipher_preferences cipher_preferences_20190801; extern const struct s2n_cipher_preferences cipher_preferences_20190120; extern const struct s2n_cipher_preferences cipher_preferences_20190121; extern const struct s2n_cipher_preferences cipher_preferences_20190122; +extern const struct s2n_cipher_preferences cipher_preferences_20210816; +extern const struct s2n_cipher_preferences cipher_preferences_20210816_gcm; +extern const struct s2n_cipher_preferences cipher_preferences_20210825; +extern const struct s2n_cipher_preferences cipher_preferences_20210825_gcm; +extern const struct s2n_cipher_preferences cipher_preferences_20210831; + extern const struct s2n_cipher_preferences cipher_preferences_test_all; extern const struct s2n_cipher_preferences cipher_preferences_test_all_tls12; @@ -86,15 +96,31 @@ extern const struct s2n_cipher_preferences cipher_preferences_cloudfront_tls_1_1 extern const struct s2n_cipher_preferences cipher_preferences_cloudfront_tls_1_2_2018_legacy; extern const struct s2n_cipher_preferences cipher_preferences_cloudfront_tls_1_2_2019_legacy; -extern const struct s2n_cipher_preferences cipher_preferences_kms_tls_1_0_2018_10; +/* AWS Common Runtime Cipher Preferences */ +extern const struct s2n_cipher_preferences cipher_preferences_aws_crt_sdk_ssl_v3; +extern const struct s2n_cipher_preferences cipher_preferences_aws_crt_sdk_default; +extern const struct s2n_cipher_preferences cipher_preferences_aws_crt_sdk_tls_13; +/* AWS KMS Cipher Preferences */ +extern const struct s2n_cipher_preferences cipher_preferences_kms_tls_1_0_2018_10; +extern const struct s2n_cipher_preferences cipher_preferences_kms_tls_1_0_2021_08; +extern const struct s2n_cipher_preferences cipher_preferences_kms_fips_tls_1_2_2018_10; +extern const struct s2n_cipher_preferences cipher_preferences_kms_fips_tls_1_2_2021_08; extern const struct s2n_cipher_preferences cipher_preferences_kms_pq_tls_1_0_2019_06; extern const struct s2n_cipher_preferences cipher_preferences_kms_pq_tls_1_0_2020_02; extern const struct s2n_cipher_preferences cipher_preferences_kms_pq_tls_1_0_2020_07; extern const struct s2n_cipher_preferences cipher_preferences_pq_sike_test_tls_1_0_2019_11; extern const struct s2n_cipher_preferences cipher_preferences_pq_sike_test_tls_1_0_2020_02; extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2020_12; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_1_2021_05_17; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_18; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_19; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_1_2021_05_21; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_22; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_23; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_24; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_25; +extern const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_0_2021_05_26; -extern const struct s2n_cipher_preferences cipher_preferences_kms_fips_tls_1_2_2018_10; extern const struct s2n_cipher_preferences cipher_preferences_null; diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c b/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c index ea478e27b8..cf82b7c6f4 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c @@ -263,7 +263,7 @@ struct s2n_cipher_suite s2n_rsa_with_3des_ede_cbc_sha = /* 0x00,0x0A */ { struct s2n_cipher_suite s2n_dhe_rsa_with_3des_ede_cbc_sha = /* 0x00,0x16 */ { .available = 0, - .name = "EDH-RSA-DES-CBC3-SHA", + .name = "DHE-RSA-DES-CBC3-SHA", .iana_value = { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA }, .key_exchange_alg = &s2n_dhe, .auth_method = S2N_AUTHENTICATION_RSA, @@ -994,6 +994,14 @@ const struct s2n_cipher_preferences cipher_preferences_test_all_tls13 = { .suites = s2n_all_tls13_cipher_suites, }; +static bool should_init_crypto = true; +static bool crypto_initialized = false; +int s2n_crypto_disable_init(void) { + POSIX_ENSURE(!crypto_initialized, S2N_ERR_INITIALIZED); + should_init_crypto = false; + return S2N_SUCCESS; +} + /* Determines cipher suite availability and selects record algorithms */ int s2n_cipher_suites_init(void) { @@ -1026,7 +1034,7 @@ int s2n_cipher_suites_init(void) if (cur_suite->sslv3_record_alg && cur_suite->sslv3_record_alg->cipher->is_available()) { struct s2n_blob cur_suite_mem = { .data = (uint8_t *) cur_suite, .size = sizeof(struct s2n_cipher_suite) }; struct s2n_blob new_suite_mem = { 0 }; - GUARD(s2n_dup(&cur_suite_mem, &new_suite_mem)); + POSIX_GUARD(s2n_dup(&cur_suite_mem, &new_suite_mem)); struct s2n_cipher_suite *new_suite = (struct s2n_cipher_suite *)(void *)new_suite_mem.data; new_suite->available = 1; @@ -1037,14 +1045,18 @@ int s2n_cipher_suites_init(void) } } + if (should_init_crypto) { #if !S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) - /*https://wiki.openssl.org/index.php/Manual:OpenSSL_add_all_algorithms(3)*/ - OpenSSL_add_all_algorithms(); + /*https://wiki.openssl.org/index.php/Manual:OpenSSL_add_all_algorithms(3)*/ + OpenSSL_add_all_algorithms(); #else - OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); #endif + } - return 0; + crypto_initialized = true; + + return S2N_SUCCESS; } /* Reset any selected record algorithms */ @@ -1058,96 +1070,93 @@ int s2n_cipher_suites_cleanup(void) /* Release custom SSLv3 cipher suites */ if (cur_suite->sslv3_cipher_suite != cur_suite) { - GUARD(s2n_free_object((uint8_t **)&cur_suite->sslv3_cipher_suite, sizeof(struct s2n_cipher_suite))); + POSIX_GUARD(s2n_free_object((uint8_t **)&cur_suite->sslv3_cipher_suite, sizeof(struct s2n_cipher_suite))); } cur_suite->sslv3_cipher_suite = NULL; } + if (should_init_crypto) { #if !S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) - /*https://wiki.openssl.org/index.php/Manual:OpenSSL_add_all_algorithms(3)*/ - EVP_cleanup(); + /*https://wiki.openssl.org/index.php/Manual:OpenSSL_add_all_algorithms(3)*/ + EVP_cleanup(); - /* per the reqs here https://www.openssl.org/docs/man1.1.0/crypto/OPENSSL_init_crypto.html we don't explicitly call - * cleanup in later versions */ + /* per the reqs here https://www.openssl.org/docs/man1.1.0/crypto/OPENSSL_init_crypto.html we don't explicitly call + * cleanup in later versions */ #endif + } return 0; } -struct s2n_cipher_suite *s2n_cipher_suite_from_wire(const uint8_t cipher_suite[S2N_TLS_CIPHER_SUITE_LEN]) +S2N_RESULT s2n_cipher_suite_from_iana(const uint8_t iana[static S2N_TLS_CIPHER_SUITE_LEN], struct s2n_cipher_suite **cipher_suite) { + RESULT_ENSURE_REF(cipher_suite); + *cipher_suite = NULL; + RESULT_ENSURE_REF(iana); + int low = 0; - int top = (sizeof(s2n_all_cipher_suites) / sizeof(struct s2n_cipher_suite *)) - 1; + int top = s2n_array_len(s2n_all_cipher_suites) - 1; + /* Perform a textbook binary search */ while (low <= top) { /* Check in the middle */ - int mid = low + ((top - low) / 2); - int m = memcmp(s2n_all_cipher_suites[mid]->iana_value, cipher_suite, 2); + size_t mid = low + ((top - low) / 2); + int m = memcmp(s2n_all_cipher_suites[mid]->iana_value, iana, S2N_TLS_CIPHER_SUITE_LEN); if (m == 0) { - return s2n_all_cipher_suites[mid]; + *cipher_suite = s2n_all_cipher_suites[mid]; + return S2N_RESULT_OK; } else if (m > 0) { top = mid - 1; } else if (m < 0) { low = mid + 1; } } - - return NULL; + RESULT_BAIL(S2N_ERR_CIPHER_NOT_SUPPORTED); } int s2n_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_CIPHER_SUITE_LEN]) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); - struct s2n_cipher_suite *cipher_suite; - - /* See if the cipher is one we support */ - cipher_suite = s2n_cipher_suite_from_wire(wire); - ENSURE_POSIX(cipher_suite != NULL, S2N_ERR_CIPHER_NOT_SUPPORTED); - - /* From RFC section: https://tools.ietf.org/html/rfc8446#section-4.2.11: - * Client MUST verify that the server selected a cipher suite indicating a Hash - * associated with the chosen PSK if it exists. - * */ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); + + const struct s2n_security_policy *security_policy; + POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + POSIX_ENSURE_REF(security_policy); + + struct s2n_cipher_suite *cipher_suite = NULL; + for (size_t i = 0; i < security_policy->cipher_preferences->count; i++) { + const uint8_t *ours = security_policy->cipher_preferences->suites[i]->iana_value; + if (memcmp(wire, ours, S2N_TLS_CIPHER_SUITE_LEN) == 0) { + cipher_suite = security_policy->cipher_preferences->suites[i]; + break; + } + } + POSIX_ENSURE(cipher_suite != NULL, S2N_ERR_CIPHER_NOT_SUPPORTED); + POSIX_ENSURE(cipher_suite->available, S2N_ERR_CIPHER_NOT_SUPPORTED); + + /** Clients MUST verify + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11 + *# that the server selected a cipher suite + *# indicating a Hash associated with the PSK + **/ if (conn->psk_params.chosen_psk) { - ENSURE_POSIX(cipher_suite->prf_alg == conn->psk_params.chosen_psk->hmac_alg, + POSIX_ENSURE(cipher_suite->prf_alg == conn->psk_params.chosen_psk->hmac_alg, S2N_ERR_CIPHER_NOT_SUPPORTED); } /* Verify cipher suite sent in server hello is the same as sent in hello retry */ if (s2n_is_hello_retry_handshake(conn) && !s2n_is_hello_retry_message(conn)) { - ENSURE_POSIX(conn->secure.cipher_suite->iana_value == cipher_suite->iana_value, S2N_ERR_CIPHER_NOT_SUPPORTED); + POSIX_ENSURE(conn->secure.cipher_suite->iana_value == cipher_suite->iana_value, S2N_ERR_CIPHER_NOT_SUPPORTED); return S2N_SUCCESS; } - conn->secure.cipher_suite = cipher_suite; - - /* Verify the cipher was part of the originally offered list */ - const struct s2n_cipher_preferences *cipher_prefs; - GUARD(s2n_connection_get_cipher_preferences(conn, &cipher_prefs)); - - uint8_t found = 0; - - for (int i = 0; i < cipher_prefs->count; i++ ) { - /* The client sends all "available" ciphers in the preference list to the server. - The server must pick one of the ciphers offered by the client. */ - if (cipher_prefs->suites[i]->available) { - const uint8_t *server_iana_value = conn->secure.cipher_suite->iana_value; - const uint8_t *client_iana_value = cipher_prefs->suites[i]->iana_value; - - if (memcmp(server_iana_value, client_iana_value, S2N_TLS_CIPHER_SUITE_LEN) == 0) { - found = 1; - break; - } - } - } - S2N_ERROR_IF(found != 1, S2N_ERR_CIPHER_NOT_SUPPORTED); + conn->secure.cipher_suite = cipher_suite; /* For SSLv3 use SSLv3-specific ciphers */ if (conn->actual_protocol_version == S2N_SSLv3) { conn->secure.cipher_suite = conn->secure.cipher_suite->sslv3_cipher_suite; - notnull_check(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn->secure.cipher_suite); } return 0; @@ -1155,7 +1164,7 @@ int s2n_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_C static int s2n_wire_ciphers_contain(const uint8_t *match, const uint8_t *wire, uint32_t count, uint32_t cipher_suite_len) { - for (int i = 0; i < count; i++) { + for (uint32_t i = 0; i < count; i++) { const uint8_t *theirs = wire + (i * cipher_suite_len) + (cipher_suite_len - S2N_TLS_CIPHER_SUITE_LEN); if (!memcmp(match, theirs, S2N_TLS_CIPHER_SUITE_LEN)) { @@ -1179,7 +1188,7 @@ static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, uint8_t fallback_scsv[S2N_TLS_CIPHER_SUITE_LEN] = { TLS_FALLBACK_SCSV }; if (s2n_wire_ciphers_contain(fallback_scsv, wire, count, cipher_suite_len)) { conn->closed = 1; - S2N_ERROR(S2N_ERR_FALLBACK_DETECTED); + POSIX_BAIL(S2N_ERR_FALLBACK_DETECTED); } } @@ -1189,7 +1198,7 @@ static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, } const struct s2n_security_policy *security_policy; - GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); /* s2n supports only server order */ for (int i = 0; i < security_policy->cipher_preferences->count; i++) { @@ -1197,7 +1206,7 @@ static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, if (s2n_wire_ciphers_contain(ours, wire, count, cipher_suite_len)) { /* We have a match */ - struct s2n_cipher_suite *match = s2n_cipher_suite_from_wire(ours); + struct s2n_cipher_suite *match = security_policy->cipher_preferences->suites[i]; /* Never use TLS1.3 ciphers on a pre-TLS1.3 connection, and vice versa */ if ((conn->actual_protocol_version >= S2N_TLS13) != (match->minimum_required_tls_version >= S2N_TLS13)) { @@ -1223,7 +1232,7 @@ static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, if (match->minimum_required_tls_version < S2N_TLS13) { /* If the kex is not supported continue to the next candidate */ bool kex_supported = false; - GUARD_AS_POSIX(s2n_kex_supported(match, conn, &kex_supported)); + POSIX_GUARD_RESULT(s2n_kex_supported(match, conn, &kex_supported)); if (!kex_supported) { continue; } @@ -1264,7 +1273,7 @@ static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, return S2N_SUCCESS; } - S2N_ERROR(S2N_ERR_CIPHER_NOT_SUPPORTED); + POSIX_BAIL(S2N_ERR_CIPHER_NOT_SUPPORTED); } int s2n_set_cipher_as_sslv2_server(struct s2n_connection *conn, uint8_t *wire, uint16_t count) @@ -1276,3 +1285,34 @@ int s2n_set_cipher_as_tls_server(struct s2n_connection *conn, uint8_t *wire, uin { return s2n_set_cipher_as_server(conn, wire, count, S2N_TLS_CIPHER_SUITE_LEN); } + +bool s2n_cipher_suite_requires_ecc_extension(struct s2n_cipher_suite *cipher) +{ + if(!cipher) { + return false; + } + + /* TLS1.3 does not include key exchange algorithms in its cipher suites, + * but the elliptic curves extension is always required. */ + if (cipher->minimum_required_tls_version >= S2N_TLS13) { + return true; + } + + if (s2n_kex_includes(cipher->key_exchange_alg, &s2n_ecdhe)) { + return true; + } + + return false; +} + +bool s2n_cipher_suite_requires_pq_extension(struct s2n_cipher_suite *cipher) +{ + if(!cipher) { + return false; + } + + if (s2n_kex_includes(cipher->key_exchange_alg, &s2n_kem)) { + return true; + } + return false; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.h b/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.h index 2bee39ec4c..74a388a9b4 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.h +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.h @@ -32,10 +32,9 @@ #define S2N_MAX_POSSIBLE_RECORD_ALGS 2 -/* Kept up-to-date by s2n_cipher_suite_match_test */ +/* Kept up-to-date by s2n_cipher_suite_test */ #define S2N_CIPHER_SUITE_COUNT 39 - /* Record algorithm flags that can be OR'ed */ #define S2N_TLS12_AES_GCM_AEAD_NONCE 0x01 #define S2N_TLS12_CHACHA_POLY_AEAD_NONCE 0x02 @@ -84,6 +83,8 @@ extern const struct s2n_record_algorithm s2n_record_alg_aes256_sha384; extern const struct s2n_record_algorithm s2n_record_alg_aes128_gcm; extern const struct s2n_record_algorithm s2n_record_alg_aes256_gcm; extern const struct s2n_record_algorithm s2n_record_alg_chacha20_poly1305; +extern const struct s2n_record_algorithm s2n_tls13_record_alg_aes128_gcm; +extern const struct s2n_record_algorithm s2n_tls13_record_alg_chacha20_poly1305; struct s2n_cipher_suite { /* Is there an implementation available? Set in s2n_cipher_suites_init() */ @@ -161,7 +162,9 @@ extern struct s2n_cipher_suite s2n_tls13_chacha20_poly1305_sha256; extern int s2n_cipher_suites_init(void); extern int s2n_cipher_suites_cleanup(void); -extern struct s2n_cipher_suite *s2n_cipher_suite_from_wire(const uint8_t cipher_suite[S2N_TLS_CIPHER_SUITE_LEN]); +S2N_RESULT s2n_cipher_suite_from_iana(const uint8_t iana[S2N_TLS_CIPHER_SUITE_LEN], struct s2n_cipher_suite **cipher_suite); extern int s2n_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_CIPHER_SUITE_LEN]); extern int s2n_set_cipher_as_sslv2_server(struct s2n_connection *conn, uint8_t * wire, uint16_t count); extern int s2n_set_cipher_as_tls_server(struct s2n_connection *conn, uint8_t * wire, uint16_t count); +bool s2n_cipher_suite_requires_ecc_extension(struct s2n_cipher_suite *cipher); +bool s2n_cipher_suite_requires_pq_extension(struct s2n_cipher_suite *cipher); diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_cert.c b/contrib/restricted/aws/s2n/tls/s2n_client_cert.c index 7dde226788..757b13430d 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_cert.c +++ b/contrib/restricted/aws/s2n/tls/s2n_client_cert.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "crypto/s2n_certificate.h" #include "error/s2n_errno.h" @@ -27,32 +27,97 @@ #include "utils/s2n_blob.h" #include "utils/s2n_safety.h" +/* In TLS1.2, the certificate list is just an opaque vector of certificates: + * + * opaque ASN.1Cert<1..2^24-1>; + * + * struct { + * ASN.1Cert certificate_list<0..2^24-1>; + * } Certificate; + * + * This construction allowed us to store the entire certificate_list blob + * and return it from the s2n_connection_get_client_cert_chain method for + * customers to examine. + * + * However, TLS1.3 introduced per-certificate extensions: + * + * struct { + * opaque cert_data<1..2^24-1>; + * ----> Extension extensions<0..2^16-1>; <---- + * } CertificateEntry; + * + * struct { + * opaque certificate_request_context<0..2^8-1>; + * CertificateEntry certificate_list<0..2^24-1>; + * } Certificate; + * + * So in order to store / return the certificates in the same format as in TLS1.2, + * we need to first strip out the extensions. + */ +static S2N_RESULT s2n_client_cert_chain_store(struct s2n_connection *conn, struct s2n_blob *client_cert_chain) +{ + RESULT_ENSURE_REF(conn); + + /* Earlier versions are a basic copy */ + if (conn->actual_protocol_version < S2N_TLS13) { + RESULT_GUARD_POSIX(s2n_dup(client_cert_chain, &conn->handshake_params.client_cert_chain)); + return S2N_RESULT_OK; + } + + struct s2n_stuffer cert_chain_in = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_in, client_cert_chain)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&cert_chain_in, client_cert_chain->size)); + + struct s2n_stuffer cert_chain_out = { 0 }; + RESULT_GUARD_POSIX(s2n_realloc(&conn->handshake_params.client_cert_chain, client_cert_chain->size)); + RESULT_GUARD_POSIX(s2n_stuffer_init(&cert_chain_out, &conn->handshake_params.client_cert_chain)); + + uint32_t cert_size = 0; + uint16_t extensions_size = 0; + while(s2n_stuffer_data_available(&cert_chain_in)) { + RESULT_GUARD_POSIX(s2n_stuffer_read_uint24(&cert_chain_in, &cert_size)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint24(&cert_chain_out, cert_size)); + RESULT_GUARD_POSIX(s2n_stuffer_copy(&cert_chain_in, &cert_chain_out, cert_size)); + + /* The new TLS1.3 format includes extensions, which we must skip. + * Customers will not expect TLS extensions in a DER-encoded certificate. + */ + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&cert_chain_in, &extensions_size)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_read(&cert_chain_in, extensions_size)); + } + + /* We will have allocated more memory than actually necessary. + * If this becomes a problem, we should consider reallocing the correct amount of memory here. + */ + conn->handshake_params.client_cert_chain.size = s2n_stuffer_data_available(&cert_chain_out); + return S2N_RESULT_OK; +} int s2n_client_cert_recv(struct s2n_connection *conn) { if (conn->actual_protocol_version == S2N_TLS13) { uint8_t certificate_request_context_len; - GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &certificate_request_context_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &certificate_request_context_len)); S2N_ERROR_IF(certificate_request_context_len != 0,S2N_ERR_BAD_MESSAGE); } struct s2n_stuffer *in = &conn->handshake.io; struct s2n_blob client_cert_chain = {0}; - GUARD(s2n_stuffer_read_uint24(in, &client_cert_chain.size)); + POSIX_GUARD(s2n_stuffer_read_uint24(in, &client_cert_chain.size)); S2N_ERROR_IF(client_cert_chain.size > s2n_stuffer_data_available(in), S2N_ERR_BAD_MESSAGE); if (client_cert_chain.size == 0) { - GUARD(s2n_conn_set_handshake_no_client_cert(conn)); + POSIX_GUARD(s2n_conn_set_handshake_no_client_cert(conn)); return 0; } client_cert_chain.data = s2n_stuffer_raw_read(in, client_cert_chain.size); - notnull_check(client_cert_chain.data); + POSIX_ENSURE_REF(client_cert_chain.data); s2n_cert_public_key public_key; - GUARD(s2n_pkey_zero_init(&public_key)); + POSIX_GUARD(s2n_pkey_zero_init(&public_key)); s2n_pkey_type pkey_type; @@ -61,14 +126,14 @@ int s2n_client_cert_recv(struct s2n_connection *conn) client_cert_chain.data, client_cert_chain.size, &pkey_type, &public_key) != S2N_CERT_OK, S2N_ERR_CERT_UNTRUSTED); - conn->secure.client_cert_pkey_type = pkey_type; - GUARD(s2n_pkey_setup_for_type(&public_key, pkey_type)); - - GUARD(s2n_pkey_check_key_exists(&public_key)); - GUARD(s2n_dup(&client_cert_chain, &conn->secure.client_cert_chain)); - conn->secure.client_public_key = public_key; + conn->handshake_params.client_cert_pkey_type = pkey_type; + POSIX_GUARD(s2n_pkey_setup_for_type(&public_key, pkey_type)); - return 0; + POSIX_GUARD(s2n_pkey_check_key_exists(&public_key)); + POSIX_GUARD_RESULT(s2n_client_cert_chain_store(conn, &client_cert_chain)); + conn->handshake_params.client_public_key = public_key; + + return S2N_SUCCESS; } @@ -76,7 +141,7 @@ int s2n_client_cert_send(struct s2n_connection *conn) { struct s2n_cert_chain_and_key *chain_and_key = conn->handshake_params.our_chain_and_key; - if (conn->actual_protocol_version == S2N_TLS13) { + if (conn->actual_protocol_version >= S2N_TLS13) { /* If this message is in response to a CertificateRequest, the value of * certificate_request_context in that message. * https://tools.ietf.org/html/rfc8446#section-4.4.2 @@ -85,15 +150,15 @@ int s2n_client_cert_send(struct s2n_connection *conn) * https://tools.ietf.org/html/rfc8446#section-4.3.2 */ uint8_t certificate_request_context_len = 0; - GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, certificate_request_context_len)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, certificate_request_context_len)); } if (chain_and_key == NULL) { - GUARD(s2n_conn_set_handshake_no_client_cert(conn)); - GUARD(s2n_send_empty_cert_chain(&conn->handshake.io)); + POSIX_GUARD(s2n_conn_set_handshake_no_client_cert(conn)); + POSIX_GUARD(s2n_send_empty_cert_chain(&conn->handshake.io)); return 0; } - GUARD(s2n_send_cert_chain(conn, &conn->handshake.io, chain_and_key)); - return 0; + POSIX_GUARD(s2n_send_cert_chain(conn, &conn->handshake.io, chain_and_key)); + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_cert_verify.c b/contrib/restricted/aws/s2n/tls/s2n_client_cert_verify.c index b11150c48c..5327b5bc7e 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_cert_verify.c +++ b/contrib/restricted/aws/s2n/tls/s2n_client_cert_verify.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -25,68 +25,78 @@ #include "stuffer/s2n_stuffer.h" #include "utils/s2n_safety.h" +#include "tls/s2n_async_pkey.h" +static int s2n_client_cert_verify_send_complete(struct s2n_connection *conn, struct s2n_blob *signature); int s2n_client_cert_verify_recv(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + struct s2n_handshake_hashes *hashes = conn->handshake.hashes; + POSIX_ENSURE_REF(hashes); + struct s2n_stuffer *in = &conn->handshake.io; - struct s2n_signature_scheme chosen_sig_scheme = s2n_rsa_pkcs1_md5_sha1; + struct s2n_signature_scheme *chosen_sig_scheme = &conn->handshake_params.client_cert_sig_scheme; - if(conn->actual_protocol_version >= S2N_TLS12){ + if (conn->actual_protocol_version < S2N_TLS12) { + POSIX_GUARD(s2n_choose_default_sig_scheme(conn, chosen_sig_scheme, S2N_CLIENT)); + } else { /* Verify the SigScheme picked by the Client was in the preference list we sent (or is the default SigScheme) */ - GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, in, &chosen_sig_scheme)); + POSIX_GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, in, chosen_sig_scheme)); } + uint16_t signature_size; struct s2n_blob signature = {0}; - GUARD(s2n_stuffer_read_uint16(in, &signature_size)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &signature_size)); signature.size = signature_size; signature.data = s2n_stuffer_raw_read(in, signature.size); - notnull_check(signature.data); + POSIX_ENSURE_REF(signature.data); /* Use a copy of the hash state since the verify digest computation may modify the running hash state we need later. */ - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, chosen_sig_scheme.hash_alg, &hash_state)); - GUARD(s2n_hash_copy(&conn->handshake.ccv_hash_copy, &hash_state)); + struct s2n_hash_state *hash_state = &hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, chosen_sig_scheme->hash_alg, hash_state)); /* Verify the signature */ - GUARD(s2n_pkey_verify(&conn->secure.client_public_key, chosen_sig_scheme.sig_alg, &conn->handshake.ccv_hash_copy, &signature)); + POSIX_GUARD(s2n_pkey_verify(&conn->handshake_params.client_public_key, chosen_sig_scheme->sig_alg, hash_state, &signature)); /* Client certificate has been verified. Minimize required handshake hash algs */ - GUARD(s2n_conn_update_required_handshake_hashes(conn)); + POSIX_GUARD(s2n_conn_update_required_handshake_hashes(conn)); - return 0; + return S2N_SUCCESS; } int s2n_client_cert_verify_send(struct s2n_connection *conn) { - struct s2n_stuffer *out = &conn->handshake.io; + POSIX_ENSURE_REF(conn); + struct s2n_handshake_hashes *hashes = conn->handshake.hashes; + POSIX_ENSURE_REF(hashes); - struct s2n_signature_scheme chosen_sig_scheme = s2n_rsa_pkcs1_md5_sha1; + S2N_ASYNC_PKEY_GUARD(conn); + struct s2n_stuffer *out = &conn->handshake.io; - if (conn->actual_protocol_version >= S2N_TLS12) { - chosen_sig_scheme = conn->secure.client_cert_sig_scheme; - GUARD(s2n_stuffer_write_uint16(out, conn->secure.client_cert_sig_scheme.iana_value)); + struct s2n_signature_scheme *chosen_sig_scheme = &conn->handshake_params.client_cert_sig_scheme; + if (conn->actual_protocol_version < S2N_TLS12) { + POSIX_GUARD(s2n_choose_default_sig_scheme(conn, chosen_sig_scheme, S2N_CLIENT)); + } else { + POSIX_GUARD(s2n_stuffer_write_uint16(out, conn->handshake_params.client_cert_sig_scheme.iana_value)); } /* Use a copy of the hash state since the verify digest computation may modify the running hash state we need later. */ - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, chosen_sig_scheme.hash_alg, &hash_state)); - GUARD(s2n_hash_copy(&conn->handshake.ccv_hash_copy, &hash_state)); + struct s2n_hash_state *hash_state = &hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, chosen_sig_scheme->hash_alg, hash_state)); - struct s2n_cert_chain_and_key *cert_chain_and_key = conn->handshake_params.our_chain_and_key; - - DEFER_CLEANUP(struct s2n_blob signature = {0}, s2n_free); - uint32_t max_signature_size = 0; - GUARD_AS_POSIX(s2n_pkey_size(cert_chain_and_key->private_key, &max_signature_size)); - GUARD(s2n_alloc(&signature, max_signature_size)); + S2N_ASYNC_PKEY_SIGN(conn, chosen_sig_scheme->sig_alg, hash_state, s2n_client_cert_verify_send_complete); +} - GUARD(s2n_pkey_sign(cert_chain_and_key->private_key, chosen_sig_scheme.sig_alg, &conn->handshake.ccv_hash_copy, &signature)); +static int s2n_client_cert_verify_send_complete(struct s2n_connection *conn, struct s2n_blob *signature) +{ + struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_stuffer_write_uint16(out, signature.size)); - GUARD(s2n_stuffer_write(out, &signature)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, signature->size)); + POSIX_GUARD(s2n_stuffer_write(out, signature)); /* Client certificate has been verified. Minimize required handshake hash algs */ - GUARD(s2n_conn_update_required_handshake_hashes(conn)); + POSIX_GUARD(s2n_conn_update_required_handshake_hashes(conn)); - return 0; + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_finished.c b/contrib/restricted/aws/s2n/tls/s2n_client_finished.c index cc85970145..871e7db15f 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_finished.c +++ b/contrib/restricted/aws/s2n/tls/s2n_client_finished.c @@ -30,7 +30,7 @@ int s2n_client_finished_recv(struct s2n_connection *conn) uint8_t *our_version; our_version = conn->handshake.client_finished; uint8_t *their_version = s2n_stuffer_raw_read(&conn->handshake.io, S2N_TLS_FINISHED_LEN); - notnull_check(their_version); + POSIX_ENSURE_REF(their_version); S2N_ERROR_IF(!s2n_constant_time_equals(our_version, their_version, S2N_TLS_FINISHED_LEN) || conn->handshake.rsa_failed, S2N_ERR_BAD_MESSAGE); @@ -40,25 +40,25 @@ int s2n_client_finished_recv(struct s2n_connection *conn) int s2n_client_finished_send(struct s2n_connection *conn) { uint8_t *our_version; - GUARD(s2n_prf_client_finished(conn)); + POSIX_GUARD(s2n_prf_client_finished(conn)); struct s2n_blob seq = {.data = conn->secure.client_sequence_number,.size = sizeof(conn->secure.client_sequence_number) }; - GUARD(s2n_blob_zero(&seq)); + POSIX_GUARD(s2n_blob_zero(&seq)); our_version = conn->handshake.client_finished; /* Update the server to use the cipher suite */ conn->client = &conn->secure; if (conn->actual_protocol_version == S2N_SSLv3) { - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, S2N_SSL_FINISHED_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, S2N_SSL_FINISHED_LEN)); } else { - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, S2N_TLS_FINISHED_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, S2N_TLS_FINISHED_LEN)); } return 0; } int s2n_tls13_client_finished_recv(struct s2n_connection *conn) { - eq_check(conn->actual_protocol_version, S2N_TLS13); + POSIX_ENSURE_EQ(conn->actual_protocol_version, S2N_TLS13); uint8_t length = s2n_stuffer_data_available(&conn->handshake.io); S2N_ERROR_IF(length == 0, S2N_ERR_BAD_MESSAGE); @@ -71,40 +71,42 @@ int s2n_tls13_client_finished_recv(struct s2n_connection *conn) { s2n_tls13_connection_keys(keys, conn); /* get transcript hash */ - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, keys.hash_algorithm, hash_state)); struct s2n_blob finished_key = {0}; - GUARD(s2n_blob_init(&finished_key, conn->handshake.client_finished, keys.size)); + POSIX_GUARD(s2n_blob_init(&finished_key, conn->handshake.client_finished, keys.size)); s2n_tls13_key_blob(client_finished_mac, keys.size); - GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, &hash_state, &client_finished_mac)); + POSIX_GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, hash_state, &client_finished_mac)); - GUARD(s2n_tls13_mac_verify(&keys, &client_finished_mac, &wire_finished_mac)); + POSIX_GUARD(s2n_tls13_mac_verify(&keys, &client_finished_mac, &wire_finished_mac)); return 0; } int s2n_tls13_client_finished_send(struct s2n_connection *conn) { - eq_check(conn->actual_protocol_version, S2N_TLS13); + POSIX_ENSURE_EQ(conn->actual_protocol_version, S2N_TLS13); /* get tls13 keys */ s2n_tls13_connection_keys(keys, conn); /* get transcript hash */ - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, keys.hash_algorithm, hash_state)); /* look up finished secret key */ struct s2n_blob finished_key = {0}; - GUARD(s2n_blob_init(&finished_key, conn->handshake.client_finished, keys.size)); + POSIX_GUARD(s2n_blob_init(&finished_key, conn->handshake.client_finished, keys.size)); /* generate the hashed message authenticated code */ s2n_stack_blob(client_finished_mac, keys.size, S2N_TLS13_SECRET_MAX_LEN); - GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, &hash_state, &client_finished_mac)); + POSIX_GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, hash_state, &client_finished_mac)); /* write to handshake io */ - GUARD(s2n_stuffer_write(&conn->handshake.io, &client_finished_mac)); + POSIX_GUARD(s2n_stuffer_write(&conn->handshake.io, &client_finished_mac)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_hello.c b/contrib/restricted/aws/s2n/tls/s2n_client_hello.c index b03cda1491..0bcec3501a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_hello.c +++ b/contrib/restricted/aws/s2n/tls/s2n_client_hello.c @@ -21,8 +21,8 @@ #include "crypto/s2n_fips.h" #include "error/s2n_errno.h" - #include "crypto/s2n_hash.h" +#include "crypto/s2n_rsa_signing.h" #include "tls/extensions/s2n_extension_list.h" #include "tls/extensions/s2n_server_key_share.h" @@ -33,9 +33,9 @@ #include "tls/s2n_connection.h" #include "tls/s2n_client_hello.h" #include "tls/s2n_alerts.h" +#include "tls/s2n_handshake_type.h" #include "tls/s2n_signature_algorithms.h" #include "tls/s2n_tls.h" -#include "tls/s2n_tls_digest_preferences.h" #include "tls/s2n_security_policies.h" #include "stuffer/s2n_stuffer.h" @@ -45,7 +45,7 @@ #include "utils/s2n_safety.h" struct s2n_client_hello *s2n_connection_get_client_hello(struct s2n_connection *conn) { - if (conn->client_hello.parsed != 1) { + if (conn->client_hello.callback_invoked != 1) { return NULL; } @@ -58,8 +58,8 @@ static uint32_t min_size(struct s2n_blob *blob, uint32_t max_length) { static S2N_RESULT s2n_generate_client_session_id(struct s2n_connection *conn) { - ENSURE_REF(conn); - ENSURE_REF(conn->config); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->config); /* Session id already generated - no-op */ if (conn->session_id_len) { @@ -71,115 +71,135 @@ static S2N_RESULT s2n_generate_client_session_id(struct s2n_connection *conn) return S2N_RESULT_OK; } - /* Generate the session id for TLS1.3 if in middlebox compatibility mode. - * For now, we default to middlebox compatibility mode unless using QUIC. */ - if (conn->config->quic_enabled) { + /* Only generate the session id for TLS1.3 if in middlebox compatibility mode */ + if (conn->client_protocol_version >= S2N_TLS13 && !s2n_is_middlebox_compat_enabled(conn)) { return S2N_RESULT_OK; } struct s2n_blob session_id = {0}; - GUARD_AS_RESULT(s2n_blob_init(&session_id, conn->session_id, S2N_TLS_SESSION_ID_MAX_LEN)); - GUARD_RESULT(s2n_get_public_random_data(&session_id)); + RESULT_GUARD_POSIX(s2n_blob_init(&session_id, conn->session_id, S2N_TLS_SESSION_ID_MAX_LEN)); + RESULT_GUARD(s2n_get_public_random_data(&session_id)); conn->session_id_len = S2N_TLS_SESSION_ID_MAX_LEN; return S2N_RESULT_OK; } ssize_t s2n_client_hello_get_raw_message_length(struct s2n_client_hello *ch) { - notnull_check(ch); + POSIX_ENSURE_REF(ch); return ch->raw_message.blob.size; } ssize_t s2n_client_hello_get_raw_message(struct s2n_client_hello *ch, uint8_t *out, uint32_t max_length) { - notnull_check(ch); - notnull_check(out); + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(out); uint32_t len = min_size(&ch->raw_message.blob, max_length); struct s2n_stuffer *raw_message = &ch->raw_message; - GUARD(s2n_stuffer_reread(raw_message)); - GUARD(s2n_stuffer_read_bytes(raw_message, out, len)); + POSIX_GUARD(s2n_stuffer_reread(raw_message)); + POSIX_GUARD(s2n_stuffer_read_bytes(raw_message, out, len)); return len; } ssize_t s2n_client_hello_get_cipher_suites_length(struct s2n_client_hello *ch) { - notnull_check(ch); + POSIX_ENSURE_REF(ch); return ch->cipher_suites.size; } +int s2n_client_hello_cb_done(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE(conn->config->client_hello_cb_mode == + S2N_CLIENT_HELLO_CB_NONBLOCKING, S2N_ERR_INVALID_STATE); + POSIX_ENSURE(conn->client_hello.callback_invoked == 1, S2N_ERR_ASYNC_NOT_PERFORMED); + POSIX_ENSURE(conn->client_hello.parsed == 1, S2N_ERR_INVALID_STATE); + + conn->client_hello.callback_async_blocked = 0; + conn->client_hello.callback_async_done = 1; + + return S2N_SUCCESS; +} + ssize_t s2n_client_hello_get_cipher_suites(struct s2n_client_hello *ch, uint8_t *out, uint32_t max_length) { - notnull_check(ch); - notnull_check(out); - notnull_check(ch->cipher_suites.data); + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(ch->cipher_suites.data); uint32_t len = min_size(&ch->cipher_suites, max_length); - memcpy_check(out, &ch->cipher_suites.data, len); + POSIX_CHECKED_MEMCPY(out, ch->cipher_suites.data, len); return len; } ssize_t s2n_client_hello_get_extensions_length(struct s2n_client_hello *ch) { - notnull_check(ch); + POSIX_ENSURE_REF(ch); return ch->extensions.raw.size; } ssize_t s2n_client_hello_get_extensions(struct s2n_client_hello *ch, uint8_t *out, uint32_t max_length) { - notnull_check(ch); - notnull_check(out); - notnull_check(ch->extensions.raw.data); + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(ch->extensions.raw.data); uint32_t len = min_size(&ch->extensions.raw, max_length); - memcpy_check(out, &ch->extensions.raw.data, len); + POSIX_CHECKED_MEMCPY(out, ch->extensions.raw.data, len); return len; } int s2n_client_hello_free(struct s2n_client_hello *client_hello) { - notnull_check(client_hello); + POSIX_ENSURE_REF(client_hello); - GUARD(s2n_stuffer_free(&client_hello->raw_message)); + POSIX_GUARD(s2n_stuffer_free(&client_hello->raw_message)); /* These point to data in the raw_message stuffer, so we don't need to free them */ client_hello->cipher_suites.data = NULL; client_hello->extensions.raw.data = NULL; + /* clean the CH nonblocking callback flags + * incase we are preparing for CH retry */ + client_hello->callback_async_blocked = 0; + client_hello->callback_async_done = 0; + client_hello->parsed = 0; + return 0; } int s2n_collect_client_hello(struct s2n_connection *conn, struct s2n_stuffer *source) { - notnull_check(conn); - notnull_check(source); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(source); uint32_t size = s2n_stuffer_data_available(source); S2N_ERROR_IF(size == 0, S2N_ERR_BAD_MESSAGE); struct s2n_client_hello *ch = &conn->client_hello; - GUARD(s2n_stuffer_resize(&ch->raw_message, size)); - GUARD(s2n_stuffer_copy(source, &ch->raw_message, size)); + POSIX_GUARD(s2n_stuffer_resize(&ch->raw_message, size)); + POSIX_GUARD(s2n_stuffer_copy(source, &ch->raw_message, size)); return 0; } -static int s2n_parse_client_hello(struct s2n_connection *conn) +int s2n_parse_client_hello(struct s2n_connection *conn) { - notnull_check(conn); - GUARD(s2n_collect_client_hello(conn, &conn->handshake.io)); + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_collect_client_hello(conn, &conn->handshake.io)); if (conn->client_hello_version == S2N_SSLv2) { - GUARD(s2n_sslv2_client_hello_recv(conn)); + POSIX_GUARD(s2n_sslv2_client_hello_recv(conn)); return S2N_SUCCESS; } @@ -189,8 +209,8 @@ static int s2n_parse_client_hello(struct s2n_connection *conn) uint8_t client_protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; - GUARD(s2n_stuffer_read_bytes(in, client_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); - GUARD(s2n_stuffer_erase_and_read_bytes(in, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, client_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_erase_and_read_bytes(in, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); /* Protocol version in the ClientHello is fixed at 0x0303(TLS 1.2) for * future versions of TLS. Therefore, we will negotiate down if a client sends @@ -199,51 +219,58 @@ static int s2n_parse_client_hello(struct s2n_connection *conn) conn->client_protocol_version = MIN((client_protocol_version[0] * 10) + client_protocol_version[1], S2N_TLS12); conn->client_hello_version = conn->client_protocol_version; - GUARD(s2n_stuffer_read_uint8(in, &conn->session_id_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &conn->session_id_len)); S2N_ERROR_IF(conn->session_id_len > S2N_TLS_SESSION_ID_MAX_LEN || conn->session_id_len > s2n_stuffer_data_available(in), S2N_ERR_BAD_MESSAGE); - - GUARD(s2n_stuffer_read_bytes(in, conn->session_id, conn->session_id_len)); + POSIX_GUARD(s2n_blob_init(&client_hello->session_id, s2n_stuffer_raw_read(in, conn->session_id_len), conn->session_id_len)); + POSIX_CHECKED_MEMCPY(conn->session_id, client_hello->session_id.data, conn->session_id_len); uint16_t cipher_suites_length = 0; - GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); - ENSURE_POSIX(cipher_suites_length > 0, S2N_ERR_BAD_MESSAGE); - ENSURE_POSIX(cipher_suites_length % S2N_TLS_CIPHER_SUITE_LEN == 0, S2N_ERR_BAD_MESSAGE); - + POSIX_GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); + POSIX_ENSURE(cipher_suites_length > 0, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(cipher_suites_length % S2N_TLS_CIPHER_SUITE_LEN == 0, S2N_ERR_BAD_MESSAGE); + client_hello->cipher_suites.size = cipher_suites_length; client_hello->cipher_suites.data = s2n_stuffer_raw_read(in, cipher_suites_length); - notnull_check(client_hello->cipher_suites.data); + POSIX_ENSURE_REF(client_hello->cipher_suites.data); /* Don't choose the cipher yet, read the extensions first */ uint8_t num_compression_methods = 0; - GUARD(s2n_stuffer_read_uint8(in, &num_compression_methods)); - GUARD(s2n_stuffer_skip_read(in, num_compression_methods)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &num_compression_methods)); + POSIX_GUARD(s2n_stuffer_skip_read(in, num_compression_methods)); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); - - /* This is going to be our fallback if the client has no preference. */ - /* A TLS-compliant application MUST support key exchange with secp256r1 (NIST P-256) */ - /* and SHOULD support key exchange with X25519 [RFC7748]. */ - /* - https://tools.ietf.org/html/rfc8446#section-9.1 */ - conn->secure.server_ecc_evp_params.negotiated_curve = &s2n_ecc_curve_secp256r1; + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); + POSIX_ENSURE_GT(ecc_pref->count, 0); + + if (s2n_ecc_preferences_includes_curve(ecc_pref, TLS_EC_CURVE_SECP_256_R1)) { + /* This is going to be our fallback if the client has no preference. */ + /* A TLS-compliant application MUST support key exchange with secp256r1 (NIST P-256) */ + /* and SHOULD support key exchange with X25519 [RFC7748]. */ + /* - https://tools.ietf.org/html/rfc8446#section-9.1 */ + conn->kex_params.server_ecc_evp_params.negotiated_curve = &s2n_ecc_curve_secp256r1; + } else { + /* P-256 is the preferred fallback option. These prefs don't support it, so choose whatever curve is first. */ + conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0]; + } - GUARD(s2n_extension_list_parse(in, &conn->client_hello.extensions)); + POSIX_GUARD(s2n_extension_list_parse(in, &conn->client_hello.extensions)); return S2N_SUCCESS; } int s2n_process_client_hello(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + /* Client hello is parsed and config is finalized. * Negotiate protocol version, cipher suite, ALPN, select a cert, etc. */ struct s2n_client_hello *client_hello = &conn->client_hello; const struct s2n_security_policy *security_policy; - GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); - /* Ensure that highest supported version is set correctly */ - if (!s2n_security_policy_supports_tls13(security_policy)) { + if (!s2n_connection_supports_tls13(conn) || !s2n_security_policy_supports_tls13(security_policy)) { conn->server_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12); conn->actual_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12); } @@ -252,11 +279,11 @@ int s2n_process_client_hello(struct s2n_connection *conn) * To keep the version in client_hello intact for the extension retrieval APIs, process a copy instead. */ s2n_parsed_extensions_list copy_of_parsed_extensions = conn->client_hello.extensions; - GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, ©_of_parsed_extensions)); + POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, ©_of_parsed_extensions)); /* After parsing extensions, select a curve and corresponding keyshare to use */ if (conn->actual_protocol_version >= S2N_TLS13) { - GUARD(s2n_extensions_server_key_share_select(conn)); + POSIX_GUARD(s2n_extensions_server_key_share_select(conn)); } /* for pre TLS 1.3 connections, protocol selection is not done in supported_versions extensions, so do it here */ @@ -265,25 +292,19 @@ int s2n_process_client_hello(struct s2n_connection *conn) } if (conn->client_protocol_version < security_policy->minimum_protocol_version) { - GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); - S2N_ERROR(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + POSIX_GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); + POSIX_BAIL(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); } - if (conn->config->quic_enabled) { - ENSURE_POSIX(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); - - /* In TLS1.3, legacy_session_id is only set to indicate middlebox compatability mode. - * When running with QUIC, S2N does not support middlebox compatability mode. - * https://tools.ietf.org/html/draft-ietf-quic-tls-32#section-8.4 - */ - ENSURE_POSIX(conn->session_id_len == 0, S2N_ERR_BAD_MESSAGE); + if (s2n_connection_is_quic_enabled(conn)) { + POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); } /* Find potential certificate matches before we choose the cipher. */ - GUARD(s2n_conn_find_name_matching_certs(conn)); + POSIX_GUARD(s2n_conn_find_name_matching_certs(conn)); /* Now choose the ciphers we have certs for. */ - GUARD(s2n_set_cipher_as_tls_server(conn, client_hello->cipher_suites.data, client_hello->cipher_suites.size / 2)); + POSIX_GUARD(s2n_set_cipher_as_tls_server(conn, client_hello->cipher_suites.data, client_hello->cipher_suites.size / 2)); /* If we're using a PSK, we don't need to choose a signature algorithm or certificate, * because no additional auth is required. */ @@ -292,58 +313,104 @@ int s2n_process_client_hello(struct s2n_connection *conn) } /* And set the signature and hash algorithm used for key exchange signatures */ - GUARD(s2n_choose_sig_scheme_from_peer_preference_list(conn, + POSIX_GUARD(s2n_choose_sig_scheme_from_peer_preference_list(conn, &conn->handshake_params.client_sig_hash_algs, - &conn->secure.conn_sig_scheme)); + &conn->handshake_params.conn_sig_scheme)); /* And finally, set the certs specified by the final auth + sig_alg combo. */ - GUARD(s2n_select_certs_for_server_auth(conn, &conn->handshake_params.our_chain_and_key)); + POSIX_GUARD(s2n_select_certs_for_server_auth(conn, &conn->handshake_params.our_chain_and_key)); return S2N_SUCCESS; } +static S2N_RESULT s2n_client_hello_process_cb_response(struct s2n_connection *conn, int rc) +{ + if (rc < 0) { + goto fail; + } + switch(conn->config->client_hello_cb_mode) { + case S2N_CLIENT_HELLO_CB_BLOCKING : { + if(rc) { + conn->server_name_used = 1; + } + return S2N_RESULT_OK; + } + case S2N_CLIENT_HELLO_CB_NONBLOCKING : { + if (conn->client_hello.callback_async_done) { + return S2N_RESULT_OK; + } + conn->client_hello.callback_async_blocked = 1; + RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED); + } + } +fail: + /* rc < 0 */ + RESULT_GUARD_POSIX(s2n_queue_reader_handshake_failure_alert(conn)); + RESULT_BAIL(S2N_ERR_CANCELLED); +} + +bool s2n_client_hello_invoke_callback(struct s2n_connection *conn) { + /* Invoke only if the callback has not been called or if polling mode is enabled */ + bool invoke = !conn->client_hello.callback_invoked || conn->config->client_hello_cb_enable_poll; + /* + * The callback should not be called if this client_hello is in response to a hello retry. + */ + return invoke && !IS_HELLO_RETRY_HANDSHAKE(conn); +} + int s2n_client_hello_recv(struct s2n_connection *conn) { - /* Parse client hello */ - GUARD(s2n_parse_client_hello(conn)); + if (conn->config->client_hello_cb_enable_poll == 0) { + POSIX_ENSURE(conn->client_hello.callback_async_blocked == 0, S2N_ERR_ASYNC_BLOCKED); + } - /* If the CLIENT_HELLO has already been parsed, then we should not call - * the client_hello_cb a second time. */ if (conn->client_hello.parsed == 0) { - /* Mark the collected client hello as available when parsing is done and before the client hello callback */ + /* Parse client hello */ + POSIX_GUARD(s2n_parse_client_hello(conn)); conn->client_hello.parsed = 1; + } + /* Call the client_hello_cb once unless polling is enabled. */ + if (s2n_client_hello_invoke_callback(conn)) { + /* Mark the collected client hello as available when parsing is done and before the client hello callback */ + conn->client_hello.callback_invoked = 1; /* Call client_hello_cb if exists, letting application to modify s2n_connection or swap s2n_config */ if (conn->config->client_hello_cb) { int rc = conn->config->client_hello_cb(conn, conn->config->client_hello_cb_ctx); - if (rc < 0) { - GUARD(s2n_queue_reader_handshake_failure_alert(conn)); - S2N_ERROR(S2N_ERR_CANCELLED); - } - if (rc) { - conn->server_name_used = 1; - } + POSIX_GUARD_RESULT(s2n_client_hello_process_cb_response(conn, rc)); } } if (conn->client_hello_version != S2N_SSLv2) { - GUARD(s2n_process_client_hello(conn)); + POSIX_GUARD(s2n_process_client_hello(conn)); } return 0; } +S2N_RESULT s2n_cipher_suite_validate_available(struct s2n_connection *conn, struct s2n_cipher_suite *cipher) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(cipher); + RESULT_ENSURE_EQ(cipher->available, true); + RESULT_ENSURE_LTE(cipher->minimum_required_tls_version, conn->client_protocol_version); + if (s2n_connection_is_quic_enabled(conn)) { + RESULT_ENSURE_GTE(cipher->minimum_required_tls_version, S2N_TLS13); + } + return S2N_RESULT_OK; +} + int s2n_client_hello_send(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + const struct s2n_security_policy *security_policy; - GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); const struct s2n_cipher_preferences *cipher_preferences = security_policy->cipher_preferences; - notnull_check(cipher_preferences); + POSIX_ENSURE_REF(cipher_preferences); - /* Check whether cipher preference supports TLS 1.3. If it doesn't, - our highest supported version is S2N_TLS12 */ - if (!s2n_security_policy_supports_tls13(security_policy)) { + if (!s2n_connection_supports_tls13(conn) || !s2n_security_policy_supports_tls13(security_policy)) { conn->client_protocol_version = MIN(conn->client_protocol_version, S2N_TLS12); conn->actual_protocol_version = MIN(conn->actual_protocol_version, S2N_TLS12); } @@ -353,61 +420,74 @@ int s2n_client_hello_send(struct s2n_connection *conn) uint8_t client_protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN] = {0}; struct s2n_blob b = {0}; - GUARD(s2n_blob_init(&b, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_blob_init(&b, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); /* Create the client random data */ - GUARD(s2n_stuffer_init(&client_random, &b)); + POSIX_GUARD(s2n_stuffer_init(&client_random, &b)); struct s2n_blob r = {0}; - GUARD(s2n_blob_init(&r, s2n_stuffer_raw_write(&client_random, S2N_TLS_RANDOM_DATA_LEN), S2N_TLS_RANDOM_DATA_LEN)); - notnull_check(r.data); - GUARD_AS_POSIX(s2n_get_public_random_data(&r)); + POSIX_GUARD(s2n_blob_init(&r, s2n_stuffer_raw_write(&client_random, S2N_TLS_RANDOM_DATA_LEN), S2N_TLS_RANDOM_DATA_LEN)); + POSIX_ENSURE_REF(r.data); + POSIX_GUARD_RESULT(s2n_get_public_random_data(&r)); uint8_t reported_protocol_version = MIN(conn->client_protocol_version, S2N_TLS12); client_protocol_version[0] = reported_protocol_version / 10; client_protocol_version[1] = reported_protocol_version % 10; conn->client_hello_version = reported_protocol_version; - GUARD(s2n_stuffer_write_bytes(out, client_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); - GUARD(s2n_stuffer_copy(&client_random, out, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, client_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_copy(&client_random, out, S2N_TLS_RANDOM_DATA_LEN)); - GUARD_AS_POSIX(s2n_generate_client_session_id(conn)); - GUARD(s2n_stuffer_write_uint8(out, conn->session_id_len)); + POSIX_GUARD_RESULT(s2n_generate_client_session_id(conn)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, conn->session_id_len)); if (conn->session_id_len > 0) { - GUARD(s2n_stuffer_write_bytes(out, conn->session_id, conn->session_id_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, conn->session_id, conn->session_id_len)); } /* Reserve space for size of the list of available ciphers */ struct s2n_stuffer_reservation available_cipher_suites_size; - GUARD(s2n_stuffer_reserve_uint16(out, &available_cipher_suites_size)); + POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &available_cipher_suites_size)); /* Now, write the IANA values of every available cipher suite in our list */ + struct s2n_cipher_suite *cipher = NULL; + bool legacy_renegotiation_signal_required = false; for (int i = 0; i < security_policy->cipher_preferences->count; i++ ) { - if (cipher_preferences->suites[i]->available && - cipher_preferences->suites[i]->minimum_required_tls_version <= conn->client_protocol_version) { - GUARD(s2n_stuffer_write_bytes(out, security_policy->cipher_preferences->suites[i]->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); + cipher = cipher_preferences->suites[i]; + if (s2n_result_is_error(s2n_cipher_suite_validate_available(conn, cipher))) { + continue; + } + if (cipher->minimum_required_tls_version < S2N_TLS13) { + legacy_renegotiation_signal_required = true; } + POSIX_GUARD(s2n_stuffer_write_bytes(out, cipher->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); } - /* Lastly, write TLS_EMPTY_RENEGOTIATION_INFO_SCSV so that server knows it's an initial handshake (RFC5746 Section 3.4) */ - uint8_t renegotiation_info_scsv[S2N_TLS_CIPHER_SUITE_LEN] = { TLS_EMPTY_RENEGOTIATION_INFO_SCSV }; - GUARD(s2n_stuffer_write_bytes(out, renegotiation_info_scsv, S2N_TLS_CIPHER_SUITE_LEN)); + if (legacy_renegotiation_signal_required) { + /* Lastly, write TLS_EMPTY_RENEGOTIATION_INFO_SCSV so that server knows it's an initial handshake (RFC5746 Section 3.4) */ + uint8_t renegotiation_info_scsv[S2N_TLS_CIPHER_SUITE_LEN] = { TLS_EMPTY_RENEGOTIATION_INFO_SCSV }; + POSIX_GUARD(s2n_stuffer_write_bytes(out, renegotiation_info_scsv, S2N_TLS_CIPHER_SUITE_LEN)); + } /* Write size of the list of available ciphers */ - GUARD(s2n_stuffer_write_vector_size(&available_cipher_suites_size)); + POSIX_GUARD(s2n_stuffer_write_vector_size(&available_cipher_suites_size)); /* Zero compression methods */ - GUARD(s2n_stuffer_write_uint8(out, 1)); - GUARD(s2n_stuffer_write_uint8(out, 0)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, 1)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, 0)); /* Write the extensions */ - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, out)); + POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, out)); /* Once the message is complete, finish calculating the PSK binders. * * The PSK binders require all the sizes in the ClientHello to be written correctly, * including the extension size and extension list size, and therefore have * to be calculated AFTER we finish writing the entire extension list. */ - GUARD_AS_POSIX(s2n_finish_psk_extension(conn)); + POSIX_GUARD_RESULT(s2n_finish_psk_extension(conn)); + + /* If early data was not requested as part of the ClientHello, it never will be. */ + if (conn->early_data_state == S2N_UNKNOWN_EARLY_DATA_STATE) { + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_NOT_REQUESTED)); + } return S2N_SUCCESS; } @@ -419,54 +499,53 @@ int s2n_sslv2_client_hello_recv(struct s2n_connection *conn) struct s2n_stuffer *in = &client_hello->raw_message; const struct s2n_security_policy *security_policy; - GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); if (conn->client_protocol_version < security_policy->minimum_protocol_version) { - GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); - S2N_ERROR(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + POSIX_GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); + POSIX_BAIL(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); } conn->actual_protocol_version = MIN(conn->client_protocol_version, conn->server_protocol_version); /* We start 5 bytes into the record */ uint16_t cipher_suites_length; - GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); - ENSURE_POSIX(cipher_suites_length > 0, S2N_ERR_BAD_MESSAGE); - ENSURE_POSIX(cipher_suites_length % S2N_SSLv2_CIPHER_SUITE_LEN == 0, S2N_ERR_BAD_MESSAGE); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &cipher_suites_length)); + POSIX_ENSURE(cipher_suites_length > 0, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(cipher_suites_length % S2N_SSLv2_CIPHER_SUITE_LEN == 0, S2N_ERR_BAD_MESSAGE); uint16_t session_id_length; - GUARD(s2n_stuffer_read_uint16(in, &session_id_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &session_id_length)); uint16_t challenge_length; - GUARD(s2n_stuffer_read_uint16(in, &challenge_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &challenge_length)); S2N_ERROR_IF(challenge_length > S2N_TLS_RANDOM_DATA_LEN, S2N_ERR_BAD_MESSAGE); client_hello->cipher_suites.size = cipher_suites_length; client_hello->cipher_suites.data = s2n_stuffer_raw_read(in, cipher_suites_length); - notnull_check(client_hello->cipher_suites.data); + POSIX_ENSURE_REF(client_hello->cipher_suites.data); /* Find potential certificate matches before we choose the cipher. */ - GUARD(s2n_conn_find_name_matching_certs(conn)); + POSIX_GUARD(s2n_conn_find_name_matching_certs(conn)); - GUARD(s2n_set_cipher_as_sslv2_server(conn, client_hello->cipher_suites.data, client_hello->cipher_suites.size / S2N_SSLv2_CIPHER_SUITE_LEN)); - GUARD(s2n_choose_default_sig_scheme(conn, &conn->secure.conn_sig_scheme)); - GUARD(s2n_select_certs_for_server_auth(conn, &conn->handshake_params.our_chain_and_key)); + POSIX_GUARD(s2n_set_cipher_as_sslv2_server(conn, client_hello->cipher_suites.data, client_hello->cipher_suites.size / S2N_SSLv2_CIPHER_SUITE_LEN)); + POSIX_GUARD(s2n_choose_default_sig_scheme(conn, &conn->handshake_params.conn_sig_scheme, S2N_SERVER)); + POSIX_GUARD(s2n_select_certs_for_server_auth(conn, &conn->handshake_params.our_chain_and_key)); S2N_ERROR_IF(session_id_length > s2n_stuffer_data_available(in), S2N_ERR_BAD_MESSAGE); + POSIX_GUARD(s2n_blob_init(&client_hello->session_id, s2n_stuffer_raw_read(in, session_id_length), session_id_length)); if (session_id_length > 0 && session_id_length <= S2N_TLS_SESSION_ID_MAX_LEN) { - GUARD(s2n_stuffer_read_bytes(in, conn->session_id, session_id_length)); + POSIX_CHECKED_MEMCPY(conn->session_id, client_hello->session_id.data, session_id_length); conn->session_id_len = (uint8_t) session_id_length; - } else { - GUARD(s2n_stuffer_skip_read(in, session_id_length)); } struct s2n_blob b = {0}; - GUARD(s2n_blob_init(&b, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_blob_init(&b, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); b.data += S2N_TLS_RANDOM_DATA_LEN - challenge_length; b.size -= S2N_TLS_RANDOM_DATA_LEN - challenge_length; - GUARD(s2n_stuffer_read(in, &b)); + POSIX_GUARD(s2n_stuffer_read(in, &b)); return 0; } @@ -474,15 +553,15 @@ int s2n_sslv2_client_hello_recv(struct s2n_connection *conn) static int s2n_client_hello_get_parsed_extension(s2n_tls_extension_type extension_type, s2n_parsed_extensions_list *parsed_extension_list, s2n_parsed_extension **parsed_extension) { - notnull_check(parsed_extension_list); - notnull_check(parsed_extension); + POSIX_ENSURE_REF(parsed_extension_list); + POSIX_ENSURE_REF(parsed_extension); s2n_extension_type_id extension_type_id; - GUARD(s2n_extension_supported_iana_value_to_id(extension_type, &extension_type_id)); + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type, &extension_type_id)); s2n_parsed_extension *found_parsed_extension = &parsed_extension_list->parsed_extensions[extension_type_id]; - notnull_check(found_parsed_extension->extension.data); - ENSURE_POSIX(found_parsed_extension->extension_type == extension_type, S2N_ERR_INVALID_PARSED_EXTENSIONS); + POSIX_ENSURE_REF(found_parsed_extension->extension.data); + POSIX_ENSURE(found_parsed_extension->extension_type == extension_type, S2N_ERR_INVALID_PARSED_EXTENSIONS); *parsed_extension = found_parsed_extension; return S2N_SUCCESS; @@ -490,7 +569,7 @@ static int s2n_client_hello_get_parsed_extension(s2n_tls_extension_type extensio ssize_t s2n_client_hello_get_extension_length(struct s2n_client_hello *ch, s2n_tls_extension_type extension_type) { - notnull_check(ch); + POSIX_ENSURE_REF(ch); s2n_parsed_extension *parsed_extension = NULL; if (s2n_client_hello_get_parsed_extension(extension_type, &ch->extensions, &parsed_extension) != S2N_SUCCESS) { @@ -502,8 +581,8 @@ ssize_t s2n_client_hello_get_extension_length(struct s2n_client_hello *ch, s2n_t ssize_t s2n_client_hello_get_extension_by_id(struct s2n_client_hello *ch, s2n_tls_extension_type extension_type, uint8_t *out, uint32_t max_length) { - notnull_check(ch); - notnull_check(out); + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(out); s2n_parsed_extension *parsed_extension = NULL; if (s2n_client_hello_get_parsed_extension(extension_type, &ch->extensions, &parsed_extension) != S2N_SUCCESS) { @@ -511,6 +590,81 @@ ssize_t s2n_client_hello_get_extension_by_id(struct s2n_client_hello *ch, s2n_tl } uint32_t len = min_size(&parsed_extension->extension, max_length); - memcpy_check(out, parsed_extension->extension.data, len); + POSIX_CHECKED_MEMCPY(out, parsed_extension->extension.data, len); return len; } + +int s2n_client_hello_get_session_id_length(struct s2n_client_hello *ch, uint32_t *out_length) +{ + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(out_length); + *out_length = ch->session_id.size; + return S2N_SUCCESS; +} + +int s2n_client_hello_get_session_id(struct s2n_client_hello *ch, uint8_t *out, uint32_t *out_length, uint32_t max_length) +{ + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(out_length); + + uint32_t len = min_size(&ch->session_id, max_length); + POSIX_CHECKED_MEMCPY(out, ch->session_id.data, len); + *out_length = len; + + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_client_hello_get_raw_extension(uint16_t extension_iana, + struct s2n_blob *raw_extensions, struct s2n_blob *extension) +{ + RESULT_ENSURE_REF(raw_extensions); + RESULT_ENSURE_REF(extension); + + *extension = (struct s2n_blob) { 0 }; + + struct s2n_stuffer raw_extensions_stuffer = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_init(&raw_extensions_stuffer, raw_extensions)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&raw_extensions_stuffer, raw_extensions->size)); + + while (s2n_stuffer_data_available(&raw_extensions_stuffer) > 0) { + uint16_t extension_type = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&raw_extensions_stuffer, &extension_type)); + + uint16_t extension_size = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&raw_extensions_stuffer, &extension_size)); + + uint8_t *extension_data = s2n_stuffer_raw_read(&raw_extensions_stuffer, extension_size); + RESULT_ENSURE_REF(extension_data); + + if (extension_iana == extension_type) { + RESULT_GUARD_POSIX(s2n_blob_init(extension, extension_data, extension_size)); + return S2N_RESULT_OK; + } + } + return S2N_RESULT_OK; +} + +int s2n_client_hello_has_extension(struct s2n_client_hello *ch, uint16_t extension_iana, bool *exists) +{ + POSIX_ENSURE_REF(ch); + POSIX_ENSURE_REF(exists); + + *exists = false; + + s2n_extension_type_id extension_type_id = s2n_unsupported_extension; + if (s2n_extension_supported_iana_value_to_id(extension_iana, &extension_type_id) == S2N_SUCCESS) { + s2n_parsed_extension *parsed_extension = NULL; + if (s2n_client_hello_get_parsed_extension(extension_iana, &ch->extensions, &parsed_extension) == S2N_SUCCESS) { + *exists = true; + } + return S2N_SUCCESS; + } + + struct s2n_blob extension = { 0 }; + POSIX_GUARD_RESULT(s2n_client_hello_get_raw_extension(extension_iana, &ch->extensions.raw, &extension)); + if (extension.data != NULL) { + *exists = true; + } + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_hello.h b/contrib/restricted/aws/s2n/tls/s2n_client_hello.h index 59eb0b12c7..d319bbd606 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_hello.h +++ b/contrib/restricted/aws/s2n/tls/s2n_client_hello.h @@ -16,7 +16,7 @@ #pragma once #include <stdint.h> -#include <s2n.h> +#include "api/s2n.h" #include "stuffer/s2n_stuffer.h" #include "tls/extensions/s2n_extension_list.h" @@ -31,7 +31,18 @@ struct s2n_client_hello { s2n_parsed_extensions_list extensions; struct s2n_blob cipher_suites; - + struct s2n_blob session_id; + + unsigned int callback_invoked:1; + unsigned int callback_async_blocked:1; + unsigned int callback_async_done:1; + /* + * Marks if the client hello has been parsed. + * + * While a client_hello is only parsed once, it is possible to parse + * two different client_hello during a single handshake if the server + * issues a hello retry. + */ unsigned int parsed:1; }; diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_hello_request.c b/contrib/restricted/aws/s2n/tls/s2n_client_hello_request.c new file mode 100644 index 0000000000..6444c87f5d --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_client_hello_request.c @@ -0,0 +1,40 @@ +/* + * 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 "api/s2n.h" + +#include "tls/s2n_connection.h" +#include "utils/s2n_safety.h" + +int s2n_client_hello_request_recv(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(conn->actual_protocol_version < S2N_TLS13, S2N_ERR_BAD_MESSAGE); + + /* + *= https://tools.ietf.org/rfc/rfc5246#section-7.4.1.1 + *# The HelloRequest message MAY be sent by the server at any time. + */ + POSIX_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_BAD_MESSAGE); + + /* + *= https://tools.ietf.org/rfc/rfc5246#section-7.4.1.1 + *# This message will be ignored by the client if the client is + *# currently negotiating a session. This message MAY be ignored by + *# the client if it does not wish to renegotiate a session, or the + *# client may, if it wishes, respond with a no_renegotiation alert. + */ + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_key_exchange.c b/contrib/restricted/aws/s2n/tls/s2n_client_key_exchange.c index 1428e177b2..7b669e1ba6 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_key_exchange.c +++ b/contrib/restricted/aws/s2n/tls/s2n_client_key_exchange.c @@ -14,7 +14,7 @@ */ #include <sys/param.h> -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -24,6 +24,7 @@ #include "tls/s2n_cipher_suites.h" #include "tls/s2n_connection.h" #include "tls/s2n_kex.h" +#include "tls/s2n_key_log.h" #include "tls/s2n_resume.h" #include "stuffer/s2n_stuffer.h" @@ -45,35 +46,35 @@ static int s2n_rsa_client_key_recv_complete(struct s2n_connection *conn, bool rs static int s2n_hybrid_client_action(struct s2n_connection *conn, struct s2n_blob *combined_shared_key, s2n_kex_client_key_method kex_method, uint32_t *cursor, s2n_stuffer_action stuffer_action) { - notnull_check(kex_method); - notnull_check(stuffer_action); + POSIX_ENSURE_REF(kex_method); + POSIX_ENSURE_REF(stuffer_action); struct s2n_stuffer *io = &conn->handshake.io; const struct s2n_kex *hybrid_kex_0 = conn->secure.cipher_suite->key_exchange_alg->hybrid[0]; const struct s2n_kex *hybrid_kex_1 = conn->secure.cipher_suite->key_exchange_alg->hybrid[1]; /* Keep a copy to the start of the entire hybrid client key exchange message for the hybrid PRF */ - struct s2n_blob *client_key_exchange_message = &conn->secure.client_key_exchange_message; + struct s2n_blob *client_key_exchange_message = &conn->kex_params.client_key_exchange_message; client_key_exchange_message->data = stuffer_action(io, 0); - notnull_check(client_key_exchange_message->data); + POSIX_ENSURE_REF(client_key_exchange_message->data); const uint32_t start_cursor = *cursor; DEFER_CLEANUP(struct s2n_blob shared_key_0 = {0}, s2n_free); - GUARD_AS_POSIX(kex_method(hybrid_kex_0, conn, &shared_key_0)); + POSIX_GUARD_RESULT(kex_method(hybrid_kex_0, conn, &shared_key_0)); - struct s2n_blob *shared_key_1 = &(conn->secure.kem_params.shared_secret); - GUARD_AS_POSIX(kex_method(hybrid_kex_1, conn, shared_key_1)); + struct s2n_blob *shared_key_1 = &(conn->kex_params.kem_params.shared_secret); + POSIX_GUARD_RESULT(kex_method(hybrid_kex_1, conn, shared_key_1)); const uint32_t end_cursor = *cursor; - gte_check(end_cursor, start_cursor); + POSIX_ENSURE_GTE(end_cursor, start_cursor); client_key_exchange_message->size = end_cursor - start_cursor; - GUARD(s2n_alloc(combined_shared_key, shared_key_0.size + shared_key_1->size)); + POSIX_GUARD(s2n_alloc(combined_shared_key, shared_key_0.size + shared_key_1->size)); struct s2n_stuffer stuffer_combiner = {0}; - GUARD(s2n_stuffer_init(&stuffer_combiner, combined_shared_key)); - GUARD(s2n_stuffer_write(&stuffer_combiner, &shared_key_0)); - GUARD(s2n_stuffer_write(&stuffer_combiner, shared_key_1)); + POSIX_GUARD(s2n_stuffer_init(&stuffer_combiner, combined_shared_key)); + POSIX_GUARD(s2n_stuffer_write(&stuffer_combiner, &shared_key_0)); + POSIX_GUARD(s2n_stuffer_write(&stuffer_combiner, shared_key_1)); - GUARD(s2n_kem_free(&conn->secure.kem_params)); + POSIX_GUARD(s2n_kem_free(&conn->kex_params.kem_params)); return 0; } @@ -81,26 +82,26 @@ static int s2n_hybrid_client_action(struct s2n_connection *conn, struct s2n_blob static int s2n_calculate_keys(struct s2n_connection *conn, struct s2n_blob *shared_key) { /* Turn the pre-master secret into a master secret */ - GUARD_AS_POSIX(s2n_kex_tls_prf(conn->secure.cipher_suite->key_exchange_alg, conn, shared_key)); - /* Erase the pre-master secret */ - GUARD(s2n_blob_zero(shared_key)); - if (shared_key->allocated) { - GUARD(s2n_free(shared_key)); - } + POSIX_GUARD_RESULT(s2n_kex_tls_prf(conn->secure.cipher_suite->key_exchange_alg, conn, shared_key)); + /* Expand the keys */ - GUARD(s2n_prf_key_expansion(conn)); - /* Save the master secret in the cache */ + POSIX_GUARD(s2n_prf_key_expansion(conn)); + /* Save the master secret in the cache. + * Failing to cache the session should not affect the current handshake. + */ if (s2n_allowed_to_cache_connection(conn)) { - GUARD(s2n_store_to_cache(conn)); + s2n_result_ignore(s2n_store_to_cache(conn)); } + /* log the secret, if needed */ + s2n_result_ignore(s2n_key_log_tls12_secret(conn)); return 0; } int s2n_rsa_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shared_key) { /* Set shared_key before async guard to pass the proper shared_key to the caller upon async completion */ - notnull_check(shared_key); - shared_key->data = conn->secure.rsa_premaster_secret; + POSIX_ENSURE_REF(shared_key); + shared_key->data = conn->secrets.tls12.rsa_premaster_secret; shared_key->size = S2N_TLS_SECRET_LEN; S2N_ASYNC_PKEY_GUARD(conn); @@ -112,7 +113,7 @@ int s2n_rsa_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shared if (conn->actual_protocol_version == S2N_SSLv3) { length = s2n_stuffer_data_available(in); } else { - GUARD(s2n_stuffer_read_uint16(in, &length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &length)); } S2N_ERROR_IF(length > s2n_stuffer_data_available(in), S2N_ERR_BAD_MESSAGE); @@ -127,13 +128,13 @@ int s2n_rsa_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shared /* Decrypt the pre-master secret */ struct s2n_blob encrypted = {.size = length, .data = s2n_stuffer_raw_read(in, length)}; - notnull_check(encrypted.data); - gt_check(encrypted.size, 0); + POSIX_ENSURE_REF(encrypted.data); + POSIX_ENSURE_GT(encrypted.size, 0); /* First: use a random pre-master secret */ - GUARD_AS_POSIX(s2n_get_private_random_data(shared_key)); - conn->secure.rsa_premaster_secret[0] = client_hello_protocol_version[0]; - conn->secure.rsa_premaster_secret[1] = client_hello_protocol_version[1]; + POSIX_GUARD_RESULT(s2n_get_private_random_data(shared_key)); + conn->secrets.tls12.rsa_premaster_secret[0] = client_hello_protocol_version[0]; + conn->secrets.tls12.rsa_premaster_secret[1] = client_hello_protocol_version[1]; S2N_ASYNC_PKEY_DECRYPT(conn, &encrypted, shared_key, s2n_rsa_client_key_recv_complete); } @@ -143,9 +144,9 @@ int s2n_rsa_client_key_recv_complete(struct s2n_connection *conn, bool rsa_faile S2N_ERROR_IF(decrypted->size != S2N_TLS_SECRET_LEN, S2N_ERR_SIZE_MISMATCH); /* Avoid copying the same buffer for the case where async pkey is not used */ - if (conn->secure.rsa_premaster_secret != decrypted->data) { + if (conn->secrets.tls12.rsa_premaster_secret != decrypted->data) { /* Copy (maybe) decrypted data into shared key */ - memcpy_check(conn->secure.rsa_premaster_secret, decrypted->data, S2N_TLS_SECRET_LEN); + POSIX_CHECKED_MEMCPY(conn->secrets.tls12.rsa_premaster_secret, decrypted->data, S2N_TLS_SECRET_LEN); } /* Get client hello protocol version for comparison with decrypted data */ @@ -158,7 +159,7 @@ int s2n_rsa_client_key_recv_complete(struct s2n_connection *conn, bool rsa_faile /* Set rsa_failed to true, if it isn't already, if the protocol version isn't what we expect */ conn->handshake.rsa_failed |= !s2n_constant_time_equals(client_hello_protocol_version, - conn->secure.rsa_premaster_secret, S2N_TLS_PROTOCOL_VERSION_LEN); + conn->secrets.tls12.rsa_premaster_secret, S2N_TLS_PROTOCOL_VERSION_LEN); return 0; } @@ -168,9 +169,9 @@ int s2n_dhe_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shared struct s2n_stuffer *in = &conn->handshake.io; /* Get the shared key */ - GUARD(s2n_dh_compute_shared_secret_as_server(&conn->secure.server_dh_params, in, shared_key)); + POSIX_GUARD(s2n_dh_compute_shared_secret_as_server(&conn->kex_params.server_dh_params, in, shared_key)); /* We don't need the server params any more */ - GUARD(s2n_dh_params_free(&conn->secure.server_dh_params)); + POSIX_GUARD(s2n_dh_params_free(&conn->kex_params.server_dh_params)); return 0; } @@ -179,16 +180,16 @@ int s2n_ecdhe_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shar struct s2n_stuffer *in = &conn->handshake.io; /* Get the shared key */ - GUARD(s2n_ecc_evp_compute_shared_secret_as_server(&conn->secure.server_ecc_evp_params, in, shared_key)); + POSIX_GUARD(s2n_ecc_evp_compute_shared_secret_as_server(&conn->kex_params.server_ecc_evp_params, in, shared_key)); /* We don't need the server params any more */ - GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); + POSIX_GUARD(s2n_ecc_evp_params_free(&conn->kex_params.server_ecc_evp_params)); return 0; } int s2n_kem_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shared_key) { /* s2n_kem_recv_ciphertext() writes the KEM shared secret directly to - * conn->secure.kem_params. However, the calling function + * conn->kex_params.kem_params. However, the calling function * likely expects *shared_key to point to the shared secret. We * can't reassign *shared_key to point to kem_params.shared_secret, * because that would require us to take struct s2n_blob **shared_key @@ -197,10 +198,10 @@ int s2n_kem_client_key_recv(struct s2n_connection *conn, struct s2n_blob *shared * * So, we assert that the caller already has *shared_key pointing * to kem_params.shared_secret. */ - notnull_check(shared_key); - S2N_ERROR_IF(shared_key != &(conn->secure.kem_params.shared_secret), S2N_ERR_SAFETY); + POSIX_ENSURE_REF(shared_key); + S2N_ERROR_IF(shared_key != &(conn->kex_params.kem_params.shared_secret), S2N_ERR_SAFETY); - GUARD(s2n_kem_recv_ciphertext(&(conn->handshake.io), &(conn->secure.kem_params))); + POSIX_GUARD(s2n_kem_recv_ciphertext(&(conn->handshake.io), &(conn->kex_params.kem_params))); return 0; } @@ -214,31 +215,30 @@ int s2n_hybrid_client_key_recv(struct s2n_connection *conn, struct s2n_blob *com int s2n_client_key_recv(struct s2n_connection *conn) { const struct s2n_kex *key_exchange = conn->secure.cipher_suite->key_exchange_alg; - struct s2n_blob shared_key = {0}; - - GUARD_AS_POSIX(s2n_kex_client_key_recv(key_exchange, conn, &shared_key)); + DEFER_CLEANUP(struct s2n_blob shared_key = { 0 }, s2n_blob_zeroize_free); + POSIX_GUARD_RESULT(s2n_kex_client_key_recv(key_exchange, conn, &shared_key)); - GUARD(s2n_calculate_keys(conn, &shared_key)); + POSIX_GUARD(s2n_calculate_keys(conn, &shared_key)); return 0; } int s2n_dhe_client_key_send(struct s2n_connection *conn, struct s2n_blob *shared_key) { struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_dh_compute_shared_secret_as_client(&conn->secure.server_dh_params, out, shared_key)); + POSIX_GUARD(s2n_dh_compute_shared_secret_as_client(&conn->kex_params.server_dh_params, out, shared_key)); /* We don't need the server params any more */ - GUARD(s2n_dh_params_free(&conn->secure.server_dh_params)); + POSIX_GUARD(s2n_dh_params_free(&conn->kex_params.server_dh_params)); return 0; } int s2n_ecdhe_client_key_send(struct s2n_connection *conn, struct s2n_blob *shared_key) { struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_ecc_evp_compute_shared_secret_as_client(&conn->secure.server_ecc_evp_params, out, shared_key)); + POSIX_GUARD(s2n_ecc_evp_compute_shared_secret_as_client(&conn->kex_params.server_ecc_evp_params, out, shared_key)); /* We don't need the server params any more */ - GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); + POSIX_GUARD(s2n_ecc_evp_params_free(&conn->kex_params.server_ecc_evp_params)); return 0; } @@ -249,42 +249,42 @@ int s2n_rsa_client_key_send(struct s2n_connection *conn, struct s2n_blob *shared client_hello_protocol_version[0] = legacy_client_hello_protocol_version / 10; client_hello_protocol_version[1] = legacy_client_hello_protocol_version % 10; - shared_key->data = conn->secure.rsa_premaster_secret; + shared_key->data = conn->secrets.tls12.rsa_premaster_secret; shared_key->size = S2N_TLS_SECRET_LEN; - GUARD_AS_POSIX(s2n_get_private_random_data(shared_key)); + POSIX_GUARD_RESULT(s2n_get_private_random_data(shared_key)); /* Over-write the first two bytes with the client hello version, per RFC2246/RFC4346/RFC5246 7.4.7.1. * The latest version supported by client (as seen from the the client hello version) are <= TLS1.2 * for all clients, because TLS 1.3 clients freezes the TLS1.2 legacy version in client hello. */ - memcpy_check(conn->secure.rsa_premaster_secret, client_hello_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN); + POSIX_CHECKED_MEMCPY(conn->secrets.tls12.rsa_premaster_secret, client_hello_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN); uint32_t encrypted_size = 0; - GUARD_AS_POSIX(s2n_pkey_size(&conn->secure.server_public_key, &encrypted_size)); + POSIX_GUARD_RESULT(s2n_pkey_size(&conn->handshake_params.server_public_key, &encrypted_size)); S2N_ERROR_IF(encrypted_size > 0xffff, S2N_ERR_SIZE_MISMATCH); if (conn->actual_protocol_version > S2N_SSLv3) { - GUARD(s2n_stuffer_write_uint16(&conn->handshake.io, encrypted_size)); + POSIX_GUARD(s2n_stuffer_write_uint16(&conn->handshake.io, encrypted_size)); } struct s2n_blob encrypted = {0}; encrypted.data = s2n_stuffer_raw_write(&conn->handshake.io, encrypted_size); encrypted.size = encrypted_size; - notnull_check(encrypted.data); + POSIX_ENSURE_REF(encrypted.data); /* Encrypt the secret and send it on */ - GUARD(s2n_pkey_encrypt(&conn->secure.server_public_key, shared_key, &encrypted)); + POSIX_GUARD(s2n_pkey_encrypt(&conn->handshake_params.server_public_key, shared_key, &encrypted)); /* We don't need the key any more, so free it */ - GUARD(s2n_pkey_free(&conn->secure.server_public_key)); + POSIX_GUARD(s2n_pkey_free(&conn->handshake_params.server_public_key)); return 0; } int s2n_kem_client_key_send(struct s2n_connection *conn, struct s2n_blob *shared_key) { /* s2n_kem_send_ciphertext() writes the KEM shared secret directly to - * conn->secure.kem_params. However, the calling function + * conn->kex_params.kem_params. However, the calling function * likely expects *shared_key to point to the shared secret. We * can't reassign *shared_key to point to kem_params.shared_secret, * because that would require us to take struct s2n_blob **shared_key @@ -293,10 +293,10 @@ int s2n_kem_client_key_send(struct s2n_connection *conn, struct s2n_blob *shared * * So, we assert that the caller already has *shared_key pointing * to kem_params.shared_secret. */ - notnull_check(shared_key); - S2N_ERROR_IF(shared_key != &(conn->secure.kem_params.shared_secret), S2N_ERR_SAFETY); + POSIX_ENSURE_REF(shared_key); + S2N_ERROR_IF(shared_key != &(conn->kex_params.kem_params.shared_secret), S2N_ERR_SAFETY); - GUARD(s2n_kem_send_ciphertext(&(conn->handshake.io), &(conn->secure.kem_params))); + POSIX_GUARD(s2n_kem_send_ciphertext(&(conn->handshake.io), &(conn->kex_params.kem_params))); return 0; } @@ -310,10 +310,10 @@ int s2n_hybrid_client_key_send(struct s2n_connection *conn, struct s2n_blob *com int s2n_client_key_send(struct s2n_connection *conn) { const struct s2n_kex *key_exchange = conn->secure.cipher_suite->key_exchange_alg; - struct s2n_blob shared_key = {0}; + DEFER_CLEANUP(struct s2n_blob shared_key = { 0 }, s2n_blob_zeroize_free); - GUARD_AS_POSIX(s2n_kex_client_key_send(key_exchange, conn, &shared_key)); + POSIX_GUARD_RESULT(s2n_kex_client_key_send(key_exchange, conn, &shared_key)); - GUARD(s2n_calculate_keys(conn, &shared_key)); + POSIX_GUARD(s2n_calculate_keys(conn, &shared_key)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_config.c b/contrib/restricted/aws/s2n/tls/s2n_config.c index db3a8819bc..7c455bb642 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_config.c +++ b/contrib/restricted/aws/s2n/tls/s2n_config.c @@ -22,6 +22,7 @@ #include "crypto/s2n_fips.h" #include "tls/s2n_cipher_preferences.h" +#include "tls/s2n_internal.h" #include "tls/s2n_security_policies.h" #include "tls/s2n_tls13.h" #include "utils/s2n_safety.h" @@ -41,7 +42,7 @@ static int monotonic_clock(void *data, uint64_t *nanoseconds) { struct timespec current_time = {0}; - GUARD(clock_gettime(S2N_CLOCK_HW, ¤t_time)); + POSIX_GUARD(clock_gettime(S2N_CLOCK_HW, ¤t_time)); *nanoseconds = (uint64_t)current_time.tv_sec * 1000000000ull; *nanoseconds += current_time.tv_nsec; @@ -53,7 +54,7 @@ static int wall_clock(void *data, uint64_t *nanoseconds) { struct timespec current_time = {0}; - GUARD(clock_gettime(S2N_CLOCK_SYS, ¤t_time)); + POSIX_GUARD(clock_gettime(S2N_CLOCK_SYS, ¤t_time)); *nanoseconds = (uint64_t)current_time.tv_sec * 1000000000ull; *nanoseconds += current_time.tv_nsec; @@ -67,79 +68,54 @@ static struct s2n_config s2n_default_tls13_config = {0}; static int s2n_config_setup_default(struct s2n_config *config) { - GUARD(s2n_config_set_cipher_preferences(config, "default")); + POSIX_GUARD(s2n_config_set_cipher_preferences(config, "default")); return S2N_SUCCESS; } static int s2n_config_setup_tls13(struct s2n_config *config) { - GUARD(s2n_config_set_cipher_preferences(config, "default_tls13")); + POSIX_GUARD(s2n_config_set_cipher_preferences(config, "default_tls13")); return S2N_SUCCESS; } static int s2n_config_setup_fips(struct s2n_config *config) { - GUARD(s2n_config_set_cipher_preferences(config, "default_fips")); + POSIX_GUARD(s2n_config_set_cipher_preferences(config, "default_fips")); return S2N_SUCCESS; } static int s2n_config_init(struct s2n_config *config) { - config->cert_allocated = 0; - config->dhparams = NULL; - memset(&config->application_protocols, 0, sizeof(config->application_protocols)); config->status_request_type = S2N_STATUS_REQUEST_NONE; config->wall_clock = wall_clock; config->monotonic_clock = monotonic_clock; - config->verify_host = NULL; - config->data_for_verify_host = NULL; - config->client_hello_cb = NULL; - config->client_hello_cb_ctx = NULL; - config->cache_store = NULL; - config->cache_store_data = NULL; - config->cache_retrieve = NULL; - config->cache_retrieve_data = NULL; - config->cache_delete = NULL; - config->cache_delete_data = NULL; config->ct_type = S2N_CT_SUPPORT_NONE; config->mfl_code = S2N_TLS_MAX_FRAG_LEN_EXT_NONE; config->alert_behavior = S2N_ALERT_FAIL_ON_WARNINGS; - config->accept_mfl = 0; config->session_state_lifetime_in_nanos = S2N_STATE_LIFETIME_IN_NANOS; - config->use_tickets = 0; - config->use_session_cache = 0; - config->ticket_keys = NULL; - config->ticket_key_hashes = NULL; config->encrypt_decrypt_key_lifetime_in_nanos = S2N_TICKET_ENCRYPT_DECRYPT_KEY_LIFETIME_IN_NANOS; config->decrypt_key_lifetime_in_nanos = S2N_TICKET_DECRYPT_KEY_LIFETIME_IN_NANOS; - config->quic_enabled = 0; + config->async_pkey_validation_mode = S2N_ASYNC_PKEY_VALIDATION_FAST; /* By default, only the client will authenticate the Server's Certificate. The Server does not request or * authenticate any client certificates. */ config->client_cert_auth_type = S2N_CERT_AUTH_NONE; config->check_ocsp = 1; - config->disable_x509_validation = 0; - config->max_verify_cert_chain_depth = 0; - config->max_verify_cert_chain_depth_set = 0; - config->cert_tiebreak_cb = NULL; - config->async_pkey_cb = NULL; - config->psk_selection_cb = NULL; - config->cert_req_dss_legacy_compat_enabled = 0; - - GUARD(s2n_config_setup_default(config)); + + config->client_hello_cb_mode = S2N_CLIENT_HELLO_CB_BLOCKING; + + POSIX_GUARD(s2n_config_setup_default(config)); if (s2n_use_default_tls13_config()) { - GUARD(s2n_config_setup_tls13(config)); + POSIX_GUARD(s2n_config_setup_tls13(config)); } else if (s2n_is_in_fips_mode()) { - GUARD(s2n_config_setup_fips(config)); + POSIX_GUARD(s2n_config_setup_fips(config)); } - notnull_check(config->domain_name_to_cert_map = s2n_map_new_with_initial_capacity(1)); - GUARD_AS_POSIX(s2n_map_complete(config->domain_name_to_cert_map)); - memset(&config->default_certs_by_type, 0, sizeof(struct certs_by_type)); - config->default_certs_are_explicit = 0; + POSIX_GUARD_PTR(config->domain_name_to_cert_map = s2n_map_new_with_initial_capacity(1)); + POSIX_GUARD_RESULT(s2n_map_complete(config->domain_name_to_cert_map)); s2n_x509_trust_store_init_empty(&config->trust_store); - s2n_x509_trust_store_from_system_defaults(&config->trust_store); + POSIX_GUARD(s2n_x509_trust_store_from_system_defaults(&config->trust_store)); return 0; } @@ -149,11 +125,11 @@ static int s2n_config_cleanup(struct s2n_config *config) s2n_x509_trust_store_wipe(&config->trust_store); config->check_ocsp = 0; - GUARD(s2n_config_free_session_ticket_keys(config)); - GUARD(s2n_config_free_cert_chain_and_key(config)); - GUARD(s2n_config_free_dhparams(config)); - GUARD(s2n_free(&config->application_protocols)); - GUARD_AS_POSIX(s2n_map_free(config->domain_name_to_cert_map)); + POSIX_GUARD(s2n_config_free_session_ticket_keys(config)); + POSIX_GUARD(s2n_config_free_cert_chain_and_key(config)); + POSIX_GUARD(s2n_config_free_dhparams(config)); + POSIX_GUARD(s2n_free(&config->application_protocols)); + POSIX_GUARD_RESULT(s2n_map_free(config->domain_name_to_cert_map)); return 0; } @@ -162,8 +138,8 @@ static int s2n_config_update_domain_name_to_cert_map(struct s2n_config *config, struct s2n_blob *name, struct s2n_cert_chain_and_key *cert_key_pair) { - notnull_check(config); - notnull_check(name); + POSIX_ENSURE_REF(config); + POSIX_ENSURE_REF(name); struct s2n_map *domain_name_to_cert_map = config->domain_name_to_cert_map; /* s2n_map does not allow zero-size key */ @@ -173,16 +149,16 @@ static int s2n_config_update_domain_name_to_cert_map(struct s2n_config *config, s2n_pkey_type cert_type = s2n_cert_chain_and_key_get_pkey_type(cert_key_pair); struct s2n_blob s2n_map_value = { 0 }; bool key_found = false; - GUARD_AS_POSIX(s2n_map_lookup(domain_name_to_cert_map, name, &s2n_map_value, &key_found)); + POSIX_GUARD_RESULT(s2n_map_lookup(domain_name_to_cert_map, name, &s2n_map_value, &key_found)); if (!key_found) { struct certs_by_type value = {{ 0 }}; value.certs[cert_type] = cert_key_pair; s2n_map_value.data = (uint8_t *) &value; s2n_map_value.size = sizeof(struct certs_by_type); - GUARD_AS_POSIX(s2n_map_unlock(domain_name_to_cert_map)); - GUARD_AS_POSIX(s2n_map_add(domain_name_to_cert_map, name, &s2n_map_value)); - GUARD_AS_POSIX(s2n_map_complete(domain_name_to_cert_map)); + POSIX_GUARD_RESULT(s2n_map_unlock(domain_name_to_cert_map)); + POSIX_GUARD_RESULT(s2n_map_add(domain_name_to_cert_map, name, &s2n_map_value)); + POSIX_GUARD_RESULT(s2n_map_complete(domain_name_to_cert_map)); } else { struct certs_by_type *value = (void *) s2n_map_value.data;; if (value->certs[cert_type] == NULL) { @@ -211,21 +187,21 @@ static int s2n_config_build_domain_name_to_cert_map(struct s2n_config *config, s { uint32_t cn_len = 0; - GUARD_AS_POSIX(s2n_array_num_elements(cert_key_pair->cn_names, &cn_len)); + POSIX_GUARD_RESULT(s2n_array_num_elements(cert_key_pair->cn_names, &cn_len)); uint32_t san_len = 0; - GUARD_AS_POSIX(s2n_array_num_elements(cert_key_pair->san_names, &san_len)); + POSIX_GUARD_RESULT(s2n_array_num_elements(cert_key_pair->san_names, &san_len)); if (san_len == 0) { for (uint32_t i = 0; i < cn_len; i++) { struct s2n_blob *cn_name = NULL; - GUARD_AS_POSIX(s2n_array_get(cert_key_pair->cn_names, i, (void **)&cn_name)); - GUARD(s2n_config_update_domain_name_to_cert_map(config, cn_name, cert_key_pair)); + POSIX_GUARD_RESULT(s2n_array_get(cert_key_pair->cn_names, i, (void **)&cn_name)); + POSIX_GUARD(s2n_config_update_domain_name_to_cert_map(config, cn_name, cert_key_pair)); } } else { for (uint32_t i = 0; i < san_len; i++) { struct s2n_blob *san_name = NULL; - GUARD_AS_POSIX(s2n_array_get(cert_key_pair->san_names, i, (void **)&san_name)); - GUARD(s2n_config_update_domain_name_to_cert_map(config, san_name, cert_key_pair)); + POSIX_GUARD_RESULT(s2n_array_get(cert_key_pair->san_names, i, (void **)&san_name)); + POSIX_GUARD(s2n_config_update_domain_name_to_cert_map(config, san_name, cert_key_pair)); } } @@ -255,25 +231,27 @@ int s2n_config_set_unsafe_for_testing(struct s2n_config *config) int s2n_config_defaults_init(void) { - /* Set up default */ - GUARD(s2n_config_init(&s2n_default_config)); - GUARD(s2n_config_setup_default(&s2n_default_config)); - /* Set up fips defaults */ - GUARD(s2n_config_init(&s2n_default_fips_config)); - GUARD(s2n_config_setup_fips(&s2n_default_fips_config)); + if (s2n_is_in_fips_mode()) { + POSIX_GUARD(s2n_config_init(&s2n_default_fips_config)); + POSIX_GUARD(s2n_config_setup_fips(&s2n_default_fips_config)); + } else { + /* Set up default */ + POSIX_GUARD(s2n_config_init(&s2n_default_config)); + POSIX_GUARD(s2n_config_setup_default(&s2n_default_config)); + } /* Set up TLS 1.3 defaults */ - GUARD(s2n_config_init(&s2n_default_tls13_config)); - GUARD(s2n_config_setup_tls13(&s2n_default_tls13_config)); + POSIX_GUARD(s2n_config_init(&s2n_default_tls13_config)); + POSIX_GUARD(s2n_config_setup_tls13(&s2n_default_tls13_config)); return S2N_SUCCESS; } void s2n_wipe_static_configs(void) { - s2n_config_cleanup(&s2n_default_config); s2n_config_cleanup(&s2n_default_fips_config); + s2n_config_cleanup(&s2n_default_config); s2n_config_cleanup(&s2n_default_tls13_config); } @@ -282,7 +260,8 @@ struct s2n_config *s2n_config_new(void) struct s2n_blob allocator = {0}; struct s2n_config *new_config; - GUARD_PTR(s2n_alloc(&allocator, sizeof(struct s2n_config))); + PTR_GUARD_POSIX(s2n_alloc(&allocator, sizeof(struct s2n_config))); + PTR_GUARD_POSIX(s2n_blob_zero(&allocator)); new_config = (struct s2n_config *)(void *)allocator.data; if (s2n_config_init(new_config) != S2N_SUCCESS) { @@ -310,11 +289,11 @@ static int s2n_verify_unique_ticket_key_comparator(const void *a, const void *b) int s2n_config_init_session_ticket_keys(struct s2n_config *config) { if (config->ticket_keys == NULL) { - notnull_check(config->ticket_keys = s2n_set_new(sizeof(struct s2n_ticket_key), s2n_config_store_ticket_key_comparator)); + POSIX_ENSURE_REF(config->ticket_keys = s2n_set_new(sizeof(struct s2n_ticket_key), s2n_config_store_ticket_key_comparator)); } if (config->ticket_key_hashes == NULL) { - notnull_check(config->ticket_key_hashes = s2n_set_new(SHA_DIGEST_LENGTH, s2n_verify_unique_ticket_key_comparator)); + POSIX_ENSURE_REF(config->ticket_key_hashes = s2n_set_new(SHA_DIGEST_LENGTH, s2n_verify_unique_ticket_key_comparator)); } return 0; @@ -323,11 +302,11 @@ int s2n_config_init_session_ticket_keys(struct s2n_config *config) int s2n_config_free_session_ticket_keys(struct s2n_config *config) { if (config->ticket_keys != NULL) { - GUARD_AS_POSIX(s2n_set_free_p(&config->ticket_keys)); + POSIX_GUARD_RESULT(s2n_set_free_p(&config->ticket_keys)); } if (config->ticket_key_hashes != NULL) { - GUARD_AS_POSIX(s2n_set_free_p(&config->ticket_key_hashes)); + POSIX_GUARD_RESULT(s2n_set_free_p(&config->ticket_key_hashes)); } return 0; @@ -349,39 +328,47 @@ int s2n_config_free_cert_chain_and_key(struct s2n_config *config) int s2n_config_free_dhparams(struct s2n_config *config) { if (config->dhparams) { - GUARD(s2n_dh_params_free(config->dhparams)); + POSIX_GUARD(s2n_dh_params_free(config->dhparams)); } - GUARD(s2n_free_object((uint8_t **)&config->dhparams, sizeof(struct s2n_dh_params))); + POSIX_GUARD(s2n_free_object((uint8_t **)&config->dhparams, sizeof(struct s2n_dh_params))); return 0; } +S2N_CLEANUP_RESULT s2n_config_ptr_free(struct s2n_config **config) +{ + RESULT_ENSURE_REF(config); + RESULT_GUARD_POSIX(s2n_config_free(*config)); + *config = NULL; + return S2N_RESULT_OK; +} + int s2n_config_free(struct s2n_config *config) { s2n_config_cleanup(config); - GUARD(s2n_free_object((uint8_t **)&config, sizeof(struct s2n_config))); + POSIX_GUARD(s2n_free_object((uint8_t **)&config, sizeof(struct s2n_config))); return 0; } int s2n_config_get_client_auth_type(struct s2n_config *config, s2n_cert_auth_type *client_auth_type) { - notnull_check(config); - notnull_check(client_auth_type); + POSIX_ENSURE_REF(config); + POSIX_ENSURE_REF(client_auth_type); *client_auth_type = config->client_cert_auth_type; return 0; } int s2n_config_set_client_auth_type(struct s2n_config *config, s2n_cert_auth_type client_auth_type) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->client_cert_auth_type = client_auth_type; return 0; } int s2n_config_set_ct_support_level(struct s2n_config *config, s2n_ct_support_level type) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->ct_type = type; return 0; @@ -389,7 +376,7 @@ int s2n_config_set_ct_support_level(struct s2n_config *config, s2n_ct_support_le int s2n_config_set_alert_behavior(struct s2n_config *config, s2n_alert_behavior alert_behavior) { - notnull_check(config); + POSIX_ENSURE_REF(config); switch (alert_behavior) { case S2N_ALERT_FAIL_ON_WARNINGS: @@ -397,7 +384,7 @@ int s2n_config_set_alert_behavior(struct s2n_config *config, s2n_alert_behavior config->alert_behavior = alert_behavior; break; default: - S2N_ERROR(S2N_ERR_INVALID_ARGUMENT); + POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT); } return 0; @@ -405,7 +392,7 @@ int s2n_config_set_alert_behavior(struct s2n_config *config, s2n_alert_behavior int s2n_config_set_verify_host_callback(struct s2n_config *config, s2n_verify_host_fn verify_host_fn, void *data) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->verify_host = verify_host_fn; config->data_for_verify_host = data; return 0; @@ -413,7 +400,7 @@ int s2n_config_set_verify_host_callback(struct s2n_config *config, s2n_verify_ho int s2n_config_set_check_stapled_ocsp_response(struct s2n_config *config, uint8_t check_ocsp) { - notnull_check(config); + POSIX_ENSURE_REF(config); S2N_ERROR_IF(check_ocsp && !s2n_x509_ocsp_stapling_supported(), S2N_ERR_OCSP_NOT_SUPPORTED); config->check_ocsp = check_ocsp; return 0; @@ -421,7 +408,7 @@ int s2n_config_set_check_stapled_ocsp_response(struct s2n_config *config, uint8_ int s2n_config_disable_x509_verification(struct s2n_config *config) { - notnull_check(config); + POSIX_ENSURE_REF(config); s2n_x509_trust_store_wipe(&config->trust_store); config->disable_x509_validation = 1; return 0; @@ -429,7 +416,7 @@ int s2n_config_disable_x509_verification(struct s2n_config *config) int s2n_config_set_max_cert_chain_depth(struct s2n_config *config, uint16_t max_depth) { - notnull_check(config); + POSIX_ENSURE_REF(config); S2N_ERROR_IF(max_depth == 0, S2N_ERR_INVALID_ARGUMENT); config->max_verify_cert_chain_depth = max_depth; @@ -442,25 +429,34 @@ int s2n_config_set_status_request_type(struct s2n_config *config, s2n_status_req { S2N_ERROR_IF(type == S2N_STATUS_REQUEST_OCSP && !s2n_x509_ocsp_stapling_supported(), S2N_ERR_OCSP_NOT_SUPPORTED); - notnull_check(config); + POSIX_ENSURE_REF(config); config->status_request_type = type; return 0; } +int s2n_config_wipe_trust_store(struct s2n_config *config) +{ + POSIX_ENSURE_REF(config); + + s2n_x509_trust_store_wipe(&config->trust_store); + + return S2N_SUCCESS; +} + int s2n_config_add_pem_to_trust_store(struct s2n_config *config, const char *pem) { - notnull_check(config); - notnull_check(pem); + POSIX_ENSURE_REF(config); + POSIX_ENSURE_REF(pem); - GUARD(s2n_x509_trust_store_add_pem(&config->trust_store, pem)); + POSIX_GUARD(s2n_x509_trust_store_add_pem(&config->trust_store, pem)); return 0; } int s2n_config_set_verification_ca_location(struct s2n_config *config, const char *ca_pem_filename, const char *ca_dir) { - notnull_check(config); + POSIX_ENSURE_REF(config); int err_code = s2n_x509_trust_store_from_ca_file(&config->trust_store, ca_pem_filename, ca_dir); if (!err_code) { @@ -474,9 +470,9 @@ int s2n_config_set_verification_ca_location(struct s2n_config *config, const cha int s2n_config_add_cert_chain_and_key(struct s2n_config *config, const char *cert_chain_pem, const char *private_key_pem) { struct s2n_cert_chain_and_key *chain_and_key; - notnull_check(chain_and_key = s2n_cert_chain_and_key_new()); - GUARD(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain_pem, private_key_pem)); - GUARD(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key)); + POSIX_ENSURE_REF(chain_and_key = s2n_cert_chain_and_key_new()); + POSIX_GUARD(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain_pem, private_key_pem)); + POSIX_GUARD(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key)); config->cert_allocated = 1; return 0; @@ -484,26 +480,30 @@ int s2n_config_add_cert_chain_and_key(struct s2n_config *config, const char *cer int s2n_config_add_cert_chain_and_key_to_store(struct s2n_config *config, struct s2n_cert_chain_and_key *cert_key_pair) { - notnull_check(config->domain_name_to_cert_map); - notnull_check(cert_key_pair); - - GUARD(s2n_config_build_domain_name_to_cert_map(config, cert_key_pair)); + POSIX_ENSURE_REF(config->domain_name_to_cert_map); + POSIX_ENSURE_REF(cert_key_pair); + s2n_pkey_type cert_type = s2n_cert_chain_and_key_get_pkey_type(cert_key_pair); + config->is_rsa_cert_configured |= (cert_type == S2N_PKEY_TYPE_RSA); + POSIX_GUARD(s2n_config_build_domain_name_to_cert_map(config, cert_key_pair)); if (!config->default_certs_are_explicit) { /* Attempt to auto set default based on ordering. ie: first RSA cert is the default, first ECDSA cert is the * default, etc. */ - s2n_pkey_type cert_type = s2n_cert_chain_and_key_get_pkey_type(cert_key_pair); if (config->default_certs_by_type.certs[cert_type] == NULL) { config->default_certs_by_type.certs[cert_type] = cert_key_pair; } } - return 0; + if (s2n_pkey_check_key_exists(cert_key_pair->private_key) != S2N_SUCCESS) { + config->no_signing_key = true; + } + + return S2N_SUCCESS; } int s2n_config_set_async_pkey_callback(struct s2n_config *config, s2n_async_pkey_fn fn) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->async_pkey_cb = fn; @@ -512,7 +512,7 @@ int s2n_config_set_async_pkey_callback(struct s2n_config *config, s2n_async_pkey int s2n_config_clear_default_certificates(struct s2n_config *config) { - notnull_check(config); + POSIX_ENSURE_REF(config); for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { config->default_certs_by_type.certs[i] = NULL; } @@ -523,23 +523,24 @@ int s2n_config_set_cert_chain_and_key_defaults(struct s2n_config *config, struct s2n_cert_chain_and_key **cert_key_pairs, uint32_t num_cert_key_pairs) { - notnull_check(config); - notnull_check(cert_key_pairs); + POSIX_ENSURE_REF(config); + POSIX_ENSURE_REF(cert_key_pairs); S2N_ERROR_IF(num_cert_key_pairs < 1 || num_cert_key_pairs > S2N_CERT_TYPE_COUNT, S2N_ERR_NUM_DEFAULT_CERTIFICATES); /* Validate certs being set before clearing auto-chosen defaults or previously set defaults */ struct certs_by_type new_defaults = {{ 0 }}; - for (int i = 0; i < num_cert_key_pairs; i++) { - notnull_check(cert_key_pairs[i]); + for (uint32_t i = 0; i < num_cert_key_pairs; i++) { + POSIX_ENSURE_REF(cert_key_pairs[i]); s2n_pkey_type cert_type = s2n_cert_chain_and_key_get_pkey_type(cert_key_pairs[i]); S2N_ERROR_IF(new_defaults.certs[cert_type] != NULL, S2N_ERR_MULTIPLE_DEFAULT_CERTIFICATES_PER_AUTH_TYPE); new_defaults.certs[cert_type] = cert_key_pairs[i]; } - GUARD(s2n_config_clear_default_certificates(config)); - for (int i = 0; i < num_cert_key_pairs; i++) { + POSIX_GUARD(s2n_config_clear_default_certificates(config)); + for (uint32_t i = 0; i < num_cert_key_pairs; i++) { s2n_pkey_type cert_type = s2n_cert_chain_and_key_get_pkey_type(cert_key_pairs[i]); + config->is_rsa_cert_configured |= (cert_type == S2N_PKEY_TYPE_RSA); config->default_certs_by_type.certs[cert_type] = cert_key_pairs[i]; } @@ -555,7 +556,7 @@ int s2n_config_add_dhparams(struct s2n_config *config, const char *dhparams_pem) struct s2n_blob mem = {0}; /* Allocate the memory for the chain and key struct */ - GUARD(s2n_alloc(&mem, sizeof(struct s2n_dh_params))); + POSIX_GUARD(s2n_alloc(&mem, sizeof(struct s2n_dh_params))); config->dhparams = (struct s2n_dh_params *)(void *)mem.data; if (s2n_stuffer_alloc_ro_from_string(&dhparams_in_stuffer, dhparams_pem) != S2N_SUCCESS) { @@ -568,20 +569,20 @@ int s2n_config_add_dhparams(struct s2n_config *config, const char *dhparams_pem) } /* Convert pem to asn1 and asn1 to the private key */ - GUARD(s2n_stuffer_dhparams_from_pem(&dhparams_in_stuffer, &dhparams_out_stuffer)); + POSIX_GUARD(s2n_stuffer_dhparams_from_pem(&dhparams_in_stuffer, &dhparams_out_stuffer)); dhparams_blob.size = s2n_stuffer_data_available(&dhparams_out_stuffer); dhparams_blob.data = s2n_stuffer_raw_read(&dhparams_out_stuffer, dhparams_blob.size); - notnull_check(dhparams_blob.data); + POSIX_ENSURE_REF(dhparams_blob.data); - GUARD(s2n_pkcs3_to_dh_params(config->dhparams, &dhparams_blob)); + POSIX_GUARD(s2n_pkcs3_to_dh_params(config->dhparams, &dhparams_blob)); return 0; } extern int s2n_config_set_wall_clock(struct s2n_config *config, s2n_clock_time_nanoseconds clock_fn, void *ctx) { - notnull_check(clock_fn); + POSIX_ENSURE_REF(clock_fn); config->wall_clock = clock_fn; config->sys_clock_ctx = ctx; @@ -591,7 +592,7 @@ extern int s2n_config_set_wall_clock(struct s2n_config *config, s2n_clock_time_n extern int s2n_config_set_monotonic_clock(struct s2n_config *config, s2n_clock_time_nanoseconds clock_fn, void *ctx) { - notnull_check(clock_fn); + POSIX_ENSURE_REF(clock_fn); config->monotonic_clock = clock_fn; config->monotonic_clock_ctx = ctx; @@ -601,7 +602,7 @@ extern int s2n_config_set_monotonic_clock(struct s2n_config *config, s2n_clock_t int s2n_config_set_cache_store_callback(struct s2n_config *config, s2n_cache_store_callback cache_store_callback, void *data) { - notnull_check(cache_store_callback); + POSIX_ENSURE_REF(cache_store_callback); config->cache_store = cache_store_callback; config->cache_store_data = data; @@ -611,7 +612,7 @@ int s2n_config_set_cache_store_callback(struct s2n_config *config, s2n_cache_sto int s2n_config_set_cache_retrieve_callback(struct s2n_config *config, s2n_cache_retrieve_callback cache_retrieve_callback, void *data) { - notnull_check(cache_retrieve_callback); + POSIX_ENSURE_REF(cache_retrieve_callback); config->cache_retrieve = cache_retrieve_callback; config->cache_retrieve_data = data; @@ -621,7 +622,7 @@ int s2n_config_set_cache_retrieve_callback(struct s2n_config *config, s2n_cache_ int s2n_config_set_cache_delete_callback(struct s2n_config *config, s2n_cache_delete_callback cache_delete_callback, void *data) { - notnull_check(cache_delete_callback); + POSIX_ENSURE_REF(cache_delete_callback); config->cache_delete = cache_delete_callback; config->cache_delete_data = data; @@ -631,25 +632,25 @@ int s2n_config_set_cache_delete_callback(struct s2n_config *config, s2n_cache_de int s2n_config_set_extension_data(struct s2n_config *config, s2n_tls_extension_type type, const uint8_t *data, uint32_t length) { - notnull_check(config); + POSIX_ENSURE_REF(config); if (s2n_config_get_num_default_certs(config) == 0) { - S2N_ERROR(S2N_ERR_UPDATING_EXTENSION); + POSIX_BAIL(S2N_ERR_UPDATING_EXTENSION); } struct s2n_cert_chain_and_key *config_chain_and_key = s2n_config_get_single_default_cert(config); - notnull_check(config_chain_and_key); + POSIX_ENSURE_REF(config_chain_and_key); switch (type) { case S2N_EXTENSION_CERTIFICATE_TRANSPARENCY: { - GUARD(s2n_cert_chain_and_key_set_sct_list(config_chain_and_key, data, length)); + POSIX_GUARD(s2n_cert_chain_and_key_set_sct_list(config_chain_and_key, data, length)); } break; case S2N_EXTENSION_OCSP_STAPLING: { - GUARD(s2n_cert_chain_and_key_set_ocsp_data(config_chain_and_key, data, length)); + POSIX_GUARD(s2n_cert_chain_and_key_set_ocsp_data(config_chain_and_key, data, length)); } break; default: - S2N_ERROR(S2N_ERR_UNRECOGNIZED_EXTENSION); + POSIX_BAIL(S2N_ERR_UNRECOGNIZED_EXTENSION); } return 0; @@ -657,15 +658,26 @@ int s2n_config_set_extension_data(struct s2n_config *config, s2n_tls_extension_t int s2n_config_set_client_hello_cb(struct s2n_config *config, s2n_client_hello_fn client_hello_cb, void *ctx) { + POSIX_ENSURE_REF(config); + config->client_hello_cb = client_hello_cb; config->client_hello_cb_ctx = ctx; - return 0; } +int s2n_config_set_client_hello_cb_mode(struct s2n_config *config, s2n_client_hello_cb_mode cb_mode) +{ + POSIX_ENSURE_REF(config); + POSIX_ENSURE(cb_mode == S2N_CLIENT_HELLO_CB_BLOCKING || + cb_mode == S2N_CLIENT_HELLO_CB_NONBLOCKING, S2N_ERR_INVALID_STATE); + + config->client_hello_cb_mode = cb_mode; + return S2N_SUCCESS; +} + int s2n_config_send_max_fragment_length(struct s2n_config *config, s2n_max_frag_len mfl_code) { - notnull_check(config); + POSIX_ENSURE_REF(config); S2N_ERROR_IF(mfl_code > S2N_TLS_MAX_FRAG_LEN_4096, S2N_ERR_INVALID_MAX_FRAG_LEN); @@ -676,7 +688,7 @@ int s2n_config_send_max_fragment_length(struct s2n_config *config, s2n_max_frag_ int s2n_config_accept_max_fragment_length(struct s2n_config *config) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->accept_mfl = 1; @@ -686,7 +698,7 @@ int s2n_config_accept_max_fragment_length(struct s2n_config *config) int s2n_config_set_session_state_lifetime(struct s2n_config *config, uint64_t lifetime_in_secs) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->session_state_lifetime_in_nanos = (lifetime_in_secs * ONE_SEC_IN_NANOS); return 0; @@ -694,7 +706,7 @@ int s2n_config_set_session_state_lifetime(struct s2n_config *config, int s2n_config_set_session_tickets_onoff(struct s2n_config *config, uint8_t enabled) { - notnull_check(config); + POSIX_ENSURE_REF(config); if (config->use_tickets == enabled) { return 0; @@ -702,11 +714,18 @@ int s2n_config_set_session_tickets_onoff(struct s2n_config *config, uint8_t enab config->use_tickets = enabled; + if (config->initial_tickets_to_send == 0) { + /* Normally initial_tickets_to_send is set via s2n_config_set_initial_ticket_count. + * However, s2n_config_set_initial_ticket_count calls this method. + * So we set initial_tickets_to_send directly to avoid infinite recursion. */ + config->initial_tickets_to_send = 1; + } + /* session ticket || session id is enabled */ if (enabled) { - GUARD(s2n_config_init_session_ticket_keys(config)); + POSIX_GUARD(s2n_config_init_session_ticket_keys(config)); } else if (!config->use_session_cache) { - GUARD(s2n_config_free_session_ticket_keys(config)); + POSIX_GUARD(s2n_config_free_session_ticket_keys(config)); } return 0; @@ -714,14 +733,14 @@ int s2n_config_set_session_tickets_onoff(struct s2n_config *config, uint8_t enab int s2n_config_set_session_cache_onoff(struct s2n_config *config, uint8_t enabled) { - notnull_check(config); + POSIX_ENSURE_REF(config); if (enabled && config->cache_store && config->cache_retrieve && config->cache_delete) { - GUARD(s2n_config_init_session_ticket_keys(config)); + POSIX_GUARD(s2n_config_init_session_ticket_keys(config)); config->use_session_cache = 1; } else { if (!config->use_tickets) { - GUARD(s2n_config_free_session_ticket_keys(config)); + POSIX_GUARD(s2n_config_free_session_ticket_keys(config)); } config->use_session_cache = 0; } @@ -731,7 +750,7 @@ int s2n_config_set_session_cache_onoff(struct s2n_config *config, uint8_t enable int s2n_config_set_ticket_encrypt_decrypt_key_lifetime(struct s2n_config *config, uint64_t lifetime_in_secs) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->encrypt_decrypt_key_lifetime_in_nanos = (lifetime_in_secs * ONE_SEC_IN_NANOS); return 0; @@ -740,7 +759,7 @@ int s2n_config_set_ticket_encrypt_decrypt_key_lifetime(struct s2n_config *config int s2n_config_set_ticket_decrypt_key_lifetime(struct s2n_config *config, uint64_t lifetime_in_secs) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->decrypt_key_lifetime_in_nanos = (lifetime_in_secs * ONE_SEC_IN_NANOS); return 0; @@ -751,21 +770,21 @@ int s2n_config_add_ticket_crypto_key(struct s2n_config *config, uint8_t *key, uint32_t key_len, uint64_t intro_time_in_seconds_from_epoch) { - notnull_check(config); - notnull_check(name); - notnull_check(key); + 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; } - GUARD(s2n_config_wipe_expired_ticket_crypto_keys(config, -1)); + POSIX_GUARD(s2n_config_wipe_expired_ticket_crypto_keys(config, -1)); S2N_ERROR_IF(key_len == 0, S2N_ERR_INVALID_TICKET_KEY_LENGTH); uint32_t ticket_keys_len = 0; - GUARD_AS_POSIX(s2n_set_len(config->ticket_keys, &ticket_keys_len)); + POSIX_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len)); S2N_ERROR_IF(ticket_keys_len >= S2N_MAX_TICKET_KEYS, S2N_ERR_TICKET_KEY_LIMIT); S2N_ERROR_IF(name_len == 0 || name_len > S2N_TICKET_KEY_NAME_LEN || s2n_find_ticket_key(config, name), S2N_ERR_INVALID_TICKET_KEY_NAME_OR_NAME_LENGTH); @@ -778,45 +797,45 @@ int s2n_config_add_ticket_crypto_key(struct s2n_config *config, struct s2n_ticket_key *session_ticket_key; DEFER_CLEANUP(struct s2n_blob allocator = {0}, s2n_free); - GUARD(s2n_alloc(&allocator, sizeof(struct s2n_ticket_key))); + 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); - GUARD(s2n_hmac_new(&hmac)); - GUARD(s2n_hkdf(&hmac, S2N_HMAC_SHA256, &salt, &in_key, &info, &out_key)); + POSIX_GUARD(s2n_hmac_new(&hmac)); + POSIX_GUARD(s2n_hkdf(&hmac, S2N_HMAC_SHA256, &salt, &in_key, &info, &out_key)); DEFER_CLEANUP(struct s2n_hash_state hash = {0}, s2n_hash_free); uint8_t hash_output[SHA_DIGEST_LENGTH]; - GUARD(s2n_hash_new(&hash)); - GUARD(s2n_hash_init(&hash, S2N_HASH_SHA1)); - GUARD(s2n_hash_update(&hash, out_key.data, out_key.size)); - GUARD(s2n_hash_digest(&hash, hash_output, SHA_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_new(&hash)); + POSIX_GUARD(s2n_hash_init(&hash, S2N_HASH_SHA1)); + POSIX_GUARD(s2n_hash_update(&hash, out_key.data, out_key.size)); + POSIX_GUARD(s2n_hash_digest(&hash, hash_output, SHA_DIGEST_LENGTH)); - GUARD_AS_POSIX(s2n_set_len(config->ticket_keys, &ticket_keys_len)); + POSIX_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len)); if (ticket_keys_len >= S2N_MAX_TICKET_KEY_HASHES) { - GUARD_AS_POSIX(s2n_set_free_p(&config->ticket_key_hashes)); - notnull_check(config->ticket_key_hashes = s2n_set_new(SHA_DIGEST_LENGTH, s2n_verify_unique_ticket_key_comparator)); + POSIX_GUARD_RESULT(s2n_set_free_p(&config->ticket_key_hashes)); + POSIX_ENSURE_REF(config->ticket_key_hashes = s2n_set_new(SHA_DIGEST_LENGTH, s2n_verify_unique_ticket_key_comparator)); } /* Insert hash key into a sorted array at known index */ - GUARD_AS_POSIX(s2n_set_add(config->ticket_key_hashes, hash_output)); + POSIX_GUARD_RESULT(s2n_set_add(config->ticket_key_hashes, hash_output)); - memcpy_check(session_ticket_key->key_name, name, S2N_TICKET_KEY_NAME_LEN); - memcpy_check(session_ticket_key->aes_key, out_key.data, S2N_AES256_KEY_LEN); + POSIX_CHECKED_MEMCPY(session_ticket_key->key_name, name, S2N_TICKET_KEY_NAME_LEN); + POSIX_CHECKED_MEMCPY(session_ticket_key->aes_key, out_key.data, S2N_AES256_KEY_LEN); out_key.data = output_pad + S2N_AES256_KEY_LEN; - memcpy_check(session_ticket_key->implicit_aad, out_key.data, S2N_TICKET_AAD_IMPLICIT_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; - GUARD(config->wall_clock(config->sys_clock_ctx, &now)); + POSIX_GUARD(config->wall_clock(config->sys_clock_ctx, &now)); session_ticket_key->intro_timestamp = now; } else { session_ticket_key->intro_timestamp = (intro_time_in_seconds_from_epoch * ONE_SEC_IN_NANOS); } - GUARD(s2n_config_store_ticket_key(config, session_ticket_key)); + POSIX_GUARD(s2n_config_store_ticket_key(config, session_ticket_key)); return 0; } @@ -829,7 +848,7 @@ int s2n_config_set_cert_tiebreak_callback(struct s2n_config *config, s2n_cert_ti struct s2n_cert_chain_and_key *s2n_config_get_single_default_cert(struct s2n_config *config) { - notnull_check_ptr(config); + PTR_ENSURE_REF(config); struct s2n_cert_chain_and_key *cert = NULL; for (int i = S2N_CERT_TYPE_COUNT - 1; i >= 0; i--) { @@ -842,7 +861,7 @@ struct s2n_cert_chain_and_key *s2n_config_get_single_default_cert(struct s2n_con int s2n_config_get_num_default_certs(struct s2n_config *config) { - notnull_check(config); + POSIX_ENSURE_REF(config); int num_certs = 0; for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { if (config->default_certs_by_type.certs[i] != NULL) { @@ -855,17 +874,67 @@ int s2n_config_get_num_default_certs(struct s2n_config *config) int s2n_config_enable_cert_req_dss_legacy_compat(struct s2n_config *config) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->cert_req_dss_legacy_compat_enabled = 1; return S2N_SUCCESS; } -int s2n_config_set_psk_selection_callback(struct s2n_connection *conn, s2n_psk_selection_callback cb) +int s2n_config_set_psk_selection_callback(struct s2n_config *config, s2n_psk_selection_callback cb, void *context) { - notnull_check(conn); - notnull_check(cb); + POSIX_ENSURE_REF(config); + config->psk_selection_cb = cb; + config->psk_selection_ctx = context; + return S2N_SUCCESS; +} + +int s2n_config_set_key_log_cb(struct s2n_config *config, s2n_key_log_fn callback, void *ctx) { + POSIX_ENSURE_MUT(config); + + config->key_log_cb = callback; + config->key_log_ctx = ctx; + + return S2N_SUCCESS; +} + +int s2n_config_set_async_pkey_validation_mode(struct s2n_config *config, s2n_async_pkey_validation_mode mode) { + POSIX_ENSURE_REF(config); + + switch(mode) { + case S2N_ASYNC_PKEY_VALIDATION_FAST: + case S2N_ASYNC_PKEY_VALIDATION_STRICT: + config->async_pkey_validation_mode = mode; + return S2N_SUCCESS; + } + + POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT); +} + +int s2n_config_set_ctx(struct s2n_config *config, void *ctx) { + POSIX_ENSURE_REF(config); + + config->context = ctx; + + return S2N_SUCCESS; +} + +int s2n_config_get_ctx(struct s2n_config *config, void **ctx) { + POSIX_ENSURE_REF(config); + POSIX_ENSURE_REF(ctx); + + *ctx = config->context; + + return S2N_SUCCESS; +} + +/* + * Set the client_hello callback behavior to polling. + * + * Polling means that the callback function can be called multiple times. + */ +int s2n_config_client_hello_cb_enable_poll(struct s2n_config *config) { + POSIX_ENSURE_REF(config); - conn->config->psk_selection_cb = cb; + config->client_hello_cb_enable_poll = 1; return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_config.h b/contrib/restricted/aws/s2n/tls/s2n_config.h index c5edf02418..c0068ce133 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_config.h +++ b/contrib/restricted/aws/s2n/tls/s2n_config.h @@ -18,11 +18,11 @@ #include "api/s2n.h" #include "crypto/s2n_certificate.h" #include "crypto/s2n_dhe.h" +#include "tls/s2n_psk.h" #include "tls/s2n_resume.h" #include "tls/s2n_x509_validator.h" #include "utils/s2n_blob.h" #include "utils/s2n_set.h" -#include "tls/s2n_psk.h" #define S2N_MAX_TICKET_KEYS 48 #define S2N_MAX_TICKET_KEY_HASHES 500 /* 10KB */ @@ -30,21 +30,37 @@ struct s2n_cipher_preferences; struct s2n_config { + unsigned use_tickets:1; + + /* Whether a connection can be used by a QUIC implementation. + * See s2n_quic_support.h */ + unsigned quic_enabled:1; + unsigned cert_allocated:1; unsigned default_certs_are_explicit:1; - unsigned use_tickets:1; unsigned use_session_cache:1; /* if this is FALSE, server will ignore client's Maximum Fragment Length request */ unsigned accept_mfl:1; unsigned check_ocsp:1; unsigned disable_x509_validation:1; unsigned max_verify_cert_chain_depth_set:1; - /* Whether a connection can be used by a QUIC implementation. - * See s2n_quic_support.h */ - unsigned quic_enabled:1; /* Whether to add dss cert type during a server certificate request. - * See https://github.com/awslabs/s2n/blob/main/docs/USAGE-GUIDE.md */ + * See https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md */ unsigned cert_req_dss_legacy_compat_enabled:1; + /* Whether any RSA certificates have been configured server-side to send to clients. This is needed so that the + * server knows whether or not to self-downgrade to TLS 1.2 if the server is compiled with Openssl 1.0.2 and does + * not support RSA PSS signing (which is required for TLS 1.3). */ + unsigned is_rsa_cert_configured:1; + /* It's possible to use a certificate without loading the private key, + * but async signing must be enabled. Use this flag to enforce that restriction. + */ + unsigned no_signing_key:1; + /* + * This option exists to allow for polling the client_hello callback. + * + * Note: This defaults to false to ensure backwards compatibility. + */ + unsigned client_hello_cb_enable_poll:1; struct s2n_dh_params *dhparams; /* Needed until we can deprecate s2n_config_add_cert_chain_and_key. This is @@ -63,6 +79,8 @@ struct s2n_config { void *monotonic_clock_ctx; s2n_client_hello_fn *client_hello_cb; + s2n_client_hello_cb_mode client_hello_cb_mode; + void *client_hello_cb_ctx; uint64_t session_state_lifetime_in_nanos; @@ -98,13 +116,36 @@ struct s2n_config { uint8_t mfl_code; + uint8_t initial_tickets_to_send; + struct s2n_x509_trust_store trust_store; uint16_t max_verify_cert_chain_depth; s2n_async_pkey_fn async_pkey_cb; + s2n_psk_selection_callback psk_selection_cb; + void *psk_selection_ctx; + + s2n_key_log_fn key_log_cb; + void *key_log_ctx; + + s2n_session_ticket_fn session_ticket_cb; + void *session_ticket_ctx; + + s2n_early_data_cb early_data_cb; + + uint32_t server_max_early_data_size; + + s2n_psk_mode psk_mode; + + s2n_async_pkey_validation_mode async_pkey_validation_mode; + + /* The user defined context associated with config */ + void *context; }; +S2N_CLEANUP_RESULT s2n_config_ptr_free(struct s2n_config **config); + int s2n_config_defaults_init(void); extern struct s2n_config *s2n_fetch_default_config(void); int s2n_config_set_unsafe_for_testing(struct s2n_config *config); diff --git a/contrib/restricted/aws/s2n/tls/s2n_connection.c b/contrib/restricted/aws/s2n/tls/s2n_connection.c index f2393fd2a1..cf6334164f 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_connection.c +++ b/contrib/restricted/aws/s2n/tls/s2n_connection.c @@ -19,8 +19,9 @@ #include <strings.h> #include <time.h> #include <unistd.h> +#include <sys/param.h> -#include <s2n.h> +#include "api/s2n.h" #include <stdbool.h> #include "crypto/s2n_fips.h" @@ -34,6 +35,7 @@ #include "tls/s2n_connection_evp_digests.h" #include "tls/s2n_handshake.h" #include "tls/s2n_kem.h" +#include "tls/s2n_internal.h" #include "tls/s2n_prf.h" #include "tls/s2n_record.h" #include "tls/s2n_resume.h" @@ -43,6 +45,8 @@ #include "crypto/s2n_certificate.h" #include "crypto/s2n_cipher.h" +#include "crypto/s2n_crypto.h" +#include "crypto/s2n_openssl_x509.h" #include "utils/s2n_blob.h" #include "utils/s2n_compiler.h" @@ -55,83 +59,13 @@ #define S2N_SET_KEY_SHARE_LIST_EMPTY(keyshares) (keyshares |= 1) #define S2N_SET_KEY_SHARE_REQUEST(keyshares, i) (keyshares |= ( 1 << ( i + 1 ))) -static int s2n_connection_new_hashes(struct s2n_connection *conn) -{ - /* Allocate long-term memory for the Connection's hash states */ - GUARD(s2n_hash_new(&conn->handshake.md5)); - GUARD(s2n_hash_new(&conn->handshake.sha1)); - GUARD(s2n_hash_new(&conn->handshake.sha224)); - GUARD(s2n_hash_new(&conn->handshake.sha256)); - GUARD(s2n_hash_new(&conn->handshake.sha384)); - GUARD(s2n_hash_new(&conn->handshake.sha512)); - GUARD(s2n_hash_new(&conn->handshake.md5_sha1)); - GUARD(s2n_hash_new(&conn->handshake.ccv_hash_copy)); - GUARD(s2n_hash_new(&conn->handshake.prf_md5_hash_copy)); - GUARD(s2n_hash_new(&conn->handshake.prf_sha1_hash_copy)); - GUARD(s2n_hash_new(&conn->handshake.prf_tls12_hash_copy)); - GUARD(s2n_hash_new(&conn->handshake.server_finished_copy)); - GUARD(s2n_hash_new(&conn->prf_space.ssl3.md5)); - GUARD(s2n_hash_new(&conn->prf_space.ssl3.sha1)); - GUARD(s2n_hash_new(&conn->initial.signature_hash)); - GUARD(s2n_hash_new(&conn->secure.signature_hash)); - - return 0; -} - -static int s2n_connection_init_hashes(struct s2n_connection *conn) -{ - /* Initialize all of the Connection's hash states */ - - if (s2n_hash_is_available(S2N_HASH_MD5)) { - /* Only initialize hashes that use MD5 if available. */ - GUARD(s2n_hash_init(&conn->prf_space.ssl3.md5, S2N_HASH_MD5)); - } - - - /* Allow MD5 for hash states that are used by the PRF. This is required - * to comply with the TLS 1.0 and 1.1 RFCs and is approved as per - * NIST Special Publication 800-52 Revision 1. - */ - if (s2n_is_in_fips_mode()) { - GUARD(s2n_hash_allow_md5_for_fips(&conn->handshake.md5)); - GUARD(s2n_hash_allow_md5_for_fips(&conn->handshake.prf_md5_hash_copy)); - - /* Do not check s2n_hash_is_available before initialization. Allow MD5 and - * SHA-1 for both fips and non-fips mode. This is required to perform the - * signature checks in the CertificateVerify message in TLS 1.0 and TLS 1.1. - * This is approved per Nist SP 800-52r1.*/ - GUARD(s2n_hash_allow_md5_for_fips(&conn->handshake.md5_sha1)); - } - - GUARD(s2n_hash_init(&conn->handshake.md5, S2N_HASH_MD5)); - GUARD(s2n_hash_init(&conn->handshake.prf_md5_hash_copy, S2N_HASH_MD5)); - GUARD(s2n_hash_init(&conn->handshake.md5_sha1, S2N_HASH_MD5_SHA1)); - - GUARD(s2n_hash_init(&conn->handshake.sha1, S2N_HASH_SHA1)); - GUARD(s2n_hash_init(&conn->handshake.sha224, S2N_HASH_SHA224)); - GUARD(s2n_hash_init(&conn->handshake.sha256, S2N_HASH_SHA256)); - GUARD(s2n_hash_init(&conn->handshake.sha384, S2N_HASH_SHA384)); - GUARD(s2n_hash_init(&conn->handshake.sha512, S2N_HASH_SHA512)); - GUARD(s2n_hash_init(&conn->handshake.ccv_hash_copy, S2N_HASH_NONE)); - GUARD(s2n_hash_init(&conn->handshake.prf_tls12_hash_copy, S2N_HASH_NONE)); - GUARD(s2n_hash_init(&conn->handshake.server_finished_copy, S2N_HASH_NONE)); - GUARD(s2n_hash_init(&conn->handshake.prf_sha1_hash_copy, S2N_HASH_SHA1)); - GUARD(s2n_hash_init(&conn->prf_space.ssl3.sha1, S2N_HASH_SHA1)); - GUARD(s2n_hash_init(&conn->initial.signature_hash, S2N_HASH_NONE)); - GUARD(s2n_hash_init(&conn->secure.signature_hash, S2N_HASH_NONE)); - - return 0; -} - static int s2n_connection_new_hmacs(struct s2n_connection *conn) { /* Allocate long-term memory for the Connection's HMAC states */ - GUARD(s2n_hmac_new(&conn->initial.client_record_mac)); - GUARD(s2n_hmac_new(&conn->initial.server_record_mac)); - GUARD(s2n_hmac_new(&conn->initial.record_mac_copy_workspace)); - GUARD(s2n_hmac_new(&conn->secure.client_record_mac)); - GUARD(s2n_hmac_new(&conn->secure.server_record_mac)); - GUARD(s2n_hmac_new(&conn->secure.record_mac_copy_workspace)); + POSIX_GUARD(s2n_hmac_new(&conn->initial.client_record_mac)); + POSIX_GUARD(s2n_hmac_new(&conn->initial.server_record_mac)); + POSIX_GUARD(s2n_hmac_new(&conn->secure.client_record_mac)); + POSIX_GUARD(s2n_hmac_new(&conn->secure.server_record_mac)); return 0; } @@ -139,107 +73,92 @@ static int s2n_connection_new_hmacs(struct s2n_connection *conn) static int s2n_connection_init_hmacs(struct s2n_connection *conn) { /* Initialize all of the Connection's HMAC states */ - GUARD(s2n_hmac_init(&conn->initial.client_record_mac, S2N_HMAC_NONE, NULL, 0)); - GUARD(s2n_hmac_init(&conn->initial.server_record_mac, S2N_HMAC_NONE, NULL, 0)); - GUARD(s2n_hmac_init(&conn->initial.record_mac_copy_workspace, S2N_HMAC_NONE, NULL, 0)); - GUARD(s2n_hmac_init(&conn->secure.client_record_mac, S2N_HMAC_NONE, NULL, 0)); - GUARD(s2n_hmac_init(&conn->secure.server_record_mac, S2N_HMAC_NONE, NULL, 0)); - GUARD(s2n_hmac_init(&conn->secure.record_mac_copy_workspace, S2N_HMAC_NONE, NULL, 0)); + POSIX_GUARD(s2n_hmac_init(&conn->initial.client_record_mac, S2N_HMAC_NONE, NULL, 0)); + POSIX_GUARD(s2n_hmac_init(&conn->initial.server_record_mac, S2N_HMAC_NONE, NULL, 0)); + POSIX_GUARD(s2n_hmac_init(&conn->secure.client_record_mac, S2N_HMAC_NONE, NULL, 0)); + POSIX_GUARD(s2n_hmac_init(&conn->secure.server_record_mac, S2N_HMAC_NONE, NULL, 0)); return 0; } +/* Allocates and initializes memory for a new connection. + * + * Since customers can reuse a connection, ensure that values on the connection are + * initialized in `s2n_connection_wipe` where possible. */ struct s2n_connection *s2n_connection_new(s2n_mode mode) { struct s2n_blob blob = {0}; - GUARD_PTR(s2n_alloc(&blob, sizeof(struct s2n_connection))); - GUARD_PTR(s2n_blob_zero(&blob)); + PTR_GUARD_POSIX(s2n_alloc(&blob, sizeof(struct s2n_connection))); + PTR_GUARD_POSIX(s2n_blob_zero(&blob)); /* Cast 'through' void to acknowledge that we are changing alignment, * which is ok, as blob.data is always aligned. */ struct s2n_connection* conn = (struct s2n_connection *)(void *)blob.data; - GUARD_PTR(s2n_connection_set_config(conn, s2n_fetch_default_config())); + PTR_GUARD_POSIX(s2n_connection_set_config(conn, s2n_fetch_default_config())); + /* `mode` is initialized here since its passed in as a parameter. */ conn->mode = mode; - conn->blinding = S2N_BUILT_IN_BLINDING; - conn->close_notify_queued = 0; - conn->client_session_resumed = 0; - conn->session_id_len = 0; - conn->verify_host_fn = NULL; - conn->data_for_verify_host = NULL; - conn->verify_host_fn_overridden = 0; - conn->data_for_verify_host = NULL; - conn->send = NULL; - conn->recv = NULL; - conn->send_io_context = NULL; - conn->recv_io_context = NULL; - conn->managed_io = 0; - conn->corked_io = 0; - conn->context = NULL; - conn->security_policy_override = NULL; - conn->ticket_lifetime_hint = 0; - conn->session_ticket_status = S2N_NO_TICKET; /* Allocate the fixed-size stuffers */ blob = (struct s2n_blob) {0}; - GUARD_PTR(s2n_blob_init(&blob, conn->alert_in_data, S2N_ALERT_LENGTH)); - GUARD_PTR(s2n_stuffer_init(&conn->alert_in, &blob)); + PTR_GUARD_POSIX(s2n_blob_init(&blob, conn->alert_in_data, S2N_ALERT_LENGTH)); + PTR_GUARD_POSIX(s2n_stuffer_init(&conn->alert_in, &blob)); blob = (struct s2n_blob) {0}; - GUARD_PTR(s2n_blob_init(&blob, conn->reader_alert_out_data, S2N_ALERT_LENGTH)); - GUARD_PTR(s2n_stuffer_init(&conn->reader_alert_out, &blob)); + PTR_GUARD_POSIX(s2n_blob_init(&blob, conn->reader_alert_out_data, S2N_ALERT_LENGTH)); + PTR_GUARD_POSIX(s2n_stuffer_init(&conn->reader_alert_out, &blob)); blob = (struct s2n_blob) {0}; - GUARD_PTR(s2n_blob_init(&blob, conn->writer_alert_out_data, S2N_ALERT_LENGTH)); - GUARD_PTR(s2n_stuffer_init(&conn->writer_alert_out, &blob)); + PTR_GUARD_POSIX(s2n_blob_init(&blob, conn->writer_alert_out_data, S2N_ALERT_LENGTH)); + PTR_GUARD_POSIX(s2n_stuffer_init(&conn->writer_alert_out, &blob)); blob = (struct s2n_blob) {0}; - GUARD_PTR(s2n_blob_init(&blob, conn->ticket_ext_data, S2N_TICKET_SIZE_IN_BYTES)); - GUARD_PTR(s2n_stuffer_init(&conn->client_ticket_to_decrypt, &blob)); + PTR_GUARD_POSIX(s2n_blob_init(&blob, conn->ticket_ext_data, S2N_TLS12_TICKET_SIZE_IN_BYTES)); + PTR_GUARD_POSIX(s2n_stuffer_init(&conn->client_ticket_to_decrypt, &blob)); /* Allocate long term key memory */ - GUARD_PTR(s2n_session_key_alloc(&conn->secure.client_key)); - GUARD_PTR(s2n_session_key_alloc(&conn->secure.server_key)); - GUARD_PTR(s2n_session_key_alloc(&conn->initial.client_key)); - GUARD_PTR(s2n_session_key_alloc(&conn->initial.server_key)); + PTR_GUARD_POSIX(s2n_session_key_alloc(&conn->secure.client_key)); + PTR_GUARD_POSIX(s2n_session_key_alloc(&conn->secure.server_key)); + PTR_GUARD_POSIX(s2n_session_key_alloc(&conn->initial.client_key)); + PTR_GUARD_POSIX(s2n_session_key_alloc(&conn->initial.server_key)); /* Allocate long term hash and HMAC memory */ - GUARD_PTR(s2n_prf_new(conn)); - - GUARD_PTR(s2n_connection_new_hashes(conn)); - GUARD_PTR(s2n_connection_init_hashes(conn)); + PTR_GUARD_RESULT(s2n_prf_new(conn)); + PTR_GUARD_RESULT(s2n_handshake_hashes_new(&conn->handshake.hashes)); - GUARD_PTR(s2n_connection_new_hmacs(conn)); - GUARD_PTR(s2n_connection_init_hmacs(conn)); + PTR_GUARD_POSIX(s2n_connection_new_hmacs(conn)); + PTR_GUARD_POSIX(s2n_connection_init_hmacs(conn)); /* Initialize the growable stuffers. Zero length at first, but the resize * in _wipe will fix that */ blob = (struct s2n_blob) {0}; - GUARD_PTR(s2n_blob_init(&blob, conn->header_in_data, S2N_TLS_RECORD_HEADER_LENGTH)); - GUARD_PTR(s2n_stuffer_init(&conn->header_in, &blob)); - GUARD_PTR(s2n_stuffer_growable_alloc(&conn->out, 0)); - GUARD_PTR(s2n_stuffer_growable_alloc(&conn->in, 0)); - GUARD_PTR(s2n_stuffer_growable_alloc(&conn->handshake.io, 0)); - GUARD_PTR(s2n_stuffer_growable_alloc(&conn->client_hello.raw_message, 0)); - GUARD_PTR(s2n_connection_wipe(conn)); - GUARD_RESULT_PTR(s2n_timer_start(conn->config, &conn->write_timer)); - - /* Initialize the cookie stuffer with zero length. If a cookie extension - * is received, the stuffer will be resized according to the cookie length */ - GUARD_PTR(s2n_stuffer_growable_alloc(&conn->cookie_stuffer, 0)); - + PTR_GUARD_POSIX(s2n_blob_init(&blob, conn->header_in_data, S2N_TLS_RECORD_HEADER_LENGTH)); + PTR_GUARD_POSIX(s2n_stuffer_init(&conn->header_in, &blob)); + PTR_GUARD_POSIX(s2n_stuffer_growable_alloc(&conn->out, 0)); + PTR_GUARD_POSIX(s2n_stuffer_growable_alloc(&conn->in, 0)); + PTR_GUARD_POSIX(s2n_stuffer_growable_alloc(&conn->handshake.io, 0)); + PTR_GUARD_POSIX(s2n_stuffer_growable_alloc(&conn->client_hello.raw_message, 0)); + PTR_GUARD_RESULT(s2n_timer_start(conn->config, &conn->write_timer)); + + /* NOTE: s2n_connection_wipe MUST be called last in this function. + * + * s2n_connection_wipe is used for initializing values but also used by customers to + * reset/reuse the connection. Calling it last ensures that s2n_connection_wipe is + * implemented correctly and safe. + */ + PTR_GUARD_POSIX(s2n_connection_wipe(conn)); return conn; } static int s2n_connection_free_keys(struct s2n_connection *conn) { - GUARD(s2n_session_key_free(&conn->secure.client_key)); - GUARD(s2n_session_key_free(&conn->secure.server_key)); - GUARD(s2n_session_key_free(&conn->initial.client_key)); - GUARD(s2n_session_key_free(&conn->initial.server_key)); + POSIX_GUARD(s2n_session_key_free(&conn->secure.client_key)); + POSIX_GUARD(s2n_session_key_free(&conn->secure.server_key)); + POSIX_GUARD(s2n_session_key_free(&conn->initial.client_key)); + POSIX_GUARD(s2n_session_key_free(&conn->initial.server_key)); return 0; } @@ -247,35 +166,33 @@ static int s2n_connection_free_keys(struct s2n_connection *conn) static int s2n_connection_zero(struct s2n_connection *conn, int mode, struct s2n_config *config) { /* Zero the whole connection structure */ - memset_check(conn, 0, sizeof(struct s2n_connection)); + POSIX_CHECKED_MEMSET(conn, 0, sizeof(struct s2n_connection)); - conn->send = NULL; - conn->recv = NULL; - conn->send_io_context = NULL; - conn->recv_io_context = NULL; conn->mode = mode; - conn->close_notify_queued = 0; - conn->client_session_resumed = 0; - conn->current_user_data_consumed = 0; conn->initial.cipher_suite = &s2n_null_cipher_suite; conn->secure.cipher_suite = &s2n_null_cipher_suite; - conn->initial.kem_params.kem = NULL; - conn->secure.kem_params.kem = NULL; conn->server = &conn->initial; conn->client = &conn->initial; conn->max_outgoing_fragment_length = S2N_DEFAULT_FRAGMENT_LENGTH; - conn->mfl_code = S2N_TLS_MAX_FRAG_LEN_EXT_NONE; - conn->handshake.handshake_type = INITIAL; - conn->handshake.message_number = 0; - conn->handshake.paused = 0; - conn->verify_host_fn = NULL; - conn->verify_host_fn_overridden = 0; - conn->data_for_verify_host = NULL; + conn->handshake.end_of_messages = APPLICATION_DATA; s2n_connection_set_config(conn, config); return 0; } +S2N_RESULT s2n_connection_wipe_all_keyshares(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + RESULT_GUARD_POSIX(s2n_ecc_evp_params_free(&conn->kex_params.server_ecc_evp_params)); + RESULT_GUARD_POSIX(s2n_ecc_evp_params_free(&conn->kex_params.client_ecc_evp_params)); + + RESULT_GUARD_POSIX(s2n_kem_group_free(&conn->kex_params.server_kem_group_params)); + RESULT_GUARD_POSIX(s2n_kem_group_free(&conn->kex_params.client_kem_group_params)); + + return S2N_RESULT_OK; +} + static int s2n_connection_wipe_keys(struct s2n_connection *conn) { /* Destroy any keys - we call destroy on the object as that is where @@ -284,52 +201,22 @@ static int s2n_connection_wipe_keys(struct s2n_connection *conn) && conn->secure.cipher_suite->record_alg && conn->secure.cipher_suite->record_alg->cipher && conn->secure.cipher_suite->record_alg->cipher->destroy_key) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->destroy_key(&conn->secure.client_key)); - GUARD(conn->secure.cipher_suite->record_alg->cipher->destroy_key(&conn->secure.server_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->destroy_key(&conn->secure.client_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->destroy_key(&conn->secure.server_key)); } /* Free any server key received (we may not have completed a * handshake, so this may not have been free'd yet) */ - GUARD(s2n_pkey_free(&conn->secure.server_public_key)); - GUARD(s2n_pkey_zero_init(&conn->secure.server_public_key)); - GUARD(s2n_pkey_free(&conn->secure.client_public_key)); - GUARD(s2n_pkey_zero_init(&conn->secure.client_public_key)); + POSIX_GUARD(s2n_pkey_free(&conn->handshake_params.server_public_key)); + POSIX_GUARD(s2n_pkey_zero_init(&conn->handshake_params.server_public_key)); + POSIX_GUARD(s2n_pkey_free(&conn->handshake_params.client_public_key)); + POSIX_GUARD(s2n_pkey_zero_init(&conn->handshake_params.client_public_key)); s2n_x509_validator_wipe(&conn->x509_validator); - GUARD(s2n_dh_params_free(&conn->secure.server_dh_params)); - GUARD(s2n_ecc_evp_params_free(&conn->secure.server_ecc_evp_params)); - for (int i=0; i < S2N_ECC_EVP_SUPPORTED_CURVES_COUNT; i++) { - GUARD(s2n_ecc_evp_params_free(&conn->secure.client_ecc_evp_params[i])); - } - GUARD(s2n_kem_group_free(&conn->secure.server_kem_group_params)); - for (int i = 0; i < S2N_SUPPORTED_KEM_GROUPS_COUNT; i++) { - GUARD(s2n_kem_group_free(&conn->secure.client_kem_group_params[i])); - } - GUARD(s2n_kem_free(&conn->secure.kem_params)); - GUARD(s2n_free(&conn->secure.client_cert_chain)); - GUARD(s2n_free(&conn->ct_response)); - - return 0; -} - -static int s2n_connection_reset_hashes(struct s2n_connection *conn) -{ - /* Reset all of the Connection's hash states */ - GUARD(s2n_hash_reset(&conn->handshake.md5)); - GUARD(s2n_hash_reset(&conn->handshake.sha1)); - GUARD(s2n_hash_reset(&conn->handshake.sha224)); - GUARD(s2n_hash_reset(&conn->handshake.sha256)); - GUARD(s2n_hash_reset(&conn->handshake.sha384)); - GUARD(s2n_hash_reset(&conn->handshake.sha512)); - GUARD(s2n_hash_reset(&conn->handshake.md5_sha1)); - GUARD(s2n_hash_reset(&conn->handshake.ccv_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.prf_md5_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.prf_sha1_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.prf_tls12_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.server_finished_copy)); - GUARD(s2n_hash_reset(&conn->prf_space.ssl3.md5)); - GUARD(s2n_hash_reset(&conn->prf_space.ssl3.sha1)); - GUARD(s2n_hash_reset(&conn->initial.signature_hash)); - GUARD(s2n_hash_reset(&conn->secure.signature_hash)); + POSIX_GUARD(s2n_dh_params_free(&conn->kex_params.server_dh_params)); + POSIX_GUARD_RESULT(s2n_connection_wipe_all_keyshares(conn)); + POSIX_GUARD(s2n_kem_free(&conn->kex_params.kem_params)); + POSIX_GUARD(s2n_free(&conn->handshake_params.client_cert_chain)); + POSIX_GUARD(s2n_free(&conn->ct_response)); return 0; } @@ -337,66 +224,56 @@ static int s2n_connection_reset_hashes(struct s2n_connection *conn) static int s2n_connection_reset_hmacs(struct s2n_connection *conn) { /* Reset all of the Connection's HMAC states */ - GUARD(s2n_hmac_reset(&conn->initial.client_record_mac)); - GUARD(s2n_hmac_reset(&conn->initial.server_record_mac)); - GUARD(s2n_hmac_reset(&conn->initial.record_mac_copy_workspace)); - GUARD(s2n_hmac_reset(&conn->secure.client_record_mac)); - GUARD(s2n_hmac_reset(&conn->secure.server_record_mac)); - GUARD(s2n_hmac_reset(&conn->secure.record_mac_copy_workspace)); + POSIX_GUARD(s2n_hmac_reset(&conn->initial.client_record_mac)); + POSIX_GUARD(s2n_hmac_reset(&conn->initial.server_record_mac)); + POSIX_GUARD(s2n_hmac_reset(&conn->secure.client_record_mac)); + POSIX_GUARD(s2n_hmac_reset(&conn->secure.server_record_mac)); return 0; } -static int s2n_connection_free_io_contexts(struct s2n_connection *conn) +static int s2n_connection_free_managed_recv_io(struct s2n_connection *conn) { - /* Free the I/O context if it was allocated by s2n. Don't touch user-controlled contexts. */ - if (!conn->managed_io) { - return 0; + POSIX_ENSURE_REF(conn); + + if (conn->managed_recv_io) { + POSIX_GUARD(s2n_free_object((uint8_t **)&conn->recv_io_context, sizeof(struct s2n_socket_read_io_context))); + conn->managed_recv_io = false; + conn->recv = NULL; } + return S2N_SUCCESS; +} + +static int s2n_connection_free_managed_send_io(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); - GUARD(s2n_free_object((uint8_t **)&conn->send_io_context, sizeof(struct s2n_socket_write_io_context))); - GUARD(s2n_free_object((uint8_t **)&conn->recv_io_context, sizeof(struct s2n_socket_read_io_context))); + if (conn->managed_send_io) { + POSIX_GUARD(s2n_free_object((uint8_t **)&conn->send_io_context, sizeof(struct s2n_socket_write_io_context))); + conn->managed_send_io = false; + conn->send = NULL; + } + return S2N_SUCCESS; +} - return 0; +static int s2n_connection_free_managed_io(struct s2n_connection *conn) +{ + POSIX_GUARD(s2n_connection_free_managed_recv_io(conn)); + POSIX_GUARD(s2n_connection_free_managed_send_io(conn)); + return S2N_SUCCESS; } static int s2n_connection_wipe_io(struct s2n_connection *conn) { if (s2n_connection_is_managed_corked(conn) && conn->recv){ - GUARD(s2n_socket_read_restore(conn)); + POSIX_GUARD(s2n_socket_read_restore(conn)); } if (s2n_connection_is_managed_corked(conn) && conn->send){ - GUARD(s2n_socket_write_restore(conn)); + POSIX_GUARD(s2n_socket_write_restore(conn)); } /* Remove all I/O-related members */ - GUARD(s2n_connection_free_io_contexts(conn)); - conn->managed_io = 0; - conn->send = NULL; - conn->recv = NULL; - - return 0; -} - -static int s2n_connection_free_hashes(struct s2n_connection *conn) -{ - /* Free all of the Connection's hash states */ - GUARD(s2n_hash_free(&conn->handshake.md5)); - GUARD(s2n_hash_free(&conn->handshake.sha1)); - GUARD(s2n_hash_free(&conn->handshake.sha224)); - GUARD(s2n_hash_free(&conn->handshake.sha256)); - GUARD(s2n_hash_free(&conn->handshake.sha384)); - GUARD(s2n_hash_free(&conn->handshake.sha512)); - GUARD(s2n_hash_free(&conn->handshake.md5_sha1)); - GUARD(s2n_hash_free(&conn->handshake.ccv_hash_copy)); - GUARD(s2n_hash_free(&conn->handshake.prf_md5_hash_copy)); - GUARD(s2n_hash_free(&conn->handshake.prf_sha1_hash_copy)); - GUARD(s2n_hash_free(&conn->handshake.prf_tls12_hash_copy)); - GUARD(s2n_hash_free(&conn->handshake.server_finished_copy)); - GUARD(s2n_hash_free(&conn->prf_space.ssl3.md5)); - GUARD(s2n_hash_free(&conn->prf_space.ssl3.sha1)); - GUARD(s2n_hash_free(&conn->initial.signature_hash)); - GUARD(s2n_hash_free(&conn->secure.signature_hash)); + POSIX_GUARD(s2n_connection_free_managed_io(conn)); return 0; } @@ -404,12 +281,10 @@ static int s2n_connection_free_hashes(struct s2n_connection *conn) static int s2n_connection_free_hmacs(struct s2n_connection *conn) { /* Free all of the Connection's HMAC states */ - GUARD(s2n_hmac_free(&conn->initial.client_record_mac)); - GUARD(s2n_hmac_free(&conn->initial.server_record_mac)); - GUARD(s2n_hmac_free(&conn->initial.record_mac_copy_workspace)); - GUARD(s2n_hmac_free(&conn->secure.client_record_mac)); - GUARD(s2n_hmac_free(&conn->secure.server_record_mac)); - GUARD(s2n_hmac_free(&conn->secure.record_mac_copy_workspace)); + POSIX_GUARD(s2n_hmac_free(&conn->initial.client_record_mac)); + POSIX_GUARD(s2n_hmac_free(&conn->initial.server_record_mac)); + POSIX_GUARD(s2n_hmac_free(&conn->secure.client_record_mac)); + POSIX_GUARD(s2n_hmac_free(&conn->secure.server_record_mac)); return 0; } @@ -448,42 +323,50 @@ static uint8_t s2n_default_verify_host(const char *host_name, size_t len, void * return 0; } -int s2n_connection_free(struct s2n_connection *conn) +S2N_CLEANUP_RESULT s2n_connection_ptr_free(struct s2n_connection **conn) { - GUARD(s2n_connection_wipe_keys(conn)); - GUARD(s2n_connection_free_keys(conn)); - GUARD_AS_POSIX(s2n_psk_parameters_wipe(&conn->psk_params)); + RESULT_ENSURE_REF(conn); + RESULT_GUARD_POSIX(s2n_connection_free(*conn)); + *conn = NULL; + return S2N_RESULT_OK; +} - GUARD(s2n_prf_free(conn)); +int s2n_connection_free(struct s2n_connection *conn) +{ + POSIX_GUARD(s2n_connection_wipe_keys(conn)); + POSIX_GUARD(s2n_connection_free_keys(conn)); + POSIX_GUARD_RESULT(s2n_psk_parameters_wipe(&conn->psk_params)); - GUARD(s2n_connection_reset_hashes(conn)); - GUARD(s2n_connection_free_hashes(conn)); + POSIX_GUARD_RESULT(s2n_prf_free(conn)); + POSIX_GUARD_RESULT(s2n_handshake_hashes_free(&conn->handshake.hashes)); - GUARD(s2n_connection_reset_hmacs(conn)); - GUARD(s2n_connection_free_hmacs(conn)); + POSIX_GUARD(s2n_connection_reset_hmacs(conn)); + POSIX_GUARD(s2n_connection_free_hmacs(conn)); - GUARD(s2n_connection_free_io_contexts(conn)); + POSIX_GUARD(s2n_connection_free_managed_io(conn)); - GUARD(s2n_free(&conn->client_ticket)); - GUARD(s2n_free(&conn->status_response)); - GUARD(s2n_free(&conn->our_quic_transport_parameters)); - GUARD(s2n_free(&conn->peer_quic_transport_parameters)); - GUARD(s2n_stuffer_free(&conn->in)); - GUARD(s2n_stuffer_free(&conn->out)); - GUARD(s2n_stuffer_free(&conn->handshake.io)); + POSIX_GUARD(s2n_free(&conn->client_ticket)); + POSIX_GUARD(s2n_free(&conn->status_response)); + POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters)); + POSIX_GUARD(s2n_free(&conn->peer_quic_transport_parameters)); + POSIX_GUARD(s2n_free(&conn->server_early_data_context)); + POSIX_GUARD(s2n_free(&conn->tls13_ticket_fields.session_secret)); + POSIX_GUARD(s2n_stuffer_free(&conn->in)); + POSIX_GUARD(s2n_stuffer_free(&conn->out)); + POSIX_GUARD(s2n_stuffer_free(&conn->handshake.io)); s2n_x509_validator_wipe(&conn->x509_validator); - GUARD(s2n_client_hello_free(&conn->client_hello)); - GUARD(s2n_free(&conn->application_protocols_overridden)); - GUARD(s2n_stuffer_free(&conn->cookie_stuffer)); - GUARD(s2n_free_object((uint8_t **)&conn, sizeof(struct s2n_connection))); + POSIX_GUARD(s2n_client_hello_free(&conn->client_hello)); + POSIX_GUARD(s2n_free(&conn->application_protocols_overridden)); + POSIX_GUARD(s2n_stuffer_free(&conn->cookie_stuffer)); + POSIX_GUARD(s2n_free_object((uint8_t **)&conn, sizeof(struct s2n_connection))); return 0; } int s2n_connection_set_config(struct s2n_connection *conn, struct s2n_config *config) { - notnull_check(conn); - notnull_check(config); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(config); if (conn->config == config) { return 0; @@ -491,7 +374,7 @@ int s2n_connection_set_config(struct s2n_connection *conn, struct s2n_config *co /* We only support one client certificate */ if (s2n_config_get_num_default_certs(config) > 1 && conn->mode == S2N_CLIENT) { - S2N_ERROR(S2N_ERR_TOO_MANY_CERTIFICATES); + POSIX_BAIL(S2N_ERR_TOO_MANY_CERTIFICATES); } s2n_x509_validator_wipe(&conn->x509_validator); @@ -505,10 +388,10 @@ int s2n_connection_set_config(struct s2n_connection *conn, struct s2n_config *co int8_t dont_need_x509_validation = (conn->mode == S2N_SERVER) && (auth_type == S2N_CERT_AUTH_NONE); if (config->disable_x509_validation || dont_need_x509_validation) { - GUARD(s2n_x509_validator_init_no_x509_validation(&conn->x509_validator)); + POSIX_GUARD(s2n_x509_validator_init_no_x509_validation(&conn->x509_validator)); } else { - GUARD(s2n_x509_validator_init(&conn->x509_validator, &config->trust_store, config->check_ocsp)); + POSIX_GUARD(s2n_x509_validator_init(&conn->x509_validator, &config->trust_store, config->check_ocsp)); if (!conn->verify_host_fn_overridden) { if (config->verify_host != NULL) { conn->verify_host_fn = config->verify_host; @@ -520,18 +403,58 @@ int s2n_connection_set_config(struct s2n_connection *conn, struct s2n_config *co } if (config->max_verify_cert_chain_depth_set) { - GUARD(s2n_x509_validator_set_max_chain_depth(&conn->x509_validator, config->max_verify_cert_chain_depth)); + POSIX_GUARD(s2n_x509_validator_set_max_chain_depth(&conn->x509_validator, config->max_verify_cert_chain_depth)); } } + conn->tickets_to_send = config->initial_tickets_to_send; + + if (conn->psk_params.psk_list.len == 0 && !conn->psk_mode_overridden) { + POSIX_GUARD(s2n_connection_set_psk_mode(conn, config->psk_mode)); + conn->psk_mode_overridden = false; + } + + /* If at least one certificate does not have a private key configured, + * the config must provide an async pkey callback. + * The handshake could still fail if the callback doesn't offload the + * signature, but this at least catches configuration mistakes. + */ + if (config->no_signing_key) { + POSIX_ENSURE(config->async_pkey_cb, S2N_ERR_NO_PRIVATE_KEY); + } + + if (config->quic_enabled) { + /* If QUIC is ever enabled for a connection via the config, + * we should enforce that it can never be disabled by + * changing the config. + * + * Enabling QUIC indicates that the connection is being used by + * a QUIC implementation, which never changes. Disabling QUIC + * partially through a connection could also potentially be + * dangerous, as QUIC handles encryption. + */ + POSIX_GUARD(s2n_connection_enable_quic(conn)); + } conn->config = config; - return 0; + return S2N_SUCCESS; +} + +int s2n_connection_server_name_extension_used(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_INVALID_STATE); + POSIX_ENSURE(!(conn->handshake.client_hello_received), S2N_ERR_INVALID_STATE); + + conn->server_name_used = 1; + return S2N_SUCCESS; } int s2n_connection_set_ctx(struct s2n_connection *conn, void *ctx) { + POSIX_ENSURE_REF(conn); + conn->context = ctx; - return 0; + return S2N_SUCCESS; } void *s2n_connection_get_ctx(struct s2n_connection *conn) @@ -541,55 +464,51 @@ void *s2n_connection_get_ctx(struct s2n_connection *conn) int s2n_connection_release_buffers(struct s2n_connection *conn) { - notnull_check(conn); - PRECONDITION_POSIX(s2n_stuffer_validate(&conn->out)); - PRECONDITION_POSIX(s2n_stuffer_validate(&conn->in)); + POSIX_ENSURE_REF(conn); + POSIX_PRECONDITION(s2n_stuffer_validate(&conn->out)); + POSIX_PRECONDITION(s2n_stuffer_validate(&conn->in)); - ENSURE_POSIX(s2n_stuffer_is_consumed(&conn->out), S2N_ERR_STUFFER_HAS_UNPROCESSED_DATA); - GUARD(s2n_stuffer_resize(&conn->out, 0)); + POSIX_ENSURE(s2n_stuffer_is_consumed(&conn->out), S2N_ERR_STUFFER_HAS_UNPROCESSED_DATA); + POSIX_GUARD(s2n_stuffer_resize(&conn->out, 0)); - ENSURE_POSIX(s2n_stuffer_is_consumed(&conn->in), S2N_ERR_STUFFER_HAS_UNPROCESSED_DATA); - GUARD(s2n_stuffer_resize(&conn->in, 0)); + POSIX_ENSURE(s2n_stuffer_is_consumed(&conn->in), S2N_ERR_STUFFER_HAS_UNPROCESSED_DATA); + POSIX_GUARD(s2n_stuffer_resize(&conn->in, 0)); - POSTCONDITION_POSIX(s2n_stuffer_validate(&conn->out)); - POSTCONDITION_POSIX(s2n_stuffer_validate(&conn->in)); + POSIX_POSTCONDITION(s2n_stuffer_validate(&conn->out)); + POSIX_POSTCONDITION(s2n_stuffer_validate(&conn->in)); return S2N_SUCCESS; } int s2n_connection_free_handshake(struct s2n_connection *conn) { /* We are done with the handshake */ - GUARD(s2n_hash_reset(&conn->handshake.md5)); - GUARD(s2n_hash_reset(&conn->handshake.sha1)); - GUARD(s2n_hash_reset(&conn->handshake.sha224)); - GUARD(s2n_hash_reset(&conn->handshake.sha256)); - GUARD(s2n_hash_reset(&conn->handshake.sha384)); - GUARD(s2n_hash_reset(&conn->handshake.sha512)); - GUARD(s2n_hash_reset(&conn->handshake.md5_sha1)); - GUARD(s2n_hash_reset(&conn->handshake.ccv_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.prf_md5_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.prf_sha1_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.prf_tls12_hash_copy)); - GUARD(s2n_hash_reset(&conn->handshake.server_finished_copy)); + POSIX_GUARD_RESULT(s2n_handshake_hashes_free(&conn->handshake.hashes)); + POSIX_GUARD_RESULT(s2n_prf_free(conn)); /* Wipe the buffers we are going to free */ - GUARD(s2n_stuffer_wipe(&conn->handshake.io)); - GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message)); /* Truncate buffers to save memory, we are done with the handshake */ - GUARD(s2n_stuffer_resize(&conn->handshake.io, 0)); - GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0)); + POSIX_GUARD(s2n_stuffer_resize(&conn->handshake.io, 0)); + POSIX_GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0)); /* We can free extension data we no longer need */ - GUARD(s2n_free(&conn->client_ticket)); - GUARD(s2n_free(&conn->status_response)); - GUARD(s2n_free(&conn->our_quic_transport_parameters)); - GUARD(s2n_free(&conn->application_protocols_overridden)); - GUARD(s2n_stuffer_free(&conn->cookie_stuffer)); + POSIX_GUARD(s2n_free(&conn->client_ticket)); + POSIX_GUARD(s2n_free(&conn->status_response)); + POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters)); + POSIX_GUARD(s2n_free(&conn->application_protocols_overridden)); + POSIX_GUARD(s2n_stuffer_free(&conn->cookie_stuffer)); return 0; } +/* An idempotent operation which initializes values on the connection. + * + * Called in order to reuse a connection structure for a new connection. Should wipe + * any persistent memory, free any temporary memory, and set all fields back to their + * defaults. + */ int s2n_connection_wipe(struct s2n_connection *conn) { /* First make a copy of everything we'd like to save, which isn't very much. */ @@ -609,43 +528,59 @@ int s2n_connection_wipe(struct s2n_connection *conn) struct s2n_session_key initial_server_key = {0}; struct s2n_session_key secure_client_key = {0}; struct s2n_session_key secure_server_key = {0}; - /* Parts of the PRF working space, hash states, and hmac states will be wiped. Preserve structs to avoid reallocation */ - struct s2n_connection_prf_handles prf_handles = {0}; - struct s2n_connection_hash_handles hash_handles = {0}; + /* Parts of the hmac states will be wiped. Preserve structs to avoid reallocation */ struct s2n_connection_hmac_handles hmac_handles = {0}; + /* Some required structures might have been freed to conserve memory between handshakes. + * Restore them. + */ + if (!conn->handshake.hashes) { + POSIX_GUARD_RESULT(s2n_handshake_hashes_new(&conn->handshake.hashes)); + } + POSIX_GUARD_RESULT(s2n_handshake_hashes_wipe(conn->handshake.hashes)); + struct s2n_handshake_hashes *handshake_hashes = conn->handshake.hashes; + if (!conn->prf_space) { + POSIX_GUARD_RESULT(s2n_prf_new(conn)); + } + POSIX_GUARD_RESULT(s2n_prf_wipe(conn)); + struct s2n_prf_working_space *prf_workspace = conn->prf_space; + /* Wipe all of the sensitive stuff */ - GUARD(s2n_connection_wipe_keys(conn)); - GUARD(s2n_connection_reset_hashes(conn)); - GUARD(s2n_connection_reset_hmacs(conn)); - GUARD(s2n_stuffer_wipe(&conn->alert_in)); - GUARD(s2n_stuffer_wipe(&conn->reader_alert_out)); - GUARD(s2n_stuffer_wipe(&conn->writer_alert_out)); - GUARD(s2n_stuffer_wipe(&conn->client_ticket_to_decrypt)); - GUARD(s2n_stuffer_wipe(&conn->handshake.io)); - GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message)); - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - GUARD(s2n_stuffer_wipe(&conn->out)); - - GUARD_AS_POSIX(s2n_psk_parameters_wipe(&conn->psk_params)); + POSIX_GUARD(s2n_connection_wipe_keys(conn)); + POSIX_GUARD(s2n_connection_reset_hmacs(conn)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->alert_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->reader_alert_out)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->writer_alert_out)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->client_ticket_to_decrypt)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->out)); + + POSIX_GUARD_RESULT(s2n_psk_parameters_wipe(&conn->psk_params)); /* Wipe the I/O-related info and restore the original socket if necessary */ - GUARD(s2n_connection_wipe_io(conn)); - - GUARD(s2n_free(&conn->client_ticket)); - GUARD(s2n_free(&conn->status_response)); - GUARD(s2n_free(&conn->application_protocols_overridden)); - GUARD(s2n_free(&conn->our_quic_transport_parameters)); - GUARD(s2n_free(&conn->peer_quic_transport_parameters)); + POSIX_GUARD(s2n_connection_wipe_io(conn)); + + POSIX_GUARD(s2n_free(&conn->client_ticket)); + POSIX_GUARD(s2n_free(&conn->status_response)); + POSIX_GUARD(s2n_free(&conn->application_protocols_overridden)); + POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters)); + POSIX_GUARD(s2n_free(&conn->peer_quic_transport_parameters)); + POSIX_GUARD(s2n_free(&conn->server_early_data_context)); + POSIX_GUARD(s2n_free(&conn->tls13_ticket_fields.session_secret)); + /* TODO: Simplify cookie_stuffer implementation. + * https://github.com/aws/s2n-tls/issues/3287 */ + POSIX_GUARD(s2n_stuffer_free(&conn->cookie_stuffer)); /* Allocate memory for handling handshakes */ - GUARD(s2n_stuffer_resize(&conn->handshake.io, S2N_LARGE_RECORD_LENGTH)); + POSIX_GUARD(s2n_stuffer_resize(&conn->handshake.io, S2N_LARGE_RECORD_LENGTH)); /* Truncate the message buffers to save memory, we will dynamically resize it as needed */ - GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0)); - GUARD(s2n_stuffer_resize(&conn->in, 0)); - GUARD(s2n_stuffer_resize(&conn->out, 0)); + POSIX_GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0)); + POSIX_GUARD(s2n_stuffer_resize(&conn->in, 0)); + POSIX_GUARD(s2n_stuffer_resize(&conn->out, 0)); /* Remove context associated with connection */ conn->context = NULL; @@ -660,53 +595,51 @@ int s2n_connection_wipe(struct s2n_connection *conn) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Waddress" #endif - memcpy_check(&alert_in, &conn->alert_in, sizeof(struct s2n_stuffer)); - memcpy_check(&reader_alert_out, &conn->reader_alert_out, sizeof(struct s2n_stuffer)); - memcpy_check(&writer_alert_out, &conn->writer_alert_out, sizeof(struct s2n_stuffer)); - memcpy_check(&client_ticket_to_decrypt, &conn->client_ticket_to_decrypt, sizeof(struct s2n_stuffer)); - memcpy_check(&handshake_io, &conn->handshake.io, sizeof(struct s2n_stuffer)); - memcpy_check(&client_hello_raw_message, &conn->client_hello.raw_message, sizeof(struct s2n_stuffer)); - memcpy_check(&header_in, &conn->header_in, sizeof(struct s2n_stuffer)); - memcpy_check(&in, &conn->in, sizeof(struct s2n_stuffer)); - memcpy_check(&out, &conn->out, sizeof(struct s2n_stuffer)); - memcpy_check(&initial_client_key, &conn->initial.client_key, sizeof(struct s2n_session_key)); - memcpy_check(&initial_server_key, &conn->initial.server_key, sizeof(struct s2n_session_key)); - memcpy_check(&secure_client_key, &conn->secure.client_key, sizeof(struct s2n_session_key)); - memcpy_check(&secure_server_key, &conn->secure.server_key, sizeof(struct s2n_session_key)); - GUARD(s2n_connection_save_prf_state(&prf_handles, conn)); - GUARD(s2n_connection_save_hash_state(&hash_handles, conn)); - GUARD(s2n_connection_save_hmac_state(&hmac_handles, conn)); + POSIX_CHECKED_MEMCPY(&alert_in, &conn->alert_in, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&reader_alert_out, &conn->reader_alert_out, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&writer_alert_out, &conn->writer_alert_out, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&client_ticket_to_decrypt, &conn->client_ticket_to_decrypt, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&handshake_io, &conn->handshake.io, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&client_hello_raw_message, &conn->client_hello.raw_message, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&header_in, &conn->header_in, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&in, &conn->in, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&out, &conn->out, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&initial_client_key, &conn->initial.client_key, sizeof(struct s2n_session_key)); + POSIX_CHECKED_MEMCPY(&initial_server_key, &conn->initial.server_key, sizeof(struct s2n_session_key)); + POSIX_CHECKED_MEMCPY(&secure_client_key, &conn->secure.client_key, sizeof(struct s2n_session_key)); + POSIX_CHECKED_MEMCPY(&secure_server_key, &conn->secure.server_key, sizeof(struct s2n_session_key)); + POSIX_GUARD(s2n_connection_save_hmac_state(&hmac_handles, conn)); #if S2N_GCC_VERSION_AT_LEAST(4,6,0) #pragma GCC diagnostic pop #endif - GUARD(s2n_connection_zero(conn, mode, config)); - - memcpy_check(&conn->alert_in, &alert_in, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->reader_alert_out, &reader_alert_out, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->writer_alert_out, &writer_alert_out, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->client_ticket_to_decrypt, &client_ticket_to_decrypt, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->handshake.io, &handshake_io, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->client_hello.raw_message, &client_hello_raw_message, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->header_in, &header_in, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->in, &in, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->out, &out, sizeof(struct s2n_stuffer)); - memcpy_check(&conn->initial.client_key, &initial_client_key, sizeof(struct s2n_session_key)); - memcpy_check(&conn->initial.server_key, &initial_server_key, sizeof(struct s2n_session_key)); - memcpy_check(&conn->secure.client_key, &secure_client_key, sizeof(struct s2n_session_key)); - memcpy_check(&conn->secure.server_key, &secure_server_key, sizeof(struct s2n_session_key)); - GUARD(s2n_connection_restore_prf_state(conn, &prf_handles)); - GUARD(s2n_connection_restore_hash_state(conn, &hash_handles)); - GUARD(s2n_connection_restore_hmac_state(conn, &hmac_handles)); + POSIX_GUARD(s2n_connection_zero(conn, mode, config)); + + POSIX_CHECKED_MEMCPY(&conn->alert_in, &alert_in, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->reader_alert_out, &reader_alert_out, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->writer_alert_out, &writer_alert_out, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->client_ticket_to_decrypt, &client_ticket_to_decrypt, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->handshake.io, &handshake_io, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->client_hello.raw_message, &client_hello_raw_message, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->header_in, &header_in, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->in, &in, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->out, &out, sizeof(struct s2n_stuffer)); + POSIX_CHECKED_MEMCPY(&conn->initial.client_key, &initial_client_key, sizeof(struct s2n_session_key)); + POSIX_CHECKED_MEMCPY(&conn->initial.server_key, &initial_server_key, sizeof(struct s2n_session_key)); + POSIX_CHECKED_MEMCPY(&conn->secure.client_key, &secure_client_key, sizeof(struct s2n_session_key)); + POSIX_CHECKED_MEMCPY(&conn->secure.server_key, &secure_server_key, sizeof(struct s2n_session_key)); + POSIX_GUARD(s2n_connection_restore_hmac_state(conn, &hmac_handles)); + conn->handshake.hashes = handshake_hashes; + conn->prf_space = prf_workspace; /* Re-initialize hash and hmac states */ - GUARD(s2n_connection_init_hashes(conn)); - GUARD(s2n_connection_init_hmacs(conn)); + POSIX_GUARD(s2n_connection_init_hmacs(conn)); - GUARD_AS_POSIX(s2n_psk_parameters_init(&conn->psk_params)); + POSIX_GUARD_RESULT(s2n_psk_parameters_init(&conn->psk_params)); + conn->server_keying_material_lifetime = ONE_WEEK_IN_SEC; /* Require all handshakes hashes. This set can be reduced as the handshake progresses. */ - GUARD(s2n_handshake_require_all_hashes(&conn->handshake)); + POSIX_GUARD(s2n_handshake_require_all_hashes(&conn->handshake)); if (conn->mode == S2N_SERVER) { /* Start with the highest protocol version so that the highest common protocol version can be selected */ @@ -723,142 +656,157 @@ int s2n_connection_wipe(struct s2n_connection *conn) conn->actual_protocol_version = s2n_highest_protocol_version; } + /* Initialize remaining values */ + conn->blinding = S2N_BUILT_IN_BLINDING; + conn->session_ticket_status = S2N_NO_TICKET; + /* Initialize the cookie stuffer with zero length. If a cookie extension + * is received, the stuffer will be resized according to the cookie length */ + POSIX_GUARD(s2n_stuffer_growable_alloc(&conn->cookie_stuffer, 0)); + return 0; } int s2n_connection_set_recv_ctx(struct s2n_connection *conn, void *ctx) { + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_connection_free_managed_recv_io(conn)); conn->recv_io_context = ctx; - return 0; + return S2N_SUCCESS; } int s2n_connection_set_send_ctx(struct s2n_connection *conn, void *ctx) { + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_connection_free_managed_send_io(conn)); conn->send_io_context = ctx; - return 0; + return S2N_SUCCESS; } int s2n_connection_set_recv_cb(struct s2n_connection *conn, s2n_recv_fn recv) { + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_connection_free_managed_recv_io(conn)); conn->recv = recv; - return 0; + return S2N_SUCCESS; } int s2n_connection_set_send_cb(struct s2n_connection *conn, s2n_send_fn send) { + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_connection_free_managed_send_io(conn)); conn->send = send; - return 0; + return S2N_SUCCESS; } int s2n_connection_get_client_cert_chain(struct s2n_connection *conn, uint8_t **der_cert_chain_out, uint32_t *cert_chain_len) { - notnull_check(conn); - notnull_check(der_cert_chain_out); - notnull_check(cert_chain_len); - notnull_check(conn->secure.client_cert_chain.data); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(der_cert_chain_out); + POSIX_ENSURE_REF(cert_chain_len); + POSIX_ENSURE_REF(conn->handshake_params.client_cert_chain.data); - *der_cert_chain_out = conn->secure.client_cert_chain.data; - *cert_chain_len = conn->secure.client_cert_chain.size; + *der_cert_chain_out = conn->handshake_params.client_cert_chain.data; + *cert_chain_len = conn->handshake_params.client_cert_chain.size; return 0; } int s2n_connection_get_cipher_preferences(struct s2n_connection *conn, const struct s2n_cipher_preferences **cipher_preferences) { - notnull_check(conn); - notnull_check(conn->config); - notnull_check(cipher_preferences); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE_REF(cipher_preferences); if (conn->security_policy_override != NULL) { *cipher_preferences = conn->security_policy_override->cipher_preferences; } else if (conn->config->security_policy != NULL) { *cipher_preferences = conn->config->security_policy->cipher_preferences; } else { - S2N_ERROR(S2N_ERR_INVALID_CIPHER_PREFERENCES); + POSIX_BAIL(S2N_ERR_INVALID_CIPHER_PREFERENCES); } - notnull_check(*cipher_preferences); + POSIX_ENSURE_REF(*cipher_preferences); return 0; } int s2n_connection_get_security_policy(struct s2n_connection *conn, const struct s2n_security_policy **security_policy) { - notnull_check(conn); - notnull_check(conn->config); - notnull_check(security_policy); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE_REF(security_policy); if (conn->security_policy_override != NULL) { *security_policy = conn->security_policy_override; } else if (conn->config->security_policy != NULL) { *security_policy = conn->config->security_policy; } else { - S2N_ERROR(S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_BAIL(S2N_ERR_INVALID_SECURITY_POLICY); } - notnull_check(*security_policy); + POSIX_ENSURE_REF(*security_policy); return 0; } int s2n_connection_get_kem_preferences(struct s2n_connection *conn, const struct s2n_kem_preferences **kem_preferences) { - notnull_check(conn); - notnull_check(conn->config); - notnull_check(kem_preferences); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE_REF(kem_preferences); if (conn->security_policy_override != NULL) { *kem_preferences = conn->security_policy_override->kem_preferences; } else if (conn->config->security_policy != NULL) { *kem_preferences = conn->config->security_policy->kem_preferences; } else { - S2N_ERROR(S2N_ERR_INVALID_KEM_PREFERENCES); + POSIX_BAIL(S2N_ERR_INVALID_KEM_PREFERENCES); } - notnull_check(*kem_preferences); + POSIX_ENSURE_REF(*kem_preferences); return 0; } int s2n_connection_get_signature_preferences(struct s2n_connection *conn, const struct s2n_signature_preferences **signature_preferences) { - notnull_check(conn); - notnull_check(conn->config); - notnull_check(signature_preferences); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE_REF(signature_preferences); if (conn->security_policy_override != NULL) { *signature_preferences = conn->security_policy_override->signature_preferences; } else if (conn->config->security_policy != NULL) { *signature_preferences = conn->config->security_policy->signature_preferences; } else { - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHMS_PREFERENCES); + POSIX_BAIL(S2N_ERR_INVALID_SIGNATURE_ALGORITHMS_PREFERENCES); } - notnull_check(*signature_preferences); + POSIX_ENSURE_REF(*signature_preferences); return 0; } int s2n_connection_get_ecc_preferences(struct s2n_connection *conn, const struct s2n_ecc_preferences **ecc_preferences) { - notnull_check(conn); - notnull_check(conn->config); - notnull_check(ecc_preferences); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->config); + POSIX_ENSURE_REF(ecc_preferences); if (conn->security_policy_override != NULL) { *ecc_preferences = conn->security_policy_override->ecc_preferences; } else if (conn->config->security_policy != NULL) { *ecc_preferences = conn->config->security_policy->ecc_preferences; } else { - S2N_ERROR(S2N_ERR_INVALID_ECC_PREFERENCES); + POSIX_BAIL(S2N_ERR_INVALID_ECC_PREFERENCES); } - notnull_check(*ecc_preferences); + POSIX_ENSURE_REF(*ecc_preferences); return 0; } int s2n_connection_get_protocol_preferences(struct s2n_connection *conn, struct s2n_blob **protocol_preferences) { - notnull_check(conn); - notnull_check(protocol_preferences); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(protocol_preferences); *protocol_preferences = NULL; if (conn->application_protocols_overridden.size > 0) { @@ -867,18 +815,19 @@ int s2n_connection_get_protocol_preferences(struct s2n_connection *conn, struct *protocol_preferences = &conn->config->application_protocols; } - notnull_check(*protocol_preferences); + POSIX_ENSURE_REF(*protocol_preferences); return 0; } int s2n_connection_get_client_auth_type(struct s2n_connection *conn, s2n_cert_auth_type *client_cert_auth_type) { - notnull_check(conn); - notnull_check(client_cert_auth_type); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(client_cert_auth_type); if (conn->client_cert_auth_type_overridden) { *client_cert_auth_type = conn->client_cert_auth_type; } else { + POSIX_ENSURE_REF(conn->config); *client_cert_auth_type = conn->config->client_cert_auth_type; } @@ -897,42 +846,55 @@ int s2n_connection_set_read_fd(struct s2n_connection *conn, int rfd) struct s2n_blob ctx_mem = {0}; struct s2n_socket_read_io_context *peer_socket_ctx; - GUARD(s2n_alloc(&ctx_mem, sizeof(struct s2n_socket_read_io_context))); - GUARD(s2n_blob_zero(&ctx_mem)); + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_alloc(&ctx_mem, sizeof(struct s2n_socket_read_io_context))); + POSIX_GUARD(s2n_blob_zero(&ctx_mem)); peer_socket_ctx = (struct s2n_socket_read_io_context *)(void *)ctx_mem.data; peer_socket_ctx->fd = rfd; - s2n_connection_set_recv_cb(conn, s2n_socket_read); - s2n_connection_set_recv_ctx(conn, peer_socket_ctx); - conn->managed_io = 1; + POSIX_GUARD(s2n_connection_set_recv_cb(conn, s2n_socket_read)); + POSIX_GUARD(s2n_connection_set_recv_ctx(conn, peer_socket_ctx)); + conn->managed_recv_io = true; /* This is only needed if the user is using corked io. * Take the snapshot in case optimized io is enabled after setting the fd. */ - GUARD(s2n_socket_read_snapshot(conn)); + POSIX_GUARD(s2n_socket_read_snapshot(conn)); return 0; } +int s2n_connection_get_read_fd(struct s2n_connection *conn, int *readfd) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(readfd); + POSIX_ENSURE((conn->managed_recv_io && conn->recv_io_context), S2N_ERR_INVALID_STATE); + + const struct s2n_socket_read_io_context *peer_socket_ctx = conn->recv_io_context; + *readfd = peer_socket_ctx->fd; + return S2N_SUCCESS; +} + int s2n_connection_set_write_fd(struct s2n_connection *conn, int wfd) { struct s2n_blob ctx_mem = {0}; struct s2n_socket_write_io_context *peer_socket_ctx; - GUARD(s2n_alloc(&ctx_mem, sizeof(struct s2n_socket_write_io_context))); + POSIX_ENSURE_REF(conn); + POSIX_GUARD(s2n_alloc(&ctx_mem, sizeof(struct s2n_socket_write_io_context))); peer_socket_ctx = (struct s2n_socket_write_io_context *)(void *)ctx_mem.data; peer_socket_ctx->fd = wfd; - s2n_connection_set_send_cb(conn, s2n_socket_write); - s2n_connection_set_send_ctx(conn, peer_socket_ctx); - conn->managed_io = 1; + POSIX_GUARD(s2n_connection_set_send_cb(conn, s2n_socket_write)); + POSIX_GUARD(s2n_connection_set_send_ctx(conn, peer_socket_ctx)); + conn->managed_send_io = true; /* This is only needed if the user is using corked io. * Take the snapshot in case optimized io is enabled after setting the fd. */ - GUARD(s2n_socket_write_snapshot(conn)); + POSIX_GUARD(s2n_socket_write_snapshot(conn)); uint8_t ipv6; if (0 == s2n_socket_is_ipv6(wfd, &ipv6)) { @@ -944,19 +906,29 @@ int s2n_connection_set_write_fd(struct s2n_connection *conn, int wfd) return 0; } +int s2n_connection_get_write_fd(struct s2n_connection *conn, int *writefd) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(writefd); + POSIX_ENSURE((conn->managed_send_io && conn->send_io_context), S2N_ERR_INVALID_STATE); + + const struct s2n_socket_write_io_context *peer_socket_ctx = conn->send_io_context; + *writefd = peer_socket_ctx->fd; + return S2N_SUCCESS; +} int s2n_connection_set_fd(struct s2n_connection *conn, int fd) { - GUARD(s2n_connection_set_read_fd(conn, fd)); - GUARD(s2n_connection_set_write_fd(conn, fd)); + POSIX_GUARD(s2n_connection_set_read_fd(conn, fd)); + POSIX_GUARD(s2n_connection_set_write_fd(conn, fd)); return 0; } int s2n_connection_use_corked_io(struct s2n_connection *conn) { - if (!conn->managed_io) { - /* Caller shouldn't be trying to set s2n IO corked on non-s2n-managed IO */ - S2N_ERROR(S2N_ERR_CORK_SET_ON_UNMANAGED); - } + POSIX_ENSURE_REF(conn); + + /* Caller shouldn't be trying to set s2n IO corked on non-s2n-managed IO */ + POSIX_ENSURE(conn->managed_send_io, S2N_ERR_CORK_SET_ON_UNMANAGED); conn->corked_io = 1; return 0; @@ -974,79 +946,106 @@ uint64_t s2n_connection_get_wire_bytes_out(struct s2n_connection *conn) const char *s2n_connection_get_cipher(struct s2n_connection *conn) { - notnull_check_ptr(conn); - notnull_check_ptr(conn->secure.cipher_suite); + PTR_ENSURE_REF(conn); + PTR_ENSURE_REF(conn->secure.cipher_suite); return conn->secure.cipher_suite->name; } +int s2n_connection_get_cipher_iana_value(struct s2n_connection *conn, uint8_t *first, uint8_t *second) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); + POSIX_ENSURE_MUT(first); + POSIX_ENSURE_MUT(second); + + /* ensure we've negotiated a cipher suite */ + POSIX_ENSURE( + memcmp( + conn->secure.cipher_suite->iana_value, + s2n_null_cipher_suite.iana_value, + sizeof(s2n_null_cipher_suite.iana_value) + ) != 0, + S2N_ERR_INVALID_STATE + ); + + const uint8_t *iana_value = conn->secure.cipher_suite->iana_value; + *first = iana_value[0]; + *second = iana_value[1]; + + return S2N_SUCCESS; +} + const char *s2n_connection_get_curve(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); - if (!conn->secure.server_ecc_evp_params.negotiated_curve) { - return "NONE"; + if (conn->kex_params.server_ecc_evp_params.negotiated_curve) { + /* TLS1.3 currently only uses ECC groups. */ + if (conn->actual_protocol_version >= S2N_TLS13 || s2n_kex_includes(conn->secure.cipher_suite->key_exchange_alg, &s2n_ecdhe)) { + return conn->kex_params.server_ecc_evp_params.negotiated_curve->name; + } } - return conn->secure.server_ecc_evp_params.negotiated_curve->name; + return "NONE"; } const char *s2n_connection_get_kem_name(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); - if (!conn->secure.kem_params.kem) { + if (!conn->kex_params.kem_params.kem) { return "NONE"; } - return conn->secure.kem_params.kem->name; + return conn->kex_params.kem_params.kem->name; } const char *s2n_connection_get_kem_group_name(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); - if (!conn->secure.chosen_client_kem_group_params || !conn->secure.chosen_client_kem_group_params->kem_group) { + if (conn->actual_protocol_version < S2N_TLS13 || !conn->kex_params.client_kem_group_params.kem_group) { return "NONE"; } - return conn->secure.chosen_client_kem_group_params->kem_group->name; + return conn->kex_params.client_kem_group_params.kem_group->name; } int s2n_connection_get_client_protocol_version(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); return conn->client_protocol_version; } int s2n_connection_get_server_protocol_version(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); return conn->server_protocol_version; } int s2n_connection_get_actual_protocol_version(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); return conn->actual_protocol_version; } int s2n_connection_get_client_hello_version(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); return conn->client_hello_version; } int s2n_connection_client_cert_used(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - if ((conn->handshake.handshake_type & CLIENT_AUTH) && is_handshake_complete(conn)) { - if (conn->handshake.handshake_type & NO_CLIENT_CERT) { + if (IS_CLIENT_AUTH_HANDSHAKE(conn) && is_handshake_complete(conn)) { + if (IS_CLIENT_AUTH_NO_CERT(conn)) { return 0; } return 1; @@ -1056,41 +1055,41 @@ int s2n_connection_client_cert_used(struct s2n_connection *conn) int s2n_connection_get_alert(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); S2N_ERROR_IF(s2n_stuffer_data_available(&conn->alert_in) != 2, S2N_ERR_NO_ALERT); uint8_t alert_code = 0; - GUARD(s2n_stuffer_read_uint8(&conn->alert_in, &alert_code)); - GUARD(s2n_stuffer_read_uint8(&conn->alert_in, &alert_code)); + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->alert_in, &alert_code)); + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->alert_in, &alert_code)); return alert_code; } int s2n_set_server_name(struct s2n_connection *conn, const char *server_name) { - notnull_check(conn); - notnull_check(server_name); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(server_name); S2N_ERROR_IF(conn->mode != S2N_CLIENT, S2N_ERR_CLIENT_MODE); int len = strlen(server_name); S2N_ERROR_IF(len > S2N_MAX_SERVER_NAME, S2N_ERR_SERVER_NAME_TOO_LONG); - memcpy_check(conn->server_name, server_name, len); + POSIX_CHECKED_MEMCPY(conn->server_name, server_name, len); return 0; } const char *s2n_get_server_name(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); if (conn->server_name[0]) { return conn->server_name; } - GUARD_PTR(s2n_extension_process(&s2n_client_server_name_extension, conn, &conn->client_hello.extensions)); + PTR_GUARD_POSIX(s2n_extension_process(&s2n_client_server_name_extension, conn, &conn->client_hello.extensions)); if (!conn->server_name[0]) { return NULL; @@ -1101,7 +1100,7 @@ const char *s2n_get_server_name(struct s2n_connection *conn) const char *s2n_get_application_protocol(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); if (strlen(conn->application_protocol) == 0) { return NULL; @@ -1112,27 +1111,31 @@ const char *s2n_get_application_protocol(struct s2n_connection *conn) int s2n_connection_get_session_id_length(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); + /* Stateful session resumption in TLS1.3 using session id is not yet supported. */ + if (conn->actual_protocol_version >= S2N_TLS13) { + return 0; + } return conn->session_id_len; } int s2n_connection_get_session_id(struct s2n_connection *conn, uint8_t *session_id, size_t max_length) { - notnull_check(conn); - notnull_check(session_id); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(session_id); int session_id_len = s2n_connection_get_session_id_length(conn); S2N_ERROR_IF(session_id_len > max_length, S2N_ERR_SESSION_ID_TOO_LONG); - memcpy_check(session_id, conn->session_id, session_id_len); + POSIX_CHECKED_MEMCPY(session_id, conn->session_id, session_id_len); return session_id_len; } int s2n_connection_set_blinding(struct s2n_connection *conn, s2n_blinding blinding) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); conn->blinding = blinding; return 0; @@ -1149,7 +1152,7 @@ uint64_t s2n_connection_get_delay(struct s2n_connection *conn) uint64_t elapsed; /* This will cast -1 to max uint64_t */ - GUARD_AS_POSIX(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); + POSIX_GUARD_RESULT(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); if (elapsed > conn->delay) { return 0; @@ -1158,9 +1161,53 @@ uint64_t s2n_connection_get_delay(struct s2n_connection *conn) return conn->delay - elapsed; } +S2N_CLEANUP_RESULT s2n_connection_apply_error_blinding(struct s2n_connection **conn) +{ + RESULT_ENSURE_REF(conn); + if (*conn == NULL) { + return S2N_RESULT_OK; + } + + int error_code = s2n_errno; + int error_type = s2n_error_get_type(error_code); + + switch(error_type) { + case S2N_ERR_T_OK: + /* Ignore no error */ + return S2N_RESULT_OK; + case S2N_ERR_T_BLOCKED: + /* All blocking errors are retriable and should trigger no further action. */ + return S2N_RESULT_OK; + default: + break; + } + + switch(error_code) { + /* Don't invoke blinding on some of the common errors. + * + * Be careful adding new errors here. Disabling blinding for an + * error that can be triggered by secret / encrypted values can + * potentially lead to a side channel attack. + * + * We may want to someday add an explicit error type for these errors. + */ + case S2N_ERR_CANCELLED: + case S2N_ERR_CIPHER_NOT_SUPPORTED: + case S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED: + (*conn)->closed = 1; + break; + default: + /* Apply blinding to all other errors */ + RESULT_GUARD_POSIX(s2n_connection_kill(*conn)); + break; + } + + return S2N_RESULT_OK; +} + int s2n_connection_kill(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); conn->closed = 1; @@ -1169,12 +1216,12 @@ int s2n_connection_kill(struct s2n_connection *conn) /* Keep track of the delay so that it can be enforced */ uint64_t rand_delay = 0; - GUARD_AS_POSIX(s2n_public_random(max - min, &rand_delay)); + POSIX_GUARD_RESULT(s2n_public_random(max - min, &rand_delay)); conn->delay = min + rand_delay; /* Restart the write timer */ - GUARD_AS_POSIX(s2n_timer_start(conn->config, &conn->write_timer)); + POSIX_GUARD_RESULT(s2n_timer_start(conn->config, &conn->write_timer)); if (conn->blinding == S2N_BUILT_IN_BLINDING) { struct timespec sleep_time = {.tv_sec = conn->delay / ONE_S,.tv_nsec = conn->delay % ONE_S }; @@ -1191,38 +1238,56 @@ int s2n_connection_kill(struct s2n_connection *conn) const uint8_t *s2n_connection_get_ocsp_response(struct s2n_connection *conn, uint32_t * length) { - notnull_check_ptr(conn); - notnull_check_ptr(length); + PTR_ENSURE_REF(conn); + PTR_ENSURE_REF(length); *length = conn->status_response.size; return conn->status_response.data; } -int s2n_connection_prefer_throughput(struct s2n_connection *conn) +S2N_RESULT s2n_connection_set_max_fragment_length(struct s2n_connection *conn, uint16_t max_frag_length) { - notnull_check(conn); + RESULT_ENSURE_REF(conn); - if (!conn->mfl_code) { - conn->max_outgoing_fragment_length = S2N_LARGE_FRAGMENT_LENGTH; + if (conn->negotiated_mfl_code) { + /* Respect the upper limit agreed on with the peer */ + RESULT_ENSURE_LT(conn->negotiated_mfl_code, s2n_array_len(mfl_code_to_length)); + conn->max_outgoing_fragment_length = MIN(mfl_code_to_length[conn->negotiated_mfl_code], max_frag_length); + } else { + conn->max_outgoing_fragment_length = max_frag_length; } - return 0; + /* If no buffer has been initialized yet, no need to resize. + * The standard I/O logic will handle initializing the buffer. + */ + if (s2n_stuffer_is_freed(&conn->out)) { + return S2N_RESULT_OK; + } + + uint16_t max_wire_record_size = 0; + RESULT_GUARD(s2n_record_max_write_size(conn, conn->max_outgoing_fragment_length, &max_wire_record_size)); + if ((conn->out.blob.size < max_wire_record_size)) { + RESULT_GUARD_POSIX(s2n_realloc(&conn->out.blob, max_wire_record_size)); + } + + return S2N_RESULT_OK; } -int s2n_connection_prefer_low_latency(struct s2n_connection *conn) +int s2n_connection_prefer_throughput(struct s2n_connection *conn) { - notnull_check(conn); - - if (!conn->mfl_code) { - conn->max_outgoing_fragment_length = S2N_SMALL_FRAGMENT_LENGTH; - } + POSIX_GUARD_RESULT(s2n_connection_set_max_fragment_length(conn, S2N_LARGE_FRAGMENT_LENGTH)); + return S2N_SUCCESS; +} - return 0; +int s2n_connection_prefer_low_latency(struct s2n_connection *conn) +{ + POSIX_GUARD_RESULT(s2n_connection_set_max_fragment_length(conn, S2N_SMALL_FRAGMENT_LENGTH)); + return S2N_SUCCESS; } int s2n_connection_set_dynamic_record_threshold(struct s2n_connection *conn, uint32_t resize_threshold, uint16_t timeout_threshold) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); S2N_ERROR_IF(resize_threshold > S2N_TLS_MAX_RESIZE_THRESHOLD, S2N_ERR_INVALID_DYNAMIC_THRESHOLD); conn->dynamic_record_resize_threshold = resize_threshold; @@ -1231,7 +1296,7 @@ int s2n_connection_set_dynamic_record_threshold(struct s2n_connection *conn, uin } int s2n_connection_set_verify_host_callback(struct s2n_connection *conn, s2n_verify_host_fn verify_host_fn, void *data) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); conn->verify_host_fn = verify_host_fn; conn->data_for_verify_host = data; @@ -1242,9 +1307,9 @@ int s2n_connection_set_verify_host_callback(struct s2n_connection *conn, s2n_ver int s2n_connection_recv_stuffer(struct s2n_stuffer *stuffer, struct s2n_connection *conn, uint32_t len) { - notnull_check(conn->recv); + POSIX_ENSURE_REF(conn->recv); /* Make sure we have enough space to write */ - GUARD(s2n_stuffer_reserve_space(stuffer, len)); + POSIX_GUARD(s2n_stuffer_reserve_space(stuffer, len)); int r = 0; do { @@ -1254,16 +1319,16 @@ int s2n_connection_recv_stuffer(struct s2n_stuffer *stuffer, struct s2n_connecti } while (r < 0); /* Record just how many bytes we have written */ - GUARD(s2n_stuffer_skip_write(stuffer, r)); + POSIX_GUARD(s2n_stuffer_skip_write(stuffer, r)); return r; } int s2n_connection_send_stuffer(struct s2n_stuffer *stuffer, struct s2n_connection *conn, uint32_t len) { - notnull_check(conn); - notnull_check(conn->send); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->send); if (conn->write_fd_broken) { - S2N_ERROR(S2N_ERR_SEND_STUFFER_TO_CONN); + POSIX_BAIL(S2N_ERR_SEND_STUFFER_TO_CONN); } /* Make sure we even have the data */ S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) < len, S2N_ERR_STUFFER_OUT_OF_DATA); @@ -1278,15 +1343,15 @@ int s2n_connection_send_stuffer(struct s2n_stuffer *stuffer, struct s2n_connecti S2N_ERROR_IF(w < 0 && errno != EINTR, S2N_ERR_SEND_STUFFER_TO_CONN); } while (w < 0); - GUARD(s2n_stuffer_skip_read(stuffer, w)); + POSIX_GUARD(s2n_stuffer_skip_read(stuffer, w)); return w; } int s2n_connection_is_managed_corked(const struct s2n_connection *s2n_connection) { - notnull_check(s2n_connection); + POSIX_ENSURE_REF(s2n_connection); - return (s2n_connection->managed_io && s2n_connection->corked_io); + return (s2n_connection->managed_send_io && s2n_connection->corked_io); } const uint8_t *s2n_connection_get_sct_list(struct s2n_connection *conn, uint32_t *length) @@ -1302,14 +1367,14 @@ const uint8_t *s2n_connection_get_sct_list(struct s2n_connection *conn, uint32_t int s2n_connection_is_client_auth_enabled(struct s2n_connection *s2n_connection) { s2n_cert_auth_type auth_type; - GUARD(s2n_connection_get_client_auth_type(s2n_connection, &auth_type)); + POSIX_GUARD(s2n_connection_get_client_auth_type(s2n_connection, &auth_type)); return (auth_type != S2N_CERT_AUTH_NONE); } struct s2n_cert_chain_and_key *s2n_connection_get_selected_cert(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); return conn->handshake_params.our_chain_and_key; } @@ -1329,26 +1394,168 @@ uint8_t s2n_connection_get_protocol_version(const struct s2n_connection *conn) return conn->server_protocol_version; } -int s2n_connection_set_keyshare_by_name_for_testing(struct s2n_connection *conn, const char* curve_name) +DEFINE_POINTER_CLEANUP_FUNC(struct s2n_cert_chain *, s2n_cert_chain_free); + +int s2n_connection_get_peer_cert_chain(const struct s2n_connection *conn, struct s2n_cert_chain_and_key *cert_chain_and_key) { - ENSURE_POSIX(S2N_IN_TEST, S2N_ERR_NOT_IN_TEST); - notnull_check(conn); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(cert_chain_and_key); + + DEFER_CLEANUP(struct s2n_cert_chain *cert_chain = cert_chain_and_key->cert_chain, s2n_cert_chain_free_pointer); + struct s2n_cert **insert = &cert_chain->head; + POSIX_ENSURE(*insert == NULL, S2N_ERR_INVALID_ARGUMENT); + + const struct s2n_x509_validator *validator = &conn->x509_validator; + POSIX_ENSURE_REF(validator); + POSIX_ENSURE(s2n_x509_validator_is_cert_chain_validated(validator), S2N_ERR_CERT_NOT_VALIDATED); + + /* X509_STORE_CTX_get1_chain() returns a validated cert chain if a previous call to X509_verify_cert() was successful. + * X509_STORE_CTX_get0_chain() is a better API because it doesn't return a copy. But it's not available for Openssl 1.0.2. + * See the comments here: + * https://www.openssl.org/docs/man1.0.2/man3/X509_STORE_CTX_get1_chain.html + */ + DEFER_CLEANUP(STACK_OF(X509) *cert_chain_validated = X509_STORE_CTX_get1_chain(validator->store_ctx), + s2n_openssl_x509_stack_pop_free); + POSIX_ENSURE_REF(cert_chain_validated); + + for (size_t cert_idx = 0; cert_idx < sk_X509_num(cert_chain_validated); cert_idx++) { + X509 *cert = sk_X509_value(cert_chain_validated, cert_idx); + POSIX_ENSURE_REF(cert); + DEFER_CLEANUP(uint8_t *cert_data = NULL, s2n_crypto_free); + int cert_size = i2d_X509(cert, &cert_data); + POSIX_ENSURE_GT(cert_size, 0); - if (!strcmp(curve_name, "none")) { - S2N_SET_KEY_SHARE_LIST_EMPTY(conn->preferred_key_shares); - return S2N_SUCCESS; + struct s2n_blob mem = { 0 }; + POSIX_GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert))); + + struct s2n_cert *new_node = (struct s2n_cert *)(void *)mem.data; + POSIX_ENSURE_REF(new_node); + + new_node->next = NULL; + *insert = new_node; + insert = &new_node->next; + + POSIX_GUARD(s2n_alloc(&new_node->raw, cert_size)); + POSIX_CHECKED_MEMCPY(new_node->raw.data, cert_data, cert_size); } - const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + ZERO_TO_DISABLE_DEFER_CLEANUP(cert_chain); - for (size_t i = 0; i < ecc_pref->count; i++) { - if (!strcmp(ecc_pref->ecc_curves[i]->name, curve_name)) { - S2N_SET_KEY_SHARE_REQUEST(conn->preferred_key_shares, i); - return S2N_SUCCESS; - } + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_signature_scheme_to_tls_iana(struct s2n_signature_scheme *sig_scheme, s2n_tls_hash_algorithm *converted_scheme) +{ + RESULT_ENSURE_REF(sig_scheme); + RESULT_ENSURE_REF(converted_scheme); + + switch (sig_scheme->hash_alg) { + case S2N_HASH_MD5: + *converted_scheme = S2N_TLS_HASH_MD5; + break; + case S2N_HASH_SHA1: + *converted_scheme = S2N_TLS_HASH_SHA1; + break; + case S2N_HASH_SHA224: + *converted_scheme = S2N_TLS_HASH_SHA224; + break; + case S2N_HASH_SHA256: + *converted_scheme = S2N_TLS_HASH_SHA256; + break; + case S2N_HASH_SHA384: + *converted_scheme = S2N_TLS_HASH_SHA384; + break; + case S2N_HASH_SHA512: + *converted_scheme = S2N_TLS_HASH_SHA512; + break; + case S2N_HASH_MD5_SHA1: + *converted_scheme = S2N_TLS_HASH_MD5_SHA1; + break; + default: + *converted_scheme = S2N_TLS_HASH_NONE; + break; + } + + return S2N_RESULT_OK; +} + +int s2n_connection_get_selected_digest_algorithm(struct s2n_connection *conn, s2n_tls_hash_algorithm *converted_scheme) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(converted_scheme); + + POSIX_GUARD_RESULT(s2n_signature_scheme_to_tls_iana(&conn->handshake_params.conn_sig_scheme, converted_scheme)); + + return S2N_SUCCESS; +} + +int s2n_connection_get_selected_client_cert_digest_algorithm(struct s2n_connection *conn, s2n_tls_hash_algorithm *converted_scheme) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(converted_scheme); + + POSIX_GUARD_RESULT(s2n_signature_scheme_to_tls_iana(&conn->handshake_params.client_cert_sig_scheme, converted_scheme)); + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_signature_scheme_to_signature_algorithm(struct s2n_signature_scheme *sig_scheme, s2n_tls_signature_algorithm *converted_scheme) +{ + RESULT_ENSURE_REF(sig_scheme); + RESULT_ENSURE_REF(converted_scheme); + + switch (sig_scheme->sig_alg) { + case S2N_SIGNATURE_RSA: + *converted_scheme = S2N_TLS_SIGNATURE_RSA; + break; + case S2N_SIGNATURE_ECDSA: + *converted_scheme = S2N_TLS_SIGNATURE_ECDSA; + break; + case S2N_SIGNATURE_RSA_PSS_RSAE: + *converted_scheme = S2N_TLS_SIGNATURE_RSA_PSS_RSAE; + break; + case S2N_SIGNATURE_RSA_PSS_PSS: + *converted_scheme = S2N_TLS_SIGNATURE_RSA_PSS_PSS; + break; + default: + *converted_scheme = S2N_TLS_SIGNATURE_ANONYMOUS; + break; } - S2N_ERROR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + return S2N_RESULT_OK; +} + +int s2n_connection_get_selected_signature_algorithm(struct s2n_connection *conn, s2n_tls_signature_algorithm *converted_scheme) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(converted_scheme); + + POSIX_GUARD_RESULT(s2n_signature_scheme_to_signature_algorithm(&conn->handshake_params.conn_sig_scheme, converted_scheme)); + + return S2N_SUCCESS; +} + +int s2n_connection_get_selected_client_cert_signature_algorithm(struct s2n_connection *conn, s2n_tls_signature_algorithm *converted_scheme) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(converted_scheme); + + POSIX_GUARD_RESULT(s2n_signature_scheme_to_signature_algorithm(&conn->handshake_params.client_cert_sig_scheme, converted_scheme)); + + return S2N_SUCCESS; +} + +/* + * Gets the config set on the connection. + */ +int s2n_connection_get_config(struct s2n_connection *conn, struct s2n_config **config) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(config); + + if (s2n_fetch_default_config() == conn->config) { + POSIX_BAIL(S2N_ERR_NULL); + } + + *config = conn->config; + + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_connection.h b/contrib/restricted/aws/s2n/tls/s2n_connection.h index 9864111db1..0332241d63 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_connection.h +++ b/contrib/restricted/aws/s2n/tls/s2n_connection.h @@ -16,7 +16,7 @@ #pragma once #include <errno.h> -#include <s2n.h> +#include "api/s2n.h" #include <signal.h> #include <stdint.h> @@ -25,15 +25,17 @@ #include "tls/s2n_client_hello.h" #include "tls/s2n_config.h" #include "tls/s2n_crypto.h" +#include "tls/s2n_early_data.h" +#include "tls/s2n_ecc_preferences.h" #include "tls/s2n_handshake.h" +#include "tls/s2n_kem_preferences.h" +#include "tls/s2n_key_update.h" #include "tls/s2n_prf.h" #include "tls/s2n_quic_support.h" +#include "tls/s2n_record.h" +#include "tls/s2n_security_policies.h" #include "tls/s2n_tls_parameters.h" #include "tls/s2n_x509_validator.h" -#include "tls/s2n_key_update.h" -#include "tls/s2n_kem_preferences.h" -#include "tls/s2n_ecc_preferences.h" -#include "tls/s2n_security_policies.h" #include "crypto/s2n_hash.h" #include "crypto/s2n_hmac.h" @@ -43,6 +45,8 @@ #define S2N_TLS_PROTOCOL_VERSION_LEN 2 +#define S2N_PEER_MODE(our_mode) ((our_mode + 1) % 2) + #define is_handshake_complete(conn) (APPLICATION_DATA == s2n_conn_get_current_message_type(conn)) typedef enum { @@ -52,39 +56,17 @@ typedef enum { } s2n_session_ticket_status; struct s2n_connection { - /* The configuration (cert, key .. etc ) */ - struct s2n_config *config; - - /* Overrides Security Policy in config if non-null */ - const struct s2n_security_policy *security_policy_override; - - /* The user defined context associated with connection */ - void *context; - - /* The user defined secret callback and context */ - s2n_secret_cb secret_cb; - void *secret_cb_context; - - /* The send and receive callbacks don't have to be the same (e.g. two pipes) */ - s2n_send_fn *send; - s2n_recv_fn *recv; - - /* The context passed to the I/O callbacks */ - void *send_io_context; - void *recv_io_context; - - /* Has the user set their own I/O callbacks or is this connection using the - * default socket-based I/O set by s2n */ - uint8_t managed_io; - /* Is this connection using CORK/SO_RCVLOWAT optimizations? Only valid when the connection is using - * managed_io + * managed_send_io */ unsigned corked_io:1; /* Session resumption indicator on client side */ unsigned client_session_resumed:1; + /* Connection can be used by a QUIC implementation */ + unsigned quic_enabled:1; + /* Determines if we're currently sending or receiving in s2n_shutdown */ unsigned close_notify_queued:1; @@ -110,6 +92,58 @@ struct s2n_connection { /* If write fd is broken */ unsigned write_fd_broken:1; + /* Has the user set their own I/O callbacks or is this connection using the + * default socket-based I/O set by s2n */ + unsigned managed_send_io:1; + unsigned managed_recv_io:1; + + /* Key update data */ + unsigned key_update_pending:1; + + /* Early data supported by caller. + * If a caller does not use any APIs that support early data, + * do not negotiate early data. + */ + unsigned early_data_expected:1; + + /* Connection overrides server_max_early_data_size */ + unsigned server_max_early_data_size_overridden:1; + + /* Connection overrides psk_mode. + * This means that the connection will keep the existing value of psk_params->type, + * even when setting a new config. */ + unsigned psk_mode_overridden:1; + + /* Have we received a close notify alert from the peer. */ + unsigned close_notify_received:1; + + /* Connection negotiated an EMS */ + unsigned ems_negotiated:1; + + /* Connection successfully set a ticket on the connection */ + unsigned set_session:1; + + /* The configuration (cert, key .. etc ) */ + struct s2n_config *config; + + /* Overrides Security Policy in config if non-null */ + const struct s2n_security_policy *security_policy_override; + + /* The user defined context associated with connection */ + void *context; + + /* The user defined secret callback and context */ + s2n_secret_cb secret_cb; + void *secret_cb_context; + + /* The send and receive callbacks don't have to be the same (e.g. two pipes) */ + s2n_send_fn *send; + s2n_recv_fn *recv; + + /* The context passed to the I/O callbacks */ + void *send_io_context; + void *recv_io_context; + /* Track request extensions to ensure correct response extension behavior. * * We need to track client and server extensions separately because some @@ -156,11 +190,15 @@ struct s2n_connection { /* Our crypto parameters */ struct s2n_crypto_parameters initial; struct s2n_crypto_parameters secure; + union s2n_secrets secrets; /* Which set is the client/server actually using? */ struct s2n_crypto_parameters *client; struct s2n_crypto_parameters *server; + /* Contains parameters needed to negotiate a shared secret */ + struct s2n_kex_parameters kex_params; + /* Contains parameters needed during the handshake phase */ struct s2n_handshake_parameters handshake_params; @@ -168,7 +206,7 @@ struct s2n_connection { struct s2n_psk_parameters psk_params; /* The PRF needs some storage elements to work with */ - struct s2n_prf_working_space prf_space; + struct s2n_prf_working_space *prf_space; /* Whether to use client_cert_auth_type stored in s2n_config or in this s2n_connection. * @@ -241,12 +279,14 @@ struct s2n_connection { /* number of bytes consumed during application activity */ uint64_t active_application_bytes_consumed; - /* Negotiated TLS extension Maximum Fragment Length code */ - uint8_t mfl_code; + /* Negotiated TLS extension Maximum Fragment Length code. + * If set, the client and server have both agreed to fragment their records to the given length. */ + uint8_t negotiated_mfl_code; /* Keep some accounting on each connection */ uint64_t wire_bytes_in; uint64_t wire_bytes_out; + uint64_t early_data_bytes; /* Is the connection open or closed ? We use C's only * atomic type as both the reader and the writer threads @@ -302,37 +342,36 @@ struct s2n_connection { s2n_session_ticket_status session_ticket_status; struct s2n_blob client_ticket; uint32_t ticket_lifetime_hint; + struct s2n_ticket_fields tls13_ticket_fields; /* Session ticket extension from client to attempt to decrypt as the server. */ - uint8_t ticket_ext_data[S2N_TICKET_SIZE_IN_BYTES]; + uint8_t ticket_ext_data[S2N_TLS12_TICKET_SIZE_IN_BYTES]; struct s2n_stuffer client_ticket_to_decrypt; - uint8_t resumption_master_secret[S2N_TLS13_SECRET_MAX_LEN]; - /* application protocols overridden */ struct s2n_blob application_protocols_overridden; /* Cookie extension data */ struct s2n_stuffer cookie_stuffer; - /* Key update data */ - unsigned key_update_pending:1; - - /* Bitmap to represent preferred list of keyshare for client to generate and send keyshares in the ClientHello message. - * The least significant bit (lsb), if set, indicates that the client must send an empty keyshare list. - * Each bit value in the bitmap indiciates the corresponding curve in the ecc_preferences list for which a key share needs to be generated. - * The order of the curves represented in the bitmap is obtained from the security_policy->ecc_preferences. - * Setting and manipulating this value requires security_policy to be configured prior. - * */ - uint8_t preferred_key_shares; - /* Flags to prevent users from calling methods recursively. - * This can be an easy mistake to make when implementing send/receive callbacks. + * This can be an easy mistake to make when implementing callbacks. */ bool send_in_use; bool recv_in_use; + bool negotiate_in_use; + + uint16_t tickets_to_send; + uint16_t tickets_sent; + + s2n_early_data_state early_data_state; + uint32_t server_max_early_data_size; + struct s2n_blob server_early_data_context; + uint32_t server_keying_material_lifetime; }; +S2N_CLEANUP_RESULT s2n_connection_ptr_free(struct s2n_connection **s2n_connection); + int s2n_connection_is_managed_corked(const struct s2n_connection *s2n_connection); int s2n_connection_is_client_auth_enabled(struct s2n_connection *s2n_connection); @@ -343,6 +382,8 @@ int s2n_connection_kill(struct s2n_connection *conn); int s2n_connection_send_stuffer(struct s2n_stuffer *stuffer, struct s2n_connection *conn, uint32_t len); int s2n_connection_recv_stuffer(struct s2n_stuffer *stuffer, struct s2n_connection *conn, uint32_t len); +S2N_RESULT s2n_connection_wipe_all_keyshares(struct s2n_connection *conn); + int s2n_connection_get_cipher_preferences(struct s2n_connection *conn, const struct s2n_cipher_preferences **cipher_preferences); int s2n_connection_get_security_policy(struct s2n_connection *conn, const struct s2n_security_policy **security_policy); int s2n_connection_get_kem_preferences(struct s2n_connection *conn, const struct s2n_kem_preferences **kem_preferences); @@ -352,6 +393,6 @@ int s2n_connection_get_protocol_preferences(struct s2n_connection *conn, struct int s2n_connection_set_client_auth_type(struct s2n_connection *conn, s2n_cert_auth_type cert_auth_type); int s2n_connection_get_client_auth_type(struct s2n_connection *conn, s2n_cert_auth_type *client_cert_auth_type); int s2n_connection_get_client_cert_chain(struct s2n_connection *conn, uint8_t **der_cert_chain_out, uint32_t *cert_chain_len); +int s2n_connection_get_peer_cert_chain(const struct s2n_connection *conn, struct s2n_cert_chain_and_key *cert_chain_and_key); uint8_t s2n_connection_get_protocol_version(const struct s2n_connection *conn); -/* `none` keyword represents a list of empty keyshares */ -int s2n_connection_set_keyshare_by_name_for_testing(struct s2n_connection *conn, const char* curve_name); +S2N_RESULT s2n_connection_set_max_fragment_length(struct s2n_connection *conn, uint16_t length); diff --git a/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.c b/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.c index f7c08dc594..856ca79f89 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.c +++ b/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.c @@ -18,109 +18,15 @@ #include "utils/s2n_safety.h" /* On s2n_connection_wipe, save all pointers to OpenSSL EVP digest structs in a temporary - * s2n_connection_prf_handles struct to avoid re-allocation after zeroing the connection struct. - * Do not store any additional hash/HMAC state as it is unnecessary and excessive copying would impact performance. - */ -int s2n_connection_save_prf_state(struct s2n_connection_prf_handles *prf_handles, struct s2n_connection *conn) -{ - /* Preserve only the handlers for TLS PRF p_hash pointers to avoid re-allocation */ - GUARD(s2n_hmac_save_evp_hash_state(&prf_handles->p_hash_s2n_hmac, &conn->prf_space.tls.p_hash.s2n_hmac)); - prf_handles->p_hash_evp_hmac = conn->prf_space.tls.p_hash.evp_hmac; - - return 0; -} - -/* On s2n_connection_wipe, save all pointers to OpenSSL EVP digest structs in a temporary - * s2n_connection_hash_handles struct to avoid re-allocation after zeroing the connection struct. - * Do not store any additional hash state as it is unnecessary and excessive copying would impact performance. - */ -int s2n_connection_save_hash_state(struct s2n_connection_hash_handles *hash_handles, struct s2n_connection *conn) -{ - /* Preserve only the handlers for handshake hash state pointers to avoid re-allocation */ - hash_handles->md5 = conn->handshake.md5.digest.high_level; - hash_handles->sha1 = conn->handshake.sha1.digest.high_level; - hash_handles->sha224 = conn->handshake.sha224.digest.high_level; - hash_handles->sha256 = conn->handshake.sha256.digest.high_level; - hash_handles->sha384 = conn->handshake.sha384.digest.high_level; - hash_handles->sha512 = conn->handshake.sha512.digest.high_level; - hash_handles->md5_sha1 = conn->handshake.md5_sha1.digest.high_level; - hash_handles->ccv_hash_copy = conn->handshake.ccv_hash_copy.digest.high_level; - hash_handles->prf_md5_hash_copy = conn->handshake.prf_md5_hash_copy.digest.high_level; - hash_handles->prf_sha1_hash_copy = conn->handshake.prf_sha1_hash_copy.digest.high_level; - hash_handles->prf_tls12_hash_copy = conn->handshake.prf_tls12_hash_copy.digest.high_level; - hash_handles->server_finished_copy = conn->handshake.server_finished_copy.digest.high_level; - - /* Preserve only the handlers for SSLv3 PRF hash state pointers to avoid re-allocation */ - hash_handles->prf_md5 = conn->prf_space.ssl3.md5.digest.high_level; - hash_handles->prf_sha1 = conn->prf_space.ssl3.sha1.digest.high_level; - - /* Preserve only the handlers for initial signature hash state pointers to avoid re-allocation */ - hash_handles->initial_signature_hash = conn->initial.signature_hash.digest.high_level; - - /* Preserve only the handlers for secure signature hash state pointers to avoid re-allocation */ - hash_handles->secure_signature_hash = conn->secure.signature_hash.digest.high_level; - - return 0; -} - -/* On s2n_connection_wipe, save all pointers to OpenSSL EVP digest structs in a temporary * s2n_connection_hmac_handles struct to avoid re-allocation after zeroing the connection struct. * Do not store any additional HMAC state as it is unnecessary and excessive copying would impact performance. */ int s2n_connection_save_hmac_state(struct s2n_connection_hmac_handles *hmac_handles, struct s2n_connection *conn) { - GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->initial_client, &conn->initial.client_record_mac)); - GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->initial_server, &conn->initial.server_record_mac)); - GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->initial_client_copy, &conn->initial.record_mac_copy_workspace)); - GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->secure_client, &conn->secure.client_record_mac)); - GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->secure_server, &conn->secure.server_record_mac)); - GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->secure_client_copy, &conn->secure.record_mac_copy_workspace)); - return 0; -} - -/* On s2n_connection_wipe, restore all pointers to OpenSSL EVP digest structs after zeroing the connection struct - * to avoid re-allocation. Do not store any additional hash/HMAC state as it is unnecessary and excessive copying - * would impact performance. - */ -int s2n_connection_restore_prf_state(struct s2n_connection *conn, struct s2n_connection_prf_handles *prf_handles) -{ - /* Restore s2n_connection handlers for TLS PRF p_hash */ - GUARD(s2n_hmac_restore_evp_hash_state(&prf_handles->p_hash_s2n_hmac, &conn->prf_space.tls.p_hash.s2n_hmac)); - conn->prf_space.tls.p_hash.evp_hmac = prf_handles->p_hash_evp_hmac; - - return 0; -} - -/* On s2n_connection_wipe, restore all pointers to OpenSSL EVP digest structs after zeroing the connection struct - * to avoid re-allocation. Do not store any additional hash state as it is unnecessary and excessive copying - * would impact performance. - */ -int s2n_connection_restore_hash_state(struct s2n_connection *conn, struct s2n_connection_hash_handles *hash_handles) -{ - /* Restore s2n_connection handlers for handshake hash states */ - conn->handshake.md5.digest.high_level = hash_handles->md5; - conn->handshake.sha1.digest.high_level = hash_handles->sha1; - conn->handshake.sha224.digest.high_level = hash_handles->sha224; - conn->handshake.sha256.digest.high_level = hash_handles->sha256; - conn->handshake.sha384.digest.high_level = hash_handles->sha384; - conn->handshake.sha512.digest.high_level = hash_handles->sha512; - conn->handshake.md5_sha1.digest.high_level = hash_handles->md5_sha1; - conn->handshake.ccv_hash_copy.digest.high_level = hash_handles->ccv_hash_copy; - conn->handshake.prf_md5_hash_copy.digest.high_level = hash_handles->prf_md5_hash_copy; - conn->handshake.prf_sha1_hash_copy.digest.high_level = hash_handles->prf_sha1_hash_copy; - conn->handshake.prf_tls12_hash_copy.digest.high_level = hash_handles->prf_tls12_hash_copy; - conn->handshake.server_finished_copy.digest.high_level = hash_handles->server_finished_copy; - - /* Restore s2n_connection handlers for SSLv3 PRF hash states */ - conn->prf_space.ssl3.md5.digest.high_level = hash_handles->prf_md5; - conn->prf_space.ssl3.sha1.digest.high_level = hash_handles->prf_sha1; - - /* Restore s2n_connection handlers for initial signature hash states */ - conn->initial.signature_hash.digest.high_level = hash_handles->initial_signature_hash; - - /* Restore s2n_connection handlers for secure signature hash states */ - conn->secure.signature_hash.digest.high_level = hash_handles->secure_signature_hash; - + POSIX_GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->initial_client, &conn->initial.client_record_mac)); + POSIX_GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->initial_server, &conn->initial.server_record_mac)); + POSIX_GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->secure_client, &conn->secure.client_record_mac)); + POSIX_GUARD(s2n_hmac_save_evp_hash_state(&hmac_handles->secure_server, &conn->secure.server_record_mac)); return 0; } @@ -130,11 +36,9 @@ int s2n_connection_restore_hash_state(struct s2n_connection *conn, struct s2n_co */ int s2n_connection_restore_hmac_state(struct s2n_connection *conn, struct s2n_connection_hmac_handles *hmac_handles) { - GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->initial_client, &conn->initial.client_record_mac)); - GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->initial_server, &conn->initial.server_record_mac)); - GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->initial_client_copy, &conn->initial.record_mac_copy_workspace)); - GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->secure_client, &conn->secure.client_record_mac)); - GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->secure_server, &conn->secure.server_record_mac)); - GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->secure_client_copy, &conn->secure.record_mac_copy_workspace)); + POSIX_GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->initial_client, &conn->initial.client_record_mac)); + POSIX_GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->initial_server, &conn->initial.server_record_mac)); + POSIX_GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->secure_client, &conn->secure.client_record_mac)); + POSIX_GUARD(s2n_hmac_restore_evp_hash_state(&hmac_handles->secure_server, &conn->secure.server_record_mac)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.h b/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.h index 80e16823ba..e94e19d010 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.h +++ b/contrib/restricted/aws/s2n/tls/s2n_connection_evp_digests.h @@ -20,38 +20,6 @@ #include "crypto/s2n_hash.h" -struct s2n_connection_prf_handles { - /* TLS PRF HMAC p_hash */ - struct s2n_hmac_evp_backup p_hash_s2n_hmac; - - /* TLS PRF EVP p_hash */ - struct s2n_evp_hmac_state p_hash_evp_hmac; -}; - -struct s2n_connection_hash_handles { - /* Handshake hash states */ - struct s2n_hash_evp_digest md5; - struct s2n_hash_evp_digest sha1; - struct s2n_hash_evp_digest sha224; - struct s2n_hash_evp_digest sha256; - struct s2n_hash_evp_digest sha384; - struct s2n_hash_evp_digest sha512; - struct s2n_hash_evp_digest md5_sha1; - struct s2n_hash_evp_digest ccv_hash_copy; - struct s2n_hash_evp_digest prf_md5_hash_copy; - struct s2n_hash_evp_digest prf_sha1_hash_copy; - struct s2n_hash_evp_digest prf_tls12_hash_copy; - struct s2n_hash_evp_digest server_finished_copy; - struct s2n_hash_evp_digest prf_md5; - - /* SSLv3 PRF hash states */ - struct s2n_hash_evp_digest prf_sha1; - - /* Initial signature hash states */ - struct s2n_hash_evp_digest initial_signature_hash; - struct s2n_hash_evp_digest secure_signature_hash; -}; - /* Allocationg new EVP structs is expensive, so we back them up here and reuse them */ struct s2n_connection_hmac_handles { struct s2n_hmac_evp_backup initial_client; @@ -62,9 +30,5 @@ struct s2n_connection_hmac_handles { struct s2n_hmac_evp_backup secure_server; }; -extern int s2n_connection_save_prf_state(struct s2n_connection_prf_handles *prf_handles, struct s2n_connection *conn); -extern int s2n_connection_save_hash_state(struct s2n_connection_hash_handles *hash_handles, struct s2n_connection *conn); extern int s2n_connection_save_hmac_state(struct s2n_connection_hmac_handles *hmac_handles, struct s2n_connection *conn); -extern int s2n_connection_restore_prf_state(struct s2n_connection *conn, struct s2n_connection_prf_handles *prf_handles); -extern int s2n_connection_restore_hash_state(struct s2n_connection *conn, struct s2n_connection_hash_handles *hash_handles); extern int s2n_connection_restore_hmac_state(struct s2n_connection *conn, struct s2n_connection_hmac_handles *hmac_handles); diff --git a/contrib/restricted/aws/s2n/tls/s2n_crypto.h b/contrib/restricted/aws/s2n/tls/s2n_crypto.h index 515165c09d..de6c18b332 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_crypto.h +++ b/contrib/restricted/aws/s2n/tls/s2n_crypto.h @@ -19,6 +19,7 @@ #include "tls/s2n_signature_scheme.h" #include "tls/s2n_crypto_constants.h" #include "tls/s2n_kem.h" +#include "tls/s2n_tls13_secrets.h" #include "crypto/s2n_certificate.h" #include "crypto/s2n_cipher.h" @@ -30,44 +31,37 @@ #include "crypto/s2n_dhe.h" #include "crypto/s2n_ecc_evp.h" -struct s2n_crypto_parameters { - struct s2n_pkey server_public_key; - struct s2n_pkey client_public_key; +struct s2n_kex_parameters { struct s2n_dh_params server_dh_params; struct s2n_ecc_evp_params server_ecc_evp_params; const struct s2n_ecc_named_curve *mutually_supported_curves[S2N_ECC_EVP_SUPPORTED_CURVES_COUNT]; - struct s2n_ecc_evp_params client_ecc_evp_params[S2N_ECC_EVP_SUPPORTED_CURVES_COUNT]; + struct s2n_ecc_evp_params client_ecc_evp_params; struct s2n_kem_group_params server_kem_group_params; - struct s2n_kem_group_params *chosen_client_kem_group_params; - struct s2n_kem_group_params client_kem_group_params[S2N_SUPPORTED_KEM_GROUPS_COUNT]; + struct s2n_kem_group_params client_kem_group_params; const struct s2n_kem_group *mutually_supported_kem_groups[S2N_SUPPORTED_KEM_GROUPS_COUNT]; struct s2n_kem_params kem_params; struct s2n_blob client_key_exchange_message; struct s2n_blob client_pq_kem_extension; +}; - struct s2n_signature_scheme conn_sig_scheme; - - struct s2n_blob client_cert_chain; - s2n_pkey_type client_cert_pkey_type; +struct s2n_tls12_secrets { + uint8_t rsa_premaster_secret[S2N_TLS_SECRET_LEN]; + uint8_t master_secret[S2N_TLS_SECRET_LEN]; +}; - struct s2n_signature_scheme client_cert_sig_scheme; +union s2n_secrets { + struct s2n_tls12_secrets tls12; + struct s2n_tls13_secrets tls13; +}; +struct s2n_crypto_parameters { struct s2n_cipher_suite *cipher_suite; struct s2n_session_key client_key; struct s2n_session_key server_key; - - uint8_t rsa_premaster_secret[S2N_TLS_SECRET_LEN]; - uint8_t master_secret[S2N_TLS_SECRET_LEN]; - uint8_t client_random[S2N_TLS_RANDOM_DATA_LEN]; - uint8_t server_random[S2N_TLS_RANDOM_DATA_LEN]; - uint8_t client_implicit_iv[S2N_TLS_MAX_IV_LEN]; - uint8_t server_implicit_iv[S2N_TLS_MAX_IV_LEN]; - uint8_t client_app_secret[S2N_TLS13_SECRET_MAX_LEN]; - uint8_t server_app_secret[S2N_TLS13_SECRET_MAX_LEN]; - struct s2n_hash_state signature_hash; struct s2n_hmac_state client_record_mac; struct s2n_hmac_state server_record_mac; - struct s2n_hmac_state record_mac_copy_workspace; + uint8_t client_implicit_iv[S2N_TLS_MAX_IV_LEN]; + uint8_t server_implicit_iv[S2N_TLS_MAX_IV_LEN]; uint8_t client_sequence_number[S2N_TLS_SEQUENCE_NUM_LEN]; uint8_t server_sequence_number[S2N_TLS_SEQUENCE_NUM_LEN]; }; diff --git a/contrib/restricted/aws/s2n/tls/s2n_early_data.c b/contrib/restricted/aws/s2n/tls/s2n_early_data.c new file mode 100644 index 0000000000..102ceed334 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_early_data.c @@ -0,0 +1,435 @@ +/* + * 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 <sys/param.h> + +#include "tls/s2n_early_data.h" + +#include "tls/s2n_connection.h" +#include "tls/s2n_cipher_suites.h" +#include "tls/s2n_psk.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" + +const s2n_early_data_state valid_previous_states[] = { + [S2N_EARLY_DATA_REQUESTED] = S2N_UNKNOWN_EARLY_DATA_STATE, + [S2N_EARLY_DATA_NOT_REQUESTED] = S2N_UNKNOWN_EARLY_DATA_STATE, + [S2N_EARLY_DATA_REJECTED] = S2N_EARLY_DATA_REQUESTED, + [S2N_EARLY_DATA_ACCEPTED] = S2N_EARLY_DATA_REQUESTED, + [S2N_END_OF_EARLY_DATA] = S2N_EARLY_DATA_ACCEPTED, +}; + +S2N_RESULT s2n_connection_set_early_data_state(struct s2n_connection *conn, s2n_early_data_state next_state) +{ + RESULT_ENSURE_REF(conn); + if (conn->early_data_state == next_state) { + return S2N_RESULT_OK; + } + RESULT_ENSURE(next_state < S2N_EARLY_DATA_STATES_COUNT, S2N_ERR_INVALID_EARLY_DATA_STATE); + RESULT_ENSURE(next_state != S2N_UNKNOWN_EARLY_DATA_STATE, S2N_ERR_INVALID_EARLY_DATA_STATE); + RESULT_ENSURE(conn->early_data_state == valid_previous_states[next_state], S2N_ERR_INVALID_EARLY_DATA_STATE); + conn->early_data_state = next_state; + return S2N_RESULT_OK; +} + +int s2n_connection_set_early_data_expected(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + conn->early_data_expected = true; + return S2N_SUCCESS; +} + +int s2n_connection_set_end_of_early_data(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + conn->early_data_expected = false; + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_early_data_validate(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# In order to accept early data, the server MUST have accepted a PSK + *# cipher suite and selected the first key offered in the client's + *# "pre_shared_key" extension. + **/ + RESULT_ENSURE_REF(conn->psk_params.chosen_psk); + RESULT_ENSURE_EQ(conn->psk_params.chosen_psk_wire_index, 0); + + struct s2n_early_data_config *config = &conn->psk_params.chosen_psk->early_data_config; + RESULT_ENSURE_GT(config->max_early_data_size, 0); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# In addition, it MUST verify that the + *# following values are the same as those associated with the + *# selected PSK: + *# + *# - The TLS version number + **/ + RESULT_ENSURE_EQ(config->protocol_version, s2n_connection_get_protocol_version(conn)); + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# - The selected cipher suite + **/ + RESULT_ENSURE_EQ(config->cipher_suite, conn->secure.cipher_suite); + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# - The selected ALPN [RFC7301] protocol, if any + **/ + const size_t app_protocol_size = strlen(conn->application_protocol); + if (app_protocol_size > 0 || config->application_protocol.size > 0) { + RESULT_ENSURE_EQ(config->application_protocol.size, app_protocol_size + 1 /* null-terminating char */); + RESULT_ENSURE_EQ(memcmp(config->application_protocol.data, conn->application_protocol, app_protocol_size), 0); + } + + return S2N_RESULT_OK; +} + +bool s2n_early_data_is_valid_for_connection(struct s2n_connection *conn) +{ + return s2n_result_is_ok(s2n_early_data_validate(conn)); +} + +S2N_RESULT s2n_early_data_accept_or_reject(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + if (conn->early_data_state != S2N_EARLY_DATA_REQUESTED) { + return S2N_RESULT_OK; + } + + if (conn->handshake.early_data_async_state.conn) { + RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED); + } + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# If any of these checks fail, the server MUST NOT respond with the + *# extension + **/ + if (!s2n_early_data_is_valid_for_connection(conn)) { + RESULT_GUARD(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REJECTED)); + return S2N_RESULT_OK; + } + + /* Even if the connection is valid for early data, the client can't consider + * early data accepted until the server sends the early data indication. */ + if (conn->mode == S2N_CLIENT) { + return S2N_RESULT_OK; + } + + /* The server should reject early data if the application is not prepared to handle it. */ + if (!conn->early_data_expected) { + RESULT_GUARD(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REJECTED)); + return S2N_RESULT_OK; + } + + /* If early data would otherwise be accepted, let the application apply any additional restrictions. + * For example, an application could use this callback to implement anti-replay protections. + * + * This callback can be either synchronous or asynchronous. The handshake will not proceed until + * the application either accepts or rejects early data. + */ + RESULT_ENSURE_REF(conn->config); + if (conn->config->early_data_cb) { + conn->handshake.early_data_async_state.conn = conn; + RESULT_GUARD_POSIX(conn->config->early_data_cb(conn, &conn->handshake.early_data_async_state)); + if (conn->early_data_state == S2N_EARLY_DATA_REQUESTED) { + RESULT_BAIL(S2N_ERR_ASYNC_BLOCKED); + } + } else { + RESULT_GUARD(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_ACCEPTED)); + } + return S2N_RESULT_OK; +} + +int s2n_config_set_server_max_early_data_size(struct s2n_config *config, uint32_t max_early_data_size) +{ + POSIX_ENSURE_REF(config); + config->server_max_early_data_size = max_early_data_size; + return S2N_SUCCESS; +} + +int s2n_connection_set_server_max_early_data_size(struct s2n_connection *conn, uint32_t max_early_data_size) +{ + POSIX_ENSURE_REF(conn); + conn->server_max_early_data_size = max_early_data_size; + conn->server_max_early_data_size_overridden = true; + return S2N_SUCCESS; +} + +S2N_RESULT s2n_early_data_get_server_max_size(struct s2n_connection *conn, uint32_t *max_early_data_size) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(max_early_data_size); + if (conn->server_max_early_data_size_overridden) { + *max_early_data_size = conn->server_max_early_data_size; + } else { + RESULT_ENSURE_REF(conn->config); + *max_early_data_size = conn->config->server_max_early_data_size; + } + return S2N_RESULT_OK; +} + +int s2n_connection_set_server_early_data_context(struct s2n_connection *conn, const uint8_t *context, uint16_t context_size) +{ + POSIX_ENSURE_REF(conn); + if (context_size > 0) { + POSIX_ENSURE_REF(context); + } + + POSIX_GUARD(s2n_realloc(&conn->server_early_data_context, context_size)); + POSIX_CHECKED_MEMCPY(conn->server_early_data_context.data, context, context_size); + return S2N_SUCCESS; +} + +S2N_CLEANUP_RESULT s2n_early_data_config_free(struct s2n_early_data_config *config) +{ + if (config == NULL) { + return S2N_RESULT_OK; + } + RESULT_GUARD_POSIX(s2n_free(&config->application_protocol)); + RESULT_GUARD_POSIX(s2n_free(&config->context)); + return S2N_RESULT_OK; +} + +int s2n_psk_configure_early_data(struct s2n_psk *psk, uint32_t max_early_data_size, + uint8_t cipher_suite_first_byte, uint8_t cipher_suite_second_byte) +{ + POSIX_ENSURE_REF(psk); + + const uint8_t cipher_suite_iana[] = { cipher_suite_first_byte, cipher_suite_second_byte }; + struct s2n_cipher_suite *cipher_suite = NULL; + POSIX_GUARD_RESULT(s2n_cipher_suite_from_iana(cipher_suite_iana, &cipher_suite)); + POSIX_ENSURE_REF(cipher_suite); + POSIX_ENSURE(cipher_suite->prf_alg == psk->hmac_alg, S2N_ERR_INVALID_ARGUMENT); + + psk->early_data_config.max_early_data_size = max_early_data_size; + psk->early_data_config.protocol_version = S2N_TLS13; + psk->early_data_config.cipher_suite = cipher_suite; + return S2N_SUCCESS; +} + +int s2n_psk_set_application_protocol(struct s2n_psk *psk, const uint8_t *application_protocol, uint8_t size) +{ + POSIX_ENSURE_REF(psk); + if (size > 0) { + POSIX_ENSURE_REF(application_protocol); + } + struct s2n_blob *protocol_blob = &psk->early_data_config.application_protocol; + POSIX_GUARD(s2n_realloc(protocol_blob, size)); + POSIX_CHECKED_MEMCPY(protocol_blob->data, application_protocol, size); + return S2N_SUCCESS; +} + +int s2n_psk_set_early_data_context(struct s2n_psk *psk, const uint8_t *context, uint16_t size) +{ + POSIX_ENSURE_REF(psk); + if (size > 0) { + POSIX_ENSURE_REF(context); + } + struct s2n_blob *context_blob = &psk->early_data_config.context; + POSIX_GUARD(s2n_realloc(context_blob, size)); + POSIX_CHECKED_MEMCPY(context_blob->data, context, size); + return S2N_SUCCESS; +} + +S2N_RESULT s2n_early_data_config_clone(struct s2n_psk *new_psk, struct s2n_early_data_config *old_config) +{ + RESULT_ENSURE_REF(old_config); + RESULT_ENSURE_REF(new_psk); + + struct s2n_early_data_config config_copy = new_psk->early_data_config; + + /* Copy all fields from the old_config EXCEPT the blobs, which we need to reallocate. */ + new_psk->early_data_config = *old_config; + new_psk->early_data_config.application_protocol = config_copy.application_protocol; + new_psk->early_data_config.context = config_copy.context; + + /* Clone / realloc blobs */ + RESULT_GUARD_POSIX(s2n_psk_set_application_protocol(new_psk, old_config->application_protocol.data, + old_config->application_protocol.size)); + RESULT_GUARD_POSIX(s2n_psk_set_early_data_context(new_psk, old_config->context.data, + old_config->context.size)); + + return S2N_RESULT_OK; +} + +int s2n_connection_get_early_data_status(struct s2n_connection *conn, s2n_early_data_status_t *status) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(status); + + switch(conn->early_data_state) { + case S2N_EARLY_DATA_STATES_COUNT: + break; + case S2N_EARLY_DATA_NOT_REQUESTED: + *status = S2N_EARLY_DATA_STATUS_NOT_REQUESTED; + return S2N_SUCCESS; + case S2N_EARLY_DATA_REJECTED: + *status = S2N_EARLY_DATA_STATUS_REJECTED; + return S2N_SUCCESS; + case S2N_END_OF_EARLY_DATA: + *status = S2N_EARLY_DATA_STATUS_END; + return S2N_SUCCESS; + case S2N_UNKNOWN_EARLY_DATA_STATE: + case S2N_EARLY_DATA_REQUESTED: + case S2N_EARLY_DATA_ACCEPTED: + *status = S2N_EARLY_DATA_STATUS_OK; + return S2N_SUCCESS; + } + POSIX_BAIL(S2N_ERR_INVALID_EARLY_DATA_STATE); +} + +static S2N_RESULT s2n_get_remaining_early_data_bytes(struct s2n_connection *conn, uint32_t *early_data_allowed) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(early_data_allowed); + *early_data_allowed = 0; + + uint32_t max_early_data_size = 0; + RESULT_GUARD_POSIX(s2n_connection_get_max_early_data_size(conn, &max_early_data_size)); + + RESULT_ENSURE(max_early_data_size >= conn->early_data_bytes, S2N_ERR_MAX_EARLY_DATA_SIZE); + *early_data_allowed = (max_early_data_size - conn->early_data_bytes); + + return S2N_RESULT_OK; +} + +int s2n_connection_get_remaining_early_data_size(struct s2n_connection *conn, uint32_t *allowed_early_data_size) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(allowed_early_data_size); + *allowed_early_data_size = 0; + + switch(conn->early_data_state) { + case S2N_EARLY_DATA_STATES_COUNT: + case S2N_EARLY_DATA_NOT_REQUESTED: + case S2N_EARLY_DATA_REJECTED: + case S2N_END_OF_EARLY_DATA: + *allowed_early_data_size = 0; + break; + case S2N_UNKNOWN_EARLY_DATA_STATE: + case S2N_EARLY_DATA_REQUESTED: + case S2N_EARLY_DATA_ACCEPTED: + POSIX_GUARD_RESULT(s2n_get_remaining_early_data_bytes(conn, allowed_early_data_size)); + break; + } + return S2N_SUCCESS; +} + +int s2n_connection_get_max_early_data_size(struct s2n_connection *conn, uint32_t *max_early_data_size) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(max_early_data_size); + *max_early_data_size = 0; + + uint32_t server_max_early_data_size = 0; + POSIX_GUARD_RESULT(s2n_early_data_get_server_max_size(conn, &server_max_early_data_size)); + + if (conn->psk_params.psk_list.len == 0) { + /* This method may be called by the server before loading its PSKs. + * The server can load its PSKs during the handshake, either via the PSK selection callback + * or by receiving a stateless session ticket. + * + * Before that happens, we should make an optimistic assumption of the early data size. + * That way, the max early data size always decreases (for example, it won't go from 0 -> UINT32_MAX + * after receiving a PSK in the ClientHello). + */ + if (conn->mode == S2N_SERVER && !IS_NEGOTIATED(conn)) { + *max_early_data_size = server_max_early_data_size; + } + return S2N_SUCCESS; + } + + struct s2n_psk *first_psk = NULL; + POSIX_GUARD_RESULT(s2n_array_get(&conn->psk_params.psk_list, 0, (void**) &first_psk)); + POSIX_ENSURE_REF(first_psk); + *max_early_data_size = first_psk->early_data_config.max_early_data_size; + + /* For the server, we should use the minimum of the limit retrieved from the ticket + * and the current limit being set for new tickets. + * + * This is defensive: even if more early data was previously allowed, the server may not be + * willing or able to handle that much early data now. + * + * We don't do this for external PSKs because the server has intentionally set the limit + * while setting up this connection, not during a previous connection. + */ + if (conn->mode == S2N_SERVER && first_psk->type == S2N_PSK_TYPE_RESUMPTION) { + *max_early_data_size = MIN(*max_early_data_size, server_max_early_data_size); + } + + return S2N_SUCCESS; +} + +int s2n_config_set_early_data_cb(struct s2n_config *config, s2n_early_data_cb cb) +{ + POSIX_ENSURE_REF(config); + config->early_data_cb = cb; + return S2N_SUCCESS; +} + +int s2n_offered_early_data_get_context_length(struct s2n_offered_early_data *early_data, uint16_t *context_len) +{ + POSIX_ENSURE_REF(context_len); + POSIX_ENSURE_REF(early_data); + struct s2n_connection *conn = early_data->conn; + + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->psk_params.chosen_psk); + struct s2n_early_data_config *early_data_config = &conn->psk_params.chosen_psk->early_data_config; + + *context_len = early_data_config->context.size; + + return S2N_SUCCESS; +} + +int s2n_offered_early_data_get_context(struct s2n_offered_early_data *early_data, uint8_t *context, uint16_t max_len) +{ + POSIX_ENSURE_REF(context); + POSIX_ENSURE_REF(early_data); + struct s2n_connection *conn = early_data->conn; + + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->psk_params.chosen_psk); + struct s2n_early_data_config *early_data_config = &conn->psk_params.chosen_psk->early_data_config; + + POSIX_ENSURE(early_data_config->context.size <= max_len, S2N_ERR_INSUFFICIENT_MEM_SIZE); + POSIX_CHECKED_MEMCPY(context, early_data_config->context.data, early_data_config->context.size); + + return S2N_SUCCESS; +} + +int s2n_offered_early_data_reject(struct s2n_offered_early_data *early_data) +{ + POSIX_ENSURE_REF(early_data); + struct s2n_connection *conn = early_data->conn; + POSIX_ENSURE_REF(conn); + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REJECTED)); + return S2N_SUCCESS; +} + +int s2n_offered_early_data_accept(struct s2n_offered_early_data *early_data) +{ + POSIX_ENSURE_REF(early_data); + struct s2n_connection *conn = early_data->conn; + POSIX_ENSURE_REF(conn); + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_ACCEPTED)); + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_early_data.h b/contrib/restricted/aws/s2n/tls/s2n_early_data.h new file mode 100644 index 0000000000..eae7f84367 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_early_data.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#pragma once + +#include "api/s2n.h" + +#include "tls/s2n_crypto_constants.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +struct s2n_psk; + +typedef enum { + S2N_UNKNOWN_EARLY_DATA_STATE = 0, + S2N_EARLY_DATA_REQUESTED, + S2N_EARLY_DATA_NOT_REQUESTED, + S2N_EARLY_DATA_ACCEPTED, + S2N_EARLY_DATA_REJECTED, + S2N_END_OF_EARLY_DATA, + S2N_EARLY_DATA_STATES_COUNT +} s2n_early_data_state; + +S2N_RESULT s2n_connection_set_early_data_state(struct s2n_connection *conn, s2n_early_data_state state); + +struct s2n_early_data_config { + uint32_t max_early_data_size; + uint8_t protocol_version; + struct s2n_cipher_suite *cipher_suite; + struct s2n_blob application_protocol; + struct s2n_blob context; +}; +S2N_CLEANUP_RESULT s2n_early_data_config_free(struct s2n_early_data_config *config); +S2N_RESULT s2n_early_data_config_clone(struct s2n_psk *new_psk, struct s2n_early_data_config *old_config); + +struct s2n_offered_early_data { + struct s2n_connection *conn; +}; + +bool s2n_early_data_is_valid_for_connection(struct s2n_connection *conn); +S2N_RESULT s2n_early_data_accept_or_reject(struct s2n_connection *conn); + +S2N_RESULT s2n_early_data_get_server_max_size(struct s2n_connection *conn, uint32_t *max_early_data_size); + +S2N_RESULT s2n_early_data_record_bytes(struct s2n_connection *conn, ssize_t data_len); +S2N_RESULT s2n_early_data_validate_send(struct s2n_connection *conn, uint32_t bytes_to_send); +S2N_RESULT s2n_early_data_validate_recv(struct s2n_connection *conn); +bool s2n_early_data_is_trial_decryption_allowed(struct s2n_connection *conn, uint8_t record_type); + +int s2n_connection_set_early_data_expected(struct s2n_connection *conn); +int s2n_connection_set_end_of_early_data(struct s2n_connection *conn); diff --git a/contrib/restricted/aws/s2n/tls/s2n_early_data_io.c b/contrib/restricted/aws/s2n/tls/s2n_early_data_io.c new file mode 100644 index 0000000000..1f3d9a9750 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_early_data_io.c @@ -0,0 +1,275 @@ +/* + * 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 <sys/param.h> + +#include "tls/s2n_early_data.h" + +#include "tls/s2n_connection.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" + +int s2n_end_of_early_data_send(struct s2n_connection *conn) +{ + if (conn->early_data_expected) { + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + POSIX_BAIL(S2N_ERR_EARLY_DATA_BLOCKED); + } + + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_END_OF_EARLY_DATA)); + return S2N_SUCCESS; +} + +int s2n_end_of_early_data_recv(struct s2n_connection *conn) +{ + POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_BAD_MESSAGE); + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_END_OF_EARLY_DATA)); + return S2N_SUCCESS; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# If the client attempts a 0-RTT handshake but the server + *# rejects it, the server will generally not have the 0-RTT record + *# protection keys and must instead use trial decryption (either with + *# the 1-RTT handshake keys or by looking for a cleartext ClientHello in + *# the case of a HelloRetryRequest) to find the first non-0-RTT message. + */ +bool s2n_early_data_is_trial_decryption_allowed(struct s2n_connection *conn, uint8_t record_type) +{ + return conn && (conn->early_data_state == S2N_EARLY_DATA_REJECTED) + && record_type == TLS_APPLICATION_DATA + /* Only servers receive early data. */ + && (conn->mode == S2N_SERVER) + /* Early data is only expected during the handshake. */ + && (s2n_conn_get_current_message_type(conn) != APPLICATION_DATA); +} + +static bool s2n_is_early_data_io(struct s2n_connection *conn) +{ + if (s2n_conn_get_current_message_type(conn) == APPLICATION_DATA) { + return false; + } + + /* It would be more accurate to not include this check. + * However, before the early data feature was added, s2n_send and s2n_recv + * did not verify that they were being called after a complete handshake. + * Enforcing that broke several S2N tests, and might have broken customers too. + * + * Therefore, only consider this early data if the customer has indicated that + * they are aware of early data, either because early data is currently expected + * or early data is in a state that indicates that early data was previously expected. + */ + if (conn->early_data_expected + || (conn->mode == S2N_CLIENT && conn->early_data_state == S2N_EARLY_DATA_REQUESTED) + || conn->early_data_state == S2N_EARLY_DATA_ACCEPTED + || conn->early_data_state == S2N_END_OF_EARLY_DATA) { + return true; + } + return false; +} + +S2N_RESULT s2n_early_data_record_bytes(struct s2n_connection *conn, ssize_t data_len) +{ + RESULT_ENSURE_REF(conn); + if (!s2n_is_early_data_io(conn)) { + return S2N_RESULT_OK; + } + + /* Ensure the bytes read are within the bounds of what we can actually record. */ + if (data_len > (UINT64_MAX - conn->early_data_bytes)) { + conn->early_data_bytes = UINT64_MAX; + RESULT_BAIL(S2N_ERR_INTEGER_OVERFLOW); + } + + /* Record the early data bytes read, even if they exceed the max_early_data_size. + * This will ensure that if this method is called again, it will fail again: + * Once we receive too many bytes, we can't proceed with the connection. */ + conn->early_data_bytes += data_len; + + uint32_t max_early_data_size = 0; + RESULT_GUARD_POSIX(s2n_connection_get_max_early_data_size(conn, &max_early_data_size)); + RESULT_ENSURE(conn->early_data_bytes <= max_early_data_size, S2N_ERR_MAX_EARLY_DATA_SIZE); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_early_data_validate_send(struct s2n_connection *conn, uint32_t bytes_to_send) +{ + RESULT_ENSURE_REF(conn); + if (!s2n_is_early_data_io(conn)) { + return S2N_RESULT_OK; + } + + RESULT_ENSURE(conn->early_data_expected, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + RESULT_ENSURE(conn->early_data_state == S2N_EARLY_DATA_REQUESTED + || conn->early_data_state == S2N_EARLY_DATA_ACCEPTED, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + + uint32_t allowed_early_data_size = 0; + RESULT_GUARD_POSIX(s2n_connection_get_remaining_early_data_size(conn, &allowed_early_data_size)); + RESULT_ENSURE(bytes_to_send <= allowed_early_data_size, S2N_ERR_MAX_EARLY_DATA_SIZE); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_early_data_validate_recv(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + if (!s2n_is_early_data_io(conn)) { + return S2N_RESULT_OK; + } + + RESULT_ENSURE(conn->early_data_expected, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + RESULT_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + RESULT_ENSURE(conn->early_data_state == S2N_EARLY_DATA_ACCEPTED, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + RESULT_ENSURE(s2n_conn_get_current_message_type(conn) == END_OF_EARLY_DATA, S2N_ERR_EARLY_DATA_NOT_ALLOWED); + return S2N_RESULT_OK; +} + +static bool s2n_early_data_can_continue(struct s2n_connection *conn) +{ + uint32_t remaining_early_data_size = 0; + return s2n_connection_get_remaining_early_data_size(conn, &remaining_early_data_size) >= S2N_SUCCESS + && remaining_early_data_size > 0; +} + +S2N_RESULT s2n_send_early_data_impl(struct s2n_connection *conn, const uint8_t *data, ssize_t data_len, + ssize_t *data_sent, s2n_blocked_status *blocked) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(blocked); + *blocked = S2N_NOT_BLOCKED; + RESULT_ENSURE_REF(data_sent); + *data_sent = 0; + + RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_SERVER_MODE); + RESULT_ENSURE(s2n_connection_supports_tls13(conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + + if (!s2n_early_data_can_continue(conn)) { + return S2N_RESULT_OK; + } + + /* Attempt to make progress in the handshake even if s2n_send eventually fails. + * We only care about the result of this call if it would prevent us from calling s2n_send. */ + int negotiate_result = s2n_negotiate(conn, blocked); + if (negotiate_result < S2N_SUCCESS) { + if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { + return S2N_RESULT_ERROR; + } else if (*blocked != S2N_BLOCKED_ON_EARLY_DATA && *blocked != S2N_BLOCKED_ON_READ) { + return S2N_RESULT_ERROR; + } + } + /* Save the error status for later */ + int negotiate_error = s2n_errno; + s2n_blocked_status negotiate_blocked = *blocked; + + /* Attempt to send the early data. + * We only care about the result of this call if it fails. */ + uint32_t early_data_to_send = 0; + RESULT_GUARD_POSIX(s2n_connection_get_remaining_early_data_size(conn, &early_data_to_send)); + early_data_to_send = MIN(data_len, early_data_to_send); + if (early_data_to_send) { + ssize_t send_result = s2n_send(conn, data, early_data_to_send, blocked); + RESULT_GUARD_POSIX(send_result); + *data_sent = send_result; + } + *blocked = S2N_NOT_BLOCKED; + + /* Since the send was successful, report the result of the original negotiate call. + * If we got this far, the result must have been success or a blocking error. */ + if (negotiate_result < S2N_SUCCESS) { + RESULT_ENSURE_EQ(s2n_error_get_type(negotiate_error), S2N_ERR_T_BLOCKED); + if (negotiate_blocked == S2N_BLOCKED_ON_EARLY_DATA) { + return S2N_RESULT_OK; + } else if (s2n_early_data_can_continue(conn)) { + *blocked = negotiate_blocked; + RESULT_BAIL(negotiate_error); + } else { + return S2N_RESULT_OK; + } + } + return S2N_RESULT_OK; +} + +int s2n_send_early_data(struct s2n_connection *conn, const uint8_t *data, ssize_t data_len, + ssize_t *data_sent, s2n_blocked_status *blocked) +{ + POSIX_ENSURE_REF(conn); + + /* Calling this method indicates that we expect early data. */ + POSIX_GUARD(s2n_connection_set_early_data_expected(conn)); + + s2n_result result = s2n_send_early_data_impl(conn, data, data_len, data_sent, blocked); + + /* Unless s2n_send_early_data is called again (undoing this), we are done sending early data. + * If s2n_negotiate is called next, we could send the EndOfEarlyData message. */ + POSIX_GUARD(s2n_connection_set_end_of_early_data(conn)); + + POSIX_GUARD_RESULT(result); + return S2N_SUCCESS; +} + +S2N_RESULT s2n_recv_early_data_impl(struct s2n_connection *conn, uint8_t *data, ssize_t max_data_len, + ssize_t *data_received, s2n_blocked_status *blocked) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(blocked); + *blocked = S2N_NOT_BLOCKED; + RESULT_ENSURE_REF(data_received); + *data_received = 0; + + RESULT_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_CLIENT_MODE); + + if (!s2n_early_data_can_continue(conn)) { + return S2N_RESULT_OK; + } + + while(s2n_negotiate(conn, blocked) < S2N_SUCCESS) { + if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { + return S2N_RESULT_ERROR; + } else if (max_data_len <= *data_received) { + return S2N_RESULT_ERROR; + } else if (*blocked != S2N_BLOCKED_ON_EARLY_DATA) { + if (s2n_early_data_can_continue(conn)) { + return S2N_RESULT_ERROR; + } else { + *blocked = S2N_NOT_BLOCKED; + return S2N_RESULT_OK; + } + } + + ssize_t recv_result = s2n_recv(conn, data + *data_received, + max_data_len - *data_received, blocked); + RESULT_GUARD_POSIX(recv_result); + *data_received += recv_result; + } + return S2N_RESULT_OK; +} + +int s2n_recv_early_data(struct s2n_connection *conn, uint8_t *data, ssize_t max_data_len, + ssize_t *data_received, s2n_blocked_status *blocked) +{ + /* Calling this method indicates that we expect early data. */ + POSIX_GUARD(s2n_connection_set_early_data_expected(conn)); + + s2n_result result = s2n_recv_early_data_impl(conn, data, max_data_len, data_received, blocked); + + /* Unless s2n_recv_early_data is called again (undoing this), we are done accepting early data. */ + POSIX_GUARD(s2n_connection_set_end_of_early_data(conn)); + + POSIX_GUARD_RESULT(result); + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c index 12db371abb..f1632a0a53 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c +++ b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "tls/s2n_ecc_preferences.h" #include "tls/s2n_connection.h" @@ -39,6 +39,10 @@ const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_20201021[] = { &s2n_ecc_curve_secp521r1, }; +const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_20210816[] = { + &s2n_ecc_curve_secp384r1, +}; + const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_test_all[] = { #if EVP_APIS_SUPPORTED &s2n_ecc_curve_x25519, @@ -63,6 +67,11 @@ const struct s2n_ecc_preferences s2n_ecc_preferences_20201021 = { .ecc_curves = s2n_ecc_pref_list_20201021, }; +const struct s2n_ecc_preferences s2n_ecc_preferences_20210816 = { + .count = s2n_array_len(s2n_ecc_pref_list_20210816), + .ecc_curves = s2n_ecc_pref_list_20210816, +}; + const struct s2n_ecc_preferences s2n_ecc_preferences_test_all = { .count = s2n_array_len(s2n_ecc_pref_list_test_all), .ecc_curves = s2n_ecc_pref_list_test_all, @@ -80,7 +89,7 @@ int s2n_check_ecc_preferences_curves_list(const struct s2n_ecc_preferences *ecc_ for (int i = 0; i < ecc_preferences->count; i++) { const struct s2n_ecc_named_curve *named_curve = ecc_preferences->ecc_curves[i]; int curve_found = 0; - for (int j = 0; j < s2n_all_supported_curves_list_len; j++) { + for (size_t j = 0; j < s2n_all_supported_curves_list_len; j++) { if (named_curve->iana_id == s2n_all_supported_curves_list[j]->iana_id) { curve_found = 1; break; @@ -88,7 +97,7 @@ int s2n_check_ecc_preferences_curves_list(const struct s2n_ecc_preferences *ecc_ } check *= curve_found; if (check == 0) { - S2N_ERROR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); } } return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h index 96afa8051a..564d722726 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h +++ b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h @@ -15,7 +15,7 @@ #pragma once -#include <s2n.h> +#include "api/s2n.h" #include <strings.h> #include <stdbool.h> @@ -28,6 +28,7 @@ struct s2n_ecc_preferences { extern const struct s2n_ecc_preferences s2n_ecc_preferences_20140601; extern const struct s2n_ecc_preferences s2n_ecc_preferences_20200310; extern const struct s2n_ecc_preferences s2n_ecc_preferences_20201021; +extern const struct s2n_ecc_preferences s2n_ecc_preferences_20210816; extern const struct s2n_ecc_preferences s2n_ecc_preferences_test_all; extern const struct s2n_ecc_preferences s2n_ecc_preferences_null; diff --git a/contrib/restricted/aws/s2n/tls/s2n_encrypted_extensions.c b/contrib/restricted/aws/s2n/tls/s2n_encrypted_extensions.c index d61d7c1b2d..9f47acd8fd 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_encrypted_extensions.c +++ b/contrib/restricted/aws/s2n/tls/s2n_encrypted_extensions.c @@ -36,20 +36,20 @@ int s2n_encrypted_extensions_send(struct s2n_connection *conn) { - notnull_check(conn); - ENSURE_POSIX(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE); struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS, conn, out)); + POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS, conn, out)); return S2N_SUCCESS; } int s2n_encrypted_extensions_recv(struct s2n_connection *conn) { - notnull_check(conn); - ENSURE_POSIX(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE); struct s2n_stuffer *in = &conn->handshake.io; - GUARD(s2n_extension_list_recv(S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS, conn, in)); + POSIX_GUARD(s2n_extension_list_recv(S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS, conn, in)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_establish_session.c b/contrib/restricted/aws/s2n/tls/s2n_establish_session.c index e61b9f2850..18c4fcc8bf 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_establish_session.c +++ b/contrib/restricted/aws/s2n/tls/s2n_establish_session.c @@ -14,7 +14,7 @@ */ #include <stdint.h> -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -32,24 +32,21 @@ * provided session ID in its cache. */ int s2n_establish_session(struct s2n_connection *conn) { - GUARD(s2n_conn_set_handshake_read_block(conn)); - /* Start by receiving and processing the entire CLIENT_HELLO message */ if (!conn->handshake.client_hello_received) { - GUARD(s2n_client_hello_recv(conn)); + POSIX_GUARD(s2n_client_hello_recv(conn)); conn->handshake.client_hello_received = 1; } - GUARD(s2n_conn_set_handshake_type(conn)); + POSIX_GUARD_RESULT(s2n_early_data_accept_or_reject(conn)); + POSIX_GUARD(s2n_conn_set_handshake_type(conn)); if (conn->client_hello_version != S2N_SSLv2) { /* We've selected the parameters for the handshake, update the required hashes for this connection */ - GUARD(s2n_conn_update_required_handshake_hashes(conn)); + POSIX_GUARD(s2n_conn_update_required_handshake_hashes(conn)); } - GUARD(s2n_conn_clear_handshake_read_block(conn)); - return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake.c b/contrib/restricted/aws/s2n/tls/s2n_handshake.c index 922cd67c2b..eb46950ebe 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_handshake.c +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake.c @@ -32,13 +32,13 @@ int s2n_handshake_write_header(struct s2n_stuffer *out, uint8_t message_type) S2N_ERROR_IF(s2n_stuffer_data_available(out), S2N_ERR_HANDSHAKE_STATE); /* Write the message header */ - GUARD(s2n_stuffer_write_uint8(out, message_type)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, message_type)); /* Leave the length blank for now */ uint16_t length = 0; - GUARD(s2n_stuffer_write_uint24(out, length)); + POSIX_GUARD(s2n_stuffer_write_uint24(out, length)); - return 0; + return S2N_SUCCESS; } int s2n_handshake_finish_header(struct s2n_stuffer *out) @@ -49,12 +49,12 @@ int s2n_handshake_finish_header(struct s2n_stuffer *out) uint16_t payload = length - TLS_HANDSHAKE_HEADER_LENGTH; /* Write the message header */ - GUARD(s2n_stuffer_rewrite(out)); - GUARD(s2n_stuffer_skip_write(out, 1)); - GUARD(s2n_stuffer_write_uint24(out, payload)); - GUARD(s2n_stuffer_skip_write(out, payload)); + POSIX_GUARD(s2n_stuffer_rewrite(out)); + POSIX_GUARD(s2n_stuffer_skip_write(out, 1)); + POSIX_GUARD(s2n_stuffer_write_uint24(out, payload)); + POSIX_GUARD(s2n_stuffer_skip_write(out, payload)); - return 0; + return S2N_SUCCESS; } int s2n_handshake_parse_header(struct s2n_connection *conn, uint8_t * message_type, uint32_t * length) @@ -62,85 +62,73 @@ int s2n_handshake_parse_header(struct s2n_connection *conn, uint8_t * message_ty S2N_ERROR_IF(s2n_stuffer_data_available(&conn->handshake.io) < TLS_HANDSHAKE_HEADER_LENGTH, S2N_ERR_SIZE_MISMATCH); /* read the message header */ - GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, message_type)); - GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, length)); + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, message_type)); + POSIX_GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, length)); - return 0; + return S2N_SUCCESS; } static int s2n_handshake_get_hash_state_ptr(struct s2n_connection *conn, s2n_hash_algorithm hash_alg, struct s2n_hash_state **hash_state) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); switch (hash_alg) { case S2N_HASH_MD5: - *hash_state = &conn->handshake.md5; + *hash_state = &conn->handshake.hashes->md5; break; case S2N_HASH_SHA1: - *hash_state = &conn->handshake.sha1; + *hash_state = &conn->handshake.hashes->sha1; break; case S2N_HASH_SHA224: - *hash_state = &conn->handshake.sha224; + *hash_state = &conn->handshake.hashes->sha224; break; case S2N_HASH_SHA256: - *hash_state = &conn->handshake.sha256; + *hash_state = &conn->handshake.hashes->sha256; break; case S2N_HASH_SHA384: - *hash_state = &conn->handshake.sha384; + *hash_state = &conn->handshake.hashes->sha384; break; case S2N_HASH_SHA512: - *hash_state = &conn->handshake.sha512; + *hash_state = &conn->handshake.hashes->sha512; break; case S2N_HASH_MD5_SHA1: - *hash_state = &conn->handshake.md5_sha1; + *hash_state = &conn->handshake.hashes->md5_sha1; break; default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + POSIX_BAIL(S2N_ERR_HASH_INVALID_ALGORITHM); break; } - return 0; + return S2N_SUCCESS; } -int s2n_handshake_reset_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg) +S2N_RESULT s2n_handshake_reset_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg) { - struct s2n_hash_state *hash_state_ptr = NULL; - GUARD(s2n_handshake_get_hash_state_ptr(conn, hash_alg, &hash_state_ptr)); - - GUARD(s2n_hash_reset(hash_state_ptr)); - - return 0; + struct s2n_hash_state *hash_state = NULL; + RESULT_GUARD_POSIX(s2n_handshake_get_hash_state_ptr(conn, hash_alg, &hash_state)); + RESULT_GUARD_POSIX(s2n_hash_reset(hash_state)); + return S2N_RESULT_OK; } -/* Copy the current hash state into the caller supplied pointer. - * NOTE: If the underlying digest implementation is using the EVP API - * then a pointer to the EVP ctx and md is copied. So you are actually - * taking a reference, not a value. - * Before using the hash_state returned by this function you must - * use s2n_hash_copy() to avoid modifying the underlying value. - */ -int s2n_handshake_get_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg, struct s2n_hash_state *hash_state) +S2N_RESULT s2n_handshake_copy_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg, struct s2n_hash_state *copy) { - notnull_check(hash_state); - - struct s2n_hash_state *hash_state_ptr = NULL; - GUARD(s2n_handshake_get_hash_state_ptr(conn, hash_alg, &hash_state_ptr)); - - *hash_state = *hash_state_ptr; - - return 0; + struct s2n_hash_state *hash_state = NULL; + RESULT_GUARD_POSIX(s2n_handshake_get_hash_state_ptr(conn, hash_alg, &hash_state)); + RESULT_GUARD_POSIX(s2n_hash_copy(copy, hash_state)); + return S2N_RESULT_OK; } int s2n_handshake_require_all_hashes(struct s2n_handshake *handshake) { memset(handshake->required_hash_algs, 1, sizeof(handshake->required_hash_algs)); - return 0; + return S2N_SUCCESS; } static int s2n_handshake_require_hash(struct s2n_handshake *handshake, s2n_hash_algorithm hash_alg) { handshake->required_hash_algs[hash_alg] = 1; - return 0; + return S2N_SUCCESS; } uint8_t s2n_handshake_is_hash_required(struct s2n_handshake *handshake, s2n_hash_algorithm hash_alg) @@ -161,12 +149,12 @@ int s2n_conn_update_required_handshake_hashes(struct s2n_connection *conn) message_type_t handshake_message = s2n_conn_get_current_message_type(conn); const uint8_t client_cert_verify_done = (handshake_message >= CLIENT_CERT_VERIFY) ? 1 : 0; s2n_cert_auth_type client_cert_auth_type; - GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); + POSIX_GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); /* If client authentication is possible, all hashes are needed until we're past CLIENT_CERT_VERIFY. */ if ((client_cert_auth_type != S2N_CERT_AUTH_NONE) && !client_cert_verify_done) { - GUARD(s2n_handshake_require_all_hashes(&conn->handshake)); - return 0; + POSIX_GUARD(s2n_handshake_require_all_hashes(&conn->handshake)); + return S2N_SUCCESS; } /* We don't need all of the hashes. Set the hash alg(s) required for the PRF */ @@ -174,8 +162,8 @@ int s2n_conn_update_required_handshake_hashes(struct s2n_connection *conn) case S2N_SSLv3: case S2N_TLS10: case S2N_TLS11: - GUARD(s2n_handshake_require_hash(&conn->handshake, S2N_HASH_MD5)); - GUARD(s2n_handshake_require_hash(&conn->handshake, S2N_HASH_SHA1)); + POSIX_GUARD(s2n_handshake_require_hash(&conn->handshake, S2N_HASH_MD5)); + POSIX_GUARD(s2n_handshake_require_hash(&conn->handshake, S2N_HASH_SHA1)); break; case S2N_TLS12: /* fall through */ @@ -184,13 +172,13 @@ int s2n_conn_update_required_handshake_hashes(struct s2n_connection *conn) /* For TLS 1.2 and TLS 1.3, the cipher suite defines the PRF hash alg */ s2n_hmac_algorithm prf_alg = conn->secure.cipher_suite->prf_alg; s2n_hash_algorithm hash_alg; - GUARD(s2n_hmac_hash_alg(prf_alg, &hash_alg)); - GUARD(s2n_handshake_require_hash(&conn->handshake, hash_alg)); + POSIX_GUARD(s2n_hmac_hash_alg(prf_alg, &hash_alg)); + POSIX_GUARD(s2n_handshake_require_hash(&conn->handshake, hash_alg)); break; } } - return 0; + return S2N_SUCCESS; } /* @@ -216,20 +204,20 @@ int s2n_conn_update_required_handshake_hashes(struct s2n_connection *conn) int s2n_create_wildcard_hostname(struct s2n_stuffer *hostname_stuffer, struct s2n_stuffer *output) { /* Find the end of the first label */ - GUARD(s2n_stuffer_skip_to_char(hostname_stuffer, '.')); + POSIX_GUARD(s2n_stuffer_skip_to_char(hostname_stuffer, '.')); /* No first label found */ if (s2n_stuffer_data_available(hostname_stuffer) == 0) { - return 0; + return S2N_SUCCESS; } /* Slap a single wildcard character to be the first label in output */ - GUARD(s2n_stuffer_write_uint8(output, '*')); + POSIX_GUARD(s2n_stuffer_write_uint8(output, '*')); /* Simply copy the rest of the input to the output. */ - GUARD(s2n_stuffer_copy(hostname_stuffer, output, s2n_stuffer_data_available(hostname_stuffer))); + POSIX_GUARD(s2n_stuffer_copy(hostname_stuffer, output, s2n_stuffer_data_available(hostname_stuffer))); - return 0; + return S2N_SUCCESS; } static int s2n_find_cert_matches(struct s2n_map *domain_name_to_cert_map, @@ -239,7 +227,7 @@ static int s2n_find_cert_matches(struct s2n_map *domain_name_to_cert_map, { struct s2n_blob map_value; bool key_found = false; - GUARD_AS_POSIX(s2n_map_lookup(domain_name_to_cert_map, dns_name, &map_value, &key_found)); + POSIX_GUARD_RESULT(s2n_map_lookup(domain_name_to_cert_map, dns_name, &map_value, &key_found)); if (key_found) { struct certs_by_type *value = (void *) map_value.data; for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) { @@ -248,7 +236,7 @@ static int s2n_find_cert_matches(struct s2n_map *domain_name_to_cert_map, *match_exists = 1; } - return 0; + return S2N_SUCCESS; } /* Find certificates that match the ServerName TLS extension sent by the client. @@ -261,21 +249,21 @@ static int s2n_find_cert_matches(struct s2n_map *domain_name_to_cert_map, int s2n_conn_find_name_matching_certs(struct s2n_connection *conn) { if (!s2n_server_received_server_name(conn)) { - return 0; + return S2N_SUCCESS; } const char *name = conn->server_name; struct s2n_blob hostname_blob = { .data = (uint8_t *) (uintptr_t) name, .size = strlen(name) }; - lte_check(hostname_blob.size, S2N_MAX_SERVER_NAME); + POSIX_ENSURE_LTE(hostname_blob.size, S2N_MAX_SERVER_NAME); char normalized_hostname[S2N_MAX_SERVER_NAME + 1] = { 0 }; - memcpy_check(normalized_hostname, hostname_blob.data, hostname_blob.size); + POSIX_CHECKED_MEMCPY(normalized_hostname, hostname_blob.data, hostname_blob.size); struct s2n_blob normalized_name = { .data = (uint8_t *) normalized_hostname, .size = hostname_blob.size }; - GUARD(s2n_blob_char_to_lower(&normalized_name)); + POSIX_GUARD(s2n_blob_char_to_lower(&normalized_name)); struct s2n_stuffer normalized_hostname_stuffer; - GUARD(s2n_stuffer_init(&normalized_hostname_stuffer, &normalized_name)); - GUARD(s2n_stuffer_skip_write(&normalized_hostname_stuffer, normalized_name.size)); + POSIX_GUARD(s2n_stuffer_init(&normalized_hostname_stuffer, &normalized_name)); + POSIX_GUARD(s2n_stuffer_skip_write(&normalized_hostname_stuffer, normalized_name.size)); /* Find the exact matches for the ServerName */ - GUARD(s2n_find_cert_matches(conn->config->domain_name_to_cert_map, + POSIX_GUARD(s2n_find_cert_matches(conn->config->domain_name_to_cert_map, &normalized_name, conn->handshake_params.exact_sni_matches, &(conn->handshake_params.exact_sni_match_exists))); @@ -285,18 +273,18 @@ int s2n_conn_find_name_matching_certs(struct s2n_connection *conn) char wildcard_hostname[S2N_MAX_SERVER_NAME + 1] = { 0 }; struct s2n_blob wildcard_blob = { .data = (uint8_t *) wildcard_hostname, .size = sizeof(wildcard_hostname) }; struct s2n_stuffer wildcard_stuffer; - GUARD(s2n_stuffer_init(&wildcard_stuffer, &wildcard_blob)); - GUARD(s2n_create_wildcard_hostname(&normalized_hostname_stuffer, &wildcard_stuffer)); + POSIX_GUARD(s2n_stuffer_init(&wildcard_stuffer, &wildcard_blob)); + POSIX_GUARD(s2n_create_wildcard_hostname(&normalized_hostname_stuffer, &wildcard_stuffer)); const uint32_t wildcard_len = s2n_stuffer_data_available(&wildcard_stuffer); /* Couldn't create a valid wildcard from the input */ if (wildcard_len == 0) { - return 0; + return S2N_SUCCESS; } /* The client's SNI is wildcardified, do an exact match against the set of server certs. */ wildcard_blob.size = wildcard_len; - GUARD(s2n_find_cert_matches(conn->config->domain_name_to_cert_map, + POSIX_GUARD(s2n_find_cert_matches(conn->config->domain_name_to_cert_map, &wildcard_blob, conn->handshake_params.wc_sni_matches, &(conn->handshake_params.wc_sni_match_exists))); @@ -309,7 +297,7 @@ int s2n_conn_find_name_matching_certs(struct s2n_connection *conn) || conn->handshake_params.exact_sni_match_exists || conn->handshake_params.wc_sni_match_exists; - return 0; + return S2N_SUCCESS; } /* Find the optimal certificate of a specific type. @@ -329,3 +317,29 @@ struct s2n_cert_chain_and_key *s2n_get_compatible_cert_chain_and_key(struct s2n_ return conn->config->default_certs_by_type.certs[cert_type]; } } + +/* This method will work when testing S2N, and for the EndOfEarlyData message. + * + * However, it will NOT work for arbitrary message types when potentially receiving records + * that contain multiple messages, like when talking to a non-S2N TLS implementation. If the "end_message" + * is not the first message in a multi-message record, negotiation will not stop. + * (This is not an issue for EndOfEarlyData because encryption and message order requirements force + * EndOfEarlyData to always be the first and only handshake message in its handshake record) + */ +S2N_RESULT s2n_negotiate_until_message(struct s2n_connection *conn, s2n_blocked_status *blocked, message_type_t end_message) +{ + RESULT_ENSURE_REF(conn); + conn->handshake.end_of_messages = end_message; + int r = s2n_negotiate(conn, blocked); + conn->handshake.end_of_messages = APPLICATION_DATA; + RESULT_GUARD_POSIX(r); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_handshake_validate(const struct s2n_handshake *s2n_handshake) +{ + RESULT_ENSURE_REF(s2n_handshake); + RESULT_DEBUG_ENSURE(s2n_handshake->handshake_type < 256, S2N_ERR_SAFETY); + RESULT_DEBUG_ENSURE(s2n_handshake->message_number >= 0 && s2n_handshake->message_number < 32, S2N_ERR_SAFETY); + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake.h b/contrib/restricted/aws/s2n/tls/s2n_handshake.h index cb871889e4..5b73d1f626 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_handshake.h +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake.h @@ -16,9 +16,11 @@ #pragma once #include <stdint.h> -#include <s2n.h> +#include "api/s2n.h" #include "tls/s2n_crypto.h" +#include "tls/s2n_handshake_hashes.h" +#include "tls/s2n_handshake_type.h" #include "tls/s2n_signature_algorithms.h" #include "tls/s2n_tls_parameters.h" @@ -32,6 +34,7 @@ #define TLS_CLIENT_HELLO 1 #define TLS_SERVER_HELLO 2 #define TLS_SERVER_NEW_SESSION_TICKET 4 +#define TLS_END_OF_EARLY_DATA 5 #define TLS_ENCRYPTED_EXTENSIONS 8 #define TLS_CERTIFICATE 11 #define TLS_SERVER_KEY 12 @@ -67,23 +70,33 @@ typedef enum { ENCRYPTED_EXTENSIONS, SERVER_CERT_VERIFY, HELLO_RETRY_MSG, + END_OF_EARLY_DATA, APPLICATION_DATA, } message_type_t; typedef enum { S2N_ASYNC_NOT_INVOKED = 0, - S2N_ASYNC_INVOKING_CALLBACK, - S2N_ASYNC_INVOKED_WAITING, - S2N_ASYNC_INVOKED_COMPLETE, + S2N_ASYNC_INVOKED, + S2N_ASYNC_COMPLETE, } s2n_async_state; struct s2n_handshake_parameters { + /* Public keys for server / client */ + struct s2n_pkey server_public_key; + struct s2n_pkey client_public_key; + struct s2n_blob client_cert_chain; + s2n_pkey_type client_cert_pkey_type; + /* Signature/hash algorithm pairs offered by the client in the signature_algorithms extension */ struct s2n_sig_scheme_list client_sig_hash_algs; + /* Signature scheme chosen by the server */ + struct s2n_signature_scheme conn_sig_scheme; /* Signature/hash algorithm pairs offered by the server in the certificate request */ struct s2n_sig_scheme_list server_sig_hash_algs; + /* Signature scheme chosen by the client */ + struct s2n_signature_scheme client_cert_sig_scheme; /* The cert chain we will send the peer. */ struct s2n_cert_chain_and_key *our_chain_and_key; @@ -114,28 +127,15 @@ struct s2n_handshake_parameters { struct s2n_cert_chain_and_key *wc_sni_matches[S2N_CERT_TYPE_COUNT]; uint8_t exact_sni_match_exists; uint8_t wc_sni_match_exists; + + uint8_t client_random[S2N_TLS_RANDOM_DATA_LEN]; + uint8_t server_random[S2N_TLS_RANDOM_DATA_LEN]; }; struct s2n_handshake { struct s2n_stuffer io; - struct s2n_hash_state md5; - struct s2n_hash_state sha1; - struct s2n_hash_state sha224; - struct s2n_hash_state sha256; - struct s2n_hash_state sha384; - struct s2n_hash_state sha512; - struct s2n_hash_state md5_sha1; - - /* A copy of the handshake messages hash used to validate the CertificateVerify message */ - struct s2n_hash_state ccv_hash_copy; - - /* Used for SSLv3, TLS 1.0, and TLS 1.1 PRFs */ - struct s2n_hash_state prf_md5_hash_copy; - struct s2n_hash_state prf_sha1_hash_copy; - /*Used for TLS 1.2 PRF */ - struct s2n_hash_state prf_tls12_hash_copy; - struct s2n_hash_state server_finished_copy; + struct s2n_handshake_hashes *hashes; /* Hash algorithms required for this handshake. The set of required hashes can be reduced as session parameters are * negotiated, i.e. cipher suite and protocol version. @@ -145,53 +145,23 @@ struct s2n_handshake { uint8_t server_finished[S2N_TLS_SECRET_LEN]; uint8_t client_finished[S2N_TLS_SECRET_LEN]; - /* Handshake type is a bitset, with the following - bit positions */ + /* Which message-order affecting features are enabled */ uint32_t handshake_type; -/* Has the handshake been negotiated yet? */ -#define INITIAL 0x00 -#define NEGOTIATED 0x01 -#define IS_NEGOTIATED( type ) ( (type) & NEGOTIATED ) - -/* Handshake is a full handshake */ -#define FULL_HANDSHAKE 0x02 -#define IS_FULL_HANDSHAKE( type ) ( (type) & FULL_HANDSHAKE ) -#define IS_RESUMPTION_HANDSHAKE( type ) ( !IS_FULL_HANDSHAKE( (type) ) && IS_NEGOTIATED ( (type) ) ) - -/* Handshake uses perfect forward secrecy */ -#define TLS12_PERFECT_FORWARD_SECRECY 0x04 - -/* Handshake needs OCSP status message */ -#define OCSP_STATUS 0x08 -#define IS_OCSP_STAPLED( type ) ( ( (type) & OCSP_STATUS ) != 0 ) - -/* Handshake should request a Client Certificate */ -#define CLIENT_AUTH 0x10 -#define IS_CLIENT_AUTH_HANDSHAKE( type ) ( (type) & CLIENT_AUTH ) - -/* Session Resumption via session-tickets */ -#define WITH_SESSION_TICKET 0x20 -#define IS_ISSUING_NEW_SESSION_TICKET( type ) ( (type) & WITH_SESSION_TICKET ) - -/* Handshake requested a Client Certificate but did not get one */ -#define NO_CLIENT_CERT 0x40 -#define IS_CLIENT_AUTH_NO_CERT( type ) ( IS_CLIENT_AUTH_HANDSHAKE( (type) ) && ( (type) & NO_CLIENT_CERT) ) - -/* A HelloRetryRequest was needed to proceed with the handshake */ -#define HELLO_RETRY_REQUEST 0x80 - -/* Disguise a TLS1.3 handshake as a TLS1.2 handshake for backwards compatibility - * with some middleboxes: https://tools.ietf.org/html/rfc8446#appendix-D.4 */ -#define MIDDLEBOX_COMPAT 0x100 -#define IS_MIDDLEBOX_COMPAT_MODE( type ) ( (type) & MIDDLEBOX_COMPAT ) - /* Which handshake message number are we processing */ int message_number; + /* Last message in the handshake. Unless using early data or testing, + * should always be APPLICATION_DATA. */ + message_type_t end_of_messages; + /* State of the async pkey operation during handshake */ s2n_async_state async_state; + /* State of the async early data callback. + * If not initialized, then the callback has not been triggered yet. */ + struct s2n_offered_early_data early_data_async_state; + /* Indicates the CLIENT_HELLO message has been completely received */ unsigned client_hello_received:1; @@ -202,19 +172,28 @@ struct s2n_handshake { unsigned rsa_failed:1; }; -extern message_type_t s2n_conn_get_current_message_type(struct s2n_connection *conn); -extern int s2n_conn_set_handshake_type(struct s2n_connection *conn); -extern int s2n_conn_set_handshake_no_client_cert(struct s2n_connection *conn); -extern int s2n_conn_set_handshake_read_block(struct s2n_connection *conn); -extern int s2n_conn_clear_handshake_read_block(struct s2n_connection *conn); -extern int s2n_handshake_require_all_hashes(struct s2n_handshake *handshake); -extern uint8_t s2n_handshake_is_hash_required(struct s2n_handshake *handshake, s2n_hash_algorithm hash_alg); -extern int s2n_conn_update_required_handshake_hashes(struct s2n_connection *conn); -extern int s2n_handshake_get_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg, struct s2n_hash_state *hash_state); -extern int s2n_handshake_reset_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg); -extern int s2n_conn_find_name_matching_certs(struct s2n_connection *conn); -extern int s2n_create_wildcard_hostname(struct s2n_stuffer *hostname, struct s2n_stuffer *output); +/* Only used in our test cases. */ +message_type_t s2n_conn_get_current_message_type(struct s2n_connection *conn); + +/* s2n_handshake */ +int s2n_handshake_require_all_hashes(struct s2n_handshake *handshake); +uint8_t s2n_handshake_is_hash_required(struct s2n_handshake *handshake, s2n_hash_algorithm hash_alg); +int s2n_conn_update_required_handshake_hashes(struct s2n_connection *conn); +S2N_RESULT s2n_handshake_copy_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg, struct s2n_hash_state *hash_state); +S2N_RESULT s2n_handshake_reset_hash_state(struct s2n_connection *conn, s2n_hash_algorithm hash_alg); +int s2n_conn_find_name_matching_certs(struct s2n_connection *conn); +int s2n_create_wildcard_hostname(struct s2n_stuffer *hostname, struct s2n_stuffer *output); struct s2n_cert_chain_and_key *s2n_get_compatible_cert_chain_and_key(struct s2n_connection *conn, const s2n_pkey_type cert_type); +S2N_RESULT s2n_negotiate_until_message(struct s2n_connection *conn, s2n_blocked_status *blocked, message_type_t end_message); +S2N_RESULT s2n_handshake_validate(const struct s2n_handshake *s2n_handshake); + +/* s2n_handshake_io */ +int s2n_conn_set_handshake_type(struct s2n_connection *conn); +int s2n_conn_set_handshake_no_client_cert(struct s2n_connection *conn); + +/* s2n_handshake_transcript */ int s2n_conn_update_handshake_hashes(struct s2n_connection *conn, struct s2n_blob *data); + +/* s2n_quic_support */ S2N_RESULT s2n_quic_read_handshake_message(struct s2n_connection *conn, uint8_t *message_type); S2N_RESULT s2n_quic_write_handshake_message(struct s2n_connection *conn, struct s2n_blob *in); diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_hashes.c b/contrib/restricted/aws/s2n/tls/s2n_handshake_hashes.c new file mode 100644 index 0000000000..c3c727af81 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_hashes.c @@ -0,0 +1,126 @@ +/* + * 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_handshake_hashes.h" + +#include "crypto/s2n_fips.h" +#include "tls/s2n_connection.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" + +static S2N_RESULT s2n_handshake_hashes_new_hashes(struct s2n_handshake_hashes *hashes) +{ + RESULT_ENSURE_REF(hashes); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->md5)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->sha1)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->sha224)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->sha256)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->sha384)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->sha512)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->md5_sha1)); + RESULT_GUARD_POSIX(s2n_hash_new(&hashes->hash_workspace)); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_handshake_hashes_reset_hashes(struct s2n_handshake_hashes *hashes) +{ + RESULT_ENSURE_REF(hashes); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->md5)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->sha1)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->sha224)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->sha256)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->sha384)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->sha512)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->md5_sha1)); + RESULT_GUARD_POSIX(s2n_hash_reset(&hashes->hash_workspace)); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_handshake_hashes_free_hashes(struct s2n_handshake_hashes *hashes) +{ + if (!hashes) { + return S2N_RESULT_OK; + } + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->md5)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->sha1)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->sha224)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->sha256)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->sha384)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->sha512)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->md5_sha1)); + RESULT_GUARD_POSIX(s2n_hash_free(&hashes->hash_workspace)); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_handshake_hashes_init_hashes(struct s2n_handshake_hashes *hashes) +{ + /* Allow MD5 for hash states that are used by the PRF. This is required + * to comply with the TLS 1.0 and 1.1 RFCs and is approved as per + * NIST Special Publication 800-52 Revision 1. + */ + if (s2n_is_in_fips_mode()) { + RESULT_GUARD_POSIX(s2n_hash_allow_md5_for_fips(&hashes->md5)); + RESULT_GUARD_POSIX(s2n_hash_allow_md5_for_fips(&hashes->hash_workspace)); + + /* Do not check s2n_hash_is_available before initialization. Allow MD5 and + * SHA-1 for both fips and non-fips mode. This is required to perform the + * signature checks in the CertificateVerify message in TLS 1.0 and TLS 1.1. + * This is approved per Nist SP 800-52r1.*/ + RESULT_GUARD_POSIX(s2n_hash_allow_md5_for_fips(&hashes->md5_sha1)); + } + + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->md5, S2N_HASH_MD5)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->sha1, S2N_HASH_SHA1)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->sha224, S2N_HASH_SHA224)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->sha256, S2N_HASH_SHA256)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->sha384, S2N_HASH_SHA384)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->sha512, S2N_HASH_SHA512)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->md5_sha1, S2N_HASH_MD5_SHA1)); + RESULT_GUARD_POSIX(s2n_hash_init(&hashes->hash_workspace, S2N_HASH_NONE)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_handshake_hashes_new(struct s2n_handshake_hashes **hashes) +{ + RESULT_ENSURE_REF(hashes); + RESULT_ENSURE_EQ(*hashes, NULL); + + DEFER_CLEANUP(struct s2n_blob data = { 0 }, s2n_free); + RESULT_GUARD_POSIX(s2n_realloc(&data, sizeof(struct s2n_handshake_hashes))); + RESULT_GUARD_POSIX(s2n_blob_zero(&data)); + *hashes = (struct s2n_handshake_hashes*)(void*) data.data; + ZERO_TO_DISABLE_DEFER_CLEANUP(data); + + RESULT_GUARD(s2n_handshake_hashes_new_hashes(*hashes)); + RESULT_GUARD(s2n_handshake_hashes_init_hashes(*hashes)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_handshake_hashes_wipe(struct s2n_handshake_hashes *hashes) +{ + RESULT_GUARD(s2n_handshake_hashes_reset_hashes(hashes)); + return S2N_RESULT_OK; +} + +S2N_CLEANUP_RESULT s2n_handshake_hashes_free(struct s2n_handshake_hashes **hashes) +{ + RESULT_ENSURE_REF(hashes); + RESULT_GUARD(s2n_handshake_hashes_free_hashes(*hashes)); + RESULT_GUARD_POSIX(s2n_free_object((uint8_t**) hashes, sizeof(struct s2n_handshake_hashes))); + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_hashes.h b/contrib/restricted/aws/s2n/tls/s2n_handshake_hashes.h new file mode 100644 index 0000000000..22d157deb4 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_hashes.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#pragma once + +#include "api/s2n.h" + +#include "crypto/s2n_hash.h" +#include "crypto/s2n_tls13_keys.h" + +struct s2n_handshake_hashes { + struct s2n_hash_state md5; + struct s2n_hash_state sha1; + struct s2n_hash_state sha224; + struct s2n_hash_state sha256; + struct s2n_hash_state sha384; + struct s2n_hash_state sha512; + struct s2n_hash_state md5_sha1; + + /* TLS1.3 requires transcript hash digests to calculate secrets. + */ + uint8_t transcript_hash_digest[S2N_TLS13_SECRET_MAX_LEN]; + + /* To avoid allocating memory for hash objects, we reuse one temporary hash object. + * Do NOT rely on this hash state maintaining its value outside of the current context. + */ + struct s2n_hash_state hash_workspace; +}; + +S2N_RESULT s2n_handshake_hashes_new(struct s2n_handshake_hashes **hashes); +S2N_RESULT s2n_handshake_hashes_wipe(struct s2n_handshake_hashes *hashes); +S2N_CLEANUP_RESULT s2n_handshake_hashes_free(struct s2n_handshake_hashes **hashes); diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c b/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c index 5b78ef79c6..3c490212a7 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c @@ -16,7 +16,7 @@ #include <sys/param.h> #include <errno.h> -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -31,14 +31,16 @@ #include "tls/s2n_tls.h" #include "tls/s2n_tls13.h" #include "tls/s2n_tls13_handshake.h" +#include "tls/s2n_tls13_key_schedule.h" #include "tls/s2n_kex.h" +#include "tls/s2n_post_handshake.h" #include "stuffer/s2n_stuffer.h" #include "utils/s2n_safety.h" #include "utils/s2n_socket.h" #include "utils/s2n_random.h" -#include "utils/s2n_str.h" +#include "utils/s2n_bitmap.h" /* clang-format off */ struct s2n_handshake_action { @@ -51,13 +53,13 @@ struct s2n_handshake_action { static int s2n_always_fail_send(struct s2n_connection *conn) { /* This state should never be sending a handshake message. */ - S2N_ERROR(S2N_ERR_HANDSHAKE_UNREACHABLE); + POSIX_BAIL(S2N_ERR_HANDSHAKE_UNREACHABLE); } static int s2n_always_fail_recv(struct s2n_connection *conn) { /* This state should never have an incoming handshake message. */ - S2N_ERROR(S2N_ERR_HANDSHAKE_UNREACHABLE); + POSIX_BAIL(S2N_ERR_HANDSHAKE_UNREACHABLE); } /* Client and Server handlers for each message type we support. @@ -100,6 +102,7 @@ static struct s2n_handshake_action tls13_state_machine[] = { [CLIENT_CERT] = {TLS_HANDSHAKE, TLS_CERTIFICATE, 'C', {s2n_client_cert_recv, s2n_client_cert_send}}, [CLIENT_CERT_VERIFY] = {TLS_HANDSHAKE, TLS_CERT_VERIFY, 'C', {s2n_tls13_cert_verify_recv, s2n_tls13_cert_verify_send}}, [CLIENT_FINISHED] = {TLS_HANDSHAKE, TLS_FINISHED, 'C', {s2n_tls13_client_finished_recv, s2n_tls13_client_finished_send}}, + [END_OF_EARLY_DATA] = {TLS_HANDSHAKE, TLS_END_OF_EARLY_DATA, 'C', {s2n_end_of_early_data_recv, s2n_end_of_early_data_send}}, /* Not used by TLS1.3, except to maintain middlebox compatibility */ [CLIENT_CHANGE_CIPHER_SPEC] = {TLS_CHANGE_CIPHER_SPEC, 0, 'C', {s2n_basic_ccs_recv, s2n_ccs_send}}, @@ -129,12 +132,10 @@ static const char *message_names[] = { MESSAGE_NAME_ENTRY(SERVER_CHANGE_CIPHER_SPEC), MESSAGE_NAME_ENTRY(SERVER_FINISHED), MESSAGE_NAME_ENTRY(HELLO_RETRY_MSG), + MESSAGE_NAME_ENTRY(END_OF_EARLY_DATA), MESSAGE_NAME_ENTRY(APPLICATION_DATA), }; -/* Maximum number of valid handshakes */ -#define S2N_HANDSHAKES_COUNT 512 - /* Maximum number of messages in a handshake */ #define S2N_MAX_HANDSHAKE_LENGTH 32 @@ -366,11 +367,21 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L SERVER_HELLO }, + [INITIAL | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + SERVER_HELLO + }, + [INITIAL | HELLO_RETRY_REQUEST] = { CLIENT_HELLO, HELLO_RETRY_MSG }, + [INITIAL | HELLO_RETRY_REQUEST | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + HELLO_RETRY_MSG + }, + [NEGOTIATED] = { CLIENT_HELLO, SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, @@ -378,6 +389,13 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | WITH_EARLY_DATA] = { + CLIENT_HELLO, + SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, + END_OF_EARLY_DATA, CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | MIDDLEBOX_COMPAT] = { CLIENT_HELLO, SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, @@ -385,6 +403,27 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, + CLIENT_FINISHED, + APPLICATION_DATA + }, + + [NEGOTIATED | MIDDLEBOX_COMPAT | WITH_EARLY_DATA] = { + CLIENT_HELLO, + SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, + CLIENT_CHANGE_CIPHER_SPEC, END_OF_EARLY_DATA, CLIENT_FINISHED, + APPLICATION_DATA + }, + + [NEGOTIATED | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS | WITH_EARLY_DATA] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, + END_OF_EARLY_DATA, CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | HELLO_RETRY_REQUEST] = { CLIENT_HELLO, HELLO_RETRY_MSG, @@ -403,6 +442,15 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | HELLO_RETRY_REQUEST | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + HELLO_RETRY_MSG, SERVER_CHANGE_CIPHER_SPEC, + CLIENT_HELLO, + SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_FINISHED, + CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | FULL_HANDSHAKE] = { CLIENT_HELLO, SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, @@ -417,6 +465,13 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | FULL_HANDSHAKE | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, + CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | FULL_HANDSHAKE | HELLO_RETRY_REQUEST] = { CLIENT_HELLO, HELLO_RETRY_MSG, @@ -435,6 +490,15 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | FULL_HANDSHAKE | HELLO_RETRY_REQUEST | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + HELLO_RETRY_MSG, SERVER_CHANGE_CIPHER_SPEC, + CLIENT_HELLO, + SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, + CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | FULL_HANDSHAKE | HELLO_RETRY_REQUEST | CLIENT_AUTH] = { CLIENT_HELLO, HELLO_RETRY_MSG, @@ -453,6 +517,15 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | FULL_HANDSHAKE | HELLO_RETRY_REQUEST | CLIENT_AUTH | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + HELLO_RETRY_MSG, SERVER_CHANGE_CIPHER_SPEC, + CLIENT_HELLO, + SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_CERT_REQ, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, + CLIENT_CERT, CLIENT_CERT_VERIFY, CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | FULL_HANDSHAKE | HELLO_RETRY_REQUEST | CLIENT_AUTH | NO_CLIENT_CERT] = { CLIENT_HELLO, HELLO_RETRY_MSG, @@ -471,6 +544,15 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | FULL_HANDSHAKE | HELLO_RETRY_REQUEST | CLIENT_AUTH | NO_CLIENT_CERT | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + HELLO_RETRY_MSG, SERVER_CHANGE_CIPHER_SPEC, + CLIENT_HELLO, + SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_CERT_REQ, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, + CLIENT_CERT, CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | FULL_HANDSHAKE | CLIENT_AUTH] = { CLIENT_HELLO, SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_CERT_REQ, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, @@ -485,6 +567,13 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L APPLICATION_DATA }, + [NEGOTIATED | FULL_HANDSHAKE | CLIENT_AUTH | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_CERT_REQ, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, + CLIENT_CERT, CLIENT_CERT_VERIFY, CLIENT_FINISHED, + APPLICATION_DATA + }, + [NEGOTIATED | FULL_HANDSHAKE | CLIENT_AUTH | NO_CLIENT_CERT] = { CLIENT_HELLO, SERVER_HELLO, ENCRYPTED_EXTENSIONS, SERVER_CERT_REQ, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, @@ -498,22 +587,38 @@ static message_type_t tls13_handshakes[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_L CLIENT_CHANGE_CIPHER_SPEC, CLIENT_CERT, CLIENT_FINISHED, APPLICATION_DATA }, + + [NEGOTIATED | FULL_HANDSHAKE | CLIENT_AUTH | NO_CLIENT_CERT | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] = { + CLIENT_HELLO, CLIENT_CHANGE_CIPHER_SPEC, + SERVER_HELLO, SERVER_CHANGE_CIPHER_SPEC, ENCRYPTED_EXTENSIONS, SERVER_CERT_REQ, SERVER_CERT, SERVER_CERT_VERIFY, SERVER_FINISHED, + CLIENT_CERT, CLIENT_FINISHED, + APPLICATION_DATA + }, }; /* clang-format on */ -#define MAX_HANDSHAKE_TYPE_LEN 152 +#define MAX_HANDSHAKE_TYPE_LEN 123 static char handshake_type_str[S2N_HANDSHAKES_COUNT][MAX_HANDSHAKE_TYPE_LEN] = {0}; -static const char* handshake_type_names[] = { +static const char* tls12_handshake_type_names[] = { "NEGOTIATED|", "FULL_HANDSHAKE|", + "CLIENT_AUTH|", + "NO_CLIENT_CERT|", "TLS12_PERFECT_FORWARD_SECRECY|", "OCSP_STATUS|", - "CLIENT_AUTH|", "WITH_SESSION_TICKET|", +}; + +static const char* tls13_handshake_type_names[] = { + "NEGOTIATED|", + "FULL_HANDSHAKE|", + "CLIENT_AUTH|", "NO_CLIENT_CERT|", "HELLO_RETRY_REQUEST|", "MIDDLEBOX_COMPAT|", + "WITH_EARLY_DATA|", + "EARLY_CLIENT_CCS|", }; #define IS_TLS13_HANDSHAKE( conn ) ((conn)->actual_protocol_version == S2N_TLS13) @@ -533,7 +638,7 @@ static const char* handshake_type_names[] = { #define CONNECTION_WRITER( conn ) (conn->mode == S2N_CLIENT ? 'C' : 'S') #define CONNECTION_IS_WRITER( conn ) (ACTIVE_STATE(conn).writer == CONNECTION_WRITER(conn)) -/* Used in our test cases */ +/* Only used in our test cases. */ message_type_t s2n_conn_get_current_message_type(struct s2n_connection *conn) { return ACTIVE_MESSAGE(conn); @@ -556,37 +661,37 @@ static int s2n_advance_message(struct s2n_connection *conn) } /* Set TCP_QUICKACK to avoid artificial delay during the handshake */ - GUARD(s2n_socket_quickack(conn)); + POSIX_GUARD(s2n_socket_quickack(conn)); /* If optimized io hasn't been enabled or if the caller started out with a corked socket, * we don't mess with it */ if (!conn->corked_io || s2n_socket_was_corked(conn)) { - return 0; + return S2N_SUCCESS; } /* Are we changing I/O directions */ if (ACTIVE_STATE(conn).writer == previous_writer || ACTIVE_STATE(conn).writer == 'A') { - return 0; + return S2N_SUCCESS; } /* We're the new writer */ if (ACTIVE_STATE(conn).writer == this_mode) { if (s2n_connection_is_managed_corked(conn)) { /* Set TCP_CORK/NOPUSH */ - GUARD(s2n_socket_write_cork(conn)); + POSIX_GUARD(s2n_socket_write_cork(conn)); } - return 0; + return S2N_SUCCESS; } /* We're the new reader, or we reached the "B" writer stage indicating that we're at the application data stage - uncork the data */ if (s2n_connection_is_managed_corked(conn)) { - GUARD(s2n_socket_write_uncork(conn)); + POSIX_GUARD(s2n_socket_write_uncork(conn)); } - return 0; + return S2N_SUCCESS; } int s2n_generate_new_client_session_id(struct s2n_connection *conn) @@ -595,104 +700,149 @@ int s2n_generate_new_client_session_id(struct s2n_connection *conn) struct s2n_blob session_id = { .data = conn->session_id, .size = S2N_TLS_SESSION_ID_MAX_LEN }; /* Generate a new session id */ - GUARD_AS_POSIX(s2n_get_public_random_data(&session_id)); + POSIX_GUARD_RESULT(s2n_get_public_random_data(&session_id)); conn->session_id_len = S2N_TLS_SESSION_ID_MAX_LEN; } - return 0; + return S2N_SUCCESS; } /* Lets the server flag whether a HelloRetryRequest is needed while processing extensions */ int s2n_set_hello_retry_required(struct s2n_connection *conn) { - notnull_check(conn); - - ENSURE_POSIX(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_INVALID_HELLO_RETRY); - conn->handshake.handshake_type |= HELLO_RETRY_REQUEST; + POSIX_ENSURE_REF(conn); + + POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_INVALID_HELLO_RETRY); + POSIX_GUARD_RESULT(s2n_handshake_type_set_tls13_flag(conn, HELLO_RETRY_REQUEST)); + + /* HelloRetryRequests also indicate rejection of early data. + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# A server which receives an "early_data" extension MUST behave in one + *# of three ways: + * + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# - Request that the client send another ClientHello by responding + *# with a HelloRetryRequest. + **/ + if (conn->early_data_state == S2N_EARLY_DATA_REQUESTED) { + POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REJECTED)); + } return S2N_SUCCESS; } bool s2n_is_hello_retry_message(struct s2n_connection *conn) { - return (ACTIVE_MESSAGE(conn) == HELLO_RETRY_MSG); + return (conn != NULL && + s2n_result_is_ok(s2n_handshake_validate(&(conn->handshake))) && + ACTIVE_MESSAGE(conn) == HELLO_RETRY_MSG); } bool s2n_is_hello_retry_handshake(struct s2n_connection *conn) { - return conn->handshake.handshake_type & HELLO_RETRY_REQUEST; + return IS_HELLO_RETRY_HANDSHAKE(conn); } static S2N_RESULT s2n_conn_set_tls13_handshake_type(struct s2n_connection *conn) { - ENSURE_REF(conn); + RESULT_ENSURE_REF(conn); - if (conn->handshake.handshake_type & HELLO_RETRY_REQUEST) { - conn->handshake.handshake_type = HELLO_RETRY_REQUEST; - } else { - conn->handshake.handshake_type = INITIAL; - } + /* Most handshake type flags should be reset before we calculate the handshake type, + * in order to handle changes during retries. + * However, flags that have already affected the message order must be kept to avoid + * rewriting the past. + */ + conn->handshake.handshake_type &= (HELLO_RETRY_REQUEST | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS); /* A handshake type has been negotiated */ - conn->handshake.handshake_type |= NEGOTIATED; + RESULT_GUARD(s2n_handshake_type_set_flag(conn, NEGOTIATED)); if (conn->psk_params.chosen_psk == NULL) { - conn->handshake.handshake_type |= FULL_HANDSHAKE; + RESULT_GUARD(s2n_handshake_type_set_flag(conn, FULL_HANDSHAKE)); + } + + if (conn->early_data_state == S2N_EARLY_DATA_ACCEPTED) { + conn->handshake.handshake_type |= WITH_EARLY_DATA; } s2n_cert_auth_type client_cert_auth_type; - GUARD_AS_RESULT(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); + RESULT_GUARD_POSIX(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); if (conn->mode == S2N_CLIENT && client_cert_auth_type == S2N_CERT_AUTH_REQUIRED - && conn->handshake.handshake_type & FULL_HANDSHAKE) { + && IS_FULL_HANDSHAKE(conn)) { /* If we're a client, and Client Auth is REQUIRED, then the Client must expect the CLIENT_CERT_REQ Message */ - conn->handshake.handshake_type |= CLIENT_AUTH; + RESULT_GUARD(s2n_handshake_type_set_flag(conn, CLIENT_AUTH)); } else if (conn->mode == S2N_SERVER && client_cert_auth_type != S2N_CERT_AUTH_NONE - && conn->handshake.handshake_type & FULL_HANDSHAKE) { + && IS_FULL_HANDSHAKE(conn)) { /* If we're a server, and Client Auth is REQUIRED or OPTIONAL, then the server must send the CLIENT_CERT_REQ Message*/ - conn->handshake.handshake_type |= CLIENT_AUTH; + RESULT_GUARD(s2n_handshake_type_set_flag(conn, CLIENT_AUTH)); } - /* Use middlebox compatibility mode for TLS1.3 by default. - * For now, only disable it when QUIC support is enabled. */ - if (!conn->config->quic_enabled) { - conn->handshake.handshake_type |= MIDDLEBOX_COMPAT; + if (s2n_is_middlebox_compat_enabled(conn)) { + RESULT_GUARD(s2n_handshake_type_set_tls13_flag(conn, MIDDLEBOX_COMPAT)); } return S2N_RESULT_OK; } +static S2N_RESULT s2n_validate_ems_status(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + s2n_extension_type_id ems_ext_id = 0; + RESULT_GUARD_POSIX(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_EMS, &ems_ext_id)); + bool ems_extension_recv = S2N_CBIT_TEST(conn->extension_requests_received, ems_ext_id); + + /** + *= https://tools.ietf.org/rfc/rfc7627#section-5.3 + *# If the original session used the "extended_master_secret" + *# extension but the new ClientHello does not contain it, the server + *# MUST abort the abbreviated handshake. + **/ + if (conn->ems_negotiated) { + RESULT_ENSURE(ems_extension_recv, S2N_ERR_MISSING_EXTENSION); + } + + /* Since we're discarding the resumption ticket, ignore EMS value from the ticket */ + conn->ems_negotiated = ems_extension_recv; + + return S2N_RESULT_OK; +} + int s2n_conn_set_handshake_type(struct s2n_connection *conn) { if (IS_TLS13_HANDSHAKE(conn)) { - GUARD_AS_POSIX(s2n_conn_set_tls13_handshake_type(conn)); + POSIX_GUARD_RESULT(s2n_conn_set_tls13_handshake_type(conn)); return S2N_SUCCESS; } - S2N_ERROR_IF(conn->handshake.handshake_type & HELLO_RETRY_REQUEST, S2N_ERR_INVALID_HELLO_RETRY); + POSIX_GUARD_RESULT(s2n_handshake_type_reset(conn)); /* A handshake type has been negotiated */ - conn->handshake.handshake_type = NEGOTIATED; + POSIX_GUARD_RESULT(s2n_handshake_type_set_flag(conn, NEGOTIATED)); s2n_cert_auth_type client_cert_auth_type; - GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); + POSIX_GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); if (conn->mode == S2N_CLIENT && client_cert_auth_type == S2N_CERT_AUTH_REQUIRED) { /* If we're a client, and Client Auth is REQUIRED, then the Client must expect the CLIENT_CERT_REQ Message */ - conn->handshake.handshake_type |= CLIENT_AUTH; + POSIX_GUARD_RESULT(s2n_handshake_type_set_flag(conn, CLIENT_AUTH)); } else if (conn->mode == S2N_SERVER && client_cert_auth_type != S2N_CERT_AUTH_NONE) { /* If we're a server, and Client Auth is REQUIRED or OPTIONAL, then the server must send the CLIENT_CERT_REQ Message*/ - conn->handshake.handshake_type |= CLIENT_AUTH; + POSIX_GUARD_RESULT(s2n_handshake_type_set_flag(conn, CLIENT_AUTH)); } if (conn->config->use_tickets) { if (conn->session_ticket_status == S2N_DECRYPT_TICKET) { - if (!s2n_decrypt_session_ticket(conn)) { - return 0; + if (s2n_decrypt_session_ticket(conn, &conn->client_ticket_to_decrypt) == S2N_SUCCESS) { + return S2N_SUCCESS; } + POSIX_GUARD_RESULT(s2n_validate_ems_status(conn)); + if (s2n_config_is_encrypt_decrypt_key_available(conn->config) == 1) { conn->session_ticket_status = S2N_NEW_TICKET; - conn->handshake.handshake_type |= WITH_SESSION_TICKET; + POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, WITH_SESSION_TICKET)); } /* If a session ticket is presented by the client, then skip lookup in Session ID server cache */ @@ -700,7 +850,7 @@ int s2n_conn_set_handshake_type(struct s2n_connection *conn) } if (conn->session_ticket_status == S2N_NEW_TICKET) { - conn->handshake.handshake_type |= WITH_SESSION_TICKET; + POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, WITH_SESSION_TICKET)); } } @@ -708,92 +858,92 @@ int s2n_conn_set_handshake_type(struct s2n_connection *conn) * Client sent in the ClientHello. */ if (conn->actual_protocol_version <= S2N_TLS12 && conn->mode == S2N_SERVER && s2n_allowed_to_cache_connection(conn)) { int r = s2n_resume_from_cache(conn); - if (r == S2N_SUCCESS || (r < 0 && S2N_ERROR_IS_BLOCKING(s2n_errno))) { + if (r == S2N_SUCCESS || (r < S2N_SUCCESS && S2N_ERROR_IS_BLOCKING(s2n_errno))) { return r; } + POSIX_GUARD_RESULT(s2n_validate_ems_status(conn)); } skip_cache_lookup: if (conn->mode == S2N_CLIENT && conn->client_session_resumed == 1) { - return 0; + return S2N_SUCCESS; } /* If we're doing full handshake, generate a new session id. */ - GUARD(s2n_generate_new_client_session_id(conn)); + POSIX_GUARD(s2n_generate_new_client_session_id(conn)); /* If we get this far, it's a full handshake */ - conn->handshake.handshake_type |= FULL_HANDSHAKE; + POSIX_GUARD_RESULT(s2n_handshake_type_set_flag(conn, FULL_HANDSHAKE)); bool is_ephemeral = false; - GUARD_AS_POSIX(s2n_kex_is_ephemeral(conn->secure.cipher_suite->key_exchange_alg, &is_ephemeral)); + POSIX_GUARD_RESULT(s2n_kex_is_ephemeral(conn->secure.cipher_suite->key_exchange_alg, &is_ephemeral)); if (is_ephemeral) { - conn->handshake.handshake_type |= TLS12_PERFECT_FORWARD_SECRECY; + POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, TLS12_PERFECT_FORWARD_SECRECY)); } if (s2n_server_can_send_ocsp(conn) || s2n_server_sent_ocsp(conn)) { - conn->handshake.handshake_type |= OCSP_STATUS; + POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, OCSP_STATUS)); } - return 0; + return S2N_SUCCESS; } int s2n_conn_set_handshake_no_client_cert(struct s2n_connection *conn) { s2n_cert_auth_type client_cert_auth_type; - GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); + POSIX_GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); S2N_ERROR_IF(client_cert_auth_type != S2N_CERT_AUTH_OPTIONAL, S2N_ERR_BAD_MESSAGE); - conn->handshake.handshake_type |= NO_CLIENT_CERT; - - return 0; -} - -int s2n_conn_set_handshake_read_block(struct s2n_connection *conn) -{ - notnull_check(conn); - - conn->handshake.paused = 1; - - return 0; -} - -int s2n_conn_clear_handshake_read_block(struct s2n_connection *conn) -{ - notnull_check(conn); - - conn->handshake.paused = 0; + POSIX_GUARD_RESULT(s2n_handshake_type_set_flag(conn, NO_CLIENT_CERT)); - return 0; + return S2N_SUCCESS; } const char *s2n_connection_get_last_message_name(struct s2n_connection *conn) { - notnull_check_ptr(conn); - + PTR_ENSURE_REF(conn); + PTR_GUARD_RESULT(s2n_handshake_validate(&(conn->handshake))); return message_names[ACTIVE_MESSAGE(conn)]; } const char *s2n_connection_get_handshake_type_name(struct s2n_connection *conn) { - notnull_check_ptr(conn); + PTR_ENSURE_REF(conn); + PTR_PRECONDITION(s2n_handshake_validate(&(conn->handshake))); - int handshake_type = conn->handshake.handshake_type; + uint32_t handshake_type = conn->handshake.handshake_type; if (handshake_type == INITIAL) { return "INITIAL"; } + const char** handshake_type_names = tls13_handshake_type_names; + size_t handshake_type_names_len = s2n_array_len(tls13_handshake_type_names); + if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) { + handshake_type_names = tls12_handshake_type_names; + handshake_type_names_len = s2n_array_len(tls12_handshake_type_names); + } + if (handshake_type_str[handshake_type][0] != '\0') { return handshake_type_str[handshake_type]; } - /* Compute handshake_type_str[handshake_type] */ + /* Compute handshake_type_str[handshake_type] by concatenating + * each applicable handshake_type. + * + * Unit tests enforce that the elements of handshake_type_str are always + * long enough to contain the longest possible valid handshake_type, but + * for safety we still handle the case where we need to truncate. + */ char *p = handshake_type_str[handshake_type]; - char *end = p + sizeof(handshake_type_str[0]); - - for (int i = 0; i < s2n_array_len(handshake_type_names); ++i) { + size_t remaining = sizeof(handshake_type_str[0]); + for (size_t i = 0; i < handshake_type_names_len; i++) { if (handshake_type & (1 << i)) { - p = s2n_strcpy(p, end, handshake_type_names[i]); + size_t bytes_to_copy = MIN(remaining, strlen(handshake_type_names[i])); + PTR_CHECKED_MEMCPY(p, handshake_type_names[i], bytes_to_copy); + p[bytes_to_copy] = '\0'; + p += bytes_to_copy; + remaining -= bytes_to_copy; } } @@ -820,11 +970,11 @@ static int s2n_handshake_write_io(struct s2n_connection *conn) */ if (s2n_stuffer_is_wiped(&conn->handshake.io)) { if (record_type == TLS_HANDSHAKE) { - GUARD(s2n_handshake_write_header(&conn->handshake.io, ACTIVE_STATE(conn).message_type)); + POSIX_GUARD(s2n_handshake_write_header(&conn->handshake.io, ACTIVE_STATE(conn).message_type)); } - GUARD(ACTIVE_STATE(conn).handler[conn->mode] (conn)); + POSIX_GUARD(ACTIVE_STATE(conn).handler[conn->mode] (conn)); if (record_type == TLS_HANDSHAKE) { - GUARD(s2n_handshake_finish_header(&conn->handshake.io)); + POSIX_GUARD(s2n_handshake_finish_header(&conn->handshake.io)); } } @@ -832,38 +982,39 @@ static int s2n_handshake_write_io(struct s2n_connection *conn) struct s2n_blob out = {0}; while (s2n_stuffer_data_available(&conn->handshake.io) > 0) { uint16_t max_payload_size = 0; - GUARD_AS_POSIX(s2n_record_max_write_payload_size(conn, &max_payload_size)); + POSIX_GUARD_RESULT(s2n_record_max_write_payload_size(conn, &max_payload_size)); out.size = MIN(s2n_stuffer_data_available(&conn->handshake.io), max_payload_size); out.data = s2n_stuffer_raw_read(&conn->handshake.io, out.size); - notnull_check(out.data); + POSIX_ENSURE_REF(out.data); - if (conn->config->quic_enabled) { - GUARD_AS_POSIX(s2n_quic_write_handshake_message(conn, &out)); + if (s2n_connection_is_quic_enabled(conn)) { + POSIX_GUARD_RESULT(s2n_quic_write_handshake_message(conn, &out)); } else { - GUARD(s2n_record_write(conn, record_type, &out)); + POSIX_GUARD(s2n_record_write(conn, record_type, &out)); } /* MD5 and SHA sum the handshake data too */ if (record_type == TLS_HANDSHAKE) { - GUARD(s2n_conn_update_handshake_hashes(conn, &out)); + POSIX_GUARD(s2n_conn_update_handshake_hashes(conn, &out)); } /* Actually send the record. We could block here. Assume the caller will call flush before coming back. */ - GUARD(s2n_flush(conn, &blocked)); + POSIX_GUARD(s2n_flush(conn, &blocked)); } /* We're done sending the last record, reset everything */ - GUARD(s2n_stuffer_wipe(&conn->out)); - GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->out)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); /* Update the secrets, if necessary */ - GUARD(s2n_tls13_handle_secrets(conn)); + POSIX_GUARD_RESULT(s2n_tls13_secrets_update(conn)); + POSIX_GUARD_RESULT(s2n_tls13_key_schedule_update(conn)); /* Advance the state machine */ - GUARD(s2n_advance_message(conn)); + POSIX_GUARD(s2n_advance_message(conn)); - return 0; + return S2N_SUCCESS; } /* @@ -880,16 +1031,16 @@ static int s2n_read_full_handshake_message(struct s2n_connection *conn, uint8_t * what we can and then continue to the next record read iteration. */ if (s2n_stuffer_data_available(&conn->in) < (TLS_HANDSHAKE_HEADER_LENGTH - current_handshake_data)) { - GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, s2n_stuffer_data_available(&conn->in))); + POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, s2n_stuffer_data_available(&conn->in))); return 1; } /* Get the remainder of the header */ - GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, (TLS_HANDSHAKE_HEADER_LENGTH - current_handshake_data))); + POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, (TLS_HANDSHAKE_HEADER_LENGTH - current_handshake_data))); } uint32_t handshake_message_length; - GUARD(s2n_handshake_parse_header(conn, message_type, &handshake_message_length)); + POSIX_GUARD(s2n_handshake_parse_header(conn, message_type, &handshake_message_length)); S2N_ERROR_IF(handshake_message_length > S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE); @@ -897,7 +1048,7 @@ static int s2n_read_full_handshake_message(struct s2n_connection *conn, uint8_t bytes_to_take = MIN(bytes_to_take, s2n_stuffer_data_available(&conn->in)); /* If the record is handshake data, add it to the handshake buffer */ - GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, bytes_to_take)); + POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, bytes_to_take)); /* If we have the whole handshake message, then success */ if (s2n_stuffer_data_available(&conn->handshake.io) == handshake_message_length) { @@ -905,7 +1056,7 @@ static int s2n_read_full_handshake_message(struct s2n_connection *conn, uint8_t } /* We don't have the whole message, so we'll need to go again */ - GUARD(s2n_stuffer_reread(&conn->handshake.io)); + POSIX_GUARD(s2n_stuffer_reread(&conn->handshake.io)); return 1; } @@ -915,18 +1066,18 @@ static int s2n_handshake_conn_update_hashes(struct s2n_connection *conn) uint8_t message_type; uint32_t handshake_message_length; - GUARD(s2n_stuffer_reread(&conn->handshake.io)); - GUARD(s2n_handshake_parse_header(conn, &message_type, &handshake_message_length)); + POSIX_GUARD(s2n_stuffer_reread(&conn->handshake.io)); + POSIX_GUARD(s2n_handshake_parse_header(conn, &message_type, &handshake_message_length)); struct s2n_blob handshake_record = {0}; handshake_record.data = conn->handshake.io.blob.data; handshake_record.size = TLS_HANDSHAKE_HEADER_LENGTH + handshake_message_length; - notnull_check(handshake_record.data); + POSIX_ENSURE_REF(handshake_record.data); /* MD5 and SHA sum the handshake data too */ - GUARD(s2n_conn_update_handshake_hashes(conn, &handshake_record)); + POSIX_GUARD(s2n_conn_update_handshake_hashes(conn, &handshake_record)); - return 0; + return S2N_SUCCESS; } static int s2n_handshake_handle_sslv2(struct s2n_connection *conn) @@ -935,60 +1086,64 @@ static int s2n_handshake_handle_sslv2(struct s2n_connection *conn) /* Add the message to our handshake hashes */ struct s2n_blob hashed = {.data = conn->header_in.blob.data + 2,.size = 3 }; - GUARD(s2n_conn_update_handshake_hashes(conn, &hashed)); + POSIX_GUARD(s2n_conn_update_handshake_hashes(conn, &hashed)); hashed.data = conn->in.blob.data; hashed.size = s2n_stuffer_data_available(&conn->in); - GUARD(s2n_conn_update_handshake_hashes(conn, &hashed)); + POSIX_GUARD(s2n_conn_update_handshake_hashes(conn, &hashed)); /* Handle an SSLv2 client hello */ - GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, s2n_stuffer_data_available(&conn->in))); + POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, s2n_stuffer_data_available(&conn->in))); /* Set the client hello version */ conn->client_hello_version = S2N_SSLv2; /* Execute the state machine handler */ int r = ACTIVE_STATE(conn).handler[conn->mode](conn); - GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); /* We're done with the record, wipe it */ - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - if (r < 0) { - /* Don't invoke blinding on some of the common errors */ - switch (s2n_errno) { - case S2N_ERR_CANCELLED: - case S2N_ERR_CIPHER_NOT_SUPPORTED: - case S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED: - conn->closed = 1; - break; - case S2N_ERR_IO_BLOCKED: - case S2N_ERR_ASYNC_BLOCKED: - /* A blocking condition is retryable, so we should return without killing the connection. */ - S2N_ERROR_PRESERVE_ERRNO(); - break; - default: - GUARD(s2n_connection_kill(conn)); - } + POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); - return r; - } + WITH_ERROR_BLINDING(conn, POSIX_GUARD(r)); conn->in_status = ENCRYPTED; /* Advance the state machine */ - GUARD(s2n_advance_message(conn)); + POSIX_GUARD(s2n_advance_message(conn)); - return 0; + return S2N_SUCCESS; } static int s2n_try_delete_session_cache(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); if (s2n_allowed_to_cache_connection(conn) > 0) { conn->config->cache_delete(conn, conn->config->cache_delete_data, conn->session_id, conn->session_id_len); } - return 0; + return S2N_SUCCESS; +} + +static S2N_RESULT s2n_wipe_record(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->header_in)); + RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->in)); + conn->in_status = ENCRYPTED; + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_finish_read(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + RESULT_GUARD_POSIX(s2n_handshake_conn_update_hashes(conn)); + RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->handshake.io)); + RESULT_GUARD(s2n_tls13_secrets_update(conn)); + RESULT_GUARD(s2n_tls13_key_schedule_update(conn)); + RESULT_GUARD_POSIX(s2n_advance_message(conn)); + return S2N_RESULT_OK; } /* Reading is a little more complicated than writing as the TLS RFCs allow content @@ -1006,61 +1161,84 @@ static int s2n_handshake_read_io(struct s2n_connection *conn) /* Fill conn->in stuffer necessary for the handshake. * If using TCP, read a record. If using QUIC, read a message. */ - if (conn->config->quic_enabled) { + if (s2n_connection_is_quic_enabled(conn)) { record_type = TLS_HANDSHAKE; - GUARD_AS_POSIX(s2n_quic_read_handshake_message(conn, &message_type)); + POSIX_GUARD_RESULT(s2n_quic_read_handshake_message(conn, &message_type)); } else { - GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2)); + int r = s2n_read_full_record(conn, &record_type, &isSSLv2); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# If the client attempts a 0-RTT handshake but the server + *# rejects it, the server will generally not have the 0-RTT record + *# protection keys and must instead use trial decryption (either with + *# the 1-RTT handshake keys or by looking for a cleartext ClientHello in + *# the case of a HelloRetryRequest) to find the first non-0-RTT message. + *# + *# If the server chooses to accept the "early_data" extension, then it + *# MUST comply with the same error-handling requirements specified for + *# all records when processing early data records. Specifically, if the + *# server fails to decrypt a 0-RTT record following an accepted + *# "early_data" extension, it MUST terminate the connection with a + *# "bad_record_mac" alert as per Section 5.2. + */ + if ((r < S2N_SUCCESS) && (s2n_errno == S2N_ERR_EARLY_DATA_TRIAL_DECRYPT)) { + POSIX_GUARD(s2n_stuffer_reread(&conn->in)); + POSIX_GUARD_RESULT(s2n_early_data_record_bytes(conn, s2n_stuffer_data_available(&conn->in))); + POSIX_GUARD_RESULT(s2n_wipe_record(conn)); + return S2N_SUCCESS; + } + POSIX_GUARD(r); } if (isSSLv2) { S2N_ERROR_IF(record_type != SSLv2_CLIENT_HELLO, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_handshake_handle_sslv2(conn)); + POSIX_GUARD(s2n_handshake_handle_sslv2(conn)); } /* Now we have a record, but it could be a partial fragment of a message, or it might * contain several messages. */ - S2N_ERROR_IF(record_type == TLS_APPLICATION_DATA, S2N_ERR_BAD_MESSAGE); - if (record_type == TLS_CHANGE_CIPHER_SPEC) { + + if (record_type == TLS_APPLICATION_DATA) { + POSIX_ENSURE(conn->early_data_expected, S2N_ERR_BAD_MESSAGE); + POSIX_GUARD_RESULT(s2n_early_data_validate_recv(conn)); + POSIX_BAIL(S2N_ERR_EARLY_DATA_BLOCKED); + } else if (record_type == TLS_CHANGE_CIPHER_SPEC) { /* TLS1.3 can receive unexpected CCS messages at any point in the handshake * due to a peer operating in middlebox compatibility mode. * However, when operating in QUIC mode, S2N should not accept ANY CCS messages, * including these unexpected ones.*/ - if (!IS_TLS13_HANDSHAKE(conn) || conn->config->quic_enabled) { - ENSURE_POSIX(EXPECTED_RECORD_TYPE(conn) == TLS_CHANGE_CIPHER_SPEC, S2N_ERR_BAD_MESSAGE); - ENSURE_POSIX(!CONNECTION_IS_WRITER(conn), S2N_ERR_BAD_MESSAGE); + if (!IS_TLS13_HANDSHAKE(conn) || s2n_connection_is_quic_enabled(conn)) { + POSIX_ENSURE(EXPECTED_RECORD_TYPE(conn) == TLS_CHANGE_CIPHER_SPEC, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(!CONNECTION_IS_WRITER(conn), S2N_ERR_BAD_MESSAGE); } S2N_ERROR_IF(s2n_stuffer_data_available(&conn->in) != 1, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, s2n_stuffer_data_available(&conn->in))); - GUARD(CCS_STATE(conn).handler[conn->mode] (conn)); - GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->handshake.io, s2n_stuffer_data_available(&conn->in))); + POSIX_GUARD(CCS_STATE(conn).handler[conn->mode] (conn)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); /* We're done with the record, wipe it */ - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - conn->in_status = ENCRYPTED; + POSIX_GUARD_RESULT(s2n_wipe_record(conn)); /* Advance the state machine if this was an expected message */ if (EXPECTED_RECORD_TYPE(conn) == TLS_CHANGE_CIPHER_SPEC && !CONNECTION_IS_WRITER(conn)) { - GUARD(s2n_advance_message(conn)); + POSIX_GUARD(s2n_advance_message(conn)); } - return 0; + return S2N_SUCCESS; } else if (record_type != TLS_HANDSHAKE) { if (record_type == TLS_ALERT) { - GUARD(s2n_process_alert_fragment(conn)); + POSIX_GUARD(s2n_process_alert_fragment(conn)); } /* Ignore record types that we don't support */ /* We're done with the record, wipe it */ - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - conn->in_status = ENCRYPTED; - return 0; + POSIX_GUARD_RESULT(s2n_wipe_record(conn)); + return S2N_SUCCESS; } /* Record is a handshake message */ @@ -1070,29 +1248,27 @@ static int s2n_handshake_read_io(struct s2n_connection *conn) /* We're done with negotiating but we have trailing data in this record. Bail on the handshake. */ S2N_ERROR_IF(EXPECTED_RECORD_TYPE(conn) == TLS_APPLICATION_DATA, S2N_ERR_BAD_MESSAGE); int r; - GUARD((r = s2n_read_full_handshake_message(conn, &message_type))); + POSIX_GUARD((r = s2n_read_full_handshake_message(conn, &message_type))); /* Do we need more data? This happens for message fragmentation */ if (r == 1) { /* Break out of this inner loop, but since we're not changing the state, the * outer loop in s2n_handshake_io() will read another record. */ - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - conn->in_status = ENCRYPTED; - return 0; + POSIX_GUARD_RESULT(s2n_wipe_record(conn)); + return S2N_SUCCESS; } s2n_cert_auth_type client_cert_auth_type; - GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); + POSIX_GUARD(s2n_connection_get_client_auth_type(conn, &client_cert_auth_type)); /* If we're a Client, and received a ClientCertRequest message, and ClientAuth * is set to optional, then switch the State Machine that we're using to expect the ClientCertRequest. */ if (conn->mode == S2N_CLIENT && client_cert_auth_type == S2N_CERT_AUTH_OPTIONAL && message_type == TLS_CERT_REQ) { - ENSURE_POSIX(conn->handshake.handshake_type & FULL_HANDSHAKE, S2N_ERR_HANDSHAKE_STATE); - conn->handshake.handshake_type |= CLIENT_AUTH; + POSIX_ENSURE(IS_FULL_HANDSHAKE(conn), S2N_ERR_HANDSHAKE_STATE); + POSIX_GUARD_RESULT(s2n_handshake_type_set_flag(conn, CLIENT_AUTH)); } /* According to rfc6066 section 8, server may choose not to send "CertificateStatus" message even if it has @@ -1100,55 +1276,35 @@ static int s2n_handshake_read_io(struct s2n_connection *conn) if (conn->mode == S2N_CLIENT && EXPECTED_MESSAGE_TYPE(conn) == TLS_SERVER_CERT_STATUS && message_type != TLS_SERVER_CERT_STATUS) { - conn->handshake.handshake_type &= ~OCSP_STATUS; + POSIX_GUARD_RESULT(s2n_handshake_type_unset_tls12_flag(conn, OCSP_STATUS)); } - ENSURE_POSIX(record_type == EXPECTED_RECORD_TYPE(conn), S2N_ERR_BAD_MESSAGE); - ENSURE_POSIX(message_type == EXPECTED_MESSAGE_TYPE(conn), S2N_ERR_BAD_MESSAGE); - ENSURE_POSIX(!CONNECTION_IS_WRITER(conn), S2N_ERR_BAD_MESSAGE); - - /* Call the relevant handler */ - r = ACTIVE_STATE(conn).handler[conn->mode] (conn); - - /* Don't update handshake hashes until after the handler has executed since some handlers need to read the - * hash values before they are updated. */ - GUARD(s2n_handshake_conn_update_hashes(conn)); - - GUARD(s2n_stuffer_wipe(&conn->handshake.io)); - - if (r < 0) { - /* Don't invoke blinding on some of the common errors */ - switch (s2n_errno) { - case S2N_ERR_CANCELLED: - case S2N_ERR_CIPHER_NOT_SUPPORTED: - case S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED: - conn->closed = 1; - break; - case S2N_ERR_IO_BLOCKED: - case S2N_ERR_ASYNC_BLOCKED: - /* A blocking condition is retryable, so we should return without killing the connection. */ - S2N_ERROR_PRESERVE_ERRNO(); - break; - default: - GUARD(s2n_connection_kill(conn)); - } - - return r; + /* + *= https://tools.ietf.org/rfc/rfc5246#section-7.4 + *# The one message that is not bound by these ordering rules + *# is the HelloRequest message, which can be sent at any time, but which + *# SHOULD be ignored by the client if it arrives in the middle of a handshake. + */ + if (message_type == TLS_HELLO_REQUEST) { + POSIX_GUARD(s2n_client_hello_request_recv(conn)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io)); + continue; } - /* Update the secrets, if necessary */ - GUARD(s2n_tls13_handle_secrets(conn)); + POSIX_ENSURE(record_type == EXPECTED_RECORD_TYPE(conn), S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(message_type == EXPECTED_MESSAGE_TYPE(conn), S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(!CONNECTION_IS_WRITER(conn), S2N_ERR_BAD_MESSAGE); + + /* Call the relevant handler */ + WITH_ERROR_BLINDING(conn, POSIX_GUARD(ACTIVE_STATE(conn).handler[conn->mode] (conn))); /* Advance the state machine */ - GUARD(s2n_advance_message(conn)); + POSIX_GUARD_RESULT(s2n_finish_read(conn)); } /* We're done with the record, wipe it */ - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - conn->in_status = ENCRYPTED; - - return 0; + POSIX_GUARD_RESULT(s2n_wipe_record(conn)); + return S2N_SUCCESS; } static int s2n_handle_retry_state(struct s2n_connection *conn) @@ -1160,66 +1316,66 @@ static int s2n_handle_retry_state(struct s2n_connection *conn) s2n_errno = S2N_ERR_OK; const int r = ACTIVE_STATE(conn).handler[conn->mode] (conn); - if (r < 0 && S2N_ERROR_IS_BLOCKING(s2n_errno)) { + if (r < S2N_SUCCESS && S2N_ERROR_IS_BLOCKING(s2n_errno)) { /* If the handler is still waiting for data, return control to the caller. */ S2N_ERROR_PRESERVE_ERRNO(); } + /* Resume the handshake */ + conn->handshake.paused = false; + if (!CONNECTION_IS_WRITER(conn)) { /* We're done parsing the record, reset everything */ - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; } - if (r < 0) { - /* There is some other problem and we should kill the connection. */ - if (conn->session_id_len) { - s2n_try_delete_session_cache(conn); - } - - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); - } - if (CONNECTION_IS_WRITER(conn)) { + POSIX_GUARD(r); + /* If we're the writer and handler just finished, update the record header if * needed and let the s2n_handshake_write_io write the data to the socket */ if (EXPECTED_RECORD_TYPE(conn) == TLS_HANDSHAKE) { - GUARD(s2n_handshake_finish_header(&conn->handshake.io)); + POSIX_GUARD(s2n_handshake_finish_header(&conn->handshake.io)); } } else { + if (r < S2N_SUCCESS && conn->session_id_len) { + s2n_try_delete_session_cache(conn); + } + WITH_ERROR_BLINDING(conn, POSIX_GUARD(r)); + /* The read handler processed the record successfully, we are done with this * record. Advance the state machine. */ - GUARD(s2n_advance_message(conn)); + POSIX_GUARD_RESULT(s2n_finish_read(conn)); } - return 0; + return S2N_SUCCESS; } -int s2n_negotiate(struct s2n_connection *conn, s2n_blocked_status *blocked) +int s2n_negotiate_impl(struct s2n_connection *conn, s2n_blocked_status *blocked) { - notnull_check(conn); - notnull_check(blocked); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(blocked); - while (ACTIVE_STATE(conn).writer != 'B') { + while (ACTIVE_STATE(conn).writer != 'B' && ACTIVE_MESSAGE(conn) != conn->handshake.end_of_messages) { errno = 0; s2n_errno = S2N_ERR_OK; /* Flush any pending I/O or alert messages */ - GUARD(s2n_flush(conn, blocked)); + POSIX_GUARD(s2n_flush(conn, blocked)); /* If the handshake was paused, retry the current message */ if (conn->handshake.paused) { *blocked = S2N_BLOCKED_ON_APPLICATION_INPUT; - GUARD(s2n_handle_retry_state(conn)); + POSIX_GUARD(s2n_handle_retry_state(conn)); } if (CONNECTION_IS_WRITER(conn)) { *blocked = S2N_BLOCKED_ON_WRITE; const int write_result = s2n_handshake_write_io(conn); - if (write_result < 0) { + if (write_result < S2N_SUCCESS) { if (!S2N_ERROR_IS_BLOCKING(s2n_errno)) { /* Non-retryable write error. The peer might have sent an alert. Try and read it. */ const int write_errno = errno; @@ -1240,6 +1396,9 @@ int s2n_negotiate(struct s2n_connection *conn, s2n_blocked_status *blocked) if (s2n_errno == S2N_ERR_ASYNC_BLOCKED) { *blocked = S2N_BLOCKED_ON_APPLICATION_INPUT; + conn->handshake.paused = true; + } else if (s2n_errno == S2N_ERR_EARLY_DATA_BLOCKED) { + *blocked = S2N_BLOCKED_ON_EARLY_DATA; } S2N_ERROR_PRESERVE_ERRNO(); @@ -1248,7 +1407,7 @@ int s2n_negotiate(struct s2n_connection *conn, s2n_blocked_status *blocked) *blocked = S2N_BLOCKED_ON_READ; const int read_result = s2n_handshake_read_io(conn); - if (read_result < 0) { + if (read_result < S2N_SUCCESS) { /* One blocking condition is waiting on the session resumption cache. */ /* So we don't want to delete anything if we are blocked. */ if (!S2N_ERROR_IS_BLOCKING(s2n_errno) && conn->session_id_len) { @@ -1257,19 +1416,38 @@ int s2n_negotiate(struct s2n_connection *conn, s2n_blocked_status *blocked) if (s2n_errno == S2N_ERR_ASYNC_BLOCKED) { *blocked = S2N_BLOCKED_ON_APPLICATION_INPUT; + conn->handshake.paused = true; + } else if (s2n_errno == S2N_ERR_EARLY_DATA_BLOCKED) { + *blocked = S2N_BLOCKED_ON_EARLY_DATA; } S2N_ERROR_PRESERVE_ERRNO(); } } - /* If the handshake has just ended, free up memory */ if (ACTIVE_STATE(conn).writer == 'B') { - GUARD(s2n_stuffer_resize(&conn->handshake.io, 0)); + /* Clean up handshake secrets */ + POSIX_GUARD_RESULT(s2n_tls13_secrets_clean(conn)); + + /* Send any pending post-handshake messages */ + POSIX_GUARD(s2n_post_handshake_send(conn, blocked)); + + /* If the handshake has just ended, free up memory */ + POSIX_GUARD(s2n_stuffer_resize(&conn->handshake.io, 0)); } } *blocked = S2N_NOT_BLOCKED; - return 0; + return S2N_SUCCESS; +} + +int s2n_negotiate(struct s2n_connection *conn, s2n_blocked_status *blocked) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(!conn->negotiate_in_use, S2N_ERR_REENTRANCY); + conn->negotiate_in_use = true; + int result = s2n_negotiate_impl(conn, blocked); + conn->negotiate_in_use = false; + return result; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_transcript.c b/contrib/restricted/aws/s2n/tls/s2n_handshake_transcript.c index 7c6c3dffb6..d0eb448f41 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_handshake_transcript.c +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_transcript.c @@ -24,21 +24,12 @@ /* Length of the synthetic message header */ #define MESSAGE_HASH_HEADER_LENGTH 4 -static int s2n_tls13_conn_copy_server_finished_hash(struct s2n_connection *conn) { - notnull_check(conn); - s2n_tls13_connection_keys(keys, conn); - struct s2n_hash_state hash_state = {0}; - - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); - GUARD(s2n_hash_copy(&conn->handshake.server_finished_copy, &hash_state)); - - return 0; -} - int s2n_conn_update_handshake_hashes(struct s2n_connection *conn, struct s2n_blob *data) { - notnull_check(conn); - notnull_check(data); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(data); + struct s2n_handshake_hashes *hashes = conn->handshake.hashes; + POSIX_ENSURE_REF(hashes); if (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_MD5)) { /* The handshake MD5 hash state will fail the s2n_hash_is_available() check @@ -47,11 +38,11 @@ int s2n_conn_update_handshake_hashes(struct s2n_connection *conn, struct s2n_blo * PRF, which is required to comply with the TLS 1.0 and 1.1 RFCs and is approved * as per NIST Special Publication 800-52 Revision 1. */ - GUARD(s2n_hash_update(&conn->handshake.md5, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->md5, data->data, data->size)); } if (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_SHA1)) { - GUARD(s2n_hash_update(&conn->handshake.sha1, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->sha1, data->data, data->size)); } const uint8_t md5_sha1_required = (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_MD5) && @@ -63,33 +54,26 @@ int s2n_conn_update_handshake_hashes(struct s2n_connection *conn, struct s2n_blo * CertificateVerify message and the PRF. NIST SP 800-52r1 approves use * of MD5_SHA1 for these use cases (see footnotes 15 and 20, and section * 3.3.2) */ - GUARD(s2n_hash_update(&conn->handshake.md5_sha1, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->md5_sha1, data->data, data->size)); } if (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_SHA224)) { - GUARD(s2n_hash_update(&conn->handshake.sha224, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->sha224, data->data, data->size)); } if (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_SHA256)) { - GUARD(s2n_hash_update(&conn->handshake.sha256, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->sha256, data->data, data->size)); } if (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_SHA384)) { - GUARD(s2n_hash_update(&conn->handshake.sha384, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->sha384, data->data, data->size)); } if (s2n_handshake_is_hash_required(&conn->handshake, S2N_HASH_SHA512)) { - GUARD(s2n_hash_update(&conn->handshake.sha512, data->data, data->size)); + POSIX_GUARD(s2n_hash_update(&hashes->sha512, data->data, data->size)); } - /* Copy the CLIENT_HELLO -> SERVER_FINISHED hash. - * TLS1.3 will need it later to calculate the application secrets. */ - if (s2n_connection_get_protocol_version(conn) >= S2N_TLS13 && - s2n_conn_get_current_message_type(conn) == SERVER_FINISHED) { - GUARD(s2n_tls13_conn_copy_server_finished_hash(conn)); - } - - return 0; + return S2N_SUCCESS; } /* When a HelloRetryRequest message is used, the hash transcript needs to be recreated. @@ -99,7 +83,9 @@ int s2n_conn_update_handshake_hashes(struct s2n_connection *conn, struct s2n_blo */ int s2n_server_hello_retry_recreate_transcript(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); + struct s2n_handshake_hashes *hashes = conn->handshake.hashes; + POSIX_ENSURE_REF(hashes); s2n_tls13_connection_keys(keys, conn); uint8_t hash_digest_length = keys.size; @@ -110,27 +96,22 @@ int s2n_server_hello_retry_recreate_transcript(struct s2n_connection *conn) msghdr[MESSAGE_HASH_HEADER_LENGTH - 1] = hash_digest_length; /* Grab the current transcript hash to use as the ClientHello1 value. */ - struct s2n_hash_state hash_state, client_hello1_hash; - uint8_t client_hello1_digest_out[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); - - GUARD(s2n_hash_new(&client_hello1_hash)); - GUARD(s2n_hash_copy(&client_hello1_hash, &hash_state)); - GUARD(s2n_hash_digest(&client_hello1_hash, client_hello1_digest_out, hash_digest_length)); - GUARD(s2n_hash_free(&client_hello1_hash)); + struct s2n_hash_state *client_hello1_hash = &hashes->hash_workspace; + uint8_t client_hello1_digest_out[S2N_MAX_DIGEST_LEN] = { 0 }; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, keys.hash_algorithm, client_hello1_hash)); + POSIX_GUARD(s2n_hash_digest(client_hello1_hash, client_hello1_digest_out, hash_digest_length)); /* Step 1: Reset the hash state */ - GUARD(s2n_handshake_reset_hash_state(conn, keys.hash_algorithm)); + POSIX_GUARD_RESULT(s2n_handshake_reset_hash_state(conn, keys.hash_algorithm)); /* Step 2: Update the transcript with the synthetic message */ struct s2n_blob msg_blob = {0}; - GUARD(s2n_blob_init(&msg_blob, msghdr, MESSAGE_HASH_HEADER_LENGTH)); - GUARD(s2n_conn_update_handshake_hashes(conn, &msg_blob)); + POSIX_GUARD(s2n_blob_init(&msg_blob, msghdr, MESSAGE_HASH_HEADER_LENGTH)); + POSIX_GUARD(s2n_conn_update_handshake_hashes(conn, &msg_blob)); /* Step 3: Update the transcript with the ClientHello1 hash */ - GUARD(s2n_blob_init(&msg_blob, client_hello1_digest_out, hash_digest_length)); - GUARD(s2n_conn_update_handshake_hashes(conn, &msg_blob)); + POSIX_GUARD(s2n_blob_init(&msg_blob, client_hello1_digest_out, hash_digest_length)); + POSIX_GUARD(s2n_conn_update_handshake_hashes(conn, &msg_blob)); - return 0; + return S2N_SUCCESS; } - diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_type.c b/contrib/restricted/aws/s2n/tls/s2n_handshake_type.c new file mode 100644 index 0000000000..1ba27a3684 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_type.c @@ -0,0 +1,73 @@ +/* + * 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_connection.h" +#include "tls/s2n_handshake_type.h" +#include "utils/s2n_safety.h" + +S2N_RESULT s2n_handshake_type_set_flag(struct s2n_connection *conn, s2n_handshake_type_flag flag) +{ + RESULT_ENSURE_REF(conn); + conn->handshake.handshake_type |= flag; + return S2N_RESULT_OK; +} + +bool s2n_handshake_type_check_flag(struct s2n_connection *conn, s2n_handshake_type_flag flag) +{ + return conn && (conn->handshake.handshake_type & flag); +} + +S2N_RESULT s2n_handshake_type_set_tls12_flag(struct s2n_connection *conn, s2n_tls12_handshake_type_flag flag) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE(s2n_connection_get_protocol_version(conn) < S2N_TLS13, S2N_ERR_HANDSHAKE_STATE); + conn->handshake.handshake_type |= flag; + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_handshake_type_unset_tls12_flag(struct s2n_connection *conn, s2n_tls12_handshake_type_flag flag) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE(s2n_connection_get_protocol_version(conn) < S2N_TLS13, S2N_ERR_HANDSHAKE_STATE); + conn->handshake.handshake_type &= ~(flag); + return S2N_RESULT_OK; +} + +bool s2n_handshake_type_check_tls12_flag(struct s2n_connection *conn, s2n_tls12_handshake_type_flag flag) +{ + return conn && s2n_connection_get_protocol_version(conn) < S2N_TLS13 + && (conn->handshake.handshake_type & flag); +} + +S2N_RESULT s2n_handshake_type_set_tls13_flag(struct s2n_connection *conn, s2n_tls13_handshake_type_flag flag) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE(s2n_connection_get_protocol_version(conn) >= S2N_TLS13, S2N_ERR_HANDSHAKE_STATE); + conn->handshake.handshake_type |= flag; + return S2N_RESULT_OK; +} + +bool s2n_handshake_type_check_tls13_flag(struct s2n_connection *conn, s2n_tls13_handshake_type_flag flag) +{ + return s2n_connection_get_protocol_version(conn) >= S2N_TLS13 + && (conn->handshake.handshake_type & flag); +} + +S2N_RESULT s2n_handshake_type_reset(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + conn->handshake.handshake_type = 0; + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_type.h b/contrib/restricted/aws/s2n/tls/s2n_handshake_type.h new file mode 100644 index 0000000000..2163457eb9 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_type.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#pragma once + +#include "utils/s2n_result.h" + +/* Maximum number of valid handshakes */ +#define S2N_HANDSHAKES_COUNT 256 + +#define IS_NEGOTIATED(conn) \ + ( s2n_handshake_type_check_flag(conn, NEGOTIATED) ) + +#define IS_FULL_HANDSHAKE(conn) \ + ( s2n_handshake_type_check_flag(conn, FULL_HANDSHAKE) ) + +#define IS_RESUMPTION_HANDSHAKE(conn) \ + ( !IS_FULL_HANDSHAKE(conn) && IS_NEGOTIATED(conn) ) + +#define IS_CLIENT_AUTH_HANDSHAKE(conn) \ + ( s2n_handshake_type_check_flag(conn, CLIENT_AUTH) ) + +#define IS_CLIENT_AUTH_NO_CERT(conn) \ + ( IS_CLIENT_AUTH_HANDSHAKE(conn) && s2n_handshake_type_check_flag(conn, NO_CLIENT_CERT) ) + +#define IS_TLS12_PERFECT_FORWARD_SECRECY_HANDSHAKE(conn) \ + ( s2n_handshake_type_check_tls12_flag(conn, TLS12_PERFECT_FORWARD_SECRECY) ) + +#define IS_OCSP_STAPLED(conn) \ + ( s2n_handshake_type_check_tls12_flag(conn, OCSP_STATUS) ) + +#define IS_ISSUING_NEW_SESSION_TICKET(conn) \ + ( s2n_handshake_type_check_tls12_flag(conn, WITH_SESSION_TICKET) ) + +#define IS_HELLO_RETRY_HANDSHAKE(conn) \ + ( s2n_handshake_type_check_tls13_flag(conn, HELLO_RETRY_REQUEST) ) + +#define IS_MIDDLEBOX_COMPAT_MODE(conn) \ + ( s2n_handshake_type_check_tls13_flag(conn, MIDDLEBOX_COMPAT) ) + +#define WITH_EARLY_DATA(conn) \ + ( s2n_handshake_type_check_tls13_flag(conn, WITH_EARLY_DATA) ) + +#define WITH_EARLY_CLIENT_CCS(conn) \ + ( s2n_handshake_type_check_tls13_flag(conn, EARLY_CLIENT_CCS) ) + +typedef enum { + INITIAL = 0, + NEGOTIATED = 1, + FULL_HANDSHAKE = 2, + CLIENT_AUTH = 4, + NO_CLIENT_CERT = 8, +} s2n_handshake_type_flag; + +S2N_RESULT s2n_handshake_type_set_flag(struct s2n_connection *conn, s2n_handshake_type_flag flag); +bool s2n_handshake_type_check_flag(struct s2n_connection *conn, s2n_handshake_type_flag flag); + +typedef enum { + TLS12_PERFECT_FORWARD_SECRECY = 16, + OCSP_STATUS = 32, + WITH_SESSION_TICKET = 64, +} s2n_tls12_handshake_type_flag; + +S2N_RESULT s2n_handshake_type_set_tls12_flag(struct s2n_connection *conn, s2n_tls12_handshake_type_flag flag); +S2N_RESULT s2n_handshake_type_unset_tls12_flag(struct s2n_connection *conn, s2n_tls12_handshake_type_flag flag); +bool s2n_handshake_type_check_tls12_flag(struct s2n_connection *conn, s2n_tls12_handshake_type_flag flag); + +typedef enum { + HELLO_RETRY_REQUEST = 16, + MIDDLEBOX_COMPAT = 32, + WITH_EARLY_DATA = 64, + EARLY_CLIENT_CCS = 128, +} s2n_tls13_handshake_type_flag; + +S2N_RESULT s2n_handshake_type_set_tls13_flag(struct s2n_connection *conn, s2n_tls13_handshake_type_flag flag); +bool s2n_handshake_type_check_tls13_flag(struct s2n_connection *conn, s2n_tls13_handshake_type_flag flag); + +S2N_RESULT s2n_handshake_type_reset(struct s2n_connection *conn); diff --git a/contrib/restricted/aws/s2n/tls/s2n_internal.h b/contrib/restricted/aws/s2n/tls/s2n_internal.h new file mode 100644 index 0000000000..5728188f30 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_internal.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#pragma once + +#if ((__GNUC__ >= 4) || defined(__clang__)) && defined(S2N_EXPORTS) +# define S2N_PRIVATE_API __attribute__((visibility("default"))) +#else +# define S2N_PRIVATE_API +#endif /* __GNUC__ >= 4 || defined(__clang__) */ + + +#include <stdint.h> + +/* + * Internal APIs. + * + * These APIs change the behavior of S2N in potentially dangerous ways and should only be + * used for testing purposes. All Internal APIs are subject to change without notice. + */ + +struct s2n_config; +struct s2n_connection; + +/* + * Gets the config set on the connection. + * + * This function will return a pointer to the config set by `s2n_connection_set_config`. + * It will return NULL prior to `s2n_connection_set_config` being called and a config + * being set by the application. + * + * Caution: A config can be associated with multiple connections and should not be + * modified after it has been built. Doing so is undefined behavior. + */ +S2N_PRIVATE_API +extern int s2n_connection_get_config(struct s2n_connection *conn, struct s2n_config **config); + +/* + * Enable polling the async client_hello callback to make progress. + * + * `s2n_negotiate` must be called multiple times to poll the callback function + * and make progress. + */ +S2N_PRIVATE_API +extern int s2n_config_client_hello_cb_enable_poll(struct s2n_config *config); diff --git a/contrib/restricted/aws/s2n/tls/s2n_kem.c b/contrib/restricted/aws/s2n/tls/s2n_kem.c index aef1665918..8566502ccb 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_kem.c +++ b/contrib/restricted/aws/s2n/tls/s2n_kem.c @@ -46,6 +46,18 @@ const struct s2n_kem s2n_bike1_l1_r2 = { .decapsulate = &BIKE1_L1_R2_crypto_kem_dec, }; +const struct s2n_kem s2n_bike_l1_r3 = { + .name = "BIKEr3-Level1", + .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_BIKE1_L1_R3, + .public_key_length = BIKE_L1_R3_PUBLIC_KEY_BYTES, + .private_key_length = BIKE_L1_R3_SECRET_KEY_BYTES, + .shared_secret_key_length = BIKE_L1_R3_SHARED_SECRET_BYTES, + .ciphertext_length = BIKE_L1_R3_CIPHERTEXT_BYTES, + .generate_keypair = &BIKE_L1_R3_crypto_kem_keypair, + .encapsulate = &BIKE_L1_R3_crypto_kem_enc, + .decapsulate = &BIKE_L1_R3_crypto_kem_dec, +}; + const struct s2n_kem s2n_sike_p503_r1 = { .name = "SIKEp503r1-KEM", .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_SIKE_P503_R1, @@ -58,18 +70,6 @@ const struct s2n_kem s2n_sike_p503_r1 = { .decapsulate = &SIKE_P503_r1_crypto_kem_dec, }; -const struct s2n_kem s2n_sike_p434_r2 = { - .name = "SIKEp434r2-KEM", - .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_SIKE_P434_R2, - .public_key_length = SIKE_P434_R2_PUBLIC_KEY_BYTES, - .private_key_length = SIKE_P434_R2_SECRET_KEY_BYTES, - .shared_secret_key_length = SIKE_P434_R2_SHARED_SECRET_BYTES, - .ciphertext_length = SIKE_P434_R2_CIPHERTEXT_BYTES, - .generate_keypair = &SIKE_P434_r2_crypto_kem_keypair, - .encapsulate = &SIKE_P434_r2_crypto_kem_enc, - .decapsulate = &SIKE_P434_r2_crypto_kem_dec, -}; - const struct s2n_kem s2n_kyber_512_r2 = { .name = "kyber512r2", .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_KYBER_512_R2, @@ -94,23 +94,49 @@ const struct s2n_kem s2n_kyber_512_90s_r2 = { .decapsulate = &kyber_512_90s_r2_crypto_kem_dec, }; +const struct s2n_kem s2n_kyber_512_r3 = { + .name = "kyber512r3", + .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_KYBER_512_R3, + .public_key_length = S2N_KYBER_512_R3_PUBLIC_KEY_BYTES, + .private_key_length = S2N_KYBER_512_R3_SECRET_KEY_BYTES, + .shared_secret_key_length = S2N_KYBER_512_R3_SHARED_SECRET_BYTES, + .ciphertext_length = S2N_KYBER_512_R3_CIPHERTEXT_BYTES, + .generate_keypair = &s2n_kyber_512_r3_crypto_kem_keypair, + .encapsulate = &s2n_kyber_512_r3_crypto_kem_enc, + .decapsulate = &s2n_kyber_512_r3_crypto_kem_dec, +}; + +const struct s2n_kem s2n_sike_p434_r3 = { + .name = "SIKEp434r3-KEM", + .kem_extension_id = TLS_PQ_KEM_EXTENSION_ID_SIKE_P434_R3, + .public_key_length = S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES, + .private_key_length = S2N_SIKE_P434_R3_SECRET_KEY_BYTES, + .shared_secret_key_length = S2N_SIKE_P434_R3_SHARED_SECRET_BYTES, + .ciphertext_length = S2N_SIKE_P434_R3_CIPHERTEXT_BYTES, + .generate_keypair = &s2n_sike_p434_r3_crypto_kem_keypair, + .encapsulate = &s2n_sike_p434_r3_crypto_kem_enc, + .decapsulate = &s2n_sike_p434_r3_crypto_kem_dec, +}; + /* These lists should be kept up to date with the above KEMs. Order in the lists * does not matter. Adding a KEM to these lists will not automatically enable * support for the KEM extension - that must be added via the KEM preferences & * security policies. These lists are applicable only to PQ-TLS 1.2. */ const struct s2n_kem *bike_kems[] = { &s2n_bike1_l1_r1, - &s2n_bike1_l1_r2 + &s2n_bike1_l1_r2, + &s2n_bike_l1_r3 }; const struct s2n_kem *sike_kems[] = { &s2n_sike_p503_r1, - &s2n_sike_p434_r2, + &s2n_sike_p434_r3, }; const struct s2n_kem *kyber_kems[] = { &s2n_kyber_512_r2, &s2n_kyber_512_90s_r2, + &s2n_kyber_512_r3, }; const struct s2n_iana_to_kem kem_mapping[3] = { @@ -136,26 +162,25 @@ const struct s2n_iana_to_kem kem_mapping[3] = { * community to use values in the proposed reserved range defined in * https://tools.ietf.org/html/draft-stebila-tls-hybrid-design. * Values for interoperability are defined in - * https://docs.google.com/spreadsheets/d/12YarzaNv3XQNLnvDsWLlRKwtZFhRrDdWf36YlzwrPeg/edit#gid=0. + * https://github.com/open-quantum-safe/openssl/blob/OQS-OpenSSL_1_1_1-stable/oqs-template/oqs-kem-info.md * * The structure of the hybrid share is: * size of ECC key share (2 bytes) * || ECC key share (variable bytes) * || size of PQ key share (2 bytes) * || PQ key share (variable bytes) */ -const struct s2n_kem_group s2n_secp256r1_sike_p434_r2 = { - .name = "secp256r1_sike-p434-r2", - .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_SIKE_P434_R2, +const struct s2n_kem_group s2n_secp256r1_sike_p434_r3 = { + .name = "secp256r1_sike-p434-r3", + .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_SIKE_P434_R3, .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + - (S2N_SIZE_OF_KEY_SHARE_SIZE + SIKE_P434_R2_PUBLIC_KEY_BYTES), + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES), .server_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + - (S2N_SIZE_OF_KEY_SHARE_SIZE + SIKE_P434_R2_CIPHERTEXT_BYTES), + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIKE_P434_R3_CIPHERTEXT_BYTES), .curve = &s2n_ecc_curve_secp256r1, - .kem = &s2n_sike_p434_r2, + .kem = &s2n_sike_p434_r3, }; const struct s2n_kem_group s2n_secp256r1_bike1_l1_r2 = { - /* The name string follows the convention in the above google doc */ .name = "secp256r1_bike-1l1fo-r2", .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_BIKE1_L1_R2, .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + @@ -177,20 +202,41 @@ const struct s2n_kem_group s2n_secp256r1_kyber_512_r2 = { .kem = &s2n_kyber_512_r2, }; +const struct s2n_kem_group s2n_secp256r1_bike_l1_r3 = { + .name = "secp256r1_bike-l1-r3", + .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_BIKE_L1_R3, + .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + BIKE_L1_R3_PUBLIC_KEY_BYTES), + .server_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + BIKE_L1_R3_CIPHERTEXT_BYTES), + .curve = &s2n_ecc_curve_secp256r1, + .kem = &s2n_bike_l1_r3, +}; + +const struct s2n_kem_group s2n_secp256r1_kyber_512_r3 = { + .name = "secp256r1_kyber-512-r3", + .iana_id = TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_512_R3, + .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_KYBER_512_R3_PUBLIC_KEY_BYTES), + .server_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + SECP256R1_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_KYBER_512_R3_CIPHERTEXT_BYTES), + .curve = &s2n_ecc_curve_secp256r1, + .kem = &s2n_kyber_512_r3, +}; + #if EVP_APIS_SUPPORTED -const struct s2n_kem_group s2n_x25519_sike_p434_r2 = { - .name = "x25519_sike-p434-r2", - .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_SIKE_P434_R2, +const struct s2n_kem_group s2n_x25519_sike_p434_r3 = { + .name = "x25519_sike-p434-r3", + .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_SIKE_P434_R3, .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + - (S2N_SIZE_OF_KEY_SHARE_SIZE + SIKE_P434_R2_PUBLIC_KEY_BYTES), + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES), .server_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + - (S2N_SIZE_OF_KEY_SHARE_SIZE + SIKE_P434_R2_CIPHERTEXT_BYTES), + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_SIKE_P434_R3_CIPHERTEXT_BYTES), .curve = &s2n_ecc_curve_x25519, - .kem = &s2n_sike_p434_r2, + .kem = &s2n_sike_p434_r3, }; const struct s2n_kem_group s2n_x25519_bike1_l1_r2 = { - /* The name string follows the convention in the above google doc */ .name = "x25519_bike-1l1fo-r2", .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_BIKE1_L1_R2, .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + @@ -211,28 +257,70 @@ const struct s2n_kem_group s2n_x25519_kyber_512_r2 = { .curve = &s2n_ecc_curve_x25519, .kem = &s2n_kyber_512_r2, }; + +const struct s2n_kem_group s2n_x25519_bike_l1_r3 = { + .name = "x25519_bike-l1-r3", + .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_BIKE_L1_R3, + .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + BIKE_L1_R3_PUBLIC_KEY_BYTES), + .server_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + BIKE_L1_R3_CIPHERTEXT_BYTES), + .curve = &s2n_ecc_curve_x25519, + .kem = &s2n_bike_l1_r3, +}; + +const struct s2n_kem_group s2n_x25519_kyber_512_r3 = { + .name = "x25519_kyber-512-r3", + .iana_id = TLS_PQ_KEM_GROUP_ID_X25519_KYBER_512_R3, + .client_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_KYBER_512_R3_PUBLIC_KEY_BYTES), + .server_share_size = (S2N_SIZE_OF_KEY_SHARE_SIZE + X25519_SHARE_SIZE) + + (S2N_SIZE_OF_KEY_SHARE_SIZE + S2N_KYBER_512_R3_CIPHERTEXT_BYTES), + .curve = &s2n_ecc_curve_x25519, + .kem = &s2n_kyber_512_r3, +}; + + #else -const struct s2n_kem_group s2n_x25519_sike_p434_r2 = { 0 }; const struct s2n_kem_group s2n_x25519_bike1_l1_r2 = { 0 }; const struct s2n_kem_group s2n_x25519_kyber_512_r2 = { 0 }; +const struct s2n_kem_group s2n_x25519_sike_p434_r3 = { 0 }; +const struct s2n_kem_group s2n_x25519_bike_l1_r3 = { 0 }; +const struct s2n_kem_group s2n_x25519_kyber_512_r3 = { 0 }; #endif +const struct s2n_kem_group* ALL_SUPPORTED_KEM_GROUPS[S2N_SUPPORTED_KEM_GROUPS_COUNT] = { + &s2n_secp256r1_bike_l1_r3, + &s2n_secp256r1_sike_p434_r3, + &s2n_secp256r1_kyber_512_r3, + &s2n_secp256r1_bike1_l1_r2, + &s2n_secp256r1_kyber_512_r2, +/* x25519 based tls13_kem_groups require EVP_APIS_SUPPORTED */ +#if EVP_APIS_SUPPORTED + &s2n_x25519_bike_l1_r3, + &s2n_x25519_sike_p434_r3, + &s2n_x25519_kyber_512_r3, + &s2n_x25519_bike1_l1_r2, + &s2n_x25519_kyber_512_r2 +#endif +}; + /* Helper safety macro to call the NIST PQ KEM functions. The NIST * functions may return any non-zero value to indicate failure. */ -#define GUARD_PQ_AS_RESULT(x) ENSURE((x) == 0, S2N_ERR_PQ_CRYPTO) +#define GUARD_PQ_AS_RESULT(x) RESULT_ENSURE((x) == 0, S2N_ERR_PQ_CRYPTO) S2N_RESULT s2n_kem_generate_keypair(struct s2n_kem_params *kem_params) { - ENSURE_REF(kem_params); - ENSURE_REF(kem_params->kem); + RESULT_ENSURE_REF(kem_params); + RESULT_ENSURE_REF(kem_params->kem); const struct s2n_kem *kem = kem_params->kem; - ENSURE_REF(kem->generate_keypair); + RESULT_ENSURE_REF(kem->generate_keypair); - ENSURE_REF(kem_params->public_key.data); - ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY); + RESULT_ENSURE_REF(kem_params->public_key.data); + RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY); /* Need to save the private key for decapsulation */ - GUARD_AS_RESULT(s2n_alloc(&kem_params->private_key, kem->private_key_length)); + RESULT_GUARD_POSIX(s2n_realloc(&kem_params->private_key, kem->private_key_length)); GUARD_PQ_AS_RESULT(kem->generate_keypair(kem_params->public_key.data, kem_params->private_key.data)); return S2N_RESULT_OK; @@ -240,20 +328,20 @@ S2N_RESULT s2n_kem_generate_keypair(struct s2n_kem_params *kem_params) S2N_RESULT s2n_kem_encapsulate(struct s2n_kem_params *kem_params, struct s2n_blob *ciphertext) { - ENSURE_REF(kem_params); - ENSURE_REF(kem_params->kem); + RESULT_ENSURE_REF(kem_params); + RESULT_ENSURE_REF(kem_params->kem); const struct s2n_kem *kem = kem_params->kem; - ENSURE_REF(kem->encapsulate); + RESULT_ENSURE_REF(kem->encapsulate); - ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY); - ENSURE_REF(kem_params->public_key.data); + RESULT_ENSURE(kem_params->public_key.size == kem->public_key_length, S2N_ERR_SAFETY); + RESULT_ENSURE_REF(kem_params->public_key.data); - ENSURE_REF(ciphertext); - ENSURE_REF(ciphertext->data); - ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY); + RESULT_ENSURE_REF(ciphertext); + RESULT_ENSURE_REF(ciphertext->data); + RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY); /* Need to save the shared secret for key derivation */ - GUARD_AS_RESULT(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length)); + RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length)); GUARD_PQ_AS_RESULT(kem->encapsulate(ciphertext->data, kem_params->shared_secret.data, kem_params->public_key.data)); return S2N_RESULT_OK; @@ -261,20 +349,20 @@ S2N_RESULT s2n_kem_encapsulate(struct s2n_kem_params *kem_params, struct s2n_blo S2N_RESULT s2n_kem_decapsulate(struct s2n_kem_params *kem_params, const struct s2n_blob *ciphertext) { - ENSURE_REF(kem_params); - ENSURE_REF(kem_params->kem); + RESULT_ENSURE_REF(kem_params); + RESULT_ENSURE_REF(kem_params->kem); const struct s2n_kem *kem = kem_params->kem; - ENSURE_REF(kem->decapsulate); + RESULT_ENSURE_REF(kem->decapsulate); - ENSURE(kem_params->private_key.size == kem->private_key_length, S2N_ERR_SAFETY); - ENSURE_REF(kem_params->private_key.data); + RESULT_ENSURE(kem_params->private_key.size == kem->private_key_length, S2N_ERR_SAFETY); + RESULT_ENSURE_REF(kem_params->private_key.data); - ENSURE_REF(ciphertext); - ENSURE_REF(ciphertext->data); - ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY); + RESULT_ENSURE_REF(ciphertext); + RESULT_ENSURE_REF(ciphertext->data); + RESULT_ENSURE(ciphertext->size == kem->ciphertext_length, S2N_ERR_SAFETY); /* Need to save the shared secret for key derivation */ - GUARD_AS_RESULT(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length)); + RESULT_GUARD_POSIX(s2n_alloc(&(kem_params->shared_secret), kem->shared_secret_key_length)); GUARD_PQ_AS_RESULT(kem->decapsulate(kem_params->shared_secret.data, ciphertext->data, kem_params->private_key.data)); return S2N_RESULT_OK; @@ -283,7 +371,7 @@ S2N_RESULT s2n_kem_decapsulate(struct s2n_kem_params *kem_params, const struct s static int s2n_kem_check_kem_compatibility(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_kem *candidate_kem, uint8_t *kem_is_compatible) { const struct s2n_iana_to_kem *compatible_kems = NULL; - GUARD(s2n_cipher_suite_to_kem(iana_value, &compatible_kems)); + POSIX_GUARD(s2n_cipher_suite_to_kem(iana_value, &compatible_kems)); for (uint8_t i = 0; i < compatible_kems->kem_count; i++) { if (candidate_kem->kem_extension_id == compatible_kems->kems[i]->kem_extension_id) { @@ -299,8 +387,8 @@ static int s2n_kem_check_kem_compatibility(const uint8_t iana_value[S2N_TLS_CIPH int s2n_choose_kem_with_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], struct s2n_blob *client_kem_ids, const struct s2n_kem *server_kem_pref_list[], const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem) { struct s2n_stuffer client_kem_ids_stuffer = {0}; - GUARD(s2n_stuffer_init(&client_kem_ids_stuffer, client_kem_ids)); - GUARD(s2n_stuffer_write(&client_kem_ids_stuffer, client_kem_ids)); + POSIX_GUARD(s2n_stuffer_init(&client_kem_ids_stuffer, client_kem_ids)); + POSIX_GUARD(s2n_stuffer_write(&client_kem_ids_stuffer, client_kem_ids)); /* Each KEM ID is 2 bytes */ uint8_t num_client_candidate_kems = client_kem_ids->size / 2; @@ -309,7 +397,7 @@ int s2n_choose_kem_with_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_S const struct s2n_kem *candidate_server_kem = (server_kem_pref_list[i]); uint8_t server_kem_is_compatible = 0; - GUARD(s2n_kem_check_kem_compatibility(iana_value, candidate_server_kem, &server_kem_is_compatible)); + POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, candidate_server_kem, &server_kem_is_compatible)); if (!server_kem_is_compatible) { continue; @@ -317,25 +405,25 @@ int s2n_choose_kem_with_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_S for (uint8_t j = 0; j < num_client_candidate_kems; j++) { kem_extension_size candidate_client_kem_id; - GUARD(s2n_stuffer_read_uint16(&client_kem_ids_stuffer, &candidate_client_kem_id)); + POSIX_GUARD(s2n_stuffer_read_uint16(&client_kem_ids_stuffer, &candidate_client_kem_id)); if (candidate_server_kem->kem_extension_id == candidate_client_kem_id) { *chosen_kem = candidate_server_kem; return S2N_SUCCESS; } } - GUARD(s2n_stuffer_reread(&client_kem_ids_stuffer)); + POSIX_GUARD(s2n_stuffer_reread(&client_kem_ids_stuffer)); } /* Client and server did not propose any mutually supported KEMs compatible with the ciphersuite */ - S2N_ERROR(S2N_ERR_KEM_UNSUPPORTED_PARAMS); + POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS); } int s2n_choose_kem_without_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], const struct s2n_kem *server_kem_pref_list[], const uint8_t num_server_supported_kems, const struct s2n_kem **chosen_kem) { for (uint8_t i = 0; i < num_server_supported_kems; i++) { uint8_t kem_is_compatible = 0; - GUARD(s2n_kem_check_kem_compatibility(iana_value, server_kem_pref_list[i], &kem_is_compatible)); + POSIX_GUARD(s2n_kem_check_kem_compatibility(iana_value, server_kem_pref_list[i], &kem_is_compatible)); if (kem_is_compatible) { *chosen_kem = server_kem_pref_list[i]; return S2N_SUCCESS; @@ -343,23 +431,23 @@ int s2n_choose_kem_without_peer_pref_list(const uint8_t iana_value[S2N_TLS_CIPHE } /* The server preference list did not contain any KEM extensions compatible with the ciphersuite */ - S2N_ERROR(S2N_ERR_KEM_UNSUPPORTED_PARAMS); + POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS); } int s2n_kem_free(struct s2n_kem_params *kem_params) { if (kem_params != NULL) { - GUARD(s2n_blob_zeroize_free(&kem_params->private_key)); - GUARD(s2n_blob_zeroize_free(&kem_params->public_key)); - GUARD(s2n_blob_zeroize_free(&kem_params->shared_secret)); + POSIX_GUARD(s2n_blob_zeroize_free(&kem_params->private_key)); + POSIX_GUARD(s2n_blob_zeroize_free(&kem_params->public_key)); + POSIX_GUARD(s2n_blob_zeroize_free(&kem_params->shared_secret)); } return S2N_SUCCESS; } int s2n_kem_group_free(struct s2n_kem_group_params *kem_group_params) { if (kem_group_params != NULL) { - GUARD(s2n_kem_free(&kem_group_params->kem_params)); - GUARD(s2n_ecc_evp_params_free(&kem_group_params->ecc_params)); + POSIX_GUARD(s2n_kem_free(&kem_group_params->kem_params)); + POSIX_GUARD(s2n_ecc_evp_params_free(&kem_group_params->ecc_params)); } return S2N_SUCCESS; } @@ -372,7 +460,7 @@ int s2n_cipher_suite_to_kem(const uint8_t iana_value[S2N_TLS_CIPHER_SUITE_LEN], return S2N_SUCCESS; } } - S2N_ERROR(S2N_ERR_KEM_UNSUPPORTED_PARAMS); + POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS); } int s2n_get_kem_from_extension_id(kem_extension_size kem_id, const struct s2n_kem **kem) { @@ -388,26 +476,26 @@ int s2n_get_kem_from_extension_id(kem_extension_size kem_id, const struct s2n_ke } } - S2N_ERROR(S2N_ERR_KEM_UNSUPPORTED_PARAMS); + POSIX_BAIL(S2N_ERR_KEM_UNSUPPORTED_PARAMS); } int s2n_kem_send_public_key(struct s2n_stuffer *out, struct s2n_kem_params *kem_params) { - notnull_check(out); - notnull_check(kem_params); - notnull_check(kem_params->kem); + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(kem_params); + POSIX_ENSURE_REF(kem_params->kem); const struct s2n_kem *kem = kem_params->kem; - GUARD(s2n_stuffer_write_uint16(out, kem->public_key_length)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->public_key_length)); /* We don't need to store the public key after sending it. * We write it directly to *out. */ kem_params->public_key.data = s2n_stuffer_raw_write(out, kem->public_key_length); - notnull_check(kem_params->public_key.data); + POSIX_ENSURE_REF(kem_params->public_key.data); kem_params->public_key.size = kem->public_key_length; /* Saves the private key in kem_params */ - GUARD_AS_POSIX(s2n_kem_generate_keypair(kem_params)); + POSIX_GUARD_RESULT(s2n_kem_generate_keypair(kem_params)); /* After using s2n_stuffer_raw_write() above to write the public * key to the stuffer, we want to ensure that kem_params->public_key.data @@ -420,61 +508,61 @@ int s2n_kem_send_public_key(struct s2n_stuffer *out, struct s2n_kem_params *kem_ } int s2n_kem_recv_public_key(struct s2n_stuffer *in, struct s2n_kem_params *kem_params) { - notnull_check(in); - notnull_check(kem_params); - notnull_check(kem_params->kem); + POSIX_ENSURE_REF(in); + POSIX_ENSURE_REF(kem_params); + POSIX_ENSURE_REF(kem_params->kem); const struct s2n_kem *kem = kem_params->kem; kem_public_key_size public_key_length; - GUARD(s2n_stuffer_read_uint16(in, &public_key_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &public_key_length)); S2N_ERROR_IF(public_key_length != kem->public_key_length, S2N_ERR_BAD_MESSAGE); /* Alloc memory for the public key; the peer receiving it will need it * later during the handshake to encapsulate the shared secret. */ - GUARD(s2n_alloc(&(kem_params->public_key), public_key_length)); - GUARD(s2n_stuffer_read_bytes(in, kem_params->public_key.data, public_key_length)); + POSIX_GUARD(s2n_alloc(&(kem_params->public_key), public_key_length)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, kem_params->public_key.data, public_key_length)); return S2N_SUCCESS; } int s2n_kem_send_ciphertext(struct s2n_stuffer *out, struct s2n_kem_params *kem_params) { - notnull_check(out); - notnull_check(kem_params); - notnull_check(kem_params->kem); - notnull_check(kem_params->public_key.data); + POSIX_ENSURE_REF(out); + POSIX_ENSURE_REF(kem_params); + POSIX_ENSURE_REF(kem_params->kem); + POSIX_ENSURE_REF(kem_params->public_key.data); const struct s2n_kem *kem = kem_params->kem; - GUARD(s2n_stuffer_write_uint16(out, kem->ciphertext_length)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->ciphertext_length)); /* Ciphertext will get written to *out */ struct s2n_blob ciphertext = {.data = s2n_stuffer_raw_write(out, kem->ciphertext_length), .size = kem->ciphertext_length}; - notnull_check(ciphertext.data); + POSIX_ENSURE_REF(ciphertext.data); /* Saves the shared secret in kem_params */ - GUARD_AS_POSIX(s2n_kem_encapsulate(kem_params, &ciphertext)); + POSIX_GUARD_RESULT(s2n_kem_encapsulate(kem_params, &ciphertext)); return S2N_SUCCESS; } int s2n_kem_recv_ciphertext(struct s2n_stuffer *in, struct s2n_kem_params *kem_params) { - notnull_check(in); - notnull_check(kem_params); - notnull_check(kem_params->kem); - notnull_check(kem_params->private_key.data); + POSIX_ENSURE_REF(in); + POSIX_ENSURE_REF(kem_params); + POSIX_ENSURE_REF(kem_params->kem); + POSIX_ENSURE_REF(kem_params->private_key.data); const struct s2n_kem *kem = kem_params->kem; kem_ciphertext_key_size ciphertext_length; - GUARD(s2n_stuffer_read_uint16(in, &ciphertext_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &ciphertext_length)); S2N_ERROR_IF(ciphertext_length != kem->ciphertext_length, S2N_ERR_BAD_MESSAGE); const struct s2n_blob ciphertext = {.data = s2n_stuffer_raw_read(in, ciphertext_length), .size = ciphertext_length}; - notnull_check(ciphertext.data); + POSIX_ENSURE_REF(ciphertext.data); /* Saves the shared secret in kem_params */ - GUARD_AS_POSIX(s2n_kem_decapsulate(kem_params, &ciphertext)); + POSIX_GUARD_RESULT(s2n_kem_decapsulate(kem_params, &ciphertext)); return S2N_SUCCESS; } @@ -483,27 +571,35 @@ int s2n_kem_recv_ciphertext(struct s2n_stuffer *in, struct s2n_kem_params *kem_p /* If S2N_NO_PQ was defined at compile time, the PQ KEM code will have been entirely excluded * from compilation. We define stubs of these functions here to error if they are called. */ /* sikep503r1 */ -int SIKE_P503_r1_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int SIKE_P503_r1_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int SIKE_P503_r1_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -/* sikep434r2 */ -int SIKE_P434_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int SIKE_P434_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int SIKE_P434_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } +int SIKE_P503_r1_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int SIKE_P503_r1_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int SIKE_P503_r1_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } /* bike1l1r1 */ -int BIKE1_L1_R1_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int BIKE1_L1_R1_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int BIKE1_L1_R1_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } +int BIKE1_L1_R1_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int BIKE1_L1_R1_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int BIKE1_L1_R1_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } /* bike1l1r2*/ -int BIKE1_L1_R2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int BIKE1_L1_R2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int BIKE1_L1_R2_crypto_kem_dec(OUT unsigned char * ss, IN const unsigned char *ct, IN const unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } +int BIKE1_L1_R2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int BIKE1_L1_R2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int BIKE1_L1_R2_crypto_kem_dec(OUT unsigned char * ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +/* bike1l1r3*/ +int BIKE_L1_R3_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int BIKE_L1_R3_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int BIKE_L1_R3_crypto_kem_dec(OUT unsigned char * ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } /* kyber512r2 */ -int kyber_512_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int kyber_512_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int kyber_512_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } +int kyber_512_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int kyber_512_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int kyber_512_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } /* kyber512r2 90's version*/ -int kyber_512_90s_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int kyber_512_90s_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } -int kyber_512_90s_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { BAIL_POSIX(S2N_ERR_UNIMPLEMENTED); } +int kyber_512_90s_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int kyber_512_90s_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int kyber_512_90s_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +/* kyber512r3 */ +int s2n_kyber_512_r3_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int s2n_kyber_512_r3_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int s2n_kyber_512_r3_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +/* sikep434r3 */ +int s2n_sike_p434_r3_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int s2n_sike_p434_r3_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } +int s2n_sike_p434_r3_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk) { POSIX_BAIL(S2N_ERR_UNIMPLEMENTED); } #endif diff --git a/contrib/restricted/aws/s2n/tls/s2n_kem.h b/contrib/restricted/aws/s2n/tls/s2n_kem.h index ddea9d09ca..ca6ab90cf3 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_kem.h +++ b/contrib/restricted/aws/s2n/tls/s2n_kem.h @@ -73,25 +73,37 @@ struct s2n_kem_group_params { extern const struct s2n_kem s2n_bike1_l1_r1; extern const struct s2n_kem s2n_bike1_l1_r2; +extern const struct s2n_kem s2n_bike_l1_r3; extern const struct s2n_kem s2n_sike_p503_r1; -extern const struct s2n_kem s2n_sike_p434_r2; extern const struct s2n_kem s2n_kyber_512_r2; extern const struct s2n_kem s2n_kyber_512_90s_r2; +extern const struct s2n_kem s2n_kyber_512_r3; +extern const struct s2n_kem s2n_sike_p434_r3; /* x25519 based tls13_kem_groups require EVP_APIS_SUPPORTED */ #if EVP_APIS_SUPPORTED -#define S2N_SUPPORTED_KEM_GROUPS_COUNT 6 +#define S2N_SUPPORTED_KEM_GROUPS_COUNT 10 #else -#define S2N_SUPPORTED_KEM_GROUPS_COUNT 3 +#define S2N_SUPPORTED_KEM_GROUPS_COUNT 5 #endif -extern const struct s2n_kem_group s2n_secp256r1_sike_p434_r2; +extern const struct s2n_kem_group* ALL_SUPPORTED_KEM_GROUPS[S2N_SUPPORTED_KEM_GROUPS_COUNT]; + +/* secp256r1 KEM Groups */ +extern const struct s2n_kem_group s2n_secp256r1_bike_l1_r3; +extern const struct s2n_kem_group s2n_secp256r1_sike_p434_r3; +extern const struct s2n_kem_group s2n_secp256r1_kyber_512_r3; extern const struct s2n_kem_group s2n_secp256r1_bike1_l1_r2; extern const struct s2n_kem_group s2n_secp256r1_kyber_512_r2; -extern const struct s2n_kem_group s2n_x25519_sike_p434_r2; + +/* x25519 KEM Groups */ +extern const struct s2n_kem_group s2n_x25519_bike_l1_r3; +extern const struct s2n_kem_group s2n_x25519_sike_p434_r3; +extern const struct s2n_kem_group s2n_x25519_kyber_512_r3; extern const struct s2n_kem_group s2n_x25519_bike1_l1_r2; extern const struct s2n_kem_group s2n_x25519_kyber_512_r2; + extern S2N_RESULT s2n_kem_generate_keypair(struct s2n_kem_params *kem_params); extern S2N_RESULT s2n_kem_encapsulate(struct s2n_kem_params *kem_params, struct s2n_blob *ciphertext); extern S2N_RESULT s2n_kem_decapsulate(struct s2n_kem_params *kem_params, const struct s2n_blob *ciphertext); @@ -141,16 +153,7 @@ int SIKE_P503_r1_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk int SIKE_P503_r1_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); int SIKE_P503_r1_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk); -/* sikep434r2 */ -#define SIKE_P434_R2_PUBLIC_KEY_BYTES 330 -#define SIKE_P434_R2_SECRET_KEY_BYTES 374 -#define SIKE_P434_R2_CIPHERTEXT_BYTES 346 -#define SIKE_P434_R2_SHARED_SECRET_BYTES 16 -int SIKE_P434_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk); -int SIKE_P434_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); -int SIKE_P434_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk); - -/* bike1l1r1 */ +/* bike1_l1_r1 */ #define BIKE1_L1_R1_SECRET_KEY_BYTES 3110 #define BIKE1_L1_R1_PUBLIC_KEY_BYTES 2542 #define BIKE1_L1_R1_CIPHERTEXT_BYTES 2542 @@ -159,7 +162,7 @@ int BIKE1_L1_R1_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) int BIKE1_L1_R1_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); int BIKE1_L1_R1_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk); -/* bike1l1r2 */ +/* bike1_l1_r2 */ #define BIKE1_L1_R2_SECRET_KEY_BYTES 6460 #define BIKE1_L1_R2_PUBLIC_KEY_BYTES 2946 #define BIKE1_L1_R2_CIPHERTEXT_BYTES 2946 @@ -168,6 +171,15 @@ int BIKE1_L1_R2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk) int BIKE1_L1_R2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); int BIKE1_L1_R2_crypto_kem_dec(OUT unsigned char * ss, IN const unsigned char *ct, IN const unsigned char *sk); +/* bike_l1_r3 */ +#define BIKE_L1_R3_SECRET_KEY_BYTES 5223 +#define BIKE_L1_R3_PUBLIC_KEY_BYTES 1541 +#define BIKE_L1_R3_CIPHERTEXT_BYTES 1573 +#define BIKE_L1_R3_SHARED_SECRET_BYTES 32 +int BIKE_L1_R3_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk); +int BIKE_L1_R3_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); +int BIKE_L1_R3_crypto_kem_dec(OUT unsigned char * ss, IN const unsigned char *ct, IN const unsigned char *sk); + /* kyber512r2 (the defined constants are identical for both regular and 90's version) */ #define KYBER_512_R2_PUBLIC_KEY_BYTES 800 #define KYBER_512_R2_SECRET_KEY_BYTES 1632 @@ -179,3 +191,21 @@ int kyber_512_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *c int kyber_512_90s_r2_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk); int kyber_512_90s_r2_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); int kyber_512_90s_r2_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk); + +/* kyber512r3 */ +#define S2N_KYBER_512_R3_PUBLIC_KEY_BYTES 800 +#define S2N_KYBER_512_R3_SECRET_KEY_BYTES 1632 +#define S2N_KYBER_512_R3_CIPHERTEXT_BYTES 768 +#define S2N_KYBER_512_R3_SHARED_SECRET_BYTES 32 +int s2n_kyber_512_r3_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk); +int s2n_kyber_512_r3_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); +int s2n_kyber_512_r3_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk); + +/* sikep434r3 */ +#define S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES 330 +#define S2N_SIKE_P434_R3_SECRET_KEY_BYTES 374 +#define S2N_SIKE_P434_R3_CIPHERTEXT_BYTES 346 +#define S2N_SIKE_P434_R3_SHARED_SECRET_BYTES 16 +int s2n_sike_p434_r3_crypto_kem_keypair(OUT unsigned char *pk, OUT unsigned char *sk); +int s2n_sike_p434_r3_crypto_kem_enc(OUT unsigned char *ct, OUT unsigned char *ss, IN const unsigned char *pk); +int s2n_sike_p434_r3_crypto_kem_dec(OUT unsigned char *ss, IN const unsigned char *ct, IN const unsigned char *sk); diff --git a/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.c b/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.c index 3e3fa71323..24ce8cb49e 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.c +++ b/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.c @@ -21,18 +21,35 @@ const struct s2n_kem *pq_kems_r1[2] = { &s2n_sike_p503_r1, }; -/* Extension list for round 2 and round 1 PQ KEMs, in order of preference */ +/* Extension list for round 2 and round 1 PQ KEMs, in order of preference. + * s2n_sike_p434_r3 is compatible with, and has replaced, s2n_sike_p434_r2. */ const struct s2n_kem *pq_kems_r2r1[4] = { &s2n_bike1_l1_r2, - &s2n_sike_p434_r2, + &s2n_sike_p434_r3, &s2n_bike1_l1_r1, &s2n_sike_p503_r1, }; +/* s2n_sike_p434_r3 is compatible with, and has replaced, s2n_sike_p434_r2. */ const struct s2n_kem *pq_kems_r2r1_2020_07[5] = { &s2n_kyber_512_r2, &s2n_bike1_l1_r2, - &s2n_sike_p434_r2, + &s2n_sike_p434_r3, + &s2n_bike1_l1_r1, + &s2n_sike_p503_r1, +}; + +const struct s2n_kem *pq_kems_r3r2r1_2021_05[7] = { + /* Round 3 Algorithms */ + &s2n_kyber_512_r3, + &s2n_bike_l1_r3, + + /* Round 2 Algorithms */ + &s2n_kyber_512_r2, + &s2n_bike1_l1_r2, + &s2n_sike_p434_r3, + + /* Round 1 Algorithms */ &s2n_bike1_l1_r1, &s2n_sike_p503_r1, }; @@ -43,24 +60,48 @@ const struct s2n_kem *pq_kems_sike_r1[1] = { }; /* Extension list for SIKE P434 Round 2 and SIKE P503 Round 1 only (for testing), - * in order of preference */ + * in order of preference. s2n_sike_p434_r3 is compatible with, and has replaced, + * s2n_sike_p434_r2. */ const struct s2n_kem *pq_kems_sike_r2r1[2] = { - &s2n_sike_p434_r2, + &s2n_sike_p434_r3, &s2n_sike_p503_r1, }; +/* sike_p434_r3 has replaced sike_p434_r2 in all KEM groups */ const struct s2n_kem_group *pq_kem_groups_r2[] = { #if EVP_APIS_SUPPORTED &s2n_x25519_kyber_512_r2, &s2n_secp256r1_kyber_512_r2, &s2n_x25519_bike1_l1_r2, &s2n_secp256r1_bike1_l1_r2, - &s2n_x25519_sike_p434_r2, - &s2n_secp256r1_sike_p434_r2, + &s2n_x25519_sike_p434_r3, + &s2n_secp256r1_sike_p434_r3, +#else + &s2n_secp256r1_kyber_512_r2, + &s2n_secp256r1_bike1_l1_r2, + &s2n_secp256r1_sike_p434_r3, +#endif +}; + + +const struct s2n_kem_group *pq_kem_groups_r3r2[] = { +#if EVP_APIS_SUPPORTED + &s2n_x25519_kyber_512_r3, + &s2n_secp256r1_kyber_512_r3, + &s2n_x25519_bike_l1_r3, + &s2n_secp256r1_bike_l1_r3, + &s2n_x25519_kyber_512_r2, + &s2n_secp256r1_kyber_512_r2, + &s2n_x25519_bike1_l1_r2, + &s2n_secp256r1_bike1_l1_r2, + &s2n_x25519_sike_p434_r3, + &s2n_secp256r1_sike_p434_r3, #else + &s2n_secp256r1_kyber_512_r3, + &s2n_secp256r1_bike_l1_r3, &s2n_secp256r1_kyber_512_r2, &s2n_secp256r1_bike1_l1_r2, - &s2n_secp256r1_sike_p434_r2, + &s2n_secp256r1_sike_p434_r3, #endif }; @@ -110,6 +151,13 @@ const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2020_12 = { .tls13_kem_groups = pq_kem_groups_r2, }; +const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2021_05 = { + .kem_count = s2n_array_len(pq_kems_r3r2r1_2021_05), + .kems = pq_kems_r3r2r1_2021_05, + .tls13_kem_group_count = s2n_array_len(pq_kem_groups_r3r2), + .tls13_kem_groups = pq_kem_groups_r3r2, +}; + const struct s2n_kem_preferences kem_preferences_null = { .kem_count = 0, .kems = NULL, diff --git a/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.h index cad4f39c8e..73f86a10a1 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.h +++ b/contrib/restricted/aws/s2n/tls/s2n_kem_preferences.h @@ -34,8 +34,10 @@ extern const struct s2n_kem *pq_kems_r2r1[4]; extern const struct s2n_kem *pq_kems_r2r1_2020_07[5]; extern const struct s2n_kem *pq_kems_sike_r1[1]; extern const struct s2n_kem *pq_kems_sike_r2r1[2]; +extern const struct s2n_kem *pq_kems_r3r2r1_2021_05[7]; extern const struct s2n_kem_group *pq_kem_groups_r2[]; +extern const struct s2n_kem_group *pq_kem_groups_r3r2[]; extern const struct s2n_kem_preferences kem_preferences_kms_pq_tls_1_0_2019_06; extern const struct s2n_kem_preferences kem_preferences_kms_pq_tls_1_0_2020_02; @@ -43,6 +45,7 @@ extern const struct s2n_kem_preferences kem_preferences_kms_pq_tls_1_0_2020_07; extern const struct s2n_kem_preferences kem_preferences_pq_sike_test_tls_1_0_2019_11; extern const struct s2n_kem_preferences kem_preferences_pq_sike_test_tls_1_0_2020_02; extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2020_12; +extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2021_05; extern const struct s2n_kem_preferences kem_preferences_null; bool s2n_kem_preferences_includes_tls13_kem_group(const struct s2n_kem_preferences *kem_preferences, diff --git a/contrib/restricted/aws/s2n/tls/s2n_kex.c b/contrib/restricted/aws/s2n/tls/s2n_kex.c index b9fb9800ad..d4429ad2f8 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_kex.c +++ b/contrib/restricted/aws/s2n/tls/s2n_kex.c @@ -26,9 +26,9 @@ static S2N_RESULT s2n_check_rsa_key(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { - ENSURE_REF(cipher_suite); - ENSURE_REF(conn); - ENSURE_REF(is_supported); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(is_supported); *is_supported = s2n_get_compatible_cert_chain_and_key(conn, S2N_PKEY_TYPE_RSA) != NULL; @@ -37,10 +37,10 @@ static S2N_RESULT s2n_check_rsa_key(const struct s2n_cipher_suite *cipher_suite, static S2N_RESULT s2n_check_dhe(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { - ENSURE_REF(cipher_suite); - ENSURE_REF(conn); - ENSURE_REF(conn->config); - ENSURE_REF(is_supported); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->config); + RESULT_ENSURE_REF(is_supported); *is_supported = conn->config->dhparams != NULL; @@ -49,27 +49,27 @@ static S2N_RESULT s2n_check_dhe(const struct s2n_cipher_suite *cipher_suite, str static S2N_RESULT s2n_check_ecdhe(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { - ENSURE_REF(cipher_suite); - ENSURE_REF(conn); - ENSURE_REF(is_supported); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(is_supported); - *is_supported = conn->secure.server_ecc_evp_params.negotiated_curve != NULL; + *is_supported = conn->kex_params.server_ecc_evp_params.negotiated_curve != NULL; return S2N_RESULT_OK; } static S2N_RESULT s2n_check_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { - ENSURE_REF(cipher_suite); - ENSURE_REF(conn); - ENSURE_REF(is_supported); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(is_supported); /* If any of the necessary conditions are not met, we will return early and indicate KEM is not supported. */ *is_supported = false; const struct s2n_kem_preferences *kem_preferences = NULL; - GUARD_AS_RESULT(s2n_connection_get_kem_preferences(conn, &kem_preferences)); - ENSURE_REF(kem_preferences); + RESULT_GUARD_POSIX(s2n_connection_get_kem_preferences(conn, &kem_preferences)); + RESULT_ENSURE_REF(kem_preferences); if (!s2n_pq_is_enabled() || kem_preferences->kem_count == 0) { return S2N_RESULT_OK; @@ -80,12 +80,12 @@ static S2N_RESULT s2n_check_kem(const struct s2n_cipher_suite *cipher_suite, str return S2N_RESULT_OK; } - ENSURE_REF(supported_params); + RESULT_ENSURE_REF(supported_params); if (supported_params->kem_count == 0) { return S2N_RESULT_OK; } - struct s2n_blob *client_kem_pref_list = &(conn->secure.client_pq_kem_extension); + struct s2n_blob *client_kem_pref_list = &(conn->kex_params.client_pq_kem_extension); const struct s2n_kem *chosen_kem = NULL; if (client_kem_pref_list == NULL || client_kem_pref_list->data == NULL) { /* If the client did not send a PQ KEM extension, then the server can pick its preferred parameter */ @@ -107,28 +107,28 @@ static S2N_RESULT s2n_check_kem(const struct s2n_cipher_suite *cipher_suite, str static S2N_RESULT s2n_configure_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn) { - ENSURE_REF(cipher_suite); - ENSURE_REF(conn); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(conn); - ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); + RESULT_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); const struct s2n_kem_preferences *kem_preferences = NULL; - GUARD_AS_RESULT(s2n_connection_get_kem_preferences(conn, &kem_preferences)); - ENSURE_REF(kem_preferences); + RESULT_GUARD_POSIX(s2n_connection_get_kem_preferences(conn, &kem_preferences)); + RESULT_ENSURE_REF(kem_preferences); - struct s2n_blob *proposed_kems = &(conn->secure.client_pq_kem_extension); + struct s2n_blob *proposed_kems = &(conn->kex_params.client_pq_kem_extension); const struct s2n_kem *chosen_kem = NULL; if (proposed_kems == NULL || proposed_kems->data == NULL) { /* If the client did not send a PQ KEM extension, then the server can pick its preferred parameter */ - GUARD_AS_RESULT(s2n_choose_kem_without_peer_pref_list(cipher_suite->iana_value, kem_preferences->kems, + RESULT_GUARD_POSIX(s2n_choose_kem_without_peer_pref_list(cipher_suite->iana_value, kem_preferences->kems, kem_preferences->kem_count, &chosen_kem)); } else { /* If the client did send a PQ KEM extension, then the server must find a mutually supported parameter. */ - GUARD_AS_RESULT(s2n_choose_kem_with_peer_pref_list(cipher_suite->iana_value, proposed_kems, kem_preferences->kems, + RESULT_GUARD_POSIX(s2n_choose_kem_with_peer_pref_list(cipher_suite->iana_value, proposed_kems, kem_preferences->kems, kem_preferences->kem_count, &chosen_kem)); } - conn->secure.kem_params.kem = chosen_kem; + conn->kex_params.kem_params.kem = chosen_kem; return S2N_RESULT_OK; } @@ -139,14 +139,14 @@ static S2N_RESULT s2n_no_op_configure(const struct s2n_cipher_suite *cipher_suit static S2N_RESULT s2n_check_hybrid_ecdhe_kem(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { - ENSURE_REF(cipher_suite); - ENSURE_REF(conn); - ENSURE_REF(is_supported); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(is_supported); bool ecdhe_supported = false; bool kem_supported = false; - GUARD_RESULT(s2n_check_ecdhe(cipher_suite, conn, &ecdhe_supported)); - GUARD_RESULT(s2n_check_kem(cipher_suite, conn, &kem_supported)); + RESULT_GUARD(s2n_check_ecdhe(cipher_suite, conn, &ecdhe_supported)); + RESULT_GUARD(s2n_check_kem(cipher_suite, conn, &kem_supported)); *is_supported = ecdhe_supported && kem_supported; @@ -173,7 +173,7 @@ const struct s2n_kex s2n_rsa = { .server_key_send = NULL, .client_key_recv = &s2n_rsa_client_key_recv, .client_key_send = &s2n_rsa_client_key_send, - .prf = &s2n_tls_prf_master_secret, + .prf = &s2n_prf_calculate_master_secret, }; const struct s2n_kex s2n_dhe = { @@ -185,7 +185,7 @@ const struct s2n_kex s2n_dhe = { .server_key_send = &s2n_dhe_server_key_send, .client_key_recv = &s2n_dhe_client_key_recv, .client_key_send = &s2n_dhe_client_key_send, - .prf = &s2n_tls_prf_master_secret, + .prf = &s2n_prf_calculate_master_secret, }; const struct s2n_kex s2n_ecdhe = { @@ -197,7 +197,7 @@ const struct s2n_kex s2n_ecdhe = { .server_key_send = &s2n_ecdhe_server_key_send, .client_key_recv = &s2n_ecdhe_client_key_recv, .client_key_send = &s2n_ecdhe_client_key_send, - .prf = &s2n_tls_prf_master_secret, + .prf = &s2n_prf_calculate_master_secret, }; const struct s2n_kex s2n_hybrid_ecdhe_kem = { @@ -215,33 +215,33 @@ const struct s2n_kex s2n_hybrid_ecdhe_kem = { S2N_RESULT s2n_kex_supported(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn, bool *is_supported) { - ENSURE_REF(cipher_suite); - ENSURE_REF(cipher_suite->key_exchange_alg); - ENSURE_REF(cipher_suite->key_exchange_alg->connection_supported); - ENSURE_REF(conn); - ENSURE_REF(is_supported); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(cipher_suite->key_exchange_alg); + RESULT_ENSURE_REF(cipher_suite->key_exchange_alg->connection_supported); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(is_supported); - GUARD_RESULT(cipher_suite->key_exchange_alg->connection_supported(cipher_suite, conn, is_supported)); + RESULT_GUARD(cipher_suite->key_exchange_alg->connection_supported(cipher_suite, conn, is_supported)); return S2N_RESULT_OK; } S2N_RESULT s2n_configure_kex(const struct s2n_cipher_suite *cipher_suite, struct s2n_connection *conn) { - ENSURE_REF(cipher_suite); - ENSURE_REF(cipher_suite->key_exchange_alg); - ENSURE_REF(cipher_suite->key_exchange_alg->configure_connection); - ENSURE_REF(conn); + RESULT_ENSURE_REF(cipher_suite); + RESULT_ENSURE_REF(cipher_suite->key_exchange_alg); + RESULT_ENSURE_REF(cipher_suite->key_exchange_alg->configure_connection); + RESULT_ENSURE_REF(conn); - GUARD_RESULT(cipher_suite->key_exchange_alg->configure_connection(cipher_suite, conn)); + RESULT_GUARD(cipher_suite->key_exchange_alg->configure_connection(cipher_suite, conn)); return S2N_RESULT_OK; } S2N_RESULT s2n_kex_is_ephemeral(const struct s2n_kex *kex, bool *is_ephemeral) { - ENSURE_REF(kex); - ENSURE_REF(is_ephemeral); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(is_ephemeral); *is_ephemeral = kex->is_ephemeral; @@ -250,12 +250,12 @@ S2N_RESULT s2n_kex_is_ephemeral(const struct s2n_kex *kex, bool *is_ephemeral) S2N_RESULT s2n_kex_server_key_recv_parse_data(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_kex_raw_server_data *raw_server_data) { - ENSURE_REF(kex); - ENSURE_REF(kex->server_key_recv_parse_data); - ENSURE_REF(conn); - ENSURE_REF(raw_server_data); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(kex->server_key_recv_parse_data); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(raw_server_data); - GUARD_AS_RESULT(kex->server_key_recv_parse_data(conn, raw_server_data)); + RESULT_GUARD_POSIX(kex->server_key_recv_parse_data(conn, raw_server_data)); return S2N_RESULT_OK; } @@ -263,60 +263,60 @@ S2N_RESULT s2n_kex_server_key_recv_parse_data(const struct s2n_kex *kex, struct S2N_RESULT s2n_kex_server_key_recv_read_data(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *data_to_verify, struct s2n_kex_raw_server_data *raw_server_data) { - ENSURE_REF(kex); - ENSURE_REF(kex->server_key_recv_read_data); - ENSURE_REF(conn); - ENSURE_REF(data_to_verify); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(kex->server_key_recv_read_data); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(data_to_verify); - GUARD_AS_RESULT(kex->server_key_recv_read_data(conn, data_to_verify, raw_server_data)); + RESULT_GUARD_POSIX(kex->server_key_recv_read_data(conn, data_to_verify, raw_server_data)); return S2N_RESULT_OK; } S2N_RESULT s2n_kex_server_key_send(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *data_to_sign) { - ENSURE_REF(kex); - ENSURE_REF(kex->server_key_send); - ENSURE_REF(conn); - ENSURE_REF(data_to_sign); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(kex->server_key_send); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(data_to_sign); - GUARD_AS_RESULT(kex->server_key_send(conn, data_to_sign)); + RESULT_GUARD_POSIX(kex->server_key_send(conn, data_to_sign)); return S2N_RESULT_OK; } S2N_RESULT s2n_kex_client_key_recv(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *shared_key) { - ENSURE_REF(kex); - ENSURE_REF(kex->client_key_recv); - ENSURE_REF(conn); - ENSURE_REF(shared_key); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(kex->client_key_recv); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(shared_key); - GUARD_AS_RESULT(kex->client_key_recv(conn, shared_key)); + RESULT_GUARD_POSIX(kex->client_key_recv(conn, shared_key)); return S2N_RESULT_OK; } S2N_RESULT s2n_kex_client_key_send(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *shared_key) { - ENSURE_REF(kex); - ENSURE_REF(kex->client_key_send); - ENSURE_REF(conn); - ENSURE_REF(shared_key); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(kex->client_key_send); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(shared_key); - GUARD_AS_RESULT(kex->client_key_send(conn, shared_key)); + RESULT_GUARD_POSIX(kex->client_key_send(conn, shared_key)); return S2N_RESULT_OK; } S2N_RESULT s2n_kex_tls_prf(const struct s2n_kex *kex, struct s2n_connection *conn, struct s2n_blob *premaster_secret) { - ENSURE_REF(kex); - ENSURE_REF(kex->prf); - ENSURE_REF(conn); - ENSURE_REF(premaster_secret); + RESULT_ENSURE_REF(kex); + RESULT_ENSURE_REF(kex->prf); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(premaster_secret); - GUARD_AS_RESULT(kex->prf(conn, premaster_secret)); + RESULT_GUARD_POSIX(kex->prf(conn, premaster_secret)); return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_key_log.c b/contrib/restricted/aws/s2n/tls/s2n_key_log.c new file mode 100644 index 0000000000..d8eb3dd465 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_key_log.c @@ -0,0 +1,174 @@ +/* + * 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. + */ + +/** + * This module implements key logging as defined by the NSS Key Log Format + * + * See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format + * + * This key log file is a series of lines. Comment lines begin with a sharp + * character ('#') and are ignored. Secrets follow the format + * <Label> <space> <ClientRandom> <space> <Secret> where: + * + * <Label> describes the following secret. + * <ClientRandom> is 32 bytes Random value from the Client Hello message, encoded as 64 hexadecimal characters. + * <Secret> depends on the Label (see below). + * + * The following labels are defined, followed by a description of the secret: + * + * RSA: 48 bytes for the premaster secret, encoded as 96 hexadecimal characters (removed in NSS 3.34) + * CLIENT_RANDOM: 48 bytes for the master secret, encoded as 96 hexadecimal characters (for SSL 3.0, TLS 1.0, 1.1 and 1.2) + * CLIENT_EARLY_TRAFFIC_SECRET: the hex-encoded early traffic secret for the client side (for TLS 1.3) + * CLIENT_HANDSHAKE_TRAFFIC_SECRET: the hex-encoded handshake traffic secret for the client side (for TLS 1.3) + * SERVER_HANDSHAKE_TRAFFIC_SECRET: the hex-encoded handshake traffic secret for the server side (for TLS 1.3) + * CLIENT_TRAFFIC_SECRET_0: the first hex-encoded application traffic secret for the client side (for TLS 1.3) + * SERVER_TRAFFIC_SECRET_0: the first hex-encoded application traffic secret for the server side (for TLS 1.3) + * EARLY_EXPORTER_SECRET: the hex-encoded early exporter secret (for TLS 1.3). + * EXPORTER_SECRET: the hex-encoded exporter secret (for TLS 1.3) + */ + +#include "api/s2n.h" +#include "tls/s2n_config.h" +#include "tls/s2n_connection.h" +#include "tls/s2n_crypto_constants.h" +#include "tls/s2n_quic_support.h" /* this currently holds the s2n_secret_type_t enum */ +#include "utils/s2n_blob.h" +#include "utils/s2n_safety.h" + +/* hex requires 2 chars per byte */ +#define HEX_ENCODING_SIZE 2 + +S2N_RESULT s2n_key_log_hex_encode(struct s2n_stuffer *output, uint8_t *bytes, size_t len) +{ + RESULT_ENSURE_MUT(output); + RESULT_ENSURE_REF(bytes); + + const uint8_t chars[] = "0123456789abcdef"; + + for (size_t i = 0; i < len; i++) { + uint8_t upper = bytes[i] >> 4; + uint8_t lower = bytes[i] & 0x0f; + + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(output, chars[upper])); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(output, chars[lower])); + } + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_key_log_tls13_secret(struct s2n_connection *conn, const struct s2n_blob *secret, s2n_secret_type_t secret_type) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->config); + RESULT_ENSURE_REF(secret); + + /* only emit keys if the callback has been set */ + if (!conn->config->key_log_cb) { + return S2N_RESULT_OK; + } + + const uint8_t client_early_traffic_label[] = "CLIENT_EARLY_TRAFFIC_SECRET "; + const uint8_t client_handshake_label[] = "CLIENT_HANDSHAKE_TRAFFIC_SECRET "; + const uint8_t server_handshake_label[] = "SERVER_HANDSHAKE_TRAFFIC_SECRET "; + const uint8_t client_traffic_label[] = "CLIENT_TRAFFIC_SECRET_0 "; + const uint8_t server_traffic_label[] = "SERVER_TRAFFIC_SECRET_0 "; + + const uint8_t *label = NULL; + uint8_t label_size = 0; + + switch (secret_type) { + case S2N_CLIENT_EARLY_TRAFFIC_SECRET: + label = client_early_traffic_label; + label_size = sizeof(client_early_traffic_label) - 1; + break; + case S2N_CLIENT_HANDSHAKE_TRAFFIC_SECRET: + label = client_handshake_label; + label_size = sizeof(client_handshake_label) - 1; + break; + case S2N_SERVER_HANDSHAKE_TRAFFIC_SECRET: + label = server_handshake_label; + label_size = sizeof(server_handshake_label) - 1; + break; + case S2N_CLIENT_APPLICATION_TRAFFIC_SECRET: + label = client_traffic_label; + label_size = sizeof(client_traffic_label) - 1; + break; + case S2N_SERVER_APPLICATION_TRAFFIC_SECRET: + label = server_traffic_label; + label_size = sizeof(server_traffic_label) - 1; + break; + default: + /* Ignore the secret types we don't understand */ + return S2N_RESULT_OK; + } + + const uint8_t len + = label_size + + S2N_TLS_RANDOM_DATA_LEN * HEX_ENCODING_SIZE + + 1 /* SPACE */ + + secret->size * HEX_ENCODING_SIZE; + + DEFER_CLEANUP(struct s2n_stuffer output, s2n_stuffer_free); + RESULT_GUARD_POSIX(s2n_stuffer_alloc(&output, len)); + + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&output, label, label_size)); + RESULT_GUARD(s2n_key_log_hex_encode(&output, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(&output, ' ')); + RESULT_GUARD(s2n_key_log_hex_encode(&output, secret->data, secret->size)); + + uint8_t *data = s2n_stuffer_raw_read(&output, len); + RESULT_ENSURE_REF(data); + + conn->config->key_log_cb(conn->config->key_log_ctx, conn, data, len); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_key_log_tls12_secret(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->config); + + /* only emit keys if the callback has been set */ + if (!conn->config->key_log_cb) { + return S2N_RESULT_OK; + } + + /* CLIENT_RANDOM: 48 bytes for the master secret, encoded as 96 hexadecimal characters (for SSL 3.0, TLS 1.0, 1.1 and 1.2) */ + const uint8_t label[] = "CLIENT_RANDOM "; + const uint8_t label_size = sizeof(label) - 1; + + const uint8_t len + = label_size + + S2N_TLS_RANDOM_DATA_LEN * HEX_ENCODING_SIZE + + 1 /* SPACE */ + + S2N_TLS_SECRET_LEN * HEX_ENCODING_SIZE; + + DEFER_CLEANUP(struct s2n_stuffer output, s2n_stuffer_free); + RESULT_GUARD_POSIX(s2n_stuffer_alloc(&output, len)); + + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&output, label, label_size)); + RESULT_GUARD(s2n_key_log_hex_encode(&output, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(&output, ' ')); + RESULT_GUARD(s2n_key_log_hex_encode(&output, conn->secrets.tls12.master_secret, S2N_TLS_SECRET_LEN)); + + uint8_t *data = s2n_stuffer_raw_read(&output, len); + RESULT_ENSURE_REF(data); + + conn->config->key_log_cb(conn->config->key_log_ctx, conn, data, len); + + return S2N_RESULT_OK; +} + diff --git a/contrib/restricted/aws/s2n/tls/s2n_key_log.h b/contrib/restricted/aws/s2n/tls/s2n_key_log.h new file mode 100644 index 0000000000..d804d21c4c --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_key_log.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#pragma once + +#include "api/s2n.h" +#include "stuffer/s2n_stuffer.h" +#include "tls/s2n_quic_support.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_safety.h" + +S2N_RESULT s2n_key_log_hex_encode(struct s2n_stuffer *output, uint8_t *bytes, size_t len); +S2N_RESULT s2n_key_log_tls12_secret(struct s2n_connection *conn); +S2N_RESULT s2n_key_log_tls13_secret(struct s2n_connection *conn, const struct s2n_blob *secret, s2n_secret_type_t secret_type); + diff --git a/contrib/restricted/aws/s2n/tls/s2n_key_update.c b/contrib/restricted/aws/s2n/tls/s2n_key_update.c index 6f63e02b38..86e933a1ac 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_key_update.c +++ b/contrib/restricted/aws/s2n/tls/s2n_key_update.c @@ -19,6 +19,7 @@ #include "tls/s2n_key_update.h" #include "tls/s2n_tls13_handshake.h" #include "tls/s2n_record.h" +#include "tls/s2n_tls.h" #include "crypto/s2n_sequence.h" @@ -30,52 +31,55 @@ int s2n_check_record_limit(struct s2n_connection *conn, struct s2n_blob *sequenc int s2n_key_update_recv(struct s2n_connection *conn, struct s2n_stuffer *request) { - notnull_check(conn); - ENSURE_POSIX(!conn->config->quic_enabled, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_BAD_MESSAGE); uint8_t key_update_request; - GUARD(s2n_stuffer_read_uint8(request, &key_update_request)); + POSIX_GUARD(s2n_stuffer_read_uint8(request, &key_update_request)); S2N_ERROR_IF(key_update_request != S2N_KEY_UPDATE_NOT_REQUESTED && key_update_request != S2N_KEY_UPDATE_REQUESTED, S2N_ERR_BAD_MESSAGE); conn->key_update_pending = key_update_request; /* Update peer's key since a key_update was received */ if (conn->mode == S2N_CLIENT){ - GUARD(s2n_update_application_traffic_keys(conn, S2N_SERVER, RECEIVING)); + POSIX_GUARD(s2n_update_application_traffic_keys(conn, S2N_SERVER, RECEIVING)); } else { - GUARD(s2n_update_application_traffic_keys(conn, S2N_CLIENT, RECEIVING)); + POSIX_GUARD(s2n_update_application_traffic_keys(conn, S2N_CLIENT, RECEIVING)); } return S2N_SUCCESS; } -int s2n_key_update_send(struct s2n_connection *conn) +int s2n_key_update_send(struct s2n_connection *conn, s2n_blocked_status *blocked) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_blob sequence_number = {0}; if (conn->mode == S2N_CLIENT) { - GUARD(s2n_blob_init(&sequence_number, conn->secure.client_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_blob_init(&sequence_number, conn->secure.client_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); } else { - GUARD(s2n_blob_init(&sequence_number, conn->secure.server_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_blob_init(&sequence_number, conn->secure.server_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); } - GUARD(s2n_check_record_limit(conn, &sequence_number)); + POSIX_GUARD(s2n_check_record_limit(conn, &sequence_number)); if (conn->key_update_pending) { uint8_t key_update_data[S2N_KEY_UPDATE_MESSAGE_SIZE]; struct s2n_blob key_update_blob = {0}; - GUARD(s2n_blob_init(&key_update_blob, key_update_data, sizeof(key_update_data))); + POSIX_GUARD(s2n_blob_init(&key_update_blob, key_update_data, sizeof(key_update_data))); /* Write key update message */ - GUARD(s2n_key_update_write(&key_update_blob)); + POSIX_GUARD(s2n_key_update_write(&key_update_blob)); /* Encrypt the message */ - GUARD(s2n_record_write(conn, TLS_HANDSHAKE, &key_update_blob)); + POSIX_GUARD(s2n_record_write(conn, TLS_HANDSHAKE, &key_update_blob)); /* Update encryption key */ - GUARD(s2n_update_application_traffic_keys(conn, conn->mode, SENDING)); + POSIX_GUARD(s2n_update_application_traffic_keys(conn, conn->mode, SENDING)); conn->key_update_pending = false; + + POSIX_GUARD(s2n_flush(conn, blocked)); } return S2N_SUCCESS; @@ -83,28 +87,28 @@ int s2n_key_update_send(struct s2n_connection *conn) int s2n_key_update_write(struct s2n_blob *out) { - notnull_check(out); + POSIX_ENSURE_REF(out); struct s2n_stuffer key_update_stuffer = {0}; - GUARD(s2n_stuffer_init(&key_update_stuffer, out)); - GUARD(s2n_stuffer_write_uint8(&key_update_stuffer, TLS_KEY_UPDATE)); - GUARD(s2n_stuffer_write_uint24(&key_update_stuffer, S2N_KEY_UPDATE_LENGTH)); + POSIX_GUARD(s2n_stuffer_init(&key_update_stuffer, out)); + POSIX_GUARD(s2n_stuffer_write_uint8(&key_update_stuffer, TLS_KEY_UPDATE)); + POSIX_GUARD(s2n_stuffer_write_uint24(&key_update_stuffer, S2N_KEY_UPDATE_LENGTH)); /* s2n currently does not require peers to update their encryption keys. */ - GUARD(s2n_stuffer_write_uint8(&key_update_stuffer, S2N_KEY_UPDATE_NOT_REQUESTED)); + POSIX_GUARD(s2n_stuffer_write_uint8(&key_update_stuffer, S2N_KEY_UPDATE_NOT_REQUESTED)); return S2N_SUCCESS; } int s2n_check_record_limit(struct s2n_connection *conn, struct s2n_blob *sequence_number) { - notnull_check(conn); - notnull_check(sequence_number); - notnull_check(conn->secure.cipher_suite); - notnull_check(conn->secure.cipher_suite->record_alg); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(sequence_number); + POSIX_ENSURE_REF(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn->secure.cipher_suite->record_alg); uint64_t output = 0; - GUARD(s2n_sequence_number_to_uint64(sequence_number, &output)); + POSIX_GUARD(s2n_sequence_number_to_uint64(sequence_number, &output)); if (output + 1 > conn->secure.cipher_suite->record_alg->encryption_limit) { conn->key_update_pending = true; diff --git a/contrib/restricted/aws/s2n/tls/s2n_key_update.h b/contrib/restricted/aws/s2n/tls/s2n_key_update.h index 20ac48411c..859cd11506 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_key_update.h +++ b/contrib/restricted/aws/s2n/tls/s2n_key_update.h @@ -31,4 +31,4 @@ typedef enum { } keyupdate_request; int s2n_key_update_recv(struct s2n_connection *conn, struct s2n_stuffer *request); -int s2n_key_update_send(struct s2n_connection *conn); +int s2n_key_update_send(struct s2n_connection *conn, s2n_blocked_status *blocked); diff --git a/contrib/restricted/aws/s2n/tls/s2n_ocsp_stapling.c b/contrib/restricted/aws/s2n/tls/s2n_ocsp_stapling.c index 7ad96a4d31..441fdff27e 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_ocsp_stapling.c +++ b/contrib/restricted/aws/s2n/tls/s2n_ocsp_stapling.c @@ -28,7 +28,7 @@ int s2n_server_status_send(struct s2n_connection *conn) { if (s2n_server_can_send_ocsp(conn)) { - GUARD(s2n_server_certificate_status_send(conn, &conn->handshake.io)); + POSIX_GUARD(s2n_server_certificate_status_send(conn, &conn->handshake.io)); } return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_post_handshake.c b/contrib/restricted/aws/s2n/tls/s2n_post_handshake.c index 34594576db..7801920563 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_post_handshake.c +++ b/contrib/restricted/aws/s2n/tls/s2n_post_handshake.c @@ -20,38 +20,56 @@ #include "tls/s2n_tls.h" #include "utils/s2n_safety.h" -/* TLS 1.3 introducted several post handshake messages. This function currently only - * supports parsing for the KeyUpdate message. Once the other post-handshake messages - * have been implemented, this function can be altered to include the other messages. - */ int s2n_post_handshake_recv(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); uint8_t post_handshake_id; uint32_t message_length; - S2N_ERROR_IF(conn->actual_protocol_version != S2N_TLS13, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_read_uint8(&conn->in, &post_handshake_id)); - GUARD(s2n_stuffer_read_uint24(&conn->in, &message_length)); + while(s2n_stuffer_data_available(&conn->in)) { + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->in, &post_handshake_id)); + POSIX_GUARD(s2n_stuffer_read_uint24(&conn->in, &message_length)); - struct s2n_blob post_handshake_blob = {0}; - uint8_t *message_data = s2n_stuffer_raw_read(&conn->in, message_length); - notnull_check(message_data); - GUARD(s2n_blob_init(&post_handshake_blob, message_data, message_length)); + struct s2n_blob post_handshake_blob = { 0 }; + uint8_t *message_data = s2n_stuffer_raw_read(&conn->in, message_length); + POSIX_ENSURE_REF(message_data); + POSIX_GUARD(s2n_blob_init(&post_handshake_blob, message_data, message_length)); - struct s2n_stuffer post_handshake_stuffer = {0}; - GUARD(s2n_stuffer_init(&post_handshake_stuffer, &post_handshake_blob)); - GUARD(s2n_stuffer_skip_write(&post_handshake_stuffer, message_length)); + struct s2n_stuffer post_handshake_stuffer = { 0 }; + POSIX_GUARD(s2n_stuffer_init(&post_handshake_stuffer, &post_handshake_blob)); + POSIX_GUARD(s2n_stuffer_skip_write(&post_handshake_stuffer, message_length)); - switch (post_handshake_id) - { - case TLS_KEY_UPDATE: - GUARD(s2n_key_update_recv(conn, &post_handshake_stuffer)); - break; - default: - /* Ignore all other messages */ - break; + switch (post_handshake_id) + { + case TLS_KEY_UPDATE: + POSIX_GUARD(s2n_key_update_recv(conn, &post_handshake_stuffer)); + break; + case TLS_SERVER_NEW_SESSION_TICKET: + POSIX_GUARD_RESULT(s2n_tls13_server_nst_recv(conn, &post_handshake_stuffer)); + break; + case TLS_HELLO_REQUEST: + POSIX_GUARD(s2n_client_hello_request_recv(conn)); + break; + case TLS_CLIENT_HELLO: + case TLS_SERVER_HELLO: + case TLS_END_OF_EARLY_DATA: + case TLS_ENCRYPTED_EXTENSIONS: + case TLS_CERTIFICATE: + case TLS_SERVER_KEY: + case TLS_CERT_REQ: + case TLS_SERVER_HELLO_DONE: + case TLS_CERT_VERIFY: + case TLS_CLIENT_KEY: + case TLS_FINISHED: + case TLS_SERVER_CERT_STATUS: + /* All other known handshake messages should be rejected */ + POSIX_BAIL(S2N_ERR_BAD_MESSAGE); + break; + default: + /* Ignore all other messages */ + break; + } } return S2N_SUCCESS; @@ -59,11 +77,10 @@ int s2n_post_handshake_recv(struct s2n_connection *conn) int s2n_post_handshake_send(struct s2n_connection *conn, s2n_blocked_status *blocked) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - GUARD(s2n_key_update_send(conn)); - GUARD(s2n_flush(conn, blocked)); - GUARD(s2n_stuffer_rewrite(&conn->out)); + POSIX_GUARD(s2n_key_update_send(conn, blocked)); + POSIX_GUARD_RESULT(s2n_tls13_server_nst_send(conn, blocked)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_prf.c b/contrib/restricted/aws/s2n/tls/s2n_prf.c index fbfffb5fad..1096eb6c82 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_prf.c +++ b/contrib/restricted/aws/s2n/tls/s2n_prf.c @@ -14,6 +14,7 @@ */ #include <sys/param.h> +#include <openssl/hmac.h> #include <openssl/md5.h> #include <openssl/sha.h> #include <string.h> @@ -23,6 +24,7 @@ #include "tls/s2n_cipher_suites.h" #include "tls/s2n_connection.h" #include "tls/s2n_prf.h" +#include "tls/s2n_tls.h" #include "stuffer/s2n_stuffer.h" @@ -35,44 +37,51 @@ #include "utils/s2n_blob.h" #include "utils/s2n_mem.h" -static int s2n_sslv3_prf(struct s2n_prf_working_space *ws, struct s2n_blob *secret, struct s2n_blob *seed_a, +static int s2n_sslv3_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out) { - struct s2n_hash_state *md5 = &ws->ssl3.md5; - struct s2n_hash_state *sha1 = &ws->ssl3.sha1; + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_hash_state *workspace = &conn->handshake.hashes->hash_workspace; uint32_t outputlen = out->size; uint8_t *output = out->data; uint8_t iteration = 1; + uint8_t md5_digest[MD5_DIGEST_LENGTH] = { 0 }, sha_digest[SHA_DIGEST_LENGTH] = { 0 }; + uint8_t A = 'A'; while (outputlen) { - GUARD(s2n_hash_reset(sha1)); + struct s2n_hash_state *sha1 = workspace; + POSIX_GUARD(s2n_hash_reset(sha1)); + POSIX_GUARD(s2n_hash_init(sha1, S2N_HASH_SHA1)); for (int i = 0; i < iteration; i++) { - GUARD(s2n_hash_update(sha1, &A, 1)); + POSIX_GUARD(s2n_hash_update(sha1, &A, 1)); } - GUARD(s2n_hash_update(sha1, secret->data, secret->size)); - GUARD(s2n_hash_update(sha1, seed_a->data, seed_a->size)); + POSIX_GUARD(s2n_hash_update(sha1, secret->data, secret->size)); + POSIX_GUARD(s2n_hash_update(sha1, seed_a->data, seed_a->size)); if (seed_b) { - GUARD(s2n_hash_update(sha1, seed_b->data, seed_b->size)); + POSIX_GUARD(s2n_hash_update(sha1, seed_b->data, seed_b->size)); if (seed_c) { - GUARD(s2n_hash_update(sha1, seed_c->data, seed_c->size)); + POSIX_GUARD(s2n_hash_update(sha1, seed_c->data, seed_c->size)); } } - GUARD(s2n_hash_digest(sha1, ws->ssl3.sha1_digest, sizeof(ws->ssl3.sha1_digest))); + POSIX_GUARD(s2n_hash_digest(sha1, sha_digest, sizeof(sha_digest))); - GUARD(s2n_hash_reset(md5)); - GUARD(s2n_hash_update(md5, secret->data, secret->size)); - GUARD(s2n_hash_update(md5, ws->ssl3.sha1_digest, sizeof(ws->ssl3.sha1_digest))); - GUARD(s2n_hash_digest(md5, ws->ssl3.md5_digest, sizeof(ws->ssl3.md5_digest))); + struct s2n_hash_state *md5 = workspace; + POSIX_GUARD(s2n_hash_reset(md5)); + POSIX_GUARD(s2n_hash_init(md5, S2N_HASH_MD5)); + POSIX_GUARD(s2n_hash_update(md5, secret->data, secret->size)); + POSIX_GUARD(s2n_hash_update(md5, sha_digest, sizeof(sha_digest))); + POSIX_GUARD(s2n_hash_digest(md5, md5_digest, sizeof(md5_digest))); - uint32_t bytes_to_copy = MIN(outputlen, sizeof(ws->ssl3.md5_digest)); + uint32_t bytes_to_copy = MIN(outputlen, sizeof(md5_digest)); - memcpy_check(output, ws->ssl3.md5_digest, bytes_to_copy); + POSIX_CHECKED_MEMCPY(output, md5_digest, bytes_to_copy); outputlen -= bytes_to_copy; output += bytes_to_copy; @@ -82,129 +91,201 @@ static int s2n_sslv3_prf(struct s2n_prf_working_space *ws, struct s2n_blob *secr iteration++; } - GUARD(s2n_hash_reset(md5)); - GUARD(s2n_hash_reset(sha1)); - return 0; } +static int s2n_init_md_from_hmac_alg(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg){ + switch (alg) { + case S2N_HMAC_SSLv3_MD5: + case S2N_HMAC_MD5: + ws->p_hash.evp_hmac.evp_digest.md = EVP_md5(); + break; + case S2N_HMAC_SSLv3_SHA1: + case S2N_HMAC_SHA1: + ws->p_hash.evp_hmac.evp_digest.md = EVP_sha1(); + break; + case S2N_HMAC_SHA224: + ws->p_hash.evp_hmac.evp_digest.md = EVP_sha224(); + break; + case S2N_HMAC_SHA256: + ws->p_hash.evp_hmac.evp_digest.md = EVP_sha256(); + break; + case S2N_HMAC_SHA384: + ws->p_hash.evp_hmac.evp_digest.md = EVP_sha384(); + break; + case S2N_HMAC_SHA512: + ws->p_hash.evp_hmac.evp_digest.md = EVP_sha512(); + break; + default: + POSIX_BAIL(S2N_ERR_P_HASH_INVALID_ALGORITHM); + } + return S2N_SUCCESS; +} + #if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) -static int s2n_evp_hmac_p_hash_new(struct s2n_prf_working_space *ws) +static int s2n_evp_pkey_p_hash_alloc(struct s2n_prf_working_space *ws) { - notnull_check(ws->tls.p_hash.evp_hmac.evp_digest.ctx = S2N_EVP_MD_CTX_NEW()); + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.evp_digest.ctx = S2N_EVP_MD_CTX_NEW()); return 0; } -static int s2n_evp_hmac_p_hash_digest_init(struct s2n_prf_working_space *ws) +static int s2n_evp_pkey_p_hash_digest_init(struct s2n_prf_working_space *ws) { - notnull_check(ws->tls.p_hash.evp_hmac.evp_digest.md); - notnull_check(ws->tls.p_hash.evp_hmac.evp_digest.ctx); - notnull_check(ws->tls.p_hash.evp_hmac.mac_key); + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.evp_digest.md); + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.evp_digest.ctx); + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.ctx.evp_pkey); /* Ignore the MD5 check when in FIPS mode to comply with the TLS 1.0 RFC */ if (s2n_is_in_fips_mode()) { - GUARD(s2n_digest_allow_md5_for_fips(&ws->tls.p_hash.evp_hmac.evp_digest)); + POSIX_GUARD(s2n_digest_allow_md5_for_fips(&ws->p_hash.evp_hmac.evp_digest)); } - GUARD_OSSL(EVP_DigestSignInit(ws->tls.p_hash.evp_hmac.evp_digest.ctx, NULL, ws->tls.p_hash.evp_hmac.evp_digest.md, NULL, ws->tls.p_hash.evp_hmac.mac_key), + POSIX_GUARD_OSSL(EVP_DigestSignInit(ws->p_hash.evp_hmac.evp_digest.ctx, NULL, ws->p_hash.evp_hmac.evp_digest.md, NULL, ws->p_hash.evp_hmac.ctx.evp_pkey), S2N_ERR_P_HASH_INIT_FAILED); return 0; } -static int s2n_evp_hmac_p_hash_init(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret) +static int s2n_evp_pkey_p_hash_init(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret) { /* Initialize the message digest */ - switch (alg) { - case S2N_HMAC_SSLv3_MD5: - case S2N_HMAC_MD5: - ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_md5(); - break; - case S2N_HMAC_SSLv3_SHA1: - case S2N_HMAC_SHA1: - ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha1(); - break; - case S2N_HMAC_SHA224: - ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha224(); - break; - case S2N_HMAC_SHA256: - ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha256(); - break; - case S2N_HMAC_SHA384: - ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha384(); - break; - case S2N_HMAC_SHA512: - ws->tls.p_hash.evp_hmac.evp_digest.md = EVP_sha512(); - break; - default: - S2N_ERROR(S2N_ERR_P_HASH_INVALID_ALGORITHM); - } + POSIX_GUARD(s2n_init_md_from_hmac_alg(ws, alg)); /* Initialize the mac key using the provided secret */ - notnull_check(ws->tls.p_hash.evp_hmac.mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret->data, secret->size)); + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.ctx.evp_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret->data, secret->size)); /* Initialize the message digest context with the above message digest and mac key */ - return s2n_evp_hmac_p_hash_digest_init(ws); + return s2n_evp_pkey_p_hash_digest_init(ws); } -static int s2n_evp_hmac_p_hash_update(struct s2n_prf_working_space *ws, const void *data, uint32_t size) +static int s2n_evp_pkey_p_hash_update(struct s2n_prf_working_space *ws, const void *data, uint32_t size) { - GUARD_OSSL(EVP_DigestSignUpdate(ws->tls.p_hash.evp_hmac.evp_digest.ctx, data, (size_t)size), S2N_ERR_P_HASH_UPDATE_FAILED); + POSIX_GUARD_OSSL(EVP_DigestSignUpdate(ws->p_hash.evp_hmac.evp_digest.ctx, data, (size_t)size), S2N_ERR_P_HASH_UPDATE_FAILED); return 0; } -static int s2n_evp_hmac_p_hash_digest(struct s2n_prf_working_space *ws, void *digest, uint32_t size) +static int s2n_evp_pkey_p_hash_final(struct s2n_prf_working_space *ws, void *digest, uint32_t size) { /* EVP_DigestSign API's require size_t data structures */ size_t digest_size = size; - GUARD_OSSL(EVP_DigestSignFinal(ws->tls.p_hash.evp_hmac.evp_digest.ctx, (unsigned char *)digest, &digest_size), S2N_ERR_P_HASH_FINAL_FAILED); + POSIX_GUARD_OSSL(EVP_DigestSignFinal(ws->p_hash.evp_hmac.evp_digest.ctx, (unsigned char *)digest, &digest_size), S2N_ERR_P_HASH_FINAL_FAILED); return 0; } -static int s2n_evp_hmac_p_hash_wipe(struct s2n_prf_working_space *ws) +static int s2n_evp_pkey_p_hash_wipe(struct s2n_prf_working_space *ws) { - GUARD_OSSL(S2N_EVP_MD_CTX_RESET(ws->tls.p_hash.evp_hmac.evp_digest.ctx), S2N_ERR_P_HASH_WIPE_FAILED); + POSIX_GUARD_OSSL(S2N_EVP_MD_CTX_RESET(ws->p_hash.evp_hmac.evp_digest.ctx), S2N_ERR_P_HASH_WIPE_FAILED); return 0; } -static int s2n_evp_hmac_p_hash_reset(struct s2n_prf_working_space *ws) +static int s2n_evp_pkey_p_hash_reset(struct s2n_prf_working_space *ws) { - GUARD(s2n_evp_hmac_p_hash_wipe(ws)); + POSIX_GUARD(s2n_evp_pkey_p_hash_wipe(ws)); - return s2n_evp_hmac_p_hash_digest_init(ws); + /* + * On some cleanup paths s2n_evp_pkey_p_hash_reset can be called before s2n_evp_pkey_p_hash_init so there is nothing + * to reset. + */ + if (ws->p_hash.evp_hmac.ctx.evp_pkey == NULL) { + return S2N_SUCCESS; + } + return s2n_evp_pkey_p_hash_digest_init(ws); } -static int s2n_evp_hmac_p_hash_cleanup(struct s2n_prf_working_space *ws) +static int s2n_evp_pkey_p_hash_cleanup(struct s2n_prf_working_space *ws) { /* Prepare the workspace md_ctx for the next p_hash */ - GUARD(s2n_evp_hmac_p_hash_wipe(ws)); + POSIX_GUARD(s2n_evp_pkey_p_hash_wipe(ws)); /* Free mac key - PKEYs cannot be reused */ - notnull_check(ws->tls.p_hash.evp_hmac.mac_key); - EVP_PKEY_free(ws->tls.p_hash.evp_hmac.mac_key); - ws->tls.p_hash.evp_hmac.mac_key = NULL; + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.ctx.evp_pkey); + EVP_PKEY_free(ws->p_hash.evp_hmac.ctx.evp_pkey); + ws->p_hash.evp_hmac.ctx.evp_pkey = NULL; return 0; } -static int s2n_evp_hmac_p_hash_free(struct s2n_prf_working_space *ws) +static int s2n_evp_pkey_p_hash_free(struct s2n_prf_working_space *ws) { - notnull_check(ws->tls.p_hash.evp_hmac.evp_digest.ctx); - S2N_EVP_MD_CTX_FREE(ws->tls.p_hash.evp_hmac.evp_digest.ctx); - ws->tls.p_hash.evp_hmac.evp_digest.ctx = NULL; + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.evp_digest.ctx); + S2N_EVP_MD_CTX_FREE(ws->p_hash.evp_hmac.evp_digest.ctx); + ws->p_hash.evp_hmac.evp_digest.ctx = NULL; return 0; } -static const struct s2n_p_hash_hmac s2n_evp_hmac = { - .alloc = &s2n_evp_hmac_p_hash_new, +static const struct s2n_p_hash_hmac s2n_evp_pkey_p_hash_hmac = { + .alloc = &s2n_evp_pkey_p_hash_alloc, + .init = &s2n_evp_pkey_p_hash_init, + .update = &s2n_evp_pkey_p_hash_update, + .final = &s2n_evp_pkey_p_hash_final, + .reset = &s2n_evp_pkey_p_hash_reset, + .cleanup = &s2n_evp_pkey_p_hash_cleanup, + .free = &s2n_evp_pkey_p_hash_free, +}; +#else +static int s2n_evp_hmac_p_hash_alloc(struct s2n_prf_working_space *ws) +{ + POSIX_ENSURE_REF(ws->p_hash.evp_hmac.ctx.hmac_ctx = HMAC_CTX_new()); + return S2N_SUCCESS; +} + +static int s2n_evp_hmac_p_hash_init(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret) +{ + /* Figure out the correct EVP_MD from s2n_hmac_algorithm */ + POSIX_GUARD(s2n_init_md_from_hmac_alg(ws, alg)); + + /* Initialize the mac and digest */ + POSIX_GUARD_OSSL(HMAC_Init_ex(ws->p_hash.evp_hmac.ctx.hmac_ctx, secret->data, secret->size, ws->p_hash.evp_hmac.evp_digest.md, NULL), S2N_ERR_P_HASH_INIT_FAILED); + return S2N_SUCCESS; +} + +static int s2n_evp_hmac_p_hash_update(struct s2n_prf_working_space *ws, const void *data, uint32_t size) +{ + POSIX_GUARD_OSSL(HMAC_Update(ws->p_hash.evp_hmac.ctx.hmac_ctx, data, (size_t)size), S2N_ERR_P_HASH_UPDATE_FAILED); + return S2N_SUCCESS; +} + +static int s2n_evp_hmac_p_hash_final(struct s2n_prf_working_space *ws, void *digest, uint32_t size) +{ + /* HMAC_Final API's require size_t data structures */ + unsigned int digest_size = size; + POSIX_GUARD_OSSL(HMAC_Final(ws->p_hash.evp_hmac.ctx.hmac_ctx, (unsigned char *)digest, &digest_size), S2N_ERR_P_HASH_FINAL_FAILED); + return S2N_SUCCESS; +} + +static int s2n_evp_hmac_p_hash_reset(struct s2n_prf_working_space *ws) +{ + POSIX_ENSURE_REF(ws); + if (ws->p_hash.evp_hmac.evp_digest.md == NULL) { + return S2N_SUCCESS; + } + POSIX_GUARD_OSSL(HMAC_Init_ex(ws->p_hash.evp_hmac.ctx.hmac_ctx, NULL, 0, ws->p_hash.evp_hmac.evp_digest.md, NULL), S2N_ERR_P_HASH_INIT_FAILED); + return S2N_SUCCESS; +} + +static int s2n_evp_hmac_p_hash_cleanup(struct s2n_prf_working_space *ws) +{ + /* Prepare the workspace md_ctx for the next p_hash */ + HMAC_CTX_reset(ws->p_hash.evp_hmac.ctx.hmac_ctx); + return S2N_SUCCESS; +} + +static int s2n_evp_hmac_p_hash_free(struct s2n_prf_working_space *ws) +{ + HMAC_CTX_free(ws->p_hash.evp_hmac.ctx.hmac_ctx); + return S2N_SUCCESS; +} + +static const struct s2n_p_hash_hmac s2n_evp_hmac_p_hash_hmac = { + .alloc = &s2n_evp_hmac_p_hash_alloc, .init = &s2n_evp_hmac_p_hash_init, .update = &s2n_evp_hmac_p_hash_update, - .final = &s2n_evp_hmac_p_hash_digest, + .final = &s2n_evp_hmac_p_hash_final, .reset = &s2n_evp_hmac_p_hash_reset, .cleanup = &s2n_evp_hmac_p_hash_cleanup, .free = &s2n_evp_hmac_p_hash_free, @@ -213,29 +294,35 @@ static const struct s2n_p_hash_hmac s2n_evp_hmac = { static int s2n_hmac_p_hash_new(struct s2n_prf_working_space *ws) { - GUARD(s2n_hmac_new(&ws->tls.p_hash.s2n_hmac)); + POSIX_GUARD(s2n_hmac_new(&ws->p_hash.s2n_hmac)); - return s2n_hmac_init(&ws->tls.p_hash.s2n_hmac, S2N_HMAC_NONE, NULL, 0); + return s2n_hmac_init(&ws->p_hash.s2n_hmac, S2N_HMAC_NONE, NULL, 0); } static int s2n_hmac_p_hash_init(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret) { - return s2n_hmac_init(&ws->tls.p_hash.s2n_hmac, alg, secret->data, secret->size); + return s2n_hmac_init(&ws->p_hash.s2n_hmac, alg, secret->data, secret->size); } static int s2n_hmac_p_hash_update(struct s2n_prf_working_space *ws, const void *data, uint32_t size) { - return s2n_hmac_update(&ws->tls.p_hash.s2n_hmac, data, size); + return s2n_hmac_update(&ws->p_hash.s2n_hmac, data, size); } static int s2n_hmac_p_hash_digest(struct s2n_prf_working_space *ws, void *digest, uint32_t size) { - return s2n_hmac_digest(&ws->tls.p_hash.s2n_hmac, digest, size); + return s2n_hmac_digest(&ws->p_hash.s2n_hmac, digest, size); } static int s2n_hmac_p_hash_reset(struct s2n_prf_working_space *ws) { - return s2n_hmac_reset(&ws->tls.p_hash.s2n_hmac); + /* If we actually initialized s2n_hmac, wipe it. + * A valid, initialized s2n_hmac_state will have a valid block size. + */ + if (ws->p_hash.s2n_hmac.hash_block_size != 0) { + return s2n_hmac_reset(&ws->p_hash.s2n_hmac); + } + return S2N_SUCCESS; } static int s2n_hmac_p_hash_cleanup(struct s2n_prf_working_space *ws) @@ -245,10 +332,10 @@ static int s2n_hmac_p_hash_cleanup(struct s2n_prf_working_space *ws) static int s2n_hmac_p_hash_free(struct s2n_prf_working_space *ws) { - return s2n_hmac_free(&ws->tls.p_hash.s2n_hmac); + return s2n_hmac_free(&ws->p_hash.s2n_hmac); } -static const struct s2n_p_hash_hmac s2n_hmac = { +static const struct s2n_p_hash_hmac s2n_internal_p_hash_hmac = { .alloc = &s2n_hmac_p_hash_new, .init = &s2n_hmac_p_hash_init, .update = &s2n_hmac_p_hash_update, @@ -258,103 +345,129 @@ static const struct s2n_p_hash_hmac s2n_hmac = { .free = &s2n_hmac_p_hash_free, }; +const struct s2n_p_hash_hmac *s2n_get_hmac_implementation() { +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + return s2n_is_in_fips_mode() ? &s2n_evp_hmac_p_hash_hmac : &s2n_internal_p_hash_hmac; +#else + return s2n_is_in_fips_mode() ? &s2n_evp_pkey_p_hash_hmac : &s2n_internal_p_hash_hmac; +#endif +} + static int s2n_p_hash(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret, struct s2n_blob *label, struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out) { uint8_t digest_size; - GUARD(s2n_hmac_digest_size(alg, &digest_size)); + POSIX_GUARD(s2n_hmac_digest_size(alg, &digest_size)); - const struct s2n_p_hash_hmac *hmac = ws->tls.p_hash_hmac_impl; + const struct s2n_p_hash_hmac *hmac = s2n_get_hmac_implementation(); /* First compute hmac(secret + A(0)) */ - GUARD(hmac->init(ws, alg, secret)); - GUARD(hmac->update(ws, label->data, label->size)); - GUARD(hmac->update(ws, seed_a->data, seed_a->size)); + POSIX_GUARD(hmac->init(ws, alg, secret)); + POSIX_GUARD(hmac->update(ws, label->data, label->size)); + POSIX_GUARD(hmac->update(ws, seed_a->data, seed_a->size)); if (seed_b) { - GUARD(hmac->update(ws, seed_b->data, seed_b->size)); + POSIX_GUARD(hmac->update(ws, seed_b->data, seed_b->size)); if (seed_c) { - GUARD(hmac->update(ws, seed_c->data, seed_c->size)); + POSIX_GUARD(hmac->update(ws, seed_c->data, seed_c->size)); } } - GUARD(hmac->final(ws, ws->tls.digest0, digest_size)); + POSIX_GUARD(hmac->final(ws, ws->digest0, digest_size)); uint32_t outputlen = out->size; uint8_t *output = out->data; while (outputlen) { /* Now compute hmac(secret + A(N - 1) + seed) */ - GUARD(hmac->reset(ws)); - GUARD(hmac->update(ws, ws->tls.digest0, digest_size)); + POSIX_GUARD(hmac->reset(ws)); + POSIX_GUARD(hmac->update(ws, ws->digest0, digest_size)); /* Add the label + seed and compute this round's A */ - GUARD(hmac->update(ws, label->data, label->size)); - GUARD(hmac->update(ws, seed_a->data, seed_a->size)); + POSIX_GUARD(hmac->update(ws, label->data, label->size)); + POSIX_GUARD(hmac->update(ws, seed_a->data, seed_a->size)); if (seed_b) { - GUARD(hmac->update(ws, seed_b->data, seed_b->size)); + POSIX_GUARD(hmac->update(ws, seed_b->data, seed_b->size)); if (seed_c) { - GUARD(hmac->update(ws, seed_c->data, seed_c->size)); + POSIX_GUARD(hmac->update(ws, seed_c->data, seed_c->size)); } } - GUARD(hmac->final(ws, ws->tls.digest1, digest_size)); + POSIX_GUARD(hmac->final(ws, ws->digest1, digest_size)); uint32_t bytes_to_xor = MIN(outputlen, digest_size); - for (int i = 0; i < bytes_to_xor; i++) { - *output ^= ws->tls.digest1[i]; + for (uint32_t i = 0; i < bytes_to_xor; i++) { + *output ^= ws->digest1[i]; output++; outputlen--; } /* Stash a digest of A(N), in A(N), for the next round */ - GUARD(hmac->reset(ws)); - GUARD(hmac->update(ws, ws->tls.digest0, digest_size)); - GUARD(hmac->final(ws, ws->tls.digest0, digest_size)); + POSIX_GUARD(hmac->reset(ws)); + POSIX_GUARD(hmac->update(ws, ws->digest0, digest_size)); + POSIX_GUARD(hmac->final(ws, ws->digest0, digest_size)); } - GUARD(hmac->cleanup(ws)); + POSIX_GUARD(hmac->cleanup(ws)); return 0; } -const struct s2n_p_hash_hmac *s2n_get_hmac_implementation() { -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) - return &s2n_hmac; -#else - return s2n_is_in_fips_mode() ? &s2n_evp_hmac : &s2n_hmac; -#endif +S2N_RESULT s2n_prf_new(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_EQ(conn->prf_space, NULL); + + DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free); + RESULT_GUARD_POSIX(s2n_realloc(&mem, sizeof(struct s2n_prf_working_space))); + RESULT_GUARD_POSIX(s2n_blob_zero(&mem)); + conn->prf_space = (struct s2n_prf_working_space*)(void*) mem.data; + ZERO_TO_DISABLE_DEFER_CLEANUP(mem); + + /* Allocate the hmac state */ + const struct s2n_p_hash_hmac *hmac_impl = s2n_get_hmac_implementation(); + RESULT_GUARD_POSIX(hmac_impl->alloc(conn->prf_space)); + return S2N_RESULT_OK; } -int s2n_prf_new(struct s2n_connection *conn) +S2N_RESULT s2n_prf_wipe(struct s2n_connection *conn) { - /* Set p_hash_hmac_impl on initial prf creation. - * When in FIPS mode, the EVP API's must be used for the p_hash HMAC. - */ - conn->prf_space.tls.p_hash_hmac_impl = s2n_get_hmac_implementation(); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->prf_space); + + const struct s2n_p_hash_hmac *hmac_impl = s2n_get_hmac_implementation(); + RESULT_GUARD_POSIX(hmac_impl->reset(conn->prf_space)); - return conn->prf_space.tls.p_hash_hmac_impl->alloc(&conn->prf_space); + return S2N_RESULT_OK; } -int s2n_prf_free(struct s2n_connection *conn) +S2N_RESULT s2n_prf_free(struct s2n_connection *conn) { - /* Ensure that p_hash_hmac_impl is set, as it may have been reset for prf_space on s2n_connection_wipe. - * When in FIPS mode, the EVP API's must be used for the p_hash HMAC. - */ - conn->prf_space.tls.p_hash_hmac_impl = s2n_get_hmac_implementation(); + RESULT_ENSURE_REF(conn); + if (conn->prf_space == NULL) { + return S2N_RESULT_OK; + } - return conn->prf_space.tls.p_hash_hmac_impl->free(&conn->prf_space); + const struct s2n_p_hash_hmac *hmac_impl = s2n_get_hmac_implementation(); + RESULT_GUARD_POSIX(hmac_impl->free(conn->prf_space)); + + RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) &conn->prf_space, sizeof(struct s2n_prf_working_space))); + return S2N_RESULT_OK; } static int s2n_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label, struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(secret); + POSIX_ENSURE_REF(conn->prf_space); + /* seed_a is always required, seed_b is optional, if seed_c is provided seed_b must also be provided */ S2N_ERROR_IF(seed_a == NULL, S2N_ERR_PRF_INVALID_SEED); S2N_ERROR_IF(seed_b == NULL && seed_c != NULL, S2N_ERR_PRF_INVALID_SEED); if (conn->actual_protocol_version == S2N_SSLv3) { - return s2n_sslv3_prf(&conn->prf_space, secret, seed_a, seed_b, seed_c, out); + return s2n_sslv3_prf(conn, secret, seed_a, seed_b, seed_c, out); } /* We zero the out blob because p_hash works by XOR'ing with the existing @@ -363,32 +476,27 @@ static int s2n_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct * the right values. When we call it twice in the regular case, the two * outputs will be XORd just ass the TLS 1.0 and 1.1 RFCs require. */ - GUARD(s2n_blob_zero(out)); - - /* Ensure that p_hash_hmac_impl is set, as it may have been reset for prf_space on s2n_connection_wipe. - * When in FIPS mode, the EVP API's must be used for the p_hash HMAC. - */ - conn->prf_space.tls.p_hash_hmac_impl = s2n_get_hmac_implementation(); - + POSIX_GUARD(s2n_blob_zero(out)); + if (conn->actual_protocol_version == S2N_TLS12) { - return s2n_p_hash(&conn->prf_space, conn->secure.cipher_suite->prf_alg, secret, label, seed_a, seed_b, + return s2n_p_hash(conn->prf_space, conn->secure.cipher_suite->prf_alg, secret, label, seed_a, seed_b, seed_c, out); } struct s2n_blob half_secret = {.data = secret->data,.size = (secret->size + 1) / 2 }; - GUARD(s2n_p_hash(&conn->prf_space, S2N_HMAC_MD5, &half_secret, label, seed_a, seed_b, seed_c, out)); + POSIX_GUARD(s2n_p_hash(conn->prf_space, S2N_HMAC_MD5, &half_secret, label, seed_a, seed_b, seed_c, out)); half_secret.data += secret->size - half_secret.size; - GUARD(s2n_p_hash(&conn->prf_space, S2N_HMAC_SHA1, &half_secret, label, seed_a, seed_b, seed_c, out)); + POSIX_GUARD(s2n_p_hash(conn->prf_space, S2N_HMAC_SHA1, &half_secret, label, seed_a, seed_b, seed_c, out)); return 0; } int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret) { - struct s2n_blob client_random = {.size = sizeof(conn->secure.client_random), .data = conn->secure.client_random}; - struct s2n_blob server_random = {.size = sizeof(conn->secure.server_random), .data = conn->secure.server_random}; - struct s2n_blob master_secret = {.size = sizeof(conn->secure.master_secret), .data = conn->secure.master_secret}; + struct s2n_blob client_random = {.size = sizeof(conn->handshake_params.client_random), .data = conn->handshake_params.client_random}; + struct s2n_blob server_random = {.size = sizeof(conn->handshake_params.server_random), .data = conn->handshake_params.server_random}; + struct s2n_blob master_secret = {.size = sizeof(conn->secrets.tls12.master_secret), .data = conn->secrets.tls12.master_secret}; uint8_t master_secret_label[] = "master secret"; struct s2n_blob label = {.size = sizeof(master_secret_label) - 1, .data = master_secret_label}; @@ -398,18 +506,103 @@ int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *prem int s2n_hybrid_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret) { - struct s2n_blob client_random = {.size = sizeof(conn->secure.client_random), .data = conn->secure.client_random}; - struct s2n_blob server_random = {.size = sizeof(conn->secure.server_random), .data = conn->secure.server_random}; - struct s2n_blob master_secret = {.size = sizeof(conn->secure.master_secret), .data = conn->secure.master_secret}; + struct s2n_blob client_random = {.size = sizeof(conn->handshake_params.client_random), .data = conn->handshake_params.client_random}; + struct s2n_blob server_random = {.size = sizeof(conn->handshake_params.server_random), .data = conn->handshake_params.server_random}; + struct s2n_blob master_secret = {.size = sizeof(conn->secrets.tls12.master_secret), .data = conn->secrets.tls12.master_secret}; uint8_t master_secret_label[] = "hybrid master secret"; struct s2n_blob label = {.size = sizeof(master_secret_label) - 1, .data = master_secret_label}; - return s2n_prf(conn, premaster_secret, &label, &client_random, &server_random, &conn->secure.client_key_exchange_message, &master_secret); + return s2n_prf(conn, premaster_secret, &label, &client_random, &server_random, &conn->kex_params.client_key_exchange_message, &master_secret); } -static int s2n_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], struct s2n_hash_state *md5, struct s2n_hash_state *sha1, uint8_t * out) +int s2n_prf_calculate_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret) { + POSIX_ENSURE_REF(conn); + + POSIX_ENSURE_EQ(s2n_conn_get_current_message_type(conn), CLIENT_KEY); + + if(!conn->ems_negotiated) { + POSIX_GUARD(s2n_tls_prf_master_secret(conn, premaster_secret)); + return S2N_SUCCESS; + } + + /* Only the client writes the Client Key Exchange message */ + if (conn->mode == S2N_CLIENT) { + POSIX_GUARD(s2n_handshake_finish_header(&conn->handshake.io)); + } + struct s2n_stuffer client_key_message = conn->handshake.io; + POSIX_GUARD(s2n_stuffer_reread(&client_key_message)); + uint32_t client_key_message_size = s2n_stuffer_data_available(&client_key_message); + struct s2n_blob client_key_blob = { 0 }; + POSIX_GUARD(s2n_blob_init(&client_key_blob, client_key_message.blob.data, client_key_message_size)); + + uint8_t data[S2N_MAX_DIGEST_LEN] = { 0 }; + struct s2n_blob digest = { 0 }; + POSIX_GUARD(s2n_blob_init(&digest, data, sizeof(data))); + if (conn->actual_protocol_version < S2N_TLS12) { + uint8_t sha1_data[S2N_MAX_DIGEST_LEN] = { 0 }; + struct s2n_blob sha1_digest = { 0 }; + POSIX_GUARD(s2n_blob_init(&sha1_digest, sha1_data, sizeof(sha1_data))); + POSIX_GUARD_RESULT(s2n_prf_get_digest_for_ems(conn, &client_key_blob, S2N_HASH_MD5, &digest)); + POSIX_GUARD_RESULT(s2n_prf_get_digest_for_ems(conn, &client_key_blob, S2N_HASH_SHA1, &sha1_digest)); + POSIX_GUARD_RESULT(s2n_tls_prf_extended_master_secret(conn, premaster_secret, &digest, &sha1_digest)); + } else { + s2n_hmac_algorithm prf_alg = conn->secure.cipher_suite->prf_alg; + s2n_hash_algorithm hash_alg = 0; + POSIX_GUARD(s2n_hmac_hash_alg(prf_alg, &hash_alg)); + POSIX_GUARD_RESULT(s2n_prf_get_digest_for_ems(conn, &client_key_blob, hash_alg, &digest)); + POSIX_GUARD_RESULT(s2n_tls_prf_extended_master_secret(conn, premaster_secret, &digest, NULL)); + } + return S2N_SUCCESS; +} + +/** + *= https://tools.ietf.org/rfc/rfc7627#section-4 + *# When the extended master secret extension is negotiated in a full + *# handshake, the "master_secret" is computed as + *# + *# master_secret = PRF(pre_master_secret, "extended master secret", + *# session_hash) + *# [0..47]; + */ +S2N_RESULT s2n_tls_prf_extended_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash) +{ + struct s2n_blob extended_master_secret = {.size = sizeof(conn->secrets.tls12.master_secret), .data = conn->secrets.tls12.master_secret}; + + uint8_t extended_master_secret_label[] = "extended master secret"; + /* Subtract one from the label size to remove the "\0" */ + struct s2n_blob label = {.size = sizeof(extended_master_secret_label) - 1, .data = extended_master_secret_label}; + + RESULT_GUARD_POSIX(s2n_prf(conn, premaster_secret, &label, session_hash, sha1_hash, NULL, &extended_master_secret)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_prf_get_digest_for_ems(struct s2n_connection *conn, struct s2n_blob *message, s2n_hash_algorithm hash_alg, struct s2n_blob *output) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->handshake.hashes); + RESULT_ENSURE_REF(output); + + struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace; + RESULT_GUARD(s2n_handshake_copy_hash_state(conn, hash_alg, hash_state)); + RESULT_GUARD_POSIX(s2n_hash_update(hash_state, message->data, message->size)); + + uint8_t digest_size = 0; + RESULT_GUARD_POSIX(s2n_hash_digest_size(hash_alg, &digest_size)); + RESULT_ENSURE_GTE(output->size, digest_size); + RESULT_GUARD_POSIX(s2n_hash_digest(hash_state, output->data, digest_size)); + output->size = digest_size; + + return S2N_RESULT_OK; +} + +static int s2n_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], struct s2n_hash_state *hash_workspace, uint8_t * out) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + uint8_t xorpad1[48] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 @@ -421,55 +614,64 @@ static int s2n_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], st uint8_t *md5_digest = out; uint8_t *sha_digest = out + MD5_DIGEST_LENGTH; - lte_check(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.client_finished)); - - GUARD(s2n_hash_update(md5, prefix, 4)); - GUARD(s2n_hash_update(md5, conn->secure.master_secret, sizeof(conn->secure.master_secret))); - GUARD(s2n_hash_update(md5, xorpad1, 48)); - GUARD(s2n_hash_digest(md5, md5_digest, MD5_DIGEST_LENGTH)); - GUARD(s2n_hash_reset(md5)); - GUARD(s2n_hash_update(md5, conn->secure.master_secret, sizeof(conn->secure.master_secret))); - GUARD(s2n_hash_update(md5, xorpad2, 48)); - GUARD(s2n_hash_update(md5, md5_digest, MD5_DIGEST_LENGTH)); - GUARD(s2n_hash_digest(md5, md5_digest, MD5_DIGEST_LENGTH)); - GUARD(s2n_hash_reset(md5)); - - GUARD(s2n_hash_update(sha1, prefix, 4)); - GUARD(s2n_hash_update(sha1, conn->secure.master_secret, sizeof(conn->secure.master_secret))); - GUARD(s2n_hash_update(sha1, xorpad1, 40)); - GUARD(s2n_hash_digest(sha1, sha_digest, SHA_DIGEST_LENGTH)); - GUARD(s2n_hash_reset(sha1)); - GUARD(s2n_hash_update(sha1, conn->secure.master_secret, sizeof(conn->secure.master_secret))); - GUARD(s2n_hash_update(sha1, xorpad2, 40)); - GUARD(s2n_hash_update(sha1, sha_digest, SHA_DIGEST_LENGTH)); - GUARD(s2n_hash_digest(sha1, sha_digest, SHA_DIGEST_LENGTH)); - GUARD(s2n_hash_reset(sha1)); + POSIX_ENSURE_LTE(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.client_finished)); + + struct s2n_hash_state *md5 = hash_workspace; + POSIX_GUARD(s2n_hash_copy(md5, &conn->handshake.hashes->md5)); + POSIX_GUARD(s2n_hash_update(md5, prefix, 4)); + POSIX_GUARD(s2n_hash_update(md5, conn->secrets.tls12.master_secret, sizeof(conn->secrets.tls12.master_secret))); + POSIX_GUARD(s2n_hash_update(md5, xorpad1, 48)); + POSIX_GUARD(s2n_hash_digest(md5, md5_digest, MD5_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_reset(md5)); + POSIX_GUARD(s2n_hash_update(md5, conn->secrets.tls12.master_secret, sizeof(conn->secrets.tls12.master_secret))); + POSIX_GUARD(s2n_hash_update(md5, xorpad2, 48)); + POSIX_GUARD(s2n_hash_update(md5, md5_digest, MD5_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_digest(md5, md5_digest, MD5_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_reset(md5)); + + struct s2n_hash_state *sha1 = hash_workspace; + POSIX_GUARD(s2n_hash_copy(sha1, &conn->handshake.hashes->sha1)); + POSIX_GUARD(s2n_hash_update(sha1, prefix, 4)); + POSIX_GUARD(s2n_hash_update(sha1, conn->secrets.tls12.master_secret, sizeof(conn->secrets.tls12.master_secret))); + POSIX_GUARD(s2n_hash_update(sha1, xorpad1, 40)); + POSIX_GUARD(s2n_hash_digest(sha1, sha_digest, SHA_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_reset(sha1)); + POSIX_GUARD(s2n_hash_update(sha1, conn->secrets.tls12.master_secret, sizeof(conn->secrets.tls12.master_secret))); + POSIX_GUARD(s2n_hash_update(sha1, xorpad2, 40)); + POSIX_GUARD(s2n_hash_update(sha1, sha_digest, SHA_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_digest(sha1, sha_digest, SHA_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_reset(sha1)); return 0; } static int s2n_sslv3_client_finished(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + uint8_t prefix[4] = { 0x43, 0x4c, 0x4e, 0x54 }; - lte_check(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.client_finished)); - GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); - GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); - return s2n_sslv3_finished(conn, prefix, &conn->handshake.prf_md5_hash_copy, &conn->handshake.prf_sha1_hash_copy, conn->handshake.client_finished); + POSIX_ENSURE_LTE(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.client_finished)); + return s2n_sslv3_finished(conn, prefix, &conn->handshake.hashes->hash_workspace, conn->handshake.client_finished); } static int s2n_sslv3_server_finished(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + uint8_t prefix[4] = { 0x53, 0x52, 0x56, 0x52 }; - lte_check(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.server_finished)); - GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); - GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); - return s2n_sslv3_finished(conn, prefix, &conn->handshake.prf_md5_hash_copy, &conn->handshake.prf_sha1_hash_copy, conn->handshake.server_finished); + POSIX_ENSURE_LTE(MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, sizeof(conn->handshake.server_finished)); + return s2n_sslv3_finished(conn, prefix, &conn->handshake.hashes->hash_workspace, conn->handshake.server_finished); } int s2n_prf_client_finished(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_blob master_secret, md5, sha; uint8_t md5_digest[MD5_DIGEST_LENGTH]; uint8_t sha_digest[SHA384_DIGEST_LENGTH]; @@ -486,35 +688,35 @@ int s2n_prf_client_finished(struct s2n_connection *conn) label.data = client_finished_label; label.size = sizeof(client_finished_label) - 1; - master_secret.data = conn->secure.master_secret; - master_secret.size = sizeof(conn->secure.master_secret); + master_secret.data = conn->secrets.tls12.master_secret; + master_secret.size = sizeof(conn->secrets.tls12.master_secret); if (conn->actual_protocol_version == S2N_TLS12) { switch (conn->secure.cipher_suite->prf_alg) { case S2N_HMAC_SHA256: - GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha256)); - GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA256_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->sha256)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, sha_digest, SHA256_DIGEST_LENGTH)); sha.size = SHA256_DIGEST_LENGTH; break; case S2N_HMAC_SHA384: - GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha384)); - GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA384_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->sha384)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, sha_digest, SHA384_DIGEST_LENGTH)); sha.size = SHA384_DIGEST_LENGTH; break; default: - S2N_ERROR(S2N_ERR_PRF_INVALID_ALGORITHM); + POSIX_BAIL(S2N_ERR_PRF_INVALID_ALGORITHM); } sha.data = sha_digest; return s2n_prf(conn, &master_secret, &label, &sha, NULL, NULL, &client_finished); } - GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); - GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); - - GUARD(s2n_hash_digest(&conn->handshake.prf_md5_hash_copy, md5_digest, MD5_DIGEST_LENGTH)); - GUARD(s2n_hash_digest(&conn->handshake.prf_sha1_hash_copy, sha_digest, SHA_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->md5)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, md5_digest, MD5_DIGEST_LENGTH)); md5.data = md5_digest; md5.size = MD5_DIGEST_LENGTH; + + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->sha1)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, sha_digest, SHA_DIGEST_LENGTH)); sha.data = sha_digest; sha.size = SHA_DIGEST_LENGTH; @@ -523,6 +725,9 @@ int s2n_prf_client_finished(struct s2n_connection *conn) int s2n_prf_server_finished(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_blob master_secret, md5, sha; uint8_t md5_digest[MD5_DIGEST_LENGTH]; uint8_t sha_digest[SHA384_DIGEST_LENGTH]; @@ -539,35 +744,35 @@ int s2n_prf_server_finished(struct s2n_connection *conn) label.data = server_finished_label; label.size = sizeof(server_finished_label) - 1; - master_secret.data = conn->secure.master_secret; - master_secret.size = sizeof(conn->secure.master_secret); + master_secret.data = conn->secrets.tls12.master_secret; + master_secret.size = sizeof(conn->secrets.tls12.master_secret); if (conn->actual_protocol_version == S2N_TLS12) { switch (conn->secure.cipher_suite->prf_alg) { case S2N_HMAC_SHA256: - GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha256)); - GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA256_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->sha256)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, sha_digest, SHA256_DIGEST_LENGTH)); sha.size = SHA256_DIGEST_LENGTH; break; case S2N_HMAC_SHA384: - GUARD(s2n_hash_copy(&conn->handshake.prf_tls12_hash_copy, &conn->handshake.sha384)); - GUARD(s2n_hash_digest(&conn->handshake.prf_tls12_hash_copy, sha_digest, SHA384_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->sha384)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, sha_digest, SHA384_DIGEST_LENGTH)); sha.size = SHA384_DIGEST_LENGTH; break; default: - S2N_ERROR(S2N_ERR_PRF_INVALID_ALGORITHM); + POSIX_BAIL(S2N_ERR_PRF_INVALID_ALGORITHM); } sha.data = sha_digest; return s2n_prf(conn, &master_secret, &label, &sha, NULL, NULL, &server_finished); } - GUARD(s2n_hash_copy(&conn->handshake.prf_md5_hash_copy, &conn->handshake.md5)); - GUARD(s2n_hash_copy(&conn->handshake.prf_sha1_hash_copy, &conn->handshake.sha1)); - - GUARD(s2n_hash_digest(&conn->handshake.prf_md5_hash_copy, md5_digest, MD5_DIGEST_LENGTH)); - GUARD(s2n_hash_digest(&conn->handshake.prf_sha1_hash_copy, sha_digest, SHA_DIGEST_LENGTH)); + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->md5)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, md5_digest, MD5_DIGEST_LENGTH)); md5.data = md5_digest; md5.size = MD5_DIGEST_LENGTH; + + POSIX_GUARD(s2n_hash_copy(&conn->handshake.hashes->hash_workspace, &conn->handshake.hashes->sha1)); + POSIX_GUARD(s2n_hash_digest(&conn->handshake.hashes->hash_workspace, sha_digest, SHA_DIGEST_LENGTH)); sha.data = sha_digest; sha.size = SHA_DIGEST_LENGTH; @@ -579,12 +784,12 @@ static int s2n_prf_make_client_key(struct s2n_connection *conn, struct s2n_stuff struct s2n_blob client_key = {0}; client_key.size = conn->secure.cipher_suite->record_alg->cipher->key_material_size; client_key.data = s2n_stuffer_raw_read(key_material, client_key.size); - notnull_check(client_key.data); + POSIX_ENSURE_REF(client_key.data); if (conn->mode == S2N_CLIENT) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.client_key, &client_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.client_key, &client_key)); } else { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.client_key, &client_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.client_key, &client_key)); } return 0; @@ -595,12 +800,12 @@ static int s2n_prf_make_server_key(struct s2n_connection *conn, struct s2n_stuff struct s2n_blob server_key = {0}; server_key.size = conn->secure.cipher_suite->record_alg->cipher->key_material_size; server_key.data = s2n_stuffer_raw_read(key_material, server_key.size); - notnull_check(server_key.data); + POSIX_ENSURE_REF(server_key.data); if (conn->mode == S2N_SERVER) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.server_key, &server_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->set_encryption_key(&conn->secure.server_key, &server_key)); } else { - GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.server_key, &server_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->set_decryption_key(&conn->secure.server_key, &server_key)); } return 0; @@ -608,58 +813,58 @@ static int s2n_prf_make_server_key(struct s2n_connection *conn, struct s2n_stuff int s2n_prf_key_expansion(struct s2n_connection *conn) { - struct s2n_blob client_random = {.data = conn->secure.client_random,.size = sizeof(conn->secure.client_random) }; - struct s2n_blob server_random = {.data = conn->secure.server_random,.size = sizeof(conn->secure.server_random) }; - struct s2n_blob master_secret = {.data = conn->secure.master_secret,.size = sizeof(conn->secure.master_secret) }; + struct s2n_blob client_random = {.data = conn->handshake_params.client_random,.size = sizeof(conn->handshake_params.client_random) }; + struct s2n_blob server_random = {.data = conn->handshake_params.server_random,.size = sizeof(conn->handshake_params.server_random) }; + struct s2n_blob master_secret = {.data = conn->secrets.tls12.master_secret,.size = sizeof(conn->secrets.tls12.master_secret) }; struct s2n_blob label, out; uint8_t key_expansion_label[] = "key expansion"; uint8_t key_block[S2N_MAX_KEY_BLOCK_LEN]; label.data = key_expansion_label; label.size = sizeof(key_expansion_label) - 1; - GUARD(s2n_blob_init(&out, key_block, sizeof(key_block))); + POSIX_GUARD(s2n_blob_init(&out, key_block, sizeof(key_block))); struct s2n_stuffer key_material = {0}; - GUARD(s2n_prf(conn, &master_secret, &label, &server_random, &client_random, NULL, &out)); - GUARD(s2n_stuffer_init(&key_material, &out)); - GUARD(s2n_stuffer_write(&key_material, &out)); + POSIX_GUARD(s2n_prf(conn, &master_secret, &label, &server_random, &client_random, NULL, &out)); + POSIX_GUARD(s2n_stuffer_init(&key_material, &out)); + POSIX_GUARD(s2n_stuffer_write(&key_material, &out)); - ENSURE_POSIX(conn->secure.cipher_suite->available, S2N_ERR_PRF_INVALID_ALGORITHM); - GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.client_key)); - GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.server_key)); + POSIX_ENSURE(conn->secure.cipher_suite->available, S2N_ERR_PRF_INVALID_ALGORITHM); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.client_key)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->init(&conn->secure.server_key)); /* Check that we have a valid MAC and key size */ uint8_t mac_size; if (conn->secure.cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { mac_size = conn->secure.cipher_suite->record_alg->cipher->io.comp.mac_key_size; } else { - GUARD(s2n_hmac_digest_size(conn->secure.cipher_suite->record_alg->hmac_alg, &mac_size)); + POSIX_GUARD(s2n_hmac_digest_size(conn->secure.cipher_suite->record_alg->hmac_alg, &mac_size)); } /* Seed the client MAC */ uint8_t *client_mac_write_key = s2n_stuffer_raw_read(&key_material, mac_size); - notnull_check(client_mac_write_key); - GUARD(s2n_hmac_reset(&conn->secure.client_record_mac)); - GUARD(s2n_hmac_init(&conn->secure.client_record_mac, conn->secure.cipher_suite->record_alg->hmac_alg, client_mac_write_key, mac_size)); + POSIX_ENSURE_REF(client_mac_write_key); + POSIX_GUARD(s2n_hmac_reset(&conn->secure.client_record_mac)); + POSIX_GUARD(s2n_hmac_init(&conn->secure.client_record_mac, conn->secure.cipher_suite->record_alg->hmac_alg, client_mac_write_key, mac_size)); /* Seed the server MAC */ uint8_t *server_mac_write_key = s2n_stuffer_raw_read(&key_material, mac_size); - notnull_check(server_mac_write_key); - GUARD(s2n_hmac_reset(&conn->secure.server_record_mac)); - GUARD(s2n_hmac_init(&conn->secure.server_record_mac, conn->secure.cipher_suite->record_alg->hmac_alg, server_mac_write_key, mac_size)); + POSIX_ENSURE_REF(server_mac_write_key); + POSIX_GUARD(s2n_hmac_reset(&conn->secure.server_record_mac)); + POSIX_GUARD(s2n_hmac_init(&conn->secure.server_record_mac, conn->secure.cipher_suite->record_alg->hmac_alg, server_mac_write_key, mac_size)); /* Make the client key */ - GUARD(s2n_prf_make_client_key(conn, &key_material)); + POSIX_GUARD(s2n_prf_make_client_key(conn, &key_material)); /* Make the server key */ - GUARD(s2n_prf_make_server_key(conn, &key_material)); + POSIX_GUARD(s2n_prf_make_server_key(conn, &key_material)); /* Composite CBC does MAC inside the cipher, pass it the MAC key. * Must happen after setting encryption/decryption keys. */ if (conn->secure.cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { - GUARD(conn->secure.cipher_suite->record_alg->cipher->io.comp.set_mac_write_key(&conn->secure.server_key, server_mac_write_key, mac_size)); - GUARD(conn->secure.cipher_suite->record_alg->cipher->io.comp.set_mac_write_key(&conn->secure.client_key, client_mac_write_key, mac_size)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->io.comp.set_mac_write_key(&conn->secure.server_key, server_mac_write_key, mac_size)); + POSIX_GUARD(conn->secure.cipher_suite->record_alg->cipher->io.comp.set_mac_write_key(&conn->secure.client_key, client_mac_write_key, mac_size)); } /* TLS >= 1.1 has no implicit IVs for non AEAD ciphers */ @@ -685,8 +890,8 @@ int s2n_prf_key_expansion(struct s2n_connection *conn) struct s2n_blob client_implicit_iv = {.data = conn->secure.client_implicit_iv,.size = implicit_iv_size }; struct s2n_blob server_implicit_iv = {.data = conn->secure.server_implicit_iv,.size = implicit_iv_size }; - GUARD(s2n_stuffer_read(&key_material, &client_implicit_iv)); - GUARD(s2n_stuffer_read(&key_material, &server_implicit_iv)); + POSIX_GUARD(s2n_stuffer_read(&key_material, &client_implicit_iv)); + POSIX_GUARD(s2n_stuffer_read(&key_material, &server_implicit_iv)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_prf.h b/contrib/restricted/aws/s2n/tls/s2n_prf.h index a3679436b2..cdf8414328 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_prf.h +++ b/contrib/restricted/aws/s2n/tls/s2n_prf.h @@ -26,25 +26,15 @@ /* Enough to support TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 2*SHA384_DIGEST_LEN + 2*AES256_KEY_SIZE */ #define S2N_MAX_KEY_BLOCK_LEN 160 -struct p_hash_state { +union p_hash_state { struct s2n_hmac_state s2n_hmac; struct s2n_evp_hmac_state evp_hmac; }; struct s2n_prf_working_space { - struct { - const struct s2n_p_hash_hmac *p_hash_hmac_impl; - struct p_hash_state p_hash; - uint8_t digest0[S2N_MAX_DIGEST_LEN]; - uint8_t digest1[S2N_MAX_DIGEST_LEN]; - } tls; - - struct { - struct s2n_hash_state md5; - struct s2n_hash_state sha1; - uint8_t md5_digest[MD5_DIGEST_LENGTH]; - uint8_t sha1_digest[SHA_DIGEST_LENGTH]; - } ssl3; + union p_hash_state p_hash; + uint8_t digest0[S2N_MAX_DIGEST_LEN]; + uint8_t digest1[S2N_MAX_DIGEST_LEN]; }; /* The s2n p_hash implementation is abstracted to allow for separate implementations, using @@ -61,10 +51,15 @@ struct s2n_p_hash_hmac { #include "tls/s2n_connection.h" -extern int s2n_prf_new(struct s2n_connection *conn); -extern int s2n_prf_free(struct s2n_connection *conn); +S2N_RESULT s2n_prf_new(struct s2n_connection *conn); +S2N_RESULT s2n_prf_wipe(struct s2n_connection *conn); +S2N_RESULT s2n_prf_free(struct s2n_connection *conn); + +int s2n_prf_calculate_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret); extern int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret); extern int s2n_hybrid_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret); +S2N_RESULT s2n_tls_prf_extended_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash); +S2N_RESULT s2n_prf_get_digest_for_ems(struct s2n_connection *conn, struct s2n_blob *message, s2n_hash_algorithm hash_alg, struct s2n_blob *output); extern int s2n_prf_key_expansion(struct s2n_connection *conn); extern int s2n_prf_server_finished(struct s2n_connection *conn); extern int s2n_prf_client_finished(struct s2n_connection *conn); diff --git a/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.c b/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.c index e0157f4ae4..88212161c8 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.c +++ b/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.c @@ -17,39 +17,146 @@ #include "error/s2n_errno.h" #include "utils/s2n_safety.h" -int s2n_blob_set_protocol_preferences(struct s2n_blob *application_protocols, const char *const *protocols, int protocol_count) +S2N_RESULT s2n_protocol_preferences_read(struct s2n_stuffer *protocol_preferences, struct s2n_blob *protocol) { - struct s2n_stuffer protocol_stuffer = {0}; + RESULT_ENSURE_REF(protocol_preferences); + RESULT_ENSURE_REF(protocol); - GUARD(s2n_free(application_protocols)); + uint8_t length = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(protocol_preferences, &length)); + RESULT_ENSURE_GT(length, 0); + uint8_t *data = s2n_stuffer_raw_read(protocol_preferences, length); + RESULT_ENSURE_REF(data); + + RESULT_GUARD_POSIX(s2n_blob_init(protocol, data, length)); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_protocol_preferences_contain(struct s2n_blob *protocol_preferences, struct s2n_blob *protocol, bool *contains) +{ + RESULT_ENSURE_REF(contains); + *contains = false; + RESULT_ENSURE_REF(protocol_preferences); + RESULT_ENSURE_REF(protocol); + + struct s2n_stuffer app_protocols_stuffer = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_init(&app_protocols_stuffer, protocol_preferences)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&app_protocols_stuffer, protocol_preferences->size)); + + while (s2n_stuffer_data_available(&app_protocols_stuffer) > 0) { + struct s2n_blob match_against = { 0 }; + RESULT_GUARD(s2n_protocol_preferences_read(&app_protocols_stuffer, &match_against)); + + if (match_against.size == protocol->size && memcmp(match_against.data, protocol->data, protocol->size) == 0) { + *contains = true; + return S2N_RESULT_OK; + } + } + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_protocol_preferences_append(struct s2n_blob *application_protocols, const uint8_t *protocol, uint8_t protocol_len) +{ + RESULT_ENSURE_MUT(application_protocols); + RESULT_ENSURE_REF(protocol); + + /** + *= https://tools.ietf.org/rfc/rfc7301#section-3.1 + *# Empty strings + *# MUST NOT be included and byte strings MUST NOT be truncated. + */ + RESULT_ENSURE(protocol_len != 0, S2N_ERR_INVALID_APPLICATION_PROTOCOL); + + uint32_t prev_len = application_protocols->size; + uint32_t new_len = prev_len + /* len prefix */ 1 + protocol_len; + RESULT_ENSURE(new_len <= UINT16_MAX, S2N_ERR_INVALID_APPLICATION_PROTOCOL); + + RESULT_GUARD_POSIX(s2n_realloc(application_protocols, new_len)); + + struct s2n_stuffer protocol_stuffer = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_init(&protocol_stuffer, application_protocols)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&protocol_stuffer, prev_len)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(&protocol_stuffer, protocol_len)); + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&protocol_stuffer, protocol, protocol_len)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_protocol_preferences_set(struct s2n_blob *application_protocols, const char *const *protocols, int protocol_count) +{ + RESULT_ENSURE_MUT(application_protocols); + + /* NULL value indicates no preference so free the previous blob */ if (protocols == NULL || protocol_count == 0) { - /* NULL value indicates no preference, so nothing to do */ - return 0; + RESULT_GUARD_POSIX(s2n_free(application_protocols)); + return S2N_RESULT_OK; } - GUARD(s2n_stuffer_growable_alloc(&protocol_stuffer, 256)); - for (int i = 0; i < protocol_count; i++) { + DEFER_CLEANUP(struct s2n_blob new_protocols = { 0 }, s2n_free); + + /* Allocate enough space to avoid a reallocation for every entry + * + * We assume that each protocol is most likely 8 bytes or less. + * If it ends up being larger, we will expand the blob automatically + * in the append method. + */ + RESULT_GUARD_POSIX(s2n_realloc(&new_protocols, protocol_count * 8)); + + /* set the size back to 0 so we start at the beginning. + * s2n_realloc will just update the size field here + */ + RESULT_GUARD_POSIX(s2n_realloc(&new_protocols, 0)); + + for (size_t i = 0; i < protocol_count; i++) { + const uint8_t * protocol = (const uint8_t *)protocols[i]; size_t length = strlen(protocols[i]); - uint8_t protocol[255]; - S2N_ERROR_IF(length > 255 || (s2n_stuffer_data_available(&protocol_stuffer) + length + 1) > 65535, S2N_ERR_APPLICATION_PROTOCOL_TOO_LONG); - memcpy_check(protocol, protocols[i], length); - GUARD(s2n_stuffer_write_uint8(&protocol_stuffer, length)); - GUARD(s2n_stuffer_write_bytes(&protocol_stuffer, protocol, length)); + /** + *= https://tools.ietf.org/rfc/rfc7301#section-3.1 + *# Empty strings + *# MUST NOT be included and byte strings MUST NOT be truncated. + */ + RESULT_ENSURE(length < 256, S2N_ERR_INVALID_APPLICATION_PROTOCOL); + + RESULT_GUARD(s2n_protocol_preferences_append(&new_protocols, protocol, (uint8_t)length)); } - GUARD(s2n_stuffer_extract_blob(&protocol_stuffer, application_protocols)); - GUARD(s2n_stuffer_free(&protocol_stuffer)); - return 0; + /* now we can free the previous list since we've validated all new input */ + RESULT_GUARD_POSIX(s2n_free(application_protocols)); + + /* update the connection/config application_protocols with the newly allocated blob */ + *application_protocols = new_protocols; + + /* zero out new_protocols so the DEFER_CLEANUP from above doesn't free + * the blob that we created and assigned to application_protocols + */ + /* cppcheck-suppress unreadVariable */ + new_protocols = (struct s2n_blob){ 0 }; + + return S2N_RESULT_OK; } int s2n_config_set_protocol_preferences(struct s2n_config *config, const char *const *protocols, int protocol_count) { - return s2n_blob_set_protocol_preferences(&config->application_protocols, protocols, protocol_count); + POSIX_GUARD_RESULT(s2n_protocol_preferences_set(&config->application_protocols, protocols, protocol_count)); + return S2N_SUCCESS; +} + +int s2n_config_append_protocol_preference(struct s2n_config *config, const uint8_t *protocol, uint8_t protocol_len) +{ + POSIX_GUARD_RESULT(s2n_protocol_preferences_append(&config->application_protocols, protocol, protocol_len)); + return S2N_SUCCESS; } int s2n_connection_set_protocol_preferences(struct s2n_connection *conn, const char * const *protocols, int protocol_count) { - return s2n_blob_set_protocol_preferences(&conn->application_protocols_overridden, protocols, protocol_count); + POSIX_GUARD_RESULT(s2n_protocol_preferences_set(&conn->application_protocols_overridden, protocols, protocol_count)); + return S2N_SUCCESS; +} + +int s2n_connection_append_protocol_preference(struct s2n_connection *conn, const uint8_t *protocol, uint8_t protocol_len) +{ + POSIX_GUARD_RESULT(s2n_protocol_preferences_append(&conn->application_protocols_overridden, protocol, protocol_len)); + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.h new file mode 100644 index 0000000000..421dfae6a7 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_protocol_preferences.h @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#pragma once + +#include "api/s2n.h" + +#include "utils/s2n_result.h" + +S2N_RESULT s2n_protocol_preferences_read(struct s2n_stuffer *protocol_preferences, struct s2n_blob *protocol); +S2N_RESULT s2n_protocol_preferences_contain(struct s2n_blob *protocol_preferences, struct s2n_blob *protocol, bool *contains); diff --git a/contrib/restricted/aws/s2n/tls/s2n_psk.c b/contrib/restricted/aws/s2n/tls/s2n_psk.c index 59d4d75158..4aacb13d87 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_psk.c +++ b/contrib/restricted/aws/s2n/tls/s2n_psk.c @@ -13,11 +13,15 @@ * permissions and limitations under the License. */ +#include <sys/param.h> + #include "crypto/s2n_tls13_keys.h" #include "tls/s2n_handshake.h" #include "tls/s2n_tls13_handshake.h" #include "tls/s2n_tls.h" +#include "tls/extensions/s2n_extension_type.h" +#include "tls/s2n_tls13_secrets.h" #include "utils/s2n_array.h" #include "utils/s2n_mem.h" @@ -25,100 +29,373 @@ #define S2N_HASH_ALG_COUNT S2N_HASH_SENTINEL -int s2n_psk_init(struct s2n_psk *psk, s2n_psk_type type) +S2N_RESULT s2n_psk_init(struct s2n_psk *psk, s2n_psk_type type) { - notnull_check(psk); + RESULT_ENSURE_MUT(psk); - memset_check(psk, 0, sizeof(struct s2n_psk)); + RESULT_CHECKED_MEMSET(psk, 0, sizeof(struct s2n_psk)); psk->hmac_alg = S2N_HMAC_SHA256; psk->type = type; - return S2N_SUCCESS; + return S2N_RESULT_OK; } -int s2n_psk_new_identity(struct s2n_psk *psk, const uint8_t *identity, size_t identity_size) +struct s2n_psk* s2n_external_psk_new() { - notnull_check(psk); + DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free); + PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_psk))); - GUARD(s2n_realloc(&psk->identity, identity_size)); - memcpy_check(psk->identity.data, identity, identity_size); + struct s2n_psk *psk = (struct s2n_psk*)(void*) mem.data; + PTR_GUARD_RESULT(s2n_psk_init(psk, S2N_PSK_TYPE_EXTERNAL)); + + ZERO_TO_DISABLE_DEFER_CLEANUP(mem); + return psk; +} + +int s2n_psk_set_identity(struct s2n_psk *psk, const uint8_t *identity, uint16_t identity_size) +{ + POSIX_ENSURE_REF(psk); + POSIX_ENSURE_REF(identity); + POSIX_ENSURE(identity_size != 0, S2N_ERR_INVALID_ARGUMENT); + + POSIX_GUARD(s2n_realloc(&psk->identity, identity_size)); + POSIX_CHECKED_MEMCPY(psk->identity.data, identity, identity_size); return S2N_SUCCESS; } -int s2n_psk_new_secret(struct s2n_psk *psk, const uint8_t *secret, size_t secret_size) +int s2n_psk_set_secret(struct s2n_psk *psk, const uint8_t *secret, uint16_t secret_size) { - notnull_check(psk); + POSIX_ENSURE_REF(psk); + POSIX_ENSURE_REF(secret); + POSIX_ENSURE(secret_size != 0, S2N_ERR_INVALID_ARGUMENT); - GUARD(s2n_realloc(&psk->secret, secret_size)); - memcpy_check(psk->secret.data, secret, secret_size); + POSIX_GUARD(s2n_realloc(&psk->secret, secret_size)); + POSIX_CHECKED_MEMCPY(psk->secret.data, secret, secret_size); return S2N_SUCCESS; } -int s2n_psk_free(struct s2n_psk *psk) +S2N_RESULT s2n_psk_clone(struct s2n_psk *new_psk, struct s2n_psk *original_psk) +{ + if (original_psk == NULL) { + return S2N_RESULT_OK; + } + RESULT_ENSURE_REF(new_psk); + + struct s2n_psk psk_copy = *new_psk; + + /* Copy all fields from the old_config EXCEPT the blobs, which we need to reallocate. */ + *new_psk = *original_psk; + new_psk->identity = psk_copy.identity; + new_psk->secret = psk_copy.secret; + new_psk->early_secret = psk_copy.early_secret; + new_psk->early_data_config = psk_copy.early_data_config; + + /* Clone / realloc blobs */ + RESULT_GUARD_POSIX(s2n_psk_set_identity(new_psk, original_psk->identity.data, original_psk->identity.size)); + RESULT_GUARD_POSIX(s2n_psk_set_secret(new_psk, original_psk->secret.data, original_psk->secret.size)); + RESULT_GUARD_POSIX(s2n_realloc(&new_psk->early_secret, original_psk->early_secret.size)); + RESULT_CHECKED_MEMCPY(new_psk->early_secret.data, original_psk->early_secret.data, original_psk->early_secret.size); + RESULT_GUARD(s2n_early_data_config_clone(new_psk, &original_psk->early_data_config)); + + return S2N_RESULT_OK; +} + +S2N_CLEANUP_RESULT s2n_psk_wipe(struct s2n_psk *psk) { if (psk == NULL) { - return S2N_SUCCESS; + return S2N_RESULT_OK; } - GUARD(s2n_free(&psk->early_secret)); - GUARD(s2n_free(&psk->identity)); - GUARD(s2n_free(&psk->secret)); + RESULT_GUARD_POSIX(s2n_free(&psk->early_secret)); + RESULT_GUARD_POSIX(s2n_free(&psk->identity)); + RESULT_GUARD_POSIX(s2n_free(&psk->secret)); + RESULT_GUARD(s2n_early_data_config_free(&psk->early_data_config)); - return S2N_SUCCESS; + return S2N_RESULT_OK; +} + +int s2n_psk_free(struct s2n_psk **psk) +{ + if (psk == NULL) { + return S2N_SUCCESS; + } + POSIX_GUARD_RESULT(s2n_psk_wipe(*psk)); + return s2n_free_object((uint8_t **) psk, sizeof(struct s2n_psk)); } S2N_RESULT s2n_psk_parameters_init(struct s2n_psk_parameters *params) { - ENSURE_REF(params); - CHECKED_MEMSET(params, 0, sizeof(struct s2n_psk_parameters)); - GUARD_RESULT(s2n_array_init(¶ms->psk_list, sizeof(struct s2n_psk))); + RESULT_ENSURE_REF(params); + RESULT_CHECKED_MEMSET(params, 0, sizeof(struct s2n_psk_parameters)); + RESULT_GUARD(s2n_array_init(¶ms->psk_list, sizeof(struct s2n_psk))); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_psk_offered_psk_size(struct s2n_psk *psk, uint32_t *size) +{ + *size = sizeof(uint16_t) /* identity size */ + + sizeof(uint32_t) /* obfuscated ticket age */ + + sizeof(uint8_t) /* binder size */; + + RESULT_GUARD_POSIX(s2n_add_overflow(*size, psk->identity.size, size)); + + uint8_t binder_size = 0; + RESULT_GUARD_POSIX(s2n_hmac_digest_size(psk->hmac_alg, &binder_size)); + RESULT_GUARD_POSIX(s2n_add_overflow(*size, binder_size, size)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_psk_parameters_offered_psks_size(struct s2n_psk_parameters *params, uint32_t *size) +{ + RESULT_ENSURE_REF(params); + RESULT_ENSURE_REF(size); + + *size = sizeof(uint16_t) /* identity list size */ + + sizeof(uint16_t) /* binder list size */; + + for (uint32_t i = 0; i < params->psk_list.len; i++) { + struct s2n_psk *psk = NULL; + RESULT_GUARD(s2n_array_get(¶ms->psk_list, i, (void**)&psk)); + RESULT_ENSURE_REF(psk); + + uint32_t psk_size = 0; + RESULT_GUARD(s2n_psk_offered_psk_size(psk, &psk_size)); + RESULT_GUARD_POSIX(s2n_add_overflow(*size, psk_size, size)); + } return S2N_RESULT_OK; } S2N_CLEANUP_RESULT s2n_psk_parameters_wipe(struct s2n_psk_parameters *params) { - ENSURE_REF(params); + RESULT_ENSURE_REF(params); for (size_t i = 0; i < params->psk_list.len; i++) { - struct s2n_psk *psk; - GUARD_RESULT(s2n_array_get(¶ms->psk_list, i, (void**)&psk)); - GUARD_AS_RESULT(s2n_psk_free(psk)); + struct s2n_psk *psk = NULL; + RESULT_GUARD(s2n_array_get(¶ms->psk_list, i, (void**)&psk)); + RESULT_GUARD(s2n_psk_wipe(psk)); + } + RESULT_GUARD_POSIX(s2n_free(¶ms->psk_list.mem)); + RESULT_GUARD(s2n_psk_parameters_init(params)); + + return S2N_RESULT_OK; +} + +S2N_CLEANUP_RESULT s2n_psk_parameters_wipe_secrets(struct s2n_psk_parameters *params) +{ + RESULT_ENSURE_REF(params); + + for (size_t i = 0; i < params->psk_list.len; i++) { + struct s2n_psk *psk = NULL; + RESULT_GUARD(s2n_array_get(¶ms->psk_list, i, (void**)&psk)); + RESULT_ENSURE_REF(psk); + RESULT_GUARD_POSIX(s2n_free(&psk->early_secret)); + RESULT_GUARD_POSIX(s2n_free(&psk->secret)); + } + + return S2N_RESULT_OK; +} + +bool s2n_offered_psk_list_has_next(struct s2n_offered_psk_list *psk_list) +{ + return psk_list != NULL && s2n_stuffer_data_available(&psk_list->wire_data) > 0; +} + +S2N_RESULT s2n_offered_psk_list_read_next(struct s2n_offered_psk_list *psk_list, struct s2n_offered_psk *psk) +{ + RESULT_ENSURE_REF(psk_list); + RESULT_ENSURE_REF(psk_list->conn); + RESULT_ENSURE_MUT(psk); + + uint16_t identity_size = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&psk_list->wire_data, &identity_size)); + RESULT_ENSURE_GT(identity_size, 0); + + uint8_t *identity_data = NULL; + identity_data = s2n_stuffer_raw_read(&psk_list->wire_data, identity_size); + RESULT_ENSURE_REF(identity_data); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11 + *# For identities established externally, an obfuscated_ticket_age of 0 SHOULD be + *# used, and servers MUST ignore the value. + */ + if (psk_list->conn->psk_params.type == S2N_PSK_TYPE_EXTERNAL) { + RESULT_GUARD_POSIX(s2n_stuffer_skip_read(&psk_list->wire_data, sizeof(uint32_t))); + } else { + RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(&psk_list->wire_data, &psk->obfuscated_ticket_age)); + } + + RESULT_GUARD_POSIX(s2n_blob_init(&psk->identity, identity_data, identity_size)); + psk->wire_index = psk_list->wire_index; + + RESULT_ENSURE(psk_list->wire_index < UINT16_MAX, S2N_ERR_INTEGER_OVERFLOW); + psk_list->wire_index++; + return S2N_RESULT_OK; +} + +int s2n_offered_psk_list_next(struct s2n_offered_psk_list *psk_list, struct s2n_offered_psk *psk) +{ + POSIX_ENSURE_REF(psk_list); + POSIX_ENSURE_REF(psk); + *psk = (struct s2n_offered_psk){ 0 }; + POSIX_ENSURE(s2n_offered_psk_list_has_next(psk_list), S2N_ERR_STUFFER_OUT_OF_DATA); + POSIX_ENSURE(s2n_result_is_ok(s2n_offered_psk_list_read_next(psk_list, psk)), S2N_ERR_BAD_MESSAGE); + return S2N_SUCCESS; +} + +int s2n_offered_psk_list_reread(struct s2n_offered_psk_list *psk_list) +{ + POSIX_ENSURE_REF(psk_list); + psk_list->wire_index = 0; + return s2n_stuffer_reread(&psk_list->wire_data); +} + +/* Match a PSK identity received from the client against the server's known PSK identities. + * This method compares a single client identity to all server identities. + * + * While both the client's offered identities and whether a match was found are public, we should make an attempt + * to keep the server's known identities a secret. We will make comparisons to the server's identities constant + * time (to hide partial matches) and not end the search early when a match is found (to hide the ordering). + * + * Keeping these comparisons constant time is not high priority. There's no known attack using these timings, + * and an attacker could probably guess the server's known identities just by observing the public identities + * sent by clients. + */ +static S2N_RESULT s2n_match_psk_identity(struct s2n_array *known_psks, const struct s2n_blob *wire_identity, + struct s2n_psk **match) +{ + RESULT_ENSURE_REF(match); + RESULT_ENSURE_REF(wire_identity); + RESULT_ENSURE_REF(known_psks); + *match = NULL; + for (size_t i = 0; i < known_psks->len; i++) { + struct s2n_psk *psk = NULL; + RESULT_GUARD(s2n_array_get(known_psks, i, (void**)&psk)); + RESULT_ENSURE_REF(psk); + RESULT_ENSURE_REF(psk->identity.data); + RESULT_ENSURE_REF(wire_identity->data); + uint32_t compare_size = MIN(wire_identity->size, psk->identity.size); + if (s2n_constant_time_equals(psk->identity.data, wire_identity->data, compare_size) + & (psk->identity.size == wire_identity->size) & (!*match)) { + *match = psk; + } + } + return S2N_RESULT_OK; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.2.10 + *# For PSKs provisioned via NewSessionTicket, a server MUST validate + *# that the ticket age for the selected PSK identity (computed by + *# subtracting ticket_age_add from PskIdentity.obfuscated_ticket_age + *# modulo 2^32) is within a small tolerance of the time since the ticket + *# was issued (see Section 8). + **/ +static S2N_RESULT s2n_validate_ticket_lifetime(struct s2n_connection *conn, uint32_t obfuscated_ticket_age, uint32_t ticket_age_add) +{ + RESULT_ENSURE_REF(conn); + + if (conn->psk_params.type == S2N_PSK_TYPE_EXTERNAL) { + return S2N_RESULT_OK; } - GUARD_AS_RESULT(s2n_free(¶ms->psk_list.mem)); - GUARD_RESULT(s2n_psk_parameters_init(params)); + + /* Subtract the ticket_age_add value from the ticket age in milliseconds. The resulting uint32_t value + * may wrap, resulting in the modulo 2^32 operation. */ + uint32_t ticket_age_in_millis = obfuscated_ticket_age - ticket_age_add; + uint32_t session_lifetime_in_millis = conn->config->session_state_lifetime_in_nanos / ONE_MILLISEC_IN_NANOS; + RESULT_ENSURE(ticket_age_in_millis < session_lifetime_in_millis, S2N_ERR_INVALID_SESSION_TICKET); return S2N_RESULT_OK; } +int s2n_offered_psk_list_choose_psk(struct s2n_offered_psk_list *psk_list, struct s2n_offered_psk *psk) +{ + POSIX_ENSURE_REF(psk_list); + POSIX_ENSURE_REF(psk_list->conn); + + struct s2n_psk_parameters *psk_params = &psk_list->conn->psk_params; + struct s2n_stuffer ticket_stuffer = { 0 }; + + if (!psk) { + psk_params->chosen_psk = NULL; + return S2N_SUCCESS; + } + + if (psk_params->type == S2N_PSK_TYPE_RESUMPTION && psk_list->conn->config->use_tickets) { + POSIX_GUARD(s2n_stuffer_init(&ticket_stuffer, &psk->identity)); + POSIX_GUARD(s2n_stuffer_skip_write(&ticket_stuffer, psk->identity.size)); + + /* s2n_decrypt_session_ticket appends a new PSK with the decrypted values. */ + POSIX_GUARD(s2n_decrypt_session_ticket(psk_list->conn, &ticket_stuffer)); + } + + struct s2n_psk *chosen_psk = NULL; + POSIX_GUARD_RESULT(s2n_match_psk_identity(&psk_params->psk_list, &psk->identity, &chosen_psk)); + POSIX_ENSURE_REF(chosen_psk); + POSIX_GUARD_RESULT(s2n_validate_ticket_lifetime(psk_list->conn, psk->obfuscated_ticket_age, chosen_psk->ticket_age_add)); + psk_params->chosen_psk = chosen_psk; + psk_params->chosen_psk_wire_index = psk->wire_index; + + return S2N_SUCCESS; +} + +struct s2n_offered_psk* s2n_offered_psk_new() +{ + DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free); + PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_offered_psk))); + PTR_GUARD_POSIX(s2n_blob_zero(&mem)); + + struct s2n_offered_psk *psk = (struct s2n_offered_psk*)(void*) mem.data; + + ZERO_TO_DISABLE_DEFER_CLEANUP(mem); + return psk; +} + +int s2n_offered_psk_free(struct s2n_offered_psk **psk) +{ + if (psk == NULL) { + return S2N_SUCCESS; + } + return s2n_free_object((uint8_t **) psk, sizeof(struct s2n_offered_psk)); +} + +int s2n_offered_psk_get_identity(struct s2n_offered_psk *psk, uint8_t** identity, uint16_t *size) +{ + POSIX_ENSURE_REF(psk); + POSIX_ENSURE_REF(identity); + POSIX_ENSURE_REF(size); + *identity = psk->identity.data; + *size = psk->identity.size; + return S2N_SUCCESS; +} + /* The binder hash is computed by hashing the concatenation of the current transcript * and a partial ClientHello that does not include the binders themselves. */ int s2n_psk_calculate_binder_hash(struct s2n_connection *conn, s2n_hmac_algorithm hmac_alg, const struct s2n_blob *partial_client_hello, struct s2n_blob *output_binder_hash) { - notnull_check(partial_client_hello); - notnull_check(output_binder_hash); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(partial_client_hello); + POSIX_ENSURE_REF(output_binder_hash); + struct s2n_handshake_hashes *hashes = conn->handshake.hashes; + POSIX_ENSURE_REF(hashes); /* Retrieve the current transcript. * The current transcript will be empty unless this handshake included a HelloRetryRequest. */ - struct s2n_hash_state current_hash_state = {0}; - - s2n_hash_algorithm hash_alg; - GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg)); - GUARD(s2n_handshake_get_hash_state(conn, hash_alg, ¤t_hash_state)); - - /* Copy the current transcript to avoid modifying the original. */ - DEFER_CLEANUP(struct s2n_hash_state hash_copy, s2n_hash_free); - GUARD(s2n_hash_new(&hash_copy)); - GUARD(s2n_hash_copy(&hash_copy, ¤t_hash_state)); + s2n_hash_algorithm hash_alg = S2N_HASH_NONE; + struct s2n_hash_state *hash_state = &hashes->hash_workspace; + POSIX_GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg)); + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, hash_alg, hash_state)); /* Add the partial client hello to the transcript. */ - GUARD(s2n_hash_update(&hash_copy, partial_client_hello->data, partial_client_hello->size)); + POSIX_GUARD(s2n_hash_update(hash_state, partial_client_hello->data, partial_client_hello->size)); /* Get the transcript digest */ - GUARD(s2n_hash_digest(&hash_copy, output_binder_hash->data, output_binder_hash->size)); + POSIX_GUARD(s2n_hash_digest(hash_state, output_binder_hash->data, output_binder_hash->size)); return S2N_SUCCESS; } @@ -131,29 +408,26 @@ int s2n_psk_calculate_binder_hash(struct s2n_connection *conn, s2n_hmac_algorith int s2n_psk_calculate_binder(struct s2n_psk *psk, const struct s2n_blob *binder_hash, struct s2n_blob *output_binder) { - notnull_check(psk); - notnull_check(binder_hash); - notnull_check(output_binder); + POSIX_ENSURE_REF(psk); + POSIX_ENSURE_REF(binder_hash); + POSIX_ENSURE_REF(output_binder); DEFER_CLEANUP(struct s2n_tls13_keys psk_keys, s2n_tls13_keys_free); - GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg)); - eq_check(binder_hash->size, psk_keys.size); - eq_check(output_binder->size, psk_keys.size); - - /* Make sure the early secret is saved on the psk structure for later use */ - GUARD(s2n_realloc(&psk->early_secret, psk_keys.size)); - GUARD(s2n_blob_init(&psk_keys.extract_secret, psk->early_secret.data, psk_keys.size)); + POSIX_GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg)); + POSIX_ENSURE_EQ(binder_hash->size, psk_keys.size); + POSIX_ENSURE_EQ(output_binder->size, psk_keys.size); /* Derive the binder key */ - GUARD(s2n_tls13_derive_binder_key(&psk_keys, psk)); + POSIX_GUARD_RESULT(s2n_derive_binder_key(psk, &psk_keys.derive_secret)); + POSIX_GUARD(s2n_blob_init(&psk_keys.extract_secret, psk->early_secret.data, psk_keys.size)); struct s2n_blob *binder_key = &psk_keys.derive_secret; /* Expand the binder key into the finished key */ s2n_tls13_key_blob(finished_key, psk_keys.size); - GUARD(s2n_tls13_derive_finished_key(&psk_keys, binder_key, &finished_key)); + POSIX_GUARD(s2n_tls13_derive_finished_key(&psk_keys, binder_key, &finished_key)); /* HMAC the binder hash with the binder finished key */ - GUARD(s2n_hkdf_extract(&psk_keys.hmac, psk_keys.hmac_algorithm, &finished_key, binder_hash, output_binder)); + POSIX_GUARD(s2n_hkdf_extract(&psk_keys.hmac, psk_keys.hmac_algorithm, &finished_key, binder_hash, output_binder)); return S2N_SUCCESS; } @@ -161,24 +435,24 @@ int s2n_psk_calculate_binder(struct s2n_psk *psk, const struct s2n_blob *binder_ int s2n_psk_verify_binder(struct s2n_connection *conn, struct s2n_psk *psk, const struct s2n_blob *partial_client_hello, struct s2n_blob *binder_to_verify) { - notnull_check(psk); - notnull_check(binder_to_verify); + POSIX_ENSURE_REF(psk); + POSIX_ENSURE_REF(binder_to_verify); DEFER_CLEANUP(struct s2n_tls13_keys psk_keys, s2n_tls13_keys_free); - GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg)); - eq_check(binder_to_verify->size, psk_keys.size); + POSIX_GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg)); + POSIX_ENSURE_EQ(binder_to_verify->size, psk_keys.size); /* Calculate the binder hash from the transcript */ s2n_tls13_key_blob(binder_hash, psk_keys.size); - GUARD(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, &binder_hash)); + POSIX_GUARD(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, &binder_hash)); /* Calculate the expected binder from the binder hash */ s2n_tls13_key_blob(expected_binder, psk_keys.size); - GUARD(s2n_psk_calculate_binder(psk, &binder_hash, &expected_binder)); + POSIX_GUARD(s2n_psk_calculate_binder(psk, &binder_hash, &expected_binder)); /* Verify the expected binder matches the given binder. * This operation must be constant time. */ - GUARD(s2n_tls13_mac_verify(&psk_keys, &expected_binder, binder_to_verify)); + POSIX_GUARD(s2n_tls13_mac_verify(&psk_keys, &expected_binder, binder_to_verify)); return S2N_SUCCESS; } @@ -186,15 +460,15 @@ int s2n_psk_verify_binder(struct s2n_connection *conn, struct s2n_psk *psk, static S2N_RESULT s2n_psk_write_binder(struct s2n_connection *conn, struct s2n_psk *psk, const struct s2n_blob *binder_hash, struct s2n_stuffer *out) { - ENSURE_REF(binder_hash); + RESULT_ENSURE_REF(binder_hash); struct s2n_blob binder; uint8_t binder_data[S2N_TLS13_SECRET_MAX_LEN] = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&binder, binder_data, binder_hash->size)); + RESULT_GUARD_POSIX(s2n_blob_init(&binder, binder_data, binder_hash->size)); - GUARD_AS_RESULT(s2n_psk_calculate_binder(psk, binder_hash, &binder)); - GUARD_AS_RESULT(s2n_stuffer_write_uint8(out, binder.size)); - GUARD_AS_RESULT(s2n_stuffer_write(out, &binder)); + RESULT_GUARD_POSIX(s2n_psk_calculate_binder(psk, binder_hash, &binder)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, binder.size)); + RESULT_GUARD_POSIX(s2n_stuffer_write(out, &binder)); return S2N_RESULT_OK; } @@ -202,8 +476,8 @@ static S2N_RESULT s2n_psk_write_binder(struct s2n_connection *conn, struct s2n_p static S2N_RESULT s2n_psk_write_binder_list(struct s2n_connection *conn, const struct s2n_blob *partial_client_hello, struct s2n_stuffer *out) { - ENSURE_REF(conn); - ENSURE_REF(partial_client_hello); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(partial_client_hello); struct s2n_psk_parameters *psk_params = &conn->psk_params; struct s2n_array *psk_list = &psk_params->psk_list; @@ -214,13 +488,13 @@ static S2N_RESULT s2n_psk_write_binder_list(struct s2n_connection *conn, const s struct s2n_blob binder_hashes[S2N_HASH_ALG_COUNT] = { 0 }; struct s2n_stuffer_reservation binder_list_size = { 0 }; - GUARD_AS_RESULT(s2n_stuffer_reserve_uint16(out, &binder_list_size)); + RESULT_GUARD_POSIX(s2n_stuffer_reserve_uint16(out, &binder_list_size)); /* Write binder for every psk */ for (size_t i = 0; i < psk_list->len; i++) { struct s2n_psk *psk = NULL; - GUARD_RESULT(s2n_array_get(psk_list, i, (void**) &psk)); - ENSURE_REF(psk); + RESULT_GUARD(s2n_array_get(psk_list, i, (void**) &psk)); + RESULT_ENSURE_REF(psk); /** *= https://tools.ietf.org/rfc/rfc8446#section-4.1.4 @@ -238,21 +512,21 @@ static S2N_RESULT s2n_psk_write_binder_list(struct s2n_connection *conn, const s struct s2n_blob *binder_hash = &binder_hashes[psk->hmac_alg]; if (binder_hash->size == 0) { uint8_t hash_size = 0; - GUARD_AS_RESULT(s2n_hmac_digest_size(psk->hmac_alg, &hash_size)); - GUARD_AS_RESULT(s2n_blob_init(binder_hash, binder_hashes_data[psk->hmac_alg], hash_size)); - GUARD_AS_RESULT(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, binder_hash)); + RESULT_GUARD_POSIX(s2n_hmac_digest_size(psk->hmac_alg, &hash_size)); + RESULT_GUARD_POSIX(s2n_blob_init(binder_hash, binder_hashes_data[psk->hmac_alg], hash_size)); + RESULT_GUARD_POSIX(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, binder_hash)); } - GUARD_RESULT(s2n_psk_write_binder(conn, psk, binder_hash, out)); + RESULT_GUARD(s2n_psk_write_binder(conn, psk, binder_hash, out)); } - GUARD_AS_RESULT(s2n_stuffer_write_vector_size(&binder_list_size)); + RESULT_GUARD_POSIX(s2n_stuffer_write_vector_size(&binder_list_size)); return S2N_RESULT_OK; } S2N_RESULT s2n_finish_psk_extension(struct s2n_connection *conn) { - ENSURE_REF(conn); + RESULT_ENSURE_REF(conn); if (!conn->psk_params.binder_list_size) { return S2N_RESULT_OK; @@ -262,72 +536,161 @@ S2N_RESULT s2n_finish_psk_extension(struct s2n_connection *conn) struct s2n_psk_parameters *psk_params = &conn->psk_params; /* Fill in the correct message size. */ - GUARD_AS_RESULT(s2n_handshake_finish_header(client_hello)); + RESULT_GUARD_POSIX(s2n_handshake_finish_header(client_hello)); /* Remove the empty space allocated for the binder list. * It was originally added to ensure the extension / extension list / message sizes * were properly calculated. */ - GUARD_AS_RESULT(s2n_stuffer_wipe_n(client_hello, psk_params->binder_list_size)); + RESULT_GUARD_POSIX(s2n_stuffer_wipe_n(client_hello, psk_params->binder_list_size)); /* Store the partial client hello for use in calculating the binder hash. */ struct s2n_blob partial_client_hello = { 0 }; - GUARD_AS_RESULT(s2n_blob_init(&partial_client_hello, client_hello->blob.data, + RESULT_GUARD_POSIX(s2n_blob_init(&partial_client_hello, client_hello->blob.data, s2n_stuffer_data_available(client_hello))); - GUARD_RESULT(s2n_psk_write_binder_list(conn, &partial_client_hello, client_hello)); + RESULT_GUARD(s2n_psk_write_binder_list(conn, &partial_client_hello, client_hello)); return S2N_RESULT_OK; } -static S2N_RESULT s2n_psk_set_hmac(struct s2n_psk *psk, s2n_psk_hmac psk_hmac_alg) +int s2n_psk_set_hmac(struct s2n_psk *psk, s2n_psk_hmac hmac) { - switch(psk_hmac_alg) { - case S2N_PSK_HMAC_SHA224: psk->hmac_alg = S2N_HMAC_SHA224; break; + POSIX_ENSURE_REF(psk); + switch(hmac) { case S2N_PSK_HMAC_SHA256: psk->hmac_alg = S2N_HMAC_SHA256; break; case S2N_PSK_HMAC_SHA384: psk->hmac_alg = S2N_HMAC_SHA384; break; default: - BAIL(S2N_ERR_HMAC_INVALID_ALGORITHM); + POSIX_BAIL(S2N_ERR_HMAC_INVALID_ALGORITHM); + } + return S2N_SUCCESS; +} + +S2N_RESULT s2n_connection_set_psk_type(struct s2n_connection *conn, s2n_psk_type type) +{ + RESULT_ENSURE_REF(conn); + if (conn->psk_params.psk_list.len != 0) { + RESULT_ENSURE(conn->psk_params.type == type, S2N_ERR_PSK_MODE); } + conn->psk_params.type = type; return S2N_RESULT_OK; } -int s2n_connection_set_external_psks(struct s2n_connection *conn, struct s2n_external_psk *psk_vec, size_t psk_vec_length) +int s2n_connection_append_psk(struct s2n_connection *conn, struct s2n_psk *input_psk) { - ENSURE_POSIX_REF(conn); - ENSURE_POSIX_REF(psk_vec); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(input_psk); + POSIX_GUARD_RESULT(s2n_connection_set_psk_type(conn, input_psk->type)); + + struct s2n_array *psk_list = &conn->psk_params.psk_list; - /* Remove all previously-set external psks */ - /* The loop iterates from len to 1 instead of from len-1 to 0 to avoid size_t underflowing */ - for (size_t i = conn->psk_params.psk_list.len; i > 0; i--) { - size_t i_index = i - 1; - struct s2n_psk *psk = NULL; - GUARD_AS_POSIX(s2n_array_get(&conn->psk_params.psk_list, i_index, (void**) &psk)); - ENSURE_POSIX_REF(psk); - if (psk->type == S2N_PSK_TYPE_EXTERNAL) { - GUARD(s2n_psk_free(psk)); - GUARD_AS_POSIX(s2n_array_remove(&conn->psk_params.psk_list, i_index)); - } + /* Check for duplicate identities */ + for (uint32_t j = 0; j < psk_list->len; j++) { + struct s2n_psk *existing_psk = NULL; + POSIX_GUARD_RESULT(s2n_array_get(psk_list, j, (void**) &existing_psk)); + POSIX_ENSURE_REF(existing_psk); + + bool duplicate = existing_psk->identity.size == input_psk->identity.size + && memcmp(existing_psk->identity.data, input_psk->identity.data, existing_psk->identity.size) == 0; + POSIX_ENSURE(!duplicate, S2N_ERR_DUPLICATE_PSK_IDENTITIES); } - for (size_t i = 0; i < psk_vec_length; i++) { - /* Check for duplicate identities */ - size_t array_len = conn->psk_params.psk_list.len; - for (size_t j = 0; j < array_len; j++) { - struct s2n_psk *psk = NULL; - GUARD_AS_POSIX(s2n_array_get(&conn->psk_params.psk_list, j, (void**) &psk)); - ENSURE_POSIX_REF(psk); - if (psk->identity.size == psk_vec[i].identity_length) { - ENSURE_POSIX(memcmp(psk->identity.data, psk_vec[i].identity, psk->identity.size) != 0, S2N_ERR_DUPLICATE_PSK_IDENTITIES); - } - } + /* Verify the PSK list will fit in the ClientHello pre_shared_key extension */ + if (conn->mode == S2N_CLIENT) { + uint32_t list_size = 0; + POSIX_GUARD_RESULT(s2n_psk_parameters_offered_psks_size(&conn->psk_params, &list_size)); + + uint32_t psk_size = 0; + POSIX_GUARD_RESULT(s2n_psk_offered_psk_size(input_psk, &psk_size)); + + POSIX_ENSURE(list_size + psk_size + S2N_EXTENSION_HEADER_LENGTH <= UINT16_MAX, S2N_ERR_OFFERED_PSKS_TOO_LONG); + } + + DEFER_CLEANUP(struct s2n_psk new_psk = { 0 }, s2n_psk_wipe); + POSIX_ENSURE(s2n_result_is_ok(s2n_psk_clone(&new_psk, input_psk)), S2N_ERR_INVALID_ARGUMENT); + POSIX_GUARD_RESULT(s2n_array_insert_and_copy(psk_list, psk_list->len, &new_psk)); + + ZERO_TO_DISABLE_DEFER_CLEANUP(new_psk); + return S2N_SUCCESS; +} + +int s2n_config_set_psk_mode(struct s2n_config *config, s2n_psk_mode mode) +{ + POSIX_ENSURE_REF(config); + config->psk_mode = mode; + return S2N_SUCCESS; +} + +int s2n_connection_set_psk_mode(struct s2n_connection *conn, s2n_psk_mode mode) +{ + POSIX_ENSURE_REF(conn); + s2n_psk_type type = 0; + switch(mode) { + case S2N_PSK_MODE_RESUMPTION: + type = S2N_PSK_TYPE_RESUMPTION; + break; + case S2N_PSK_MODE_EXTERNAL: + type = S2N_PSK_TYPE_EXTERNAL; + break; + default: + POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT); + break; + } + POSIX_GUARD_RESULT(s2n_connection_set_psk_type(conn, type)); + conn->psk_mode_overridden = true; + return S2N_SUCCESS; +} + +int s2n_connection_get_negotiated_psk_identity_length(struct s2n_connection *conn, uint16_t *identity_length) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(identity_length); - struct s2n_psk *new_psk = NULL; - GUARD_AS_POSIX(s2n_array_pushback(&conn->psk_params.psk_list, (void**) &new_psk)); - ENSURE_POSIX_REF(new_psk); - GUARD(s2n_psk_init(new_psk, S2N_PSK_TYPE_EXTERNAL)); - GUARD(s2n_psk_new_identity(new_psk, psk_vec[i].identity, psk_vec[i].identity_length)); - GUARD(s2n_psk_new_secret(new_psk, psk_vec[i].secret, psk_vec[i].secret_length)); - GUARD_AS_POSIX(s2n_psk_set_hmac(new_psk, psk_vec[i].hmac)); + struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk; + + if (chosen_psk == NULL) { + *identity_length = 0; + } else { + *identity_length = chosen_psk->identity.size; } return S2N_SUCCESS; } + +int s2n_connection_get_negotiated_psk_identity(struct s2n_connection *conn, uint8_t *identity, + uint16_t max_identity_length) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(identity); + + struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk; + + if (chosen_psk == NULL) { + return S2N_SUCCESS; + } + + POSIX_ENSURE(chosen_psk->identity.size <= max_identity_length, S2N_ERR_INSUFFICIENT_MEM_SIZE); + POSIX_CHECKED_MEMCPY(identity, chosen_psk->identity.data, chosen_psk->identity.size); + + return S2N_SUCCESS; +} + +S2N_RESULT s2n_psk_validate_keying_material(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk; + if (!chosen_psk || chosen_psk->type != S2N_PSK_TYPE_RESUMPTION) { + return S2N_RESULT_OK; + } + + /* + * The minimum ticket lifetime is 1s, because ticket_lifetime is given + * in seconds and 0 indicates that the ticket should be immediately discarded. + */ + uint32_t min_lifetime = ONE_SEC_IN_NANOS; + + uint64_t current_time = 0; + RESULT_GUARD_POSIX(conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_time)); + RESULT_ENSURE(chosen_psk->keying_material_expiration > current_time + min_lifetime, S2N_ERR_KEYING_MATERIAL_EXPIRED); + + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_psk.h b/contrib/restricted/aws/s2n/tls/s2n_psk.h index 6d7052c876..38ac65f3ac 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_psk.h +++ b/contrib/restricted/aws/s2n/tls/s2n_psk.h @@ -15,15 +15,17 @@ #pragma once -#include <s2n.h> +#include "api/s2n.h" #include "crypto/s2n_hmac.h" +#include "stuffer/s2n_stuffer.h" +#include "tls/s2n_early_data.h" #include "utils/s2n_array.h" #include "utils/s2n_blob.h" #include "utils/s2n_result.h" typedef enum { - S2N_PSK_TYPE_RESUMPTION, + S2N_PSK_TYPE_RESUMPTION = 0, S2N_PSK_TYPE_EXTERNAL, } s2n_psk_type; @@ -33,52 +35,50 @@ typedef enum { S2N_PSK_DHE_KE, } s2n_psk_key_exchange_mode; -typedef enum { - S2N_PSK_HMAC_SHA224 = 0, - S2N_PSK_HMAC_SHA256, - S2N_PSK_HMAC_SHA384, -} s2n_psk_hmac; - -struct s2n_external_psk { - uint8_t *identity; - size_t identity_length; - uint8_t *secret; - size_t secret_length; - s2n_psk_hmac hmac; -}; - struct s2n_psk { s2n_psk_type type; struct s2n_blob identity; struct s2n_blob secret; s2n_hmac_algorithm hmac_alg; - uint32_t obfuscated_ticket_age; + uint32_t ticket_age_add; + uint64_t ticket_issue_time; struct s2n_blob early_secret; -}; + struct s2n_early_data_config early_data_config; -struct s2n_psk_identity { - uint8_t *data; - uint16_t length; + /* This field is used with session tickets to track the lifetime + * of the original full handshake across multiple tickets. + * See https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + */ + uint64_t keying_material_expiration; }; +S2N_RESULT s2n_psk_init(struct s2n_psk *psk, s2n_psk_type type); +S2N_CLEANUP_RESULT s2n_psk_wipe(struct s2n_psk *psk); +S2N_RESULT s2n_psk_clone(struct s2n_psk *new_psk, struct s2n_psk *original_psk); struct s2n_psk_parameters { + s2n_psk_type type; struct s2n_array psk_list; uint16_t binder_list_size; uint16_t chosen_psk_wire_index; struct s2n_psk *chosen_psk; s2n_psk_key_exchange_mode psk_ke_mode; }; - -/* This function will be labeled S2N_API and become a publicly visible api once we release the psk API. */ -int s2n_connection_set_external_psks(struct s2n_connection *conn, struct s2n_external_psk *psk_vec, size_t psk_vec_length); - -int s2n_psk_init(struct s2n_psk *psk, s2n_psk_type type); -int s2n_psk_new_identity(struct s2n_psk *psk, const uint8_t *identity, size_t identity_size); -int s2n_psk_new_secret(struct s2n_psk *psk, const uint8_t *secret, size_t secret_size); -int s2n_psk_free(struct s2n_psk *psk); - S2N_RESULT s2n_psk_parameters_init(struct s2n_psk_parameters *params); +S2N_RESULT s2n_psk_parameters_offered_psks_size(struct s2n_psk_parameters *params, uint32_t *size); S2N_CLEANUP_RESULT s2n_psk_parameters_wipe(struct s2n_psk_parameters *params); +S2N_CLEANUP_RESULT s2n_psk_parameters_wipe_secrets(struct s2n_psk_parameters *params); + +struct s2n_offered_psk { + struct s2n_blob identity; + uint16_t wire_index; + uint32_t obfuscated_ticket_age; +}; + +struct s2n_offered_psk_list { + struct s2n_connection *conn; + struct s2n_stuffer wire_data; + uint16_t wire_index; +}; S2N_RESULT s2n_finish_psk_extension(struct s2n_connection *conn); @@ -89,9 +89,5 @@ int s2n_psk_calculate_binder(struct s2n_psk *psk, const struct s2n_blob *binder_ int s2n_psk_verify_binder(struct s2n_connection *conn, struct s2n_psk *psk, const struct s2n_blob *partial_client_hello, struct s2n_blob *binder_to_verify); -typedef int (*s2n_psk_selection_callback)(struct s2n_connection *conn, - struct s2n_psk_identity *identities, size_t identities_length, - uint16_t *chosen_wire_index); -/* This function will be labeled S2N_API and become a publicly visible api once we release the psk API. */ -int s2n_config_set_psk_selection_callback(struct s2n_connection *conn, s2n_psk_selection_callback cb); - +S2N_RESULT s2n_connection_set_psk_type(struct s2n_connection *conn, s2n_psk_type type); +S2N_RESULT s2n_psk_validate_keying_material(struct s2n_connection *conn); diff --git a/contrib/restricted/aws/s2n/tls/s2n_quic_support.c b/contrib/restricted/aws/s2n/tls/s2n_quic_support.c index 226b87ee9a..bd0b44f906 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_quic_support.c +++ b/contrib/restricted/aws/s2n/tls/s2n_quic_support.c @@ -37,19 +37,33 @@ S2N_RESULT s2n_read_in_bytes(struct s2n_connection *conn, struct s2n_stuffer *ou int s2n_config_enable_quic(struct s2n_config *config) { - notnull_check(config); + POSIX_ENSURE_REF(config); config->quic_enabled = true; return S2N_SUCCESS; } +int s2n_connection_enable_quic(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + POSIX_GUARD_RESULT(s2n_connection_validate_tls13_support(conn)); + conn->quic_enabled = true; + return S2N_SUCCESS; +} + +bool s2n_connection_is_quic_enabled(struct s2n_connection *conn) +{ + return (conn && conn->quic_enabled) || + (conn && conn->config && conn->config->quic_enabled); +} + int s2n_connection_set_quic_transport_parameters(struct s2n_connection *conn, const uint8_t *data_buffer, uint16_t data_len) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - GUARD(s2n_free(&conn->our_quic_transport_parameters)); - GUARD(s2n_alloc(&conn->our_quic_transport_parameters, data_len)); - memcpy_check(conn->our_quic_transport_parameters.data, data_buffer, data_len); + POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters)); + POSIX_GUARD(s2n_alloc(&conn->our_quic_transport_parameters, data_len)); + POSIX_CHECKED_MEMCPY(conn->our_quic_transport_parameters.data, data_buffer, data_len); return S2N_SUCCESS; } @@ -57,9 +71,9 @@ int s2n_connection_set_quic_transport_parameters(struct s2n_connection *conn, int s2n_connection_get_quic_transport_parameters(struct s2n_connection *conn, const uint8_t **data_buffer, uint16_t *data_len) { - notnull_check(conn); - notnull_check(data_buffer); - notnull_check(data_len); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(data_buffer); + POSIX_ENSURE_REF(data_len); *data_buffer = conn->peer_quic_transport_parameters.data; *data_len = conn->peer_quic_transport_parameters.size; @@ -69,8 +83,8 @@ int s2n_connection_get_quic_transport_parameters(struct s2n_connection *conn, int s2n_connection_set_secret_callback(struct s2n_connection *conn, s2n_secret_cb cb_func, void *ctx) { - notnull_check(conn); - notnull_check(cb_func); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(cb_func); conn->secret_cb = cb_func; conn->secret_cb_context = ctx; @@ -83,19 +97,19 @@ int s2n_connection_set_secret_callback(struct s2n_connection *conn, s2n_secret_c */ S2N_RESULT s2n_quic_read_handshake_message(struct s2n_connection *conn, uint8_t *message_type) { - ENSURE_REF(conn); + RESULT_ENSURE_REF(conn); /* Allocate stuffer space now so that we don't have to realloc later in the handshake. */ - GUARD_AS_RESULT(s2n_stuffer_resize_if_empty(&conn->in, S2N_EXPECTED_QUIC_MESSAGE_SIZE)); + RESULT_GUARD_POSIX(s2n_stuffer_resize_if_empty(&conn->in, S2N_EXPECTED_QUIC_MESSAGE_SIZE)); - GUARD_RESULT(s2n_read_in_bytes(conn, &conn->handshake.io, TLS_HANDSHAKE_HEADER_LENGTH)); + RESULT_GUARD(s2n_read_in_bytes(conn, &conn->handshake.io, TLS_HANDSHAKE_HEADER_LENGTH)); uint32_t message_len; - GUARD_AS_RESULT(s2n_handshake_parse_header(conn, message_type, &message_len)); - GUARD_AS_RESULT(s2n_stuffer_reread(&conn->handshake.io)); + RESULT_GUARD_POSIX(s2n_handshake_parse_header(conn, message_type, &message_len)); + RESULT_GUARD_POSIX(s2n_stuffer_reread(&conn->handshake.io)); - ENSURE(message_len < S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE); - GUARD_RESULT(s2n_read_in_bytes(conn, &conn->in, message_len)); + RESULT_ENSURE(message_len < S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE); + RESULT_GUARD(s2n_read_in_bytes(conn, &conn->in, message_len)); return S2N_RESULT_OK; } @@ -105,11 +119,11 @@ S2N_RESULT s2n_quic_read_handshake_message(struct s2n_connection *conn, uint8_t */ S2N_RESULT s2n_quic_write_handshake_message(struct s2n_connection *conn, struct s2n_blob *in) { - ENSURE_REF(conn); + RESULT_ENSURE_REF(conn); /* Allocate stuffer space now so that we don't have to realloc later in the handshake. */ - GUARD_AS_RESULT(s2n_stuffer_resize_if_empty(&conn->out, S2N_EXPECTED_QUIC_MESSAGE_SIZE)); + RESULT_GUARD_POSIX(s2n_stuffer_resize_if_empty(&conn->out, S2N_EXPECTED_QUIC_MESSAGE_SIZE)); - GUARD_AS_RESULT(s2n_stuffer_write(&conn->out, in)); + RESULT_GUARD_POSIX(s2n_stuffer_write(&conn->out, in)); return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_quic_support.h b/contrib/restricted/aws/s2n/tls/s2n_quic_support.h index 459e03a2fd..c64583589a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_quic_support.h +++ b/contrib/restricted/aws/s2n/tls/s2n_quic_support.h @@ -25,11 +25,13 @@ * the behavior of S2N in potentially dangerous ways and should only be used by implementations * of the QUIC protocol. * - * Additionally, the QUIC RFC is not yet finalized, so all QUIC APIs are considered experimental - * and are subject to change without notice. They should only be used for testing purposes. + * Additionally, all QUIC APIs are considered experimental and are subject to change without + * notice. They should only be used for testing purposes. */ S2N_API int s2n_config_enable_quic(struct s2n_config *config); +S2N_API int s2n_connection_enable_quic(struct s2n_connection *conn); +S2N_API bool s2n_connection_is_quic_enabled(struct s2n_connection *conn); /* * Set the data to be sent in the quic_transport_parameters extension. @@ -73,4 +75,17 @@ typedef int (*s2n_secret_cb) (void* context, struct s2n_connection *conn, * The callback function will ONLY be triggered if QUIC is enabled. This API is not intended to be * used outside of a QUIC implementation. */ -int s2n_connection_set_secret_callback(struct s2n_connection *conn, s2n_secret_cb cb_func, void *ctx); +S2N_API int s2n_connection_set_secret_callback(struct s2n_connection *conn, s2n_secret_cb cb_func, void *ctx); + +/* + * Return the TLS alert that S2N-TLS would send, if S2N-TLS sent specific alerts. + * + * S2N-TLS only sends generic close_notify alerts for security reasons, and TLS never + * sends alerts when used by QUIC. This method returns the alert that would have been + * sent if S2N-TLS sent specific alerts as defined in the protocol specifications. + * + * WARNING: this method is still considered experimental and will not always report + * the correct alert description. It may be used for testing and logging, but + * not relied on for production logic. + */ +S2N_API int s2n_error_get_alert(int error, uint8_t *alert); diff --git a/contrib/restricted/aws/s2n/tls/s2n_record.h b/contrib/restricted/aws/s2n/tls/s2n_record.h index f5b6f27502..53aeba58bb 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record.h +++ b/contrib/restricted/aws/s2n/tls/s2n_record.h @@ -16,11 +16,56 @@ #pragma once #include <stdint.h> +#include "crypto/s2n_hmac.h" +#include "stuffer/s2n_stuffer.h" -#include "s2n_connection.h" +#define S2N_TLS_CONTENT_TYPE_LENGTH 1 -#define TLS13_CONTENT_TYPE_LENGTH 1 +/* All versions of TLS define the record header the same: + * ContentType + ProtocolVersion + length + */ +#define S2N_TLS_RECORD_HEADER_LENGTH (S2N_TLS_CONTENT_TYPE_LENGTH + S2N_TLS_PROTOCOL_VERSION_LEN + 2) + +/* + * All versions of TLS limit the data fragment to 2^14 bytes. + * + *= https://tools.ietf.org/rfc/rfc5246#section-6.2.1 + *# The record layer fragments information blocks into TLSPlaintext + *# records carrying data in chunks of 2^14 bytes or less. + * + *= https://tools.ietf.org/rfc/rfc8446#section-5.1 + *# The record layer fragments information blocks into TLSPlaintext + *# records carrying data in chunks of 2^14 bytes or less. + */ +#define S2N_TLS_MAXIMUM_FRAGMENT_LENGTH (1 << 14) + +/* The TLS1.2 record length allows for 1024 bytes of compression expansion and + * 1024 bytes of encryption expansion and padding. + * Since S2N does not support compression, we can ignore the compression overhead. + */ +#define S2N_TLS12_ENCRYPTION_OVERHEAD_SIZE 1024 +#define S2N_TLS12_MAX_RECORD_LEN_FOR(frag) ((frag) + S2N_TLS12_ENCRYPTION_OVERHEAD_SIZE \ + + S2N_TLS_RECORD_HEADER_LENGTH) +#define S2N_TLS12_MAXIMUM_RECORD_LENGTH S2N_TLS12_MAX_RECORD_LEN_FOR(S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) + +/* + *= https://tools.ietf.org/rfc/rfc8446#section-5.2 + *# An AEAD algorithm used in TLS 1.3 MUST NOT produce an expansion + *# greater than 255 octets. + */ +#define S2N_TLS13_ENCRYPTION_OVERHEAD_SIZE 255 +#define S2N_TLS13_MAX_RECORD_LEN_FOR(frag) ((frag) + S2N_TLS_CONTENT_TYPE_LENGTH \ + + S2N_TLS13_ENCRYPTION_OVERHEAD_SIZE \ + + S2N_TLS_RECORD_HEADER_LENGTH) +#define S2N_TLS13_MAXIMUM_RECORD_LENGTH S2N_TLS13_MAX_RECORD_LEN_FOR(S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) + +/* Currently, TLS1.2 records may be larger than TLS1.3 records. + * If the protocol is unknown, assume TLS1.2. + */ +#define S2N_TLS_MAX_RECORD_LEN_FOR(frag) S2N_TLS12_MAX_RECORD_LEN_FOR(frag) +#define S2N_TLS_MAXIMUM_RECORD_LENGTH S2N_TLS_MAX_RECORD_LEN_FOR(S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) +S2N_RESULT s2n_record_max_write_size(struct s2n_connection *conn, uint16_t max_fragment_size, uint16_t *max_record_size); extern S2N_RESULT s2n_record_max_write_payload_size(struct s2n_connection *conn, uint16_t *max_fragment_size); extern S2N_RESULT s2n_record_min_write_payload_size(struct s2n_connection *conn, uint16_t *payload_size); extern int s2n_record_write(struct s2n_connection *conn, uint8_t content_type, struct s2n_blob *in); @@ -30,5 +75,5 @@ extern int s2n_record_header_parse(struct s2n_connection *conn, uint8_t * conten extern int s2n_tls13_parse_record_type(struct s2n_stuffer *stuffer, uint8_t * record_type); extern int s2n_sslv2_record_header_parse(struct s2n_connection *conn, uint8_t * record_type, uint8_t * client_protocol_version, uint16_t * fragment_length); extern int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted); -extern S2N_RESULT s2n_aead_aad_init(const struct s2n_connection *conn, uint8_t * sequence_number, uint8_t content_type, uint16_t record_length, struct s2n_stuffer *ad); -extern S2N_RESULT s2n_tls13_aead_aad_init(uint16_t record_length, uint8_t tag_length, struct s2n_stuffer *ad); +extern S2N_RESULT s2n_aead_aad_init(const struct s2n_connection *conn, uint8_t * sequence_number, uint8_t content_type, uint16_t record_length, struct s2n_blob *ad); +extern S2N_RESULT s2n_tls13_aead_aad_init(uint16_t record_length, uint8_t tag_length, struct s2n_blob *ad); diff --git a/contrib/restricted/aws/s2n/tls/s2n_record_read.c b/contrib/restricted/aws/s2n/tls/s2n_record_read.c index 7b8536818e..8a1bf8836f 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record_read.c +++ b/contrib/restricted/aws/s2n/tls/s2n_record_read.c @@ -41,15 +41,16 @@ int s2n_sslv2_record_header_parse( S2N_ERROR_IF(s2n_stuffer_data_available(in) < S2N_TLS_RECORD_HEADER_LENGTH, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_read_uint16(in, fragment_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, fragment_length)); /* Adjust to account for the 3 bytes of payload data we consumed in the header */ + POSIX_ENSURE_GTE(*fragment_length, 3); *fragment_length -= 3; - GUARD(s2n_stuffer_read_uint8(in, record_type)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, record_type)); uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; - GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); *client_protocol_version = (protocol_version[0] * 10) + protocol_version[1]; @@ -65,10 +66,10 @@ int s2n_record_header_parse( S2N_ERROR_IF(s2n_stuffer_data_available(in) < S2N_TLS_RECORD_HEADER_LENGTH, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_read_uint8(in, content_type)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, content_type)); uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; - GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); const uint8_t version = (protocol_version[0] * 10) + protocol_version[1]; /* https://tools.ietf.org/html/rfc5246#appendix-E.1 states that servers must accept any value {03,XX} as the record @@ -82,13 +83,13 @@ int s2n_record_header_parse( S2N_ERROR_IF(conn->actual_protocol_version_established && MIN(conn->actual_protocol_version, S2N_TLS12) /* check against legacy record version (1.2) in tls 1.3 */ != version, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_read_uint16(in, fragment_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, fragment_length)); /* Some servers send fragments that are above the maximum length. (e.g. * Openssl 1.0.1, so we don't check if the fragment length is > * S2N_TLS_MAXIMUM_FRAGMENT_LENGTH. The on-the-wire max is 65k */ - GUARD(s2n_stuffer_reread(in)); + POSIX_GUARD(s2n_stuffer_reread(in)); return 0; } @@ -115,7 +116,7 @@ int s2n_record_parse(struct s2n_connection *conn) { uint8_t content_type; uint16_t encrypted_length; - GUARD(s2n_record_header_parse(conn, &content_type, &encrypted_length)); + POSIX_GUARD(s2n_record_header_parse(conn, &content_type, &encrypted_length)); struct s2n_crypto_parameters *current_client_crypto = conn->client; struct s2n_crypto_parameters *current_server_crypto = conn->server; @@ -143,21 +144,27 @@ int s2n_record_parse(struct s2n_connection *conn) conn->server = current_server_crypto; } + /* The NULL stream cipher MUST NEVER be used for ApplicationData. + * If ApplicationData is unencrypted, we can't trust it. */ + if (cipher_suite->record_alg->cipher == &s2n_null_cipher) { + POSIX_ENSURE(content_type != TLS_APPLICATION_DATA, S2N_ERR_DECRYPT); + } + switch (cipher_suite->record_alg->cipher->type) { case S2N_AEAD: - GUARD(s2n_record_parse_aead(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); + POSIX_GUARD(s2n_record_parse_aead(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); break; case S2N_CBC: - GUARD(s2n_record_parse_cbc(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); + POSIX_GUARD(s2n_record_parse_cbc(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); break; case S2N_COMPOSITE: - GUARD(s2n_record_parse_composite(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); + POSIX_GUARD(s2n_record_parse_composite(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); break; case S2N_STREAM: - GUARD(s2n_record_parse_stream(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); + POSIX_GUARD(s2n_record_parse_stream(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key)); break; default: - S2N_ERROR(S2N_ERR_CIPHER_TYPE); + POSIX_BAIL(S2N_ERR_CIPHER_TYPE); break; } @@ -181,7 +188,7 @@ int s2n_tls13_parse_record_type(struct s2n_stuffer *stuffer, uint8_t *record_typ S2N_ERROR_IF(bytes_left > S2N_MAXIMUM_INNER_PLAINTEXT_LENGTH + 16, S2N_ERR_MAX_INNER_PLAINTEXT_SIZE); /* set cursor to the end of the stuffer */ - GUARD(s2n_stuffer_skip_read(stuffer, bytes_left)); + POSIX_GUARD(s2n_stuffer_skip_read(stuffer, bytes_left)); /* Record type should have values greater than zero. * If zero, treat as padding, keep reading and wiping from the back @@ -190,18 +197,18 @@ int s2n_tls13_parse_record_type(struct s2n_stuffer *stuffer, uint8_t *record_typ *record_type = 0; while (*record_type == 0) { /* back the cursor by one to read off the last byte */ - GUARD(s2n_stuffer_rewind_read(stuffer, 1)); + POSIX_GUARD(s2n_stuffer_rewind_read(stuffer, 1)); /* set the record type */ - GUARD(s2n_stuffer_read_uint8(stuffer, record_type)); + POSIX_GUARD(s2n_stuffer_read_uint8(stuffer, record_type)); /* wipe the last byte at the end of the stuffer */ - GUARD(s2n_stuffer_wipe_n(stuffer, 1)); + POSIX_GUARD(s2n_stuffer_wipe_n(stuffer, 1)); } /* only the original plaintext should remain */ /* now reset the read cursor at where it should be */ - GUARD(s2n_stuffer_reread(stuffer)); + POSIX_GUARD(s2n_stuffer_reread(stuffer)); /* Even in the incorrect case above with up to 16 extra bytes, we should never see too much data after unpadding */ S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) > S2N_MAXIMUM_INNER_PLAINTEXT_LENGTH - 1, S2N_ERR_MAX_INNER_PLAINTEXT_SIZE); diff --git a/contrib/restricted/aws/s2n/tls/s2n_record_read_aead.c b/contrib/restricted/aws/s2n/tls/s2n_record_read_aead.c index 87207d3723..ba1d460d82 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record_read_aead.c +++ b/contrib/restricted/aws/s2n/tls/s2n_record_read_aead.c @@ -46,19 +46,19 @@ int s2n_record_parse_aead( s2n_stack_blob(aad, is_tls13_record ? S2N_TLS13_AAD_LEN : S2N_TLS_MAX_AAD_LEN, S2N_TLS_MAX_AAD_LEN); struct s2n_blob en = {.size = encrypted_length,.data = s2n_stuffer_raw_read(&conn->in, encrypted_length) }; - notnull_check(en.data); + POSIX_ENSURE_REF(en.data); /* In AEAD mode, the explicit IV is in the record */ - gte_check(en.size, cipher_suite->record_alg->cipher->io.aead.record_iv_size); + POSIX_ENSURE_GTE(en.size, cipher_suite->record_alg->cipher->io.aead.record_iv_size); uint8_t aad_iv[S2N_TLS_MAX_IV_LEN] = { 0 }; struct s2n_blob iv = {.data = aad_iv,.size = sizeof(aad_iv) }; struct s2n_stuffer iv_stuffer = {0}; - GUARD(s2n_stuffer_init(&iv_stuffer, &iv)); + POSIX_GUARD(s2n_stuffer_init(&iv_stuffer, &iv)); if (cipher_suite->record_alg->flags & S2N_TLS12_AES_GCM_AEAD_NONCE) { /* Partially explicit nonce. See RFC 5288 Section 3 */ - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size)); - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, en.data, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, en.data, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); } else if (cipher_suite->record_alg->flags & S2N_TLS12_CHACHA_POLY_AEAD_NONCE || is_tls13_record) { /* Fully implicit nonce. * This is introduced with ChaChaPoly with RFC 7905 Section 2 @@ -68,14 +68,14 @@ int s2n_record_parse_aead( * to align and xor-ed with the 96-bit IV. **/ uint8_t four_zeroes[4] = { 0 }; - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4)); - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); for (int i = 0; i < cipher_suite->record_alg->cipher->io.aead.fixed_iv_size; i++) { S2N_INVARIANT(i <= cipher_suite->record_alg->cipher->io.aead.fixed_iv_size); aad_iv[i] = aad_iv[i] ^ implicit_iv[i]; } } else { - S2N_ERROR(S2N_ERR_INVALID_NONCE_TYPE); + POSIX_BAIL(S2N_ERR_INVALID_NONCE_TYPE); } /* Set the IV size to the amount of data written */ @@ -83,17 +83,14 @@ int s2n_record_parse_aead( uint16_t payload_length = encrypted_length; /* remove the AEAD overhead from the record size */ - gte_check(payload_length, cipher_suite->record_alg->cipher->io.aead.record_iv_size + cipher_suite->record_alg->cipher->io.aead.tag_size); + POSIX_ENSURE_GTE(payload_length, cipher_suite->record_alg->cipher->io.aead.record_iv_size + cipher_suite->record_alg->cipher->io.aead.tag_size); payload_length -= cipher_suite->record_alg->cipher->io.aead.record_iv_size; payload_length -= cipher_suite->record_alg->cipher->io.aead.tag_size; - struct s2n_stuffer ad_stuffer = {0}; - GUARD(s2n_stuffer_init(&ad_stuffer, &aad)); - if (is_tls13_record) { - GUARD_AS_POSIX(s2n_tls13_aead_aad_init(payload_length, cipher_suite->record_alg->cipher->io.aead.tag_size, &ad_stuffer)); + POSIX_GUARD_RESULT(s2n_tls13_aead_aad_init(payload_length, cipher_suite->record_alg->cipher->io.aead.tag_size, &aad)); } else { - GUARD_AS_POSIX(s2n_aead_aad_init(conn, sequence_number, content_type, payload_length, &ad_stuffer)); + POSIX_GUARD_RESULT(s2n_aead_aad_init(conn, sequence_number, content_type, payload_length, &aad)); } /* Decrypt stuff! */ @@ -102,25 +99,25 @@ int s2n_record_parse_aead( en.data += cipher_suite->record_alg->cipher->io.aead.record_iv_size; /* Check that we have some data to decrypt */ - ne_check(en.size, 0); + POSIX_ENSURE_NE(en.size, 0); - GUARD(cipher_suite->record_alg->cipher->io.aead.decrypt(session_key, &iv, &aad, &en, &en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.aead.decrypt(session_key, &iv, &aad, &en, &en)); struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; - GUARD(s2n_increment_sequence_number(&seq)); + POSIX_GUARD(s2n_increment_sequence_number(&seq)); /* O.k., we've successfully read and decrypted the record, now we need to align the stuffer * for reading the plaintext data. */ - GUARD(s2n_stuffer_reread(&conn->in)); - GUARD(s2n_stuffer_reread(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->header_in)); /* Skip the IV, if any */ if (conn->actual_protocol_version >= S2N_TLS12) { - GUARD(s2n_stuffer_skip_read(&conn->in, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); + POSIX_GUARD(s2n_stuffer_skip_read(&conn->in, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); } /* Truncate and wipe the MAC and any padding */ - GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); + POSIX_GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); conn->in_status = PLAINTEXT; return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_record_read_cbc.c b/contrib/restricted/aws/s2n/tls/s2n_record_read_cbc.c index 9948469593..f72f090915 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record_read_cbc.c +++ b/contrib/restricted/aws/s2n/tls/s2n_record_read_cbc.c @@ -45,85 +45,85 @@ int s2n_record_parse_cbc( /* Add the header to the HMAC */ uint8_t *header = s2n_stuffer_raw_read(&conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH); - notnull_check(header); + POSIX_ENSURE_REF(header); - lte_check(cipher_suite->record_alg->cipher->io.cbc.record_iv_size, S2N_TLS_MAX_IV_LEN); + POSIX_ENSURE_LTE(cipher_suite->record_alg->cipher->io.cbc.record_iv_size, S2N_TLS_MAX_IV_LEN); /* For TLS >= 1.1 the IV is in the packet */ if (conn->actual_protocol_version > S2N_TLS10) { - GUARD(s2n_stuffer_read(&conn->in, &iv)); - gte_check(encrypted_length, iv.size); + POSIX_GUARD(s2n_stuffer_read(&conn->in, &iv)); + POSIX_ENSURE_GTE(encrypted_length, iv.size); encrypted_length -= iv.size; } struct s2n_blob en = {.size = encrypted_length,.data = s2n_stuffer_raw_read(&conn->in, encrypted_length) }; - notnull_check(en.data); + POSIX_ENSURE_REF(en.data); uint16_t payload_length = encrypted_length; uint8_t mac_digest_size; - GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); + POSIX_GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); - gte_check(payload_length, mac_digest_size); + POSIX_ENSURE_GTE(payload_length, mac_digest_size); payload_length -= mac_digest_size; /* Decrypt stuff! */ /* Check that we have some data to decrypt */ - ne_check(en.size, 0); + POSIX_ENSURE_NE(en.size, 0); /* ... and that we have a multiple of the block size */ - eq_check(en.size % iv.size, 0); + POSIX_ENSURE_EQ(en.size % iv.size, 0); /* Copy the last encrypted block to be the next IV */ if (conn->actual_protocol_version < S2N_TLS11) { - memcpy_check(ivpad, en.data + en.size - iv.size, iv.size); + POSIX_CHECKED_MEMCPY(ivpad, en.data + en.size - iv.size, iv.size); } - GUARD(cipher_suite->record_alg->cipher->io.cbc.decrypt(session_key, &iv, &en, &en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.cbc.decrypt(session_key, &iv, &en, &en)); if (conn->actual_protocol_version < S2N_TLS11) { - memcpy_check(implicit_iv, ivpad, iv.size); + POSIX_CHECKED_MEMCPY(implicit_iv, ivpad, iv.size); } /* Subtract the padding length */ - gt_check(en.size, 0); + POSIX_ENSURE_GT(en.size, 0); uint32_t out = 0; - GUARD(s2n_sub_overflow(payload_length, en.data[en.size - 1] + 1, &out)); + POSIX_GUARD(s2n_sub_overflow(payload_length, en.data[en.size - 1] + 1, &out)); payload_length = out; /* Update the MAC */ header[3] = (payload_length >> 8); header[4] = payload_length & 0xff; - GUARD(s2n_hmac_reset(mac)); - GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_hmac_reset(mac)); + POSIX_GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); if (conn->actual_protocol_version == S2N_SSLv3) { - GUARD(s2n_hmac_update(mac, header, 1)); - GUARD(s2n_hmac_update(mac, header + 3, 2)); + POSIX_GUARD(s2n_hmac_update(mac, header, 1)); + POSIX_GUARD(s2n_hmac_update(mac, header + 3, 2)); } else { - GUARD(s2n_hmac_update(mac, header, S2N_TLS_RECORD_HEADER_LENGTH)); + POSIX_GUARD(s2n_hmac_update(mac, header, S2N_TLS_RECORD_HEADER_LENGTH)); } struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; - GUARD(s2n_increment_sequence_number(&seq)); + POSIX_GUARD(s2n_increment_sequence_number(&seq)); - /* Padding */ + /* Padding. This finalizes the provided HMAC. */ if (s2n_verify_cbc(conn, mac, &en) < 0) { - GUARD(s2n_stuffer_wipe(&conn->in)); - S2N_ERROR(S2N_ERR_BAD_MESSAGE); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_BAIL(S2N_ERR_BAD_MESSAGE); } /* O.k., we've successfully read and decrypted the record, now we need to align the stuffer * for reading the plaintext data. */ - GUARD(s2n_stuffer_reread(&conn->in)); - GUARD(s2n_stuffer_reread(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->header_in)); /* Skip the IV, if any */ if (conn->actual_protocol_version > S2N_TLS10) { - GUARD(s2n_stuffer_skip_read(&conn->in, cipher_suite->record_alg->cipher->io.cbc.record_iv_size)); + POSIX_GUARD(s2n_stuffer_skip_read(&conn->in, cipher_suite->record_alg->cipher->io.cbc.record_iv_size)); } /* Truncate and wipe the MAC and any padding */ - GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); + POSIX_GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); conn->in_status = PLAINTEXT; return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_record_read_composite.c b/contrib/restricted/aws/s2n/tls/s2n_record_read_composite.c index 3d39bdd8c7..62b082f576 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record_read_composite.c +++ b/contrib/restricted/aws/s2n/tls/s2n_record_read_composite.c @@ -45,16 +45,16 @@ int s2n_record_parse_composite( /* Add the header to the HMAC */ uint8_t *header = s2n_stuffer_raw_read(&conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH); - notnull_check(header); + POSIX_ENSURE_REF(header); struct s2n_blob en = {.size = encrypted_length,.data = s2n_stuffer_raw_read(&conn->in, encrypted_length) }; - notnull_check(en.data); + POSIX_ENSURE_REF(en.data); uint16_t payload_length = encrypted_length; uint8_t mac_digest_size; - GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); + POSIX_GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); - gte_check(payload_length, mac_digest_size); + POSIX_ENSURE_GTE(payload_length, mac_digest_size); payload_length -= mac_digest_size; /* Compute non-payload parts of the MAC(seq num, type, proto vers, fragment length) for composite ciphers. @@ -63,51 +63,51 @@ int s2n_record_parse_composite( /* In the decrypt case, this outputs the MAC digest length: * https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L842 */ int mac_size = 0; - GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, conn->actual_protocol_version, payload_length, &mac_size)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, conn->actual_protocol_version, payload_length, &mac_size)); - gte_check(payload_length, mac_size); + POSIX_ENSURE_GTE(payload_length, mac_size); payload_length -= mac_size; /* Adjust payload_length for explicit IV */ if (conn->actual_protocol_version > S2N_TLS10) { uint32_t out = 0; - GUARD(s2n_sub_overflow(payload_length, cipher_suite->record_alg->cipher->io.comp.record_iv_size, &out)); + POSIX_GUARD(s2n_sub_overflow(payload_length, cipher_suite->record_alg->cipher->io.comp.record_iv_size, &out)); payload_length = out; } /* Decrypt stuff! */ - ne_check(en.size, 0); - eq_check(en.size % iv.size, 0); + POSIX_ENSURE_NE(en.size, 0); + POSIX_ENSURE_EQ(en.size % iv.size, 0); /* Copy the last encrypted block to be the next IV */ - memcpy_check(ivpad, en.data + en.size - iv.size, iv.size); + POSIX_CHECKED_MEMCPY(ivpad, en.data + en.size - iv.size, iv.size); /* This will: Skip the explicit IV(if applicable), decrypt the payload, verify the MAC and padding. */ - GUARD((cipher_suite->record_alg->cipher->io.comp.decrypt(session_key, &iv, &en, &en))); + POSIX_GUARD((cipher_suite->record_alg->cipher->io.comp.decrypt(session_key, &iv, &en, &en))); - memcpy_check(implicit_iv, ivpad, iv.size); + POSIX_CHECKED_MEMCPY(implicit_iv, ivpad, iv.size); /* Subtract the padding length */ - gt_check(en.size, 0); + POSIX_ENSURE_GT(en.size, 0); uint32_t out = 0; - GUARD(s2n_sub_overflow(payload_length, en.data[en.size - 1] + 1, &out)); + POSIX_GUARD(s2n_sub_overflow(payload_length, en.data[en.size - 1] + 1, &out)); payload_length = out; struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; - GUARD(s2n_increment_sequence_number(&seq)); + POSIX_GUARD(s2n_increment_sequence_number(&seq)); /* O.k., we've successfully read and decrypted the record, now we need to align the stuffer * for reading the plaintext data. */ - GUARD(s2n_stuffer_reread(&conn->in)); - GUARD(s2n_stuffer_reread(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->header_in)); /* Skip the IV, if any */ if (conn->actual_protocol_version > S2N_TLS10) { - GUARD(s2n_stuffer_skip_read(&conn->in, cipher_suite->record_alg->cipher->io.comp.record_iv_size)); + POSIX_GUARD(s2n_stuffer_skip_read(&conn->in, cipher_suite->record_alg->cipher->io.comp.record_iv_size)); } /* Truncate and wipe the MAC and any padding */ - GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); + POSIX_GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); conn->in_status = PLAINTEXT; return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_record_read_stream.c b/contrib/restricted/aws/s2n/tls/s2n_record_read_stream.c index dc6d6cb93e..8145d74d6a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record_read_stream.c +++ b/contrib/restricted/aws/s2n/tls/s2n_record_read_stream.c @@ -41,57 +41,57 @@ int s2n_record_parse_stream( { /* Add the header to the HMAC */ uint8_t *header = s2n_stuffer_raw_read(&conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH); - notnull_check(header); + POSIX_ENSURE_REF(header); struct s2n_blob en = {.size = encrypted_length,.data = s2n_stuffer_raw_read(&conn->in, encrypted_length) }; - notnull_check(en.data); + POSIX_ENSURE_REF(en.data); uint16_t payload_length = encrypted_length; uint8_t mac_digest_size; - GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); + POSIX_GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); - gte_check(payload_length, mac_digest_size); + POSIX_ENSURE_GTE(payload_length, mac_digest_size); payload_length -= mac_digest_size; /* Decrypt stuff! */ - GUARD(cipher_suite->record_alg->cipher->io.stream.decrypt(session_key, &en, &en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.stream.decrypt(session_key, &en, &en)); /* Update the MAC */ header[3] = (payload_length >> 8); header[4] = payload_length & 0xff; - GUARD(s2n_hmac_reset(mac)); - GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_hmac_reset(mac)); + POSIX_GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); if (conn->actual_protocol_version == S2N_SSLv3) { - GUARD(s2n_hmac_update(mac, header, 1)); - GUARD(s2n_hmac_update(mac, header + 3, 2)); + POSIX_GUARD(s2n_hmac_update(mac, header, 1)); + POSIX_GUARD(s2n_hmac_update(mac, header + 3, 2)); } else { - GUARD(s2n_hmac_update(mac, header, S2N_TLS_RECORD_HEADER_LENGTH)); + POSIX_GUARD(s2n_hmac_update(mac, header, S2N_TLS_RECORD_HEADER_LENGTH)); } struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; - GUARD(s2n_increment_sequence_number(&seq)); + POSIX_GUARD(s2n_increment_sequence_number(&seq)); /* MAC check for streaming ciphers - no padding */ - GUARD(s2n_hmac_update(mac, en.data, payload_length)); + POSIX_GUARD(s2n_hmac_update(mac, en.data, payload_length)); uint8_t check_digest[S2N_MAX_DIGEST_LEN]; - lte_check(mac_digest_size, sizeof(check_digest)); - GUARD(s2n_hmac_digest(mac, check_digest, mac_digest_size)); + POSIX_ENSURE_LTE(mac_digest_size, sizeof(check_digest)); + POSIX_GUARD(s2n_hmac_digest(mac, check_digest, mac_digest_size)); if (s2n_hmac_digest_verify(en.data + payload_length, check_digest, mac_digest_size) < 0) { - GUARD(s2n_stuffer_wipe(&conn->in)); - S2N_ERROR(S2N_ERR_BAD_MESSAGE); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_BAIL(S2N_ERR_BAD_MESSAGE); } /* O.k., we've successfully read and decrypted the record, now we need to align the stuffer * for reading the plaintext data. */ - GUARD(s2n_stuffer_reread(&conn->in)); - GUARD(s2n_stuffer_reread(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->in)); + POSIX_GUARD(s2n_stuffer_reread(&conn->header_in)); /* Truncate and wipe the MAC and any padding */ - GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); + POSIX_GUARD(s2n_stuffer_wipe_n(&conn->in, s2n_stuffer_data_available(&conn->in) - payload_length)); conn->in_status = PLAINTEXT; return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_record_write.c b/contrib/restricted/aws/s2n/tls/s2n_record_write.c index df28a9d58e..14cda738ff 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_record_write.c +++ b/contrib/restricted/aws/s2n/tls/s2n_record_write.c @@ -38,8 +38,8 @@ extern uint8_t s2n_unknown_protocol_version; /* How much overhead does the IV, MAC, TAG and padding bytes introduce ? */ static S2N_RESULT s2n_tls_record_overhead(struct s2n_connection *conn, uint16_t *out) { - ENSURE_REF(conn); - ENSURE_MUT(out); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_MUT(out); struct s2n_crypto_parameters *active = conn->server; if (conn->mode == S2N_CLIENT) { @@ -47,7 +47,7 @@ static S2N_RESULT s2n_tls_record_overhead(struct s2n_connection *conn, uint16_t } uint8_t extra; - GUARD_AS_RESULT(s2n_hmac_digest_size(active->cipher_suite->record_alg->hmac_alg, &extra)); + RESULT_GUARD_POSIX(s2n_hmac_digest_size(active->cipher_suite->record_alg->hmac_alg, &extra)); if (active->cipher_suite->record_alg->cipher->type == S2N_CBC) { /* Subtract one for the padding length byte */ @@ -73,25 +73,41 @@ static S2N_RESULT s2n_tls_record_overhead(struct s2n_connection *conn, uint16_t */ S2N_RESULT s2n_record_max_write_payload_size(struct s2n_connection *conn, uint16_t *max_fragment_size) { - ENSURE_REF(conn); - ENSURE_MUT(max_fragment_size); - ENSURE(conn->max_outgoing_fragment_length > 0, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_MUT(max_fragment_size); + RESULT_ENSURE(conn->max_outgoing_fragment_length > 0, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); *max_fragment_size = MIN(conn->max_outgoing_fragment_length, S2N_TLS_MAXIMUM_FRAGMENT_LENGTH); return S2N_RESULT_OK; } +S2N_RESULT s2n_record_max_write_size(struct s2n_connection *conn, uint16_t max_fragment_size, uint16_t *max_record_size) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_MUT(max_record_size); + + if(!IS_NEGOTIATED(conn)) { + *max_record_size = S2N_TLS_MAX_RECORD_LEN_FOR(max_fragment_size); + } else if (conn->actual_protocol_version < S2N_TLS13) { + *max_record_size = S2N_TLS12_MAX_RECORD_LEN_FOR(max_fragment_size); + } else { + *max_record_size = S2N_TLS13_MAX_RECORD_LEN_FOR(max_fragment_size); + } + return S2N_RESULT_OK; +} + /* Find the largest size that will fit within an ethernet frame for a "small" payload */ S2N_RESULT s2n_record_min_write_payload_size(struct s2n_connection *conn, uint16_t *payload_size) { - ENSURE_REF(conn); - ENSURE_MUT(payload_size); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_MUT(payload_size); + /* remove ethernet, TCP/IP and TLS header overheads */ const uint16_t min_outgoing_fragment_length = ETH_MTU - (conn->ipv6 ? IP_V6_HEADER_LENGTH : IP_V4_HEADER_LENGTH) - TCP_HEADER_LENGTH - TCP_OPTIONS_LENGTH - S2N_TLS_RECORD_HEADER_LENGTH; - ENSURE(min_outgoing_fragment_length <= S2N_TLS_MAXIMUM_FRAGMENT_LENGTH, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE); + RESULT_ENSURE(min_outgoing_fragment_length <= S2N_TLS_MAXIMUM_FRAGMENT_LENGTH, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE); uint16_t size = min_outgoing_fragment_length; const struct s2n_crypto_parameters *active = conn->mode == S2N_CLIENT ? conn->client : conn->server; @@ -107,14 +123,20 @@ S2N_RESULT s2n_record_min_write_payload_size(struct s2n_connection *conn, uint16 size -= 1; } + /* If TLS1.3, remove content type */ + if (conn->actual_protocol_version >= S2N_TLS13) { + RESULT_ENSURE(size > S2N_TLS_CONTENT_TYPE_LENGTH, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); + size -= S2N_TLS_CONTENT_TYPE_LENGTH; + } + /* subtract overheads of a TLS record */ uint16_t overhead = 0; - GUARD_RESULT(s2n_tls_record_overhead(conn, &overhead)); - ENSURE(size > overhead, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); + RESULT_GUARD(s2n_tls_record_overhead(conn, &overhead)); + RESULT_ENSURE(size > overhead, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); size -= overhead; - ENSURE(size > 0, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); - ENSURE(size <= ETH_MTU, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE); + RESULT_ENSURE(size > 0, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL); + RESULT_ENSURE(size <= ETH_MTU, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE); *payload_size = size; @@ -124,7 +146,8 @@ S2N_RESULT s2n_record_min_write_payload_size(struct s2n_connection *conn, uint16 int s2n_record_write_protocol_version(struct s2n_connection *conn) { uint8_t record_protocol_version = conn->actual_protocol_version; - if (conn->server_protocol_version == s2n_unknown_protocol_version) { + if (conn->server_protocol_version == s2n_unknown_protocol_version + && conn->early_data_state != S2N_EARLY_DATA_REQUESTED) { /* Some legacy TLS implementations can't handle records with protocol version higher than TLS1.0. * To provide maximum compatibility, send record version as TLS1.0 if server protocol version isn't * established yet, which happens only during ClientHello message. Note, this has no effect on @@ -141,7 +164,7 @@ int s2n_record_write_protocol_version(struct s2n_connection *conn) protocol_version[0] = record_protocol_version / 10; protocol_version[1] = record_protocol_version % 10; - GUARD(s2n_stuffer_write_bytes(&conn->out, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->out, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); return 0; } @@ -155,34 +178,34 @@ static inline int s2n_record_encrypt( struct s2n_blob *en, uint8_t *implicit_iv, uint16_t block_size) { - notnull_check(en->data); + POSIX_ENSURE_REF(en->data); switch (cipher_suite->record_alg->cipher->type) { case S2N_STREAM: - GUARD(cipher_suite->record_alg->cipher->io.stream.encrypt(session_key, en, en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.stream.encrypt(session_key, en, en)); break; case S2N_CBC: - GUARD(cipher_suite->record_alg->cipher->io.cbc.encrypt(session_key, iv, en, en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.cbc.encrypt(session_key, iv, en, en)); /* Copy the last encrypted block to be the next IV */ if (conn->actual_protocol_version < S2N_TLS11) { - gte_check(en->size, block_size); - memcpy_check(implicit_iv, en->data + en->size - block_size, block_size); + POSIX_ENSURE_GTE(en->size, block_size); + POSIX_CHECKED_MEMCPY(implicit_iv, en->data + en->size - block_size, block_size); } break; case S2N_AEAD: - GUARD(cipher_suite->record_alg->cipher->io.aead.encrypt(session_key, iv, aad, en, en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.aead.encrypt(session_key, iv, aad, en, en)); break; case S2N_COMPOSITE: /* This will: compute mac, append padding, append padding length, and encrypt */ - GUARD(cipher_suite->record_alg->cipher->io.comp.encrypt(session_key, iv, en, en)); + POSIX_GUARD(cipher_suite->record_alg->cipher->io.comp.encrypt(session_key, iv, en, en)); /* Copy the last encrypted block to be the next IV */ - gte_check(en->size, block_size); - memcpy_check(implicit_iv, en->data + en->size - block_size, block_size); + POSIX_ENSURE_GTE(en->size, block_size); + POSIX_CHECKED_MEMCPY(implicit_iv, en->data + en->size - block_size, block_size); break; default: - S2N_ERROR(S2N_ERR_CIPHER_TYPE); + POSIX_BAIL(S2N_ERR_CIPHER_TYPE); break; } @@ -218,23 +241,29 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s implicit_iv = conn->client->client_implicit_iv; } + /* The NULL stream cipher MUST NEVER be used for ApplicationData. + * Writing ApplicationData unencrypted defeats the purpose of TLS. */ + if (cipher_suite->record_alg->cipher == &s2n_null_cipher) { + POSIX_ENSURE(content_type != TLS_APPLICATION_DATA, S2N_ERR_ENCRYPT); + } + const int is_tls13_record = cipher_suite->record_alg->flags & S2N_TLS13_RECORD_AEAD_NONCE; s2n_stack_blob(aad, is_tls13_record ? S2N_TLS13_AAD_LEN : S2N_TLS_MAX_AAD_LEN, S2N_TLS_MAX_AAD_LEN); S2N_ERROR_IF(s2n_stuffer_data_available(&conn->out), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING); uint8_t mac_digest_size; - GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); + POSIX_GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); /* Before we do anything, we need to figure out what the length of the * fragment is going to be. */ uint16_t max_write_payload_size = 0; - GUARD_AS_POSIX(s2n_record_max_write_payload_size(conn, &max_write_payload_size)); + POSIX_GUARD_RESULT(s2n_record_max_write_payload_size(conn, &max_write_payload_size)); const uint16_t data_bytes_to_take = MIN(to_write, max_write_payload_size); uint16_t extra = 0; - GUARD_AS_POSIX(s2n_tls_record_overhead(conn, &extra)); + POSIX_GUARD_RESULT(s2n_tls_record_overhead(conn, &extra)); /* If we have padding to worry about, figure that out too */ if (cipher_suite->record_alg->cipher->type == S2N_CBC) { @@ -247,25 +276,40 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s } /* Start the MAC with the sequence number */ - GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); - - GUARD(s2n_stuffer_resize_if_empty(&conn->out, S2N_LARGE_RECORD_LENGTH)); + POSIX_GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + + if (s2n_stuffer_is_freed(&conn->out)) { + /* If the output buffer has not been allocated yet, allocate enough memory to hold + * a record with the local maximum fragment length. Because this only occurs if the + * output buffer has not been allocated, it does NOT resize existing buffers. + * + * The maximum fragment length is: + * 1) The local default configured for new connections + * 2) The local value set by the user via s2n_connection_prefer_throughput() + * or s2n_connection_prefer_low_latency() + * 3) On the server, the minimum of the local value and the value negotiated with the + * client via the max_fragment_length extension + */ + uint16_t max_wire_record_size = 0; + POSIX_GUARD_RESULT(s2n_record_max_write_size(conn, max_write_payload_size, &max_wire_record_size)); + POSIX_GUARD(s2n_stuffer_growable_alloc(&conn->out, max_wire_record_size)); + } /* Now that we know the length, start writing the record */ - GUARD(s2n_stuffer_write_uint8(&conn->out, is_tls13_record ? + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->out, is_tls13_record ? /* tls 1.3 opaque type */ TLS_APPLICATION_DATA : /* actual content_type */ content_type )); - GUARD(s2n_record_write_protocol_version(conn)); + POSIX_GUARD(s2n_record_write_protocol_version(conn)); /* First write a header that has the payload length, this is for the MAC */ - GUARD(s2n_stuffer_write_uint16(&conn->out, data_bytes_to_take)); + POSIX_GUARD(s2n_stuffer_write_uint16(&conn->out, data_bytes_to_take)); if (conn->actual_protocol_version > S2N_SSLv3) { - GUARD(s2n_hmac_update(mac, conn->out.blob.data, S2N_TLS_RECORD_HEADER_LENGTH)); + POSIX_GUARD(s2n_hmac_update(mac, conn->out.blob.data, S2N_TLS_RECORD_HEADER_LENGTH)); } else { /* SSLv3 doesn't include the protocol version in the MAC */ - GUARD(s2n_hmac_update(mac, conn->out.blob.data, 1)); - GUARD(s2n_hmac_update(mac, conn->out.blob.data + 3, 2)); + POSIX_GUARD(s2n_hmac_update(mac, conn->out.blob.data, 1)); + POSIX_GUARD(s2n_hmac_update(mac, conn->out.blob.data + 3, 2)); } /* Compute non-payload parts of the MAC(seq num, type, proto vers, fragment length) for composite ciphers. @@ -280,14 +324,14 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s /* Outputs number of extra bytes required for MAC and padding */ int pad_and_mac_len; - GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, conn->actual_protocol_version, + POSIX_GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, conn->actual_protocol_version, payload_and_eiv_len, &pad_and_mac_len)); extra += pad_and_mac_len; } /* TLS 1.3 protected record occupies one extra byte for content type */ if (is_tls13_record) { - extra += TLS13_CONTENT_TYPE_LENGTH; + extra += S2N_TLS_CONTENT_TYPE_LENGTH; } /* Rewrite the length to be the actual fragment length */ @@ -295,48 +339,45 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s /* ensure actual_fragment_length + S2N_TLS_RECORD_HEADER_LENGTH <= max record length */ const uint16_t max_record_length = is_tls13_record ? S2N_TLS13_MAXIMUM_RECORD_LENGTH : S2N_TLS_MAXIMUM_RECORD_LENGTH; S2N_ERROR_IF(actual_fragment_length + S2N_TLS_RECORD_HEADER_LENGTH > max_record_length, S2N_ERR_RECORD_LENGTH_TOO_LARGE); - GUARD(s2n_stuffer_wipe_n(&conn->out, 2)); - GUARD(s2n_stuffer_write_uint16(&conn->out, actual_fragment_length)); + POSIX_GUARD(s2n_stuffer_wipe_n(&conn->out, 2)); + POSIX_GUARD(s2n_stuffer_write_uint16(&conn->out, actual_fragment_length)); /* If we're AEAD, write the sequence number as an IV, and generate the AAD */ if (cipher_suite->record_alg->cipher->type == S2N_AEAD) { struct s2n_stuffer iv_stuffer = {0}; s2n_blob_init(&iv, aad_iv, sizeof(aad_iv)); - GUARD(s2n_stuffer_init(&iv_stuffer, &iv)); + POSIX_GUARD(s2n_stuffer_init(&iv_stuffer, &iv)); if (cipher_suite->record_alg->flags & S2N_TLS12_AES_GCM_AEAD_NONCE) { /* Partially explicit nonce. See RFC 5288 Section 3 */ - GUARD(s2n_stuffer_write_bytes(&conn->out, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size)); - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->out, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); } else if (cipher_suite->record_alg->flags & S2N_TLS12_CHACHA_POLY_AEAD_NONCE || is_tls13_record) { /* Fully implicit nonce. See RFC7905 Section 2 */ uint8_t four_zeroes[4] = { 0 }; - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4)); - GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4)); + POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); for(int i = 0; i < cipher_suite->record_alg->cipher->io.aead.fixed_iv_size; i++) { aad_iv[i] = aad_iv[i] ^ implicit_iv[i]; } } else { - S2N_ERROR(S2N_ERR_INVALID_NONCE_TYPE); + POSIX_BAIL(S2N_ERR_INVALID_NONCE_TYPE); } /* Set the IV size to the amount of data written */ iv.size = s2n_stuffer_data_available(&iv_stuffer); - - struct s2n_stuffer ad_stuffer = {0}; - GUARD(s2n_stuffer_init(&ad_stuffer, &aad)); if (is_tls13_record) { - GUARD_AS_POSIX(s2n_tls13_aead_aad_init(data_bytes_to_take + TLS13_CONTENT_TYPE_LENGTH, cipher_suite->record_alg->cipher->io.aead.tag_size, &ad_stuffer)); + POSIX_GUARD_RESULT(s2n_tls13_aead_aad_init(data_bytes_to_take + S2N_TLS_CONTENT_TYPE_LENGTH, cipher_suite->record_alg->cipher->io.aead.tag_size, &aad)); } else { - GUARD_AS_POSIX(s2n_aead_aad_init(conn, sequence_number, content_type, data_bytes_to_take, &ad_stuffer)); + POSIX_GUARD_RESULT(s2n_aead_aad_init(conn, sequence_number, content_type, data_bytes_to_take, &aad)); } } else if (cipher_suite->record_alg->cipher->type == S2N_CBC || cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { s2n_blob_init(&iv, implicit_iv, block_size); /* For TLS1.1/1.2; write the IV with random data */ if (conn->actual_protocol_version > S2N_TLS10) { - GUARD_AS_POSIX(s2n_get_public_random_data(&iv)); + POSIX_GUARD_RESULT(s2n_get_public_random_data(&iv)); if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { /* Write a separate random block to the record. This will be used along with the previously generated * iv blob to generate the final explicit_iv for this record. @@ -353,37 +394,37 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s */ struct s2n_blob explicit_iv_placeholder; uint8_t zero_block[S2N_TLS_MAX_IV_LEN] = { 0 }; - GUARD(s2n_blob_init(&explicit_iv_placeholder, zero_block, block_size)); - GUARD_AS_POSIX(s2n_get_public_random_data(&explicit_iv_placeholder)); - GUARD(s2n_stuffer_write(&conn->out, &explicit_iv_placeholder)); + POSIX_GUARD(s2n_blob_init(&explicit_iv_placeholder, zero_block, block_size)); + POSIX_GUARD_RESULT(s2n_get_public_random_data(&explicit_iv_placeholder)); + POSIX_GUARD(s2n_stuffer_write(&conn->out, &explicit_iv_placeholder)); } else { /* We can write the explicit IV directly to the record for non composite CBC because * s2n starts AES *after* the explicit IV. */ - GUARD(s2n_stuffer_write(&conn->out, &iv)); + POSIX_GUARD(s2n_stuffer_write(&conn->out, &iv)); } } } /* We are done with this sequence number, so we can increment it */ struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; - GUARD(s2n_increment_sequence_number(&seq)); + POSIX_GUARD(s2n_increment_sequence_number(&seq)); /* Write the plaintext data */ - GUARD(s2n_stuffer_writev_bytes(&conn->out, in, in_count, offs, data_bytes_to_take)); + POSIX_GUARD(s2n_stuffer_writev_bytes(&conn->out, in, in_count, offs, data_bytes_to_take)); void *orig_write_ptr = conn->out.blob.data + conn->out.write_cursor - data_bytes_to_take; - GUARD(s2n_hmac_update(mac, orig_write_ptr, data_bytes_to_take)); + POSIX_GUARD(s2n_hmac_update(mac, orig_write_ptr, data_bytes_to_take)); /* Write the digest */ uint8_t *digest = s2n_stuffer_raw_write(&conn->out, mac_digest_size); - notnull_check(digest); + POSIX_ENSURE_REF(digest); - GUARD(s2n_hmac_digest(mac, digest, mac_digest_size)); - GUARD(s2n_hmac_reset(mac)); + POSIX_GUARD(s2n_hmac_digest(mac, digest, mac_digest_size)); + POSIX_GUARD(s2n_hmac_reset(mac)); /* Write content type for TLS 1.3 record (RFC 8446 Section 5.2) */ if (is_tls13_record) { - GUARD(s2n_stuffer_write_uint8(&conn->out, content_type)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->out, content_type)); } if (cipher_suite->record_alg->cipher->type == S2N_CBC) { @@ -391,30 +432,30 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s * include an extra padding length byte, also with the value 'p'. */ for (int i = 0; i <= padding; i++) { - GUARD(s2n_stuffer_write_uint8(&conn->out, padding)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->out, padding)); } } /* Rewind to rewrite/encrypt the packet */ - GUARD(s2n_stuffer_rewrite(&conn->out)); + POSIX_GUARD(s2n_stuffer_rewrite(&conn->out)); /* Skip the header */ - GUARD(s2n_stuffer_skip_write(&conn->out, S2N_TLS_RECORD_HEADER_LENGTH)); + POSIX_GUARD(s2n_stuffer_skip_write(&conn->out, S2N_TLS_RECORD_HEADER_LENGTH)); uint16_t encrypted_length = data_bytes_to_take + mac_digest_size; switch (cipher_suite->record_alg->cipher->type) { case S2N_AEAD: - GUARD(s2n_stuffer_skip_write(&conn->out, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); + POSIX_GUARD(s2n_stuffer_skip_write(&conn->out, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); encrypted_length += cipher_suite->record_alg->cipher->io.aead.tag_size; if (is_tls13_record) { /* one extra byte for content type */ - encrypted_length += TLS13_CONTENT_TYPE_LENGTH; + encrypted_length += S2N_TLS_CONTENT_TYPE_LENGTH; } break; case S2N_CBC: if (conn->actual_protocol_version > S2N_TLS10) { /* Leave the IV alone and unencrypted */ - GUARD(s2n_stuffer_skip_write(&conn->out, iv.size)); + POSIX_GUARD(s2n_stuffer_skip_write(&conn->out, iv.size)); } /* Encrypt the padding and the padding length byte too */ encrypted_length += padding + 1; @@ -434,7 +475,7 @@ int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const s /* Do the encryption */ struct s2n_blob en = { .size = encrypted_length, .data = s2n_stuffer_raw_write(&conn->out, encrypted_length) }; - GUARD(s2n_record_encrypt(conn, cipher_suite, session_key, &iv, &aad, &en, implicit_iv, block_size)); + POSIX_GUARD(s2n_record_encrypt(conn, cipher_suite, session_key, &iv, &aad, &en, implicit_iv, block_size)); if (conn->actual_protocol_version == S2N_TLS13 && content_type == TLS_CHANGE_CIPHER_SPEC) { conn->client = current_client_crypto; diff --git a/contrib/restricted/aws/s2n/tls/s2n_recv.c b/contrib/restricted/aws/s2n/tls/s2n_recv.c index 8aa34e6d06..3d0907573f 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_recv.c +++ b/contrib/restricted/aws/s2n/tls/s2n_recv.c @@ -20,7 +20,7 @@ #include <unistd.h> #include <errno.h> -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -47,12 +47,12 @@ S2N_RESULT s2n_read_in_bytes(struct s2n_connection *conn, struct s2n_stuffer *ou int r = s2n_connection_recv_stuffer(output, conn, remaining); if (r == 0) { conn->closed = 1; - BAIL(S2N_ERR_CLOSED); + RESULT_BAIL(S2N_ERR_CLOSED); } else if (r < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) { - BAIL(S2N_ERR_IO_BLOCKED); + RESULT_BAIL(S2N_ERR_IO_BLOCKED); } - BAIL(S2N_ERR_IO); + RESULT_BAIL(S2N_ERR_IO); } conn->wire_bytes_in += r; } @@ -70,10 +70,10 @@ int s2n_read_full_record(struct s2n_connection *conn, uint8_t * record_type, int *record_type = TLS_APPLICATION_DATA; return S2N_SUCCESS; } - GUARD(s2n_stuffer_resize_if_empty(&conn->in, S2N_LARGE_FRAGMENT_LENGTH)); + POSIX_GUARD(s2n_stuffer_resize_if_empty(&conn->in, S2N_LARGE_FRAGMENT_LENGTH)); /* Read the record until we at least have a header */ - GUARD_AS_POSIX(s2n_read_in_bytes(conn, &conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH)); + POSIX_GUARD_RESULT(s2n_read_in_bytes(conn, &conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH)); uint16_t fragment_length; @@ -82,28 +82,25 @@ int s2n_read_full_record(struct s2n_connection *conn, uint8_t * record_type, int conn->header_in.blob.data[0] &= 0x7f; *isSSLv2 = 1; - if (s2n_sslv2_record_header_parse(conn, record_type, &conn->client_protocol_version, &fragment_length) < 0) { - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); - } + WITH_ERROR_BLINDING(conn, POSIX_GUARD( + s2n_sslv2_record_header_parse(conn, record_type, &conn->client_protocol_version, &fragment_length))); } else { - if (s2n_record_header_parse(conn, record_type, &fragment_length) < 0) { - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); - } + WITH_ERROR_BLINDING(conn, POSIX_GUARD( + s2n_record_header_parse(conn, record_type, &fragment_length))); } /* Read enough to have the whole record */ - GUARD_AS_POSIX(s2n_read_in_bytes(conn, &conn->in, fragment_length)); + POSIX_GUARD_RESULT(s2n_read_in_bytes(conn, &conn->in, fragment_length)); if (*isSSLv2) { return 0; } /* Decrypt and parse the record */ - if (s2n_record_parse(conn) < 0) { - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); + if (s2n_early_data_is_trial_decryption_allowed(conn, *record_type)) { + POSIX_ENSURE(s2n_record_parse(conn) >= S2N_SUCCESS, S2N_ERR_EARLY_DATA_TRIAL_DECRYPT); + } else { + WITH_ERROR_BLINDING(conn, POSIX_GUARD(s2n_record_parse(conn))); } /* In TLS 1.3, encrypted handshake records would appear to be of record type @@ -111,7 +108,7 @@ int s2n_read_full_record(struct s2n_connection *conn, uint8_t * record_type, int * is decrypted. */ if (conn->actual_protocol_version == S2N_TLS13 && *record_type == TLS_APPLICATION_DATA) { - GUARD(s2n_tls13_parse_record_type(&conn->in, record_type)); + POSIX_GUARD(s2n_tls13_parse_record_type(&conn->in, record_type)); } return 0; @@ -127,7 +124,8 @@ ssize_t s2n_recv_impl(struct s2n_connection * conn, void *buf, ssize_t size, s2n } *blocked = S2N_BLOCKED_ON_READ; - S2N_ERROR_IF(conn->config->quic_enabled, S2N_ERR_UNSUPPORTED_WITH_QUIC); + POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_UNSUPPORTED_WITH_QUIC); + POSIX_GUARD_RESULT(s2n_early_data_validate_recv(conn)); while (size && !conn->closed) { int isSSLv2 = 0; @@ -163,22 +161,22 @@ ssize_t s2n_recv_impl(struct s2n_connection * conn, void *buf, ssize_t size, s2n switch (record_type) { case TLS_ALERT: - GUARD(s2n_process_alert_fragment(conn)); - GUARD(s2n_flush(conn, blocked)); + POSIX_GUARD(s2n_process_alert_fragment(conn)); + POSIX_GUARD(s2n_flush(conn, blocked)); break; case TLS_HANDSHAKE: - GUARD(s2n_post_handshake_recv(conn)); + WITH_ERROR_BLINDING(conn, POSIX_GUARD(s2n_post_handshake_recv(conn))); break; } - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; continue; } out.size = MIN(size, s2n_stuffer_data_available(&conn->in)); - GUARD(s2n_stuffer_erase_and_read(&conn->in, &out)); + POSIX_GUARD(s2n_stuffer_erase_and_read(&conn->in, &out)); bytes_read += out.size; out.data += out.size; @@ -186,8 +184,8 @@ ssize_t s2n_recv_impl(struct s2n_connection * conn, void *buf, ssize_t size, s2n /* Are we ready for more encrypted data? */ if (s2n_stuffer_data_available(&conn->in) == 0) { - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; } @@ -201,12 +199,13 @@ ssize_t s2n_recv_impl(struct s2n_connection * conn, void *buf, ssize_t size, s2n *blocked = S2N_NOT_BLOCKED; } + POSIX_GUARD_RESULT(s2n_early_data_record_bytes(conn, bytes_read)); return bytes_read; } ssize_t s2n_recv(struct s2n_connection * conn, void *buf, ssize_t size, s2n_blocked_status * blocked) { - ENSURE_POSIX(!conn->recv_in_use, S2N_ERR_REENTRANCY); + POSIX_ENSURE(!conn->recv_in_use, S2N_ERR_REENTRANCY); conn->recv_in_use = true; ssize_t result = s2n_recv_impl(conn, buf, size, blocked); conn->recv_in_use = false; @@ -223,14 +222,14 @@ int s2n_recv_close_notify(struct s2n_connection *conn, s2n_blocked_status * bloc int isSSLv2; *blocked = S2N_BLOCKED_ON_READ; - GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2)); + POSIX_GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2)); S2N_ERROR_IF(isSSLv2, S2N_ERR_BAD_MESSAGE); S2N_ERROR_IF(record_type != TLS_ALERT, S2N_ERR_SHUTDOWN_RECORD_TYPE); /* Only succeeds for an incoming close_notify alert */ - GUARD(s2n_process_alert_fragment(conn)); + POSIX_GUARD(s2n_process_alert_fragment(conn)); *blocked = S2N_NOT_BLOCKED; return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_resume.c b/contrib/restricted/aws/s2n/tls/s2n_resume.c index f4571bf042..31ba8e97a0 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_resume.c +++ b/contrib/restricted/aws/s2n/tls/s2n_resume.c @@ -13,8 +13,9 @@ * permissions and limitations under the License. */ #include <math.h> +#include <sys/param.h> -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" #include "stuffer/s2n_stuffer.h" @@ -33,128 +34,331 @@ int s2n_allowed_to_cache_connection(struct s2n_connection *conn) { /* We're unable to cache connections with a Client Cert since we currently don't serialize the Client Cert, * which means that callers won't have access to the Client's Cert if the connection is resumed. */ - if (s2n_connection_is_client_auth_enabled(conn) > 0) { + if (s2n_connection_is_client_auth_enabled(conn)) { return 0; } struct s2n_config *config = conn->config; - notnull_check(config); + POSIX_ENSURE_REF(config); return config->use_session_cache; } -static int s2n_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *to) +static int s2n_tls12_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *to) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(to); + uint64_t now; - S2N_ERROR_IF(s2n_stuffer_space_remaining(to) < S2N_STATE_SIZE_IN_BYTES, S2N_ERR_STUFFER_IS_FULL); + S2N_ERROR_IF(s2n_stuffer_space_remaining(to) < S2N_TLS12_STATE_SIZE_IN_BYTES, S2N_ERR_STUFFER_IS_FULL); /* Get the time */ - GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, &now)); + POSIX_GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, &now)); /* Write the entry */ - GUARD(s2n_stuffer_write_uint8(to, S2N_SERIALIZED_FORMAT_VERSION)); - GUARD(s2n_stuffer_write_uint8(to, conn->actual_protocol_version)); - GUARD(s2n_stuffer_write_bytes(to, conn->secure.cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); - GUARD(s2n_stuffer_write_uint64(to, now)); - GUARD(s2n_stuffer_write_bytes(to, conn->secure.master_secret, S2N_TLS_SECRET_LEN)); + POSIX_GUARD(s2n_stuffer_write_uint8(to, S2N_SERIALIZED_FORMAT_TLS12_V3)); + POSIX_GUARD(s2n_stuffer_write_uint8(to, conn->actual_protocol_version)); + POSIX_GUARD(s2n_stuffer_write_bytes(to, conn->secure.cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); + POSIX_GUARD(s2n_stuffer_write_uint64(to, now)); + POSIX_GUARD(s2n_stuffer_write_bytes(to, conn->secrets.tls12.master_secret, S2N_TLS_SECRET_LEN)); + POSIX_GUARD(s2n_stuffer_write_uint8(to, conn->ems_negotiated)); - return 0; + return S2N_SUCCESS; } -static int s2n_deserialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *from) +static S2N_RESULT s2n_tls13_serialize_keying_material_expiration(struct s2n_connection *conn, + uint64_t now, struct s2n_stuffer *out) { - uint8_t format; - uint8_t protocol_version; - uint8_t cipher_suite[S2N_TLS_CIPHER_SUITE_LEN]; + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(out); + + if (conn->mode != S2N_SERVER) { + return S2N_RESULT_OK; + } + + uint64_t expiration_timestamp = now + (conn->server_keying_material_lifetime * (uint64_t) ONE_SEC_IN_NANOS); + + struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk; + if (chosen_psk && chosen_psk->type == S2N_PSK_TYPE_RESUMPTION) { + expiration_timestamp = MIN(chosen_psk->keying_material_expiration, expiration_timestamp); + } - S2N_ERROR_IF(s2n_stuffer_data_available(from) < S2N_STATE_SIZE_IN_BYTES, S2N_ERR_STUFFER_OUT_OF_DATA); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint64(out, expiration_timestamp)); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_tls13_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(out); - GUARD(s2n_stuffer_read_uint8(from, &format)); - S2N_ERROR_IF(format != S2N_SERIALIZED_FORMAT_VERSION, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); + uint64_t current_time = 0; + struct s2n_ticket_fields *ticket_fields = &conn->tls13_ticket_fields; - GUARD(s2n_stuffer_read_uint8(from, &protocol_version)); + /* Get the time */ + RESULT_GUARD_POSIX(conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_time)); + + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, S2N_SERIALIZED_FORMAT_TLS13_V1)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, conn->actual_protocol_version)); + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(out, conn->secure.cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint64(out, current_time)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint32(out, ticket_fields->ticket_age_add)); + RESULT_ENSURE_LTE(ticket_fields->session_secret.size, UINT8_MAX); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, ticket_fields->session_secret.size)); + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(out, ticket_fields->session_secret.data, ticket_fields->session_secret.size)); + RESULT_GUARD(s2n_tls13_serialize_keying_material_expiration(conn, current_time, out)); + + uint32_t server_max_early_data = 0; + RESULT_GUARD(s2n_early_data_get_server_max_size(conn, &server_max_early_data)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint32(out, server_max_early_data)); + if (server_max_early_data > 0) { + uint8_t application_protocol_len = strlen(conn->application_protocol); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, application_protocol_len)); + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(out, (uint8_t *) conn->application_protocol, application_protocol_len)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint16(out, conn->server_early_data_context.size)); + RESULT_GUARD_POSIX(s2n_stuffer_write(out, &conn->server_early_data_context)); + } + + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + if(conn->actual_protocol_version < S2N_TLS13) { + RESULT_GUARD_POSIX(s2n_tls12_serialize_resumption_state(conn, out)); + } else { + RESULT_GUARD(s2n_tls13_serialize_resumption_state(conn, out)); + } + return S2N_RESULT_OK; +} + +static int s2n_tls12_deserialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *from) +{ + uint8_t protocol_version = 0; + uint8_t cipher_suite[S2N_TLS_CIPHER_SUITE_LEN] = { 0 }; + + S2N_ERROR_IF(s2n_stuffer_data_available(from) < S2N_TLS12_STATE_SIZE_IN_BYTES - sizeof(uint8_t), S2N_ERR_STUFFER_OUT_OF_DATA); + + POSIX_GUARD(s2n_stuffer_read_uint8(from, &protocol_version)); S2N_ERROR_IF(protocol_version != conn->actual_protocol_version, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); - GUARD(s2n_stuffer_read_bytes(from, cipher_suite, S2N_TLS_CIPHER_SUITE_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(from, cipher_suite, S2N_TLS_CIPHER_SUITE_LEN)); S2N_ERROR_IF(memcmp(conn->secure.cipher_suite->iana_value, cipher_suite, S2N_TLS_CIPHER_SUITE_LEN), S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); uint64_t now; - GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, &now)); + POSIX_GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, &now)); uint64_t then; - GUARD(s2n_stuffer_read_uint64(from, &then)); + POSIX_GUARD(s2n_stuffer_read_uint64(from, &then)); S2N_ERROR_IF(then > now, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); S2N_ERROR_IF(now - then > conn->config->session_state_lifetime_in_nanos, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); - /* Last but not least, put the master secret in place */ - GUARD(s2n_stuffer_read_bytes(from, conn->secure.master_secret, S2N_TLS_SECRET_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(from, conn->secrets.tls12.master_secret, S2N_TLS_SECRET_LEN)); + + if (s2n_stuffer_data_available(from)) { + uint8_t ems_negotiated = 0; + POSIX_GUARD(s2n_stuffer_read_uint8(from, &ems_negotiated)); + + /** + *= https://tools.ietf.org/rfc/rfc7627#section-5.3 + *# o If the original session did not use the "extended_master_secret" + *# extension but the new ClientHello contains the extension, then the + *# server MUST NOT perform the abbreviated handshake. Instead, it + *# SHOULD continue with a full handshake (as described in + *# Section 5.2) to negotiate a new session. + *# + *# o If the original session used the "extended_master_secret" + *# extension but the new ClientHello does not contain it, the server + *# MUST abort the abbreviated handshake. + **/ + if (conn->ems_negotiated != ems_negotiated) { + /* The session ticket needs to have the same EMS state as the current session. If it doesn't + * have the same state, the current session takes the state of the session ticket and errors. + * If the deserialization process errors, we will use this state in a few extra checks + * to determine if we can fallback to a full handshake. + */ + conn->ems_negotiated = ems_negotiated; + POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); + } + } - return 0; + return S2N_SUCCESS; } static int s2n_client_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *to) { /* Serialize session ticket */ if (conn->config->use_tickets && conn->client_ticket.size > 0) { - GUARD(s2n_stuffer_write_uint8(to, S2N_STATE_WITH_SESSION_TICKET)); - GUARD(s2n_stuffer_write_uint16(to, conn->client_ticket.size)); - GUARD(s2n_stuffer_write(to, &conn->client_ticket)); + POSIX_GUARD(s2n_stuffer_write_uint8(to, S2N_STATE_WITH_SESSION_TICKET)); + POSIX_GUARD(s2n_stuffer_write_uint16(to, conn->client_ticket.size)); + POSIX_GUARD(s2n_stuffer_write(to, &conn->client_ticket)); } else { /* Serialize session id */ - GUARD(s2n_stuffer_write_uint8(to, S2N_STATE_WITH_SESSION_ID)); - GUARD(s2n_stuffer_write_uint8(to, conn->session_id_len)); - GUARD(s2n_stuffer_write_bytes(to, conn->session_id, conn->session_id_len)); + POSIX_ENSURE_LT(conn->actual_protocol_version, S2N_TLS13); + POSIX_GUARD(s2n_stuffer_write_uint8(to, S2N_STATE_WITH_SESSION_ID)); + POSIX_GUARD(s2n_stuffer_write_uint8(to, conn->session_id_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(to, conn->session_id, conn->session_id_len)); } /* Serialize session state */ - GUARD(s2n_serialize_resumption_state(conn, to)); + POSIX_GUARD_RESULT(s2n_serialize_resumption_state(conn, to)); return 0; } -static int s2n_client_deserialize_session_state(struct s2n_connection *conn, struct s2n_stuffer *from) -{ - if (s2n_stuffer_data_available(from) < S2N_STATE_SIZE_IN_BYTES) { - S2N_ERROR(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); +static S2N_RESULT s2n_tls12_client_deserialize_session_state(struct s2n_connection *conn, struct s2n_stuffer *from) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(from); + + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &conn->actual_protocol_version)); + + uint8_t *cipher_suite_wire = s2n_stuffer_raw_read(from, S2N_TLS_CIPHER_SUITE_LEN); + RESULT_ENSURE_REF(cipher_suite_wire); + RESULT_GUARD_POSIX(s2n_set_cipher_as_client(conn, cipher_suite_wire)); + + uint64_t then = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint64(from, &then)); + + RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(from, conn->secrets.tls12.master_secret, S2N_TLS_SECRET_LEN)); + + if (s2n_stuffer_data_available(from)) { + uint8_t ems_negotiated = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &ems_negotiated)); + conn->ems_negotiated = ems_negotiated; } + return S2N_RESULT_OK; +} - uint8_t format; - uint64_t then; +static S2N_RESULT s2n_validate_ticket_age(uint64_t current_time, uint64_t ticket_issue_time) +{ + RESULT_ENSURE(current_time >= ticket_issue_time, S2N_ERR_INVALID_SESSION_TICKET); + uint64_t ticket_age_in_nanos = current_time - ticket_issue_time; + uint64_t ticket_age_in_sec = ticket_age_in_nanos / ONE_SEC_IN_NANOS; + RESULT_ENSURE(ticket_age_in_sec <= ONE_WEEK_IN_SEC, S2N_ERR_INVALID_SESSION_TICKET); + return S2N_RESULT_OK; +} - GUARD(s2n_stuffer_read_uint8(from, &format)); - if (format != S2N_SERIALIZED_FORMAT_VERSION) { - S2N_ERROR(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); +static S2N_RESULT s2n_tls13_deserialize_session_state(struct s2n_connection *conn, struct s2n_blob *psk_identity, struct s2n_stuffer *from) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(psk_identity); + RESULT_ENSURE_REF(from); + + DEFER_CLEANUP(struct s2n_psk psk = { 0 }, s2n_psk_wipe); + RESULT_GUARD(s2n_psk_init(&psk, S2N_PSK_TYPE_RESUMPTION)); + RESULT_GUARD_POSIX(s2n_psk_set_identity(&psk, psk_identity->data, psk_identity->size)); + + uint8_t protocol_version = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &protocol_version)); + RESULT_ENSURE_GTE(protocol_version, S2N_TLS13); + + uint8_t iana_id[S2N_TLS_CIPHER_SUITE_LEN] = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(from, iana_id, S2N_TLS_CIPHER_SUITE_LEN)); + struct s2n_cipher_suite *cipher_suite = NULL; + RESULT_GUARD(s2n_cipher_suite_from_iana(iana_id, &cipher_suite)); + RESULT_ENSURE_REF(cipher_suite); + psk.hmac_alg = cipher_suite->prf_alg; + + RESULT_GUARD_POSIX(s2n_stuffer_read_uint64(from, &psk.ticket_issue_time)); + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# Clients MUST NOT cache + *# tickets for longer than 7 days, regardless of the ticket_lifetime, + *# and MAY delete tickets earlier based on local policy. + */ + uint64_t current_time = 0; + RESULT_GUARD_POSIX(conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_time)); + RESULT_GUARD(s2n_validate_ticket_age(current_time, psk.ticket_issue_time)); + + RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(from, &psk.ticket_age_add)); + + uint8_t secret_len = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &secret_len)); + RESULT_ENSURE_LTE(secret_len, S2N_TLS_SECRET_LEN); + uint8_t *secret_data = s2n_stuffer_raw_read(from, secret_len); + RESULT_ENSURE_REF(secret_data); + RESULT_GUARD_POSIX(s2n_psk_set_secret(&psk, secret_data, secret_len)); + + if (conn->mode == S2N_SERVER) { + RESULT_GUARD_POSIX(s2n_stuffer_read_uint64(from, &psk.keying_material_expiration)); + RESULT_ENSURE(psk.keying_material_expiration > current_time, S2N_ERR_KEYING_MATERIAL_EXPIRED); } - GUARD(s2n_stuffer_read_uint8(from, &conn->actual_protocol_version)); + uint32_t max_early_data_size = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(from, &max_early_data_size)); + if (max_early_data_size > 0) { + RESULT_GUARD_POSIX(s2n_psk_configure_early_data(&psk, max_early_data_size, + iana_id[0], iana_id[1])); + + uint8_t app_proto_size = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &app_proto_size)); + uint8_t *app_proto_data = s2n_stuffer_raw_read(from, app_proto_size); + RESULT_ENSURE_REF(app_proto_data); + RESULT_GUARD_POSIX(s2n_psk_set_application_protocol(&psk, app_proto_data, app_proto_size)); + + uint16_t early_data_context_size = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(from, &early_data_context_size)); + uint8_t *early_data_context_data = s2n_stuffer_raw_read(from, early_data_context_size); + RESULT_ENSURE_REF(early_data_context_data); + RESULT_GUARD_POSIX(s2n_psk_set_early_data_context(&psk, early_data_context_data, early_data_context_size)); + } - uint8_t *cipher_suite_wire = s2n_stuffer_raw_read(from, S2N_TLS_CIPHER_SUITE_LEN); - notnull_check(cipher_suite_wire); - GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); + /* Make sure that this connection is configured for resumption PSKs, not external PSKs */ + RESULT_GUARD(s2n_connection_set_psk_type(conn, S2N_PSK_TYPE_RESUMPTION)); + /* Remove all previously-set PSKs. To keep the session ticket API behavior consistent + * across protocol versions, we currently only support setting a single resumption PSK. */ + RESULT_GUARD(s2n_psk_parameters_wipe(&conn->psk_params)); + RESULT_GUARD_POSIX(s2n_connection_append_psk(conn, &psk)); - GUARD(s2n_stuffer_read_uint64(from, &then)); + return S2N_RESULT_OK; +} - /* Last but not least, put the master secret in place */ - GUARD(s2n_stuffer_read_bytes(from, conn->secure.master_secret, S2N_TLS_SECRET_LEN)); +static S2N_RESULT s2n_deserialize_resumption_state(struct s2n_connection *conn, struct s2n_blob *psk_identity, struct s2n_stuffer *from) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(from); - return 0; + uint8_t format = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &format)); + + if (format == S2N_SERIALIZED_FORMAT_TLS12_V3) { + if (conn->mode == S2N_SERVER) { + RESULT_GUARD_POSIX(s2n_tls12_deserialize_resumption_state(conn, from)); + } else { + RESULT_GUARD(s2n_tls12_client_deserialize_session_state(conn, from)); + } + } else if (format == S2N_SERIALIZED_FORMAT_TLS13_V1) { + RESULT_GUARD(s2n_tls13_deserialize_session_state(conn, psk_identity, from)); + if (conn->mode == S2N_CLIENT) { + /* Free the client_ticket after setting a psk on the connection. + * This prevents s2n_connection_get_session from returning a TLS1.3 + * ticket before a ticket has been received from the server. */ + RESULT_GUARD_POSIX(s2n_free(&conn->client_ticket)); + } + } else { + RESULT_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); + } + conn->set_session = true; + return S2N_RESULT_OK; } static int s2n_client_deserialize_with_session_id(struct s2n_connection *conn, struct s2n_stuffer *from) { uint8_t session_id_len; - GUARD(s2n_stuffer_read_uint8(from, &session_id_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(from, &session_id_len)); if (session_id_len == 0 || session_id_len > S2N_TLS_SESSION_ID_MAX_LEN || session_id_len > s2n_stuffer_data_available(from)) { - S2N_ERROR(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); + POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); } conn->session_id_len = session_id_len; - GUARD(s2n_stuffer_read_bytes(from, conn->session_id, session_id_len)); + POSIX_GUARD(s2n_stuffer_read_bytes(from, conn->session_id, session_id_len)); - GUARD(s2n_client_deserialize_session_state(conn, from)); + POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, NULL, from)); return 0; } @@ -162,16 +366,16 @@ static int s2n_client_deserialize_with_session_id(struct s2n_connection *conn, s static int s2n_client_deserialize_with_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *from) { uint16_t session_ticket_len; - GUARD(s2n_stuffer_read_uint16(from, &session_ticket_len)); + POSIX_GUARD(s2n_stuffer_read_uint16(from, &session_ticket_len)); if (session_ticket_len == 0 || session_ticket_len > s2n_stuffer_data_available(from)) { - S2N_ERROR(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); + POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); } - GUARD(s2n_realloc(&conn->client_ticket, session_ticket_len)); - GUARD(s2n_stuffer_read(from, &conn->client_ticket)); + POSIX_GUARD(s2n_realloc(&conn->client_ticket, session_ticket_len)); + POSIX_GUARD(s2n_stuffer_read(from, &conn->client_ticket)); - GUARD(s2n_client_deserialize_session_state(conn, from)); + POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, &conn->client_ticket, from)); return 0; } @@ -179,17 +383,17 @@ static int s2n_client_deserialize_with_session_ticket(struct s2n_connection *con static int s2n_client_deserialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *from) { uint8_t format; - GUARD(s2n_stuffer_read_uint8(from, &format)); + POSIX_GUARD(s2n_stuffer_read_uint8(from, &format)); switch (format) { case S2N_STATE_WITH_SESSION_ID: - GUARD(s2n_client_deserialize_with_session_id(conn, from)); + POSIX_GUARD(s2n_client_deserialize_with_session_id(conn, from)); break; case S2N_STATE_WITH_SESSION_TICKET: - GUARD(s2n_client_deserialize_with_session_ticket(conn, from)); + POSIX_GUARD(s2n_client_deserialize_with_session_ticket(conn, from)); break; default: - S2N_ERROR(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); + POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE); } return 0; @@ -200,67 +404,67 @@ int s2n_resume_from_cache(struct s2n_connection *conn) S2N_ERROR_IF(conn->session_id_len == 0, S2N_ERR_SESSION_ID_TOO_SHORT); S2N_ERROR_IF(conn->session_id_len > S2N_TLS_SESSION_ID_MAX_LEN, S2N_ERR_SESSION_ID_TOO_LONG); - uint8_t data[S2N_TICKET_SIZE_IN_BYTES] = { 0 }; + uint8_t data[S2N_TLS12_TICKET_SIZE_IN_BYTES] = { 0 }; struct s2n_blob entry = {0}; - GUARD(s2n_blob_init(&entry, data, S2N_TICKET_SIZE_IN_BYTES)); + POSIX_GUARD(s2n_blob_init(&entry, data, S2N_TLS12_TICKET_SIZE_IN_BYTES)); uint64_t size = entry.size; int result = conn->config->cache_retrieve(conn, conn->config->cache_retrieve_data, conn->session_id, conn->session_id_len, entry.data, &size); if (result == S2N_CALLBACK_BLOCKED) { - S2N_ERROR(S2N_ERR_ASYNC_BLOCKED); + POSIX_BAIL(S2N_ERR_ASYNC_BLOCKED); } - GUARD(result); + POSIX_GUARD(result); S2N_ERROR_IF(size != entry.size, S2N_ERR_SIZE_MISMATCH); struct s2n_stuffer from = {0}; - GUARD(s2n_stuffer_init(&from, &entry)); - GUARD(s2n_stuffer_write(&from, &entry)); - GUARD(s2n_decrypt_session_cache(conn, &from)); + POSIX_GUARD(s2n_stuffer_init(&from, &entry)); + POSIX_GUARD(s2n_stuffer_write(&from, &entry)); + POSIX_GUARD(s2n_decrypt_session_cache(conn, &from)); return 0; } -int s2n_store_to_cache(struct s2n_connection *conn) +S2N_RESULT s2n_store_to_cache(struct s2n_connection *conn) { - uint8_t data[S2N_TICKET_SIZE_IN_BYTES] = { 0 }; + uint8_t data[S2N_TLS12_TICKET_SIZE_IN_BYTES] = { 0 }; struct s2n_blob entry = {0}; - GUARD(s2n_blob_init(&entry, data, S2N_TICKET_SIZE_IN_BYTES)); + RESULT_GUARD_POSIX(s2n_blob_init(&entry, data, S2N_TLS12_TICKET_SIZE_IN_BYTES)); struct s2n_stuffer to = {0}; /* session_id_len should always be >0 since either the Client provided a SessionId or the Server generated a new * one for the Client */ - S2N_ERROR_IF(conn->session_id_len == 0, S2N_ERR_SESSION_ID_TOO_SHORT); - S2N_ERROR_IF(conn->session_id_len > S2N_TLS_SESSION_ID_MAX_LEN, S2N_ERR_SESSION_ID_TOO_LONG); + RESULT_ENSURE(conn->session_id_len > 0, S2N_ERR_SESSION_ID_TOO_SHORT); + RESULT_ENSURE(conn->session_id_len <= S2N_TLS_SESSION_ID_MAX_LEN, S2N_ERR_SESSION_ID_TOO_LONG); - GUARD(s2n_stuffer_init(&to, &entry)); - GUARD(s2n_encrypt_session_cache(conn, &to)); + RESULT_GUARD_POSIX(s2n_stuffer_init(&to, &entry)); + RESULT_GUARD_POSIX(s2n_encrypt_session_cache(conn, &to)); /* Store to the cache */ conn->config->cache_store(conn, conn->config->cache_store_data, S2N_TLS_SESSION_CACHE_TTL, conn->session_id, conn->session_id_len, entry.data, entry.size); - return 0; + return S2N_RESULT_OK; } int s2n_connection_set_session(struct s2n_connection *conn, const uint8_t *session, size_t length) { - notnull_check(conn); - notnull_check(session); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(session); DEFER_CLEANUP(struct s2n_blob session_data = {0}, s2n_free); - GUARD(s2n_alloc(&session_data, length)); - memcpy(session_data.data, session, length); + POSIX_GUARD(s2n_alloc(&session_data, length)); + POSIX_CHECKED_MEMCPY(session_data.data, session, length); struct s2n_stuffer from = {0}; - GUARD(s2n_stuffer_init(&from, &session_data)); - GUARD(s2n_stuffer_write(&from, &session_data)); - GUARD(s2n_client_deserialize_resumption_state(conn, &from)); + POSIX_GUARD(s2n_stuffer_init(&from, &session_data)); + POSIX_GUARD(s2n_stuffer_write(&from, &session_data)); + POSIX_GUARD(s2n_client_deserialize_resumption_state(conn, &from)); return 0; } int s2n_connection_get_session(struct s2n_connection *conn, uint8_t *session, size_t max_length) { - notnull_check(conn); - notnull_check(session); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(session); int len = s2n_connection_get_session_length(conn); @@ -271,52 +475,93 @@ int s2n_connection_get_session(struct s2n_connection *conn, uint8_t *session, si S2N_ERROR_IF(len > max_length, S2N_ERR_SERIALIZED_SESSION_STATE_TOO_LONG); struct s2n_blob serialized_data = {0}; - GUARD(s2n_blob_init(&serialized_data, session, len)); - GUARD(s2n_blob_zero(&serialized_data)); + POSIX_GUARD(s2n_blob_init(&serialized_data, session, len)); + POSIX_GUARD(s2n_blob_zero(&serialized_data)); struct s2n_stuffer to = {0}; - GUARD(s2n_stuffer_init(&to, &serialized_data)); - GUARD(s2n_client_serialize_resumption_state(conn, &to)); + POSIX_GUARD(s2n_stuffer_init(&to, &serialized_data)); + POSIX_GUARD(s2n_client_serialize_resumption_state(conn, &to)); return len; } int s2n_connection_get_session_ticket_lifetime_hint(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); S2N_ERROR_IF(!(conn->config->use_tickets && conn->client_ticket.size > 0), S2N_ERR_SESSION_TICKET_NOT_SUPPORTED); /* Session resumption using session ticket */ return conn->ticket_lifetime_hint; } -int s2n_connection_get_session_length(struct s2n_connection *conn) +S2N_RESULT s2n_connection_get_session_state_size(struct s2n_connection *conn, size_t *state_size) { - /* Session resumption using session ticket "format (1) + session_ticket_len + session_ticket + session state" */ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(state_size); + + if (conn->actual_protocol_version < S2N_TLS13) { + *state_size = S2N_TLS12_STATE_SIZE_IN_BYTES; + return S2N_RESULT_OK; + } + + *state_size = S2N_TLS13_FIXED_STATE_SIZE; + + uint8_t secret_size = 0; + RESULT_ENSURE_REF(conn->secure.cipher_suite); + RESULT_GUARD_POSIX(s2n_hmac_digest_size(conn->secure.cipher_suite->prf_alg, &secret_size)); + *state_size += secret_size; + + uint32_t server_max_early_data = 0; + RESULT_GUARD(s2n_early_data_get_server_max_size(conn, &server_max_early_data)); + if (server_max_early_data > 0) { + *state_size += S2N_TLS13_FIXED_EARLY_DATA_STATE_SIZE + + strlen(conn->application_protocol) + + conn->server_early_data_context.size; + } + + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_connection_get_session_length_impl(struct s2n_connection *conn, size_t *length) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(conn->config); + RESULT_ENSURE_REF(length); + *length = 0; + if (conn->config->use_tickets && conn->client_ticket.size > 0) { - return S2N_STATE_FORMAT_LEN + S2N_SESSION_TICKET_SIZE_LEN + conn->client_ticket.size + S2N_STATE_SIZE_IN_BYTES; - } else if (conn->session_id_len > 0) { - /* Session resumption using session id: "format (0) + session_id_len + session_id + session state" */ - return S2N_STATE_FORMAT_LEN + 1 + conn->session_id_len + S2N_STATE_SIZE_IN_BYTES; - } else { - return 0; + size_t session_state_size = 0; + RESULT_GUARD(s2n_connection_get_session_state_size(conn, &session_state_size)); + *length = S2N_STATE_FORMAT_LEN + S2N_SESSION_TICKET_SIZE_LEN + conn->client_ticket.size + session_state_size; + } else if (conn->session_id_len > 0 && conn->actual_protocol_version < S2N_TLS13) { + *length = S2N_STATE_FORMAT_LEN + sizeof(conn->session_id_len) + conn->session_id_len + S2N_TLS12_STATE_SIZE_IN_BYTES; } + return S2N_RESULT_OK; +} + +int s2n_connection_get_session_length(struct s2n_connection *conn) +{ + size_t length = 0; + if (s2n_result_is_ok(s2n_connection_get_session_length_impl(conn, &length))) { + return length; + } + return 0; } int s2n_connection_is_session_resumed(struct s2n_connection *conn) { - notnull_check(conn); - return IS_RESUMPTION_HANDSHAKE(conn->handshake.handshake_type) ? 1 : 0; + return conn && IS_RESUMPTION_HANDSHAKE(conn) + && (conn->actual_protocol_version < S2N_TLS13 || conn->psk_params.type == S2N_PSK_TYPE_RESUMPTION); } int s2n_connection_is_ocsp_stapled(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); if (conn->actual_protocol_version >= S2N_TLS13) { return (s2n_server_can_send_ocsp(conn) || s2n_server_sent_ocsp(conn)); } else { - return IS_OCSP_STAPLED(conn->handshake.handshake_type); + return IS_OCSP_STAPLED(conn); } } @@ -324,15 +569,15 @@ int s2n_config_is_encrypt_decrypt_key_available(struct s2n_config *config) { uint64_t now; struct s2n_ticket_key *ticket_key = NULL; - GUARD(config->wall_clock(config->sys_clock_ctx, &now)); - notnull_check(config->ticket_keys); + POSIX_GUARD(config->wall_clock(config->sys_clock_ctx, &now)); + POSIX_ENSURE_REF(config->ticket_keys); uint32_t ticket_keys_len = 0; - GUARD_AS_POSIX(s2n_set_len(config->ticket_keys, &ticket_keys_len)); + POSIX_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len)); for (uint32_t i = ticket_keys_len; i > 0; i--) { uint32_t idx = i - 1; - GUARD_AS_POSIX(s2n_set_get(config->ticket_keys, idx, (void **)&ticket_key)); + POSIX_GUARD_RESULT(s2n_set_get(config->ticket_keys, idx, (void **)&ticket_key)); uint64_t key_intro_time = ticket_key->intro_timestamp; if (key_intro_time < now @@ -359,7 +604,7 @@ int s2n_compute_weight_of_encrypt_decrypt_keys(struct s2n_config *config, /* Compute weight of encrypt-decrypt keys */ for (int i = 0; i < num_encrypt_decrypt_keys; i++) { - GUARD_AS_POSIX(s2n_set_get(config->ticket_keys, encrypt_decrypt_keys_index[i], (void **)&ticket_key)); + POSIX_GUARD_RESULT(s2n_set_get(config->ticket_keys, encrypt_decrypt_keys_index[i], (void **)&ticket_key)); uint64_t key_intro_time = ticket_key->intro_timestamp; uint64_t key_encryption_peak_time = key_intro_time + (config->encrypt_decrypt_key_lifetime_in_nanos / 2); @@ -378,7 +623,7 @@ int s2n_compute_weight_of_encrypt_decrypt_keys(struct s2n_config *config, /* Pick a random number in [0, 1). Using 53 bits (IEEE 754 double-precision floats). */ uint64_t random_int = 0; - GUARD_AS_POSIX(s2n_public_random(pow(2, 53), &random_int)); + POSIX_GUARD_RESULT(s2n_public_random(pow(2, 53), &random_int)); double random = (double)random_int / (double)pow(2, 53); /* Compute cumulative weight of encrypt-decrypt keys */ @@ -394,7 +639,7 @@ int s2n_compute_weight_of_encrypt_decrypt_keys(struct s2n_config *config, } } - S2N_ERROR(S2N_ERR_ENCRYPT_DECRYPT_KEY_SELECTION_FAILED); + POSIX_BAIL(S2N_ERR_ENCRYPT_DECRYPT_KEY_SELECTION_FAILED); } /* This function is used in s2n_encrypt_session_ticket in order for s2n to @@ -407,15 +652,15 @@ struct s2n_ticket_key *s2n_get_ticket_encrypt_decrypt_key(struct s2n_config *con struct s2n_ticket_key *ticket_key = NULL; uint64_t now; - GUARD_PTR(config->wall_clock(config->sys_clock_ctx, &now)); - notnull_check_ptr(config->ticket_keys); + PTR_GUARD_POSIX(config->wall_clock(config->sys_clock_ctx, &now)); + PTR_ENSURE_REF(config->ticket_keys); uint32_t ticket_keys_len = 0; - GUARD_RESULT_PTR(s2n_set_len(config->ticket_keys, &ticket_keys_len)); + PTR_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len)); for (uint32_t i = ticket_keys_len; i > 0; i--) { uint32_t idx = i - 1; - GUARD_RESULT_PTR(s2n_set_get(config->ticket_keys, idx, (void **)&ticket_key)); + PTR_GUARD_RESULT(s2n_set_get(config->ticket_keys, idx, (void **)&ticket_key)); uint64_t key_intro_time = ticket_key->intro_timestamp; if (key_intro_time < now @@ -426,18 +671,18 @@ struct s2n_ticket_key *s2n_get_ticket_encrypt_decrypt_key(struct s2n_config *con } if (num_encrypt_decrypt_keys == 0) { - S2N_ERROR_PTR(S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY); + PTR_BAIL(S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY); } if (num_encrypt_decrypt_keys == 1) { - GUARD_RESULT_PTR(s2n_set_get(config->ticket_keys, encrypt_decrypt_keys_index[0], (void **)&ticket_key)); + PTR_GUARD_RESULT(s2n_set_get(config->ticket_keys, encrypt_decrypt_keys_index[0], (void **)&ticket_key)); return ticket_key; } int8_t idx; - GUARD_PTR(idx = s2n_compute_weight_of_encrypt_decrypt_keys(config, encrypt_decrypt_keys_index, num_encrypt_decrypt_keys, now)); + PTR_GUARD_POSIX(idx = s2n_compute_weight_of_encrypt_decrypt_keys(config, encrypt_decrypt_keys_index, num_encrypt_decrypt_keys, now)); - GUARD_RESULT_PTR(s2n_set_get(config->ticket_keys, idx, (void **)&ticket_key)); + PTR_GUARD_RESULT(s2n_set_get(config->ticket_keys, idx, (void **)&ticket_key)); return ticket_key; } @@ -448,14 +693,14 @@ struct s2n_ticket_key *s2n_find_ticket_key(struct s2n_config *config, const uint { uint64_t now; struct s2n_ticket_key *ticket_key = NULL; - GUARD_PTR(config->wall_clock(config->sys_clock_ctx, &now)); - notnull_check_ptr(config->ticket_keys); + PTR_GUARD_POSIX(config->wall_clock(config->sys_clock_ctx, &now)); + PTR_ENSURE_REF(config->ticket_keys); uint32_t ticket_keys_len = 0; - GUARD_RESULT_PTR(s2n_set_len(config->ticket_keys, &ticket_keys_len)); + PTR_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len)); for (uint32_t i = 0; i < ticket_keys_len; i++) { - GUARD_RESULT_PTR(s2n_set_get(config->ticket_keys, i, (void **)&ticket_key)); + PTR_GUARD_RESULT(s2n_set_get(config->ticket_keys, i, (void **)&ticket_key)); if (memcmp(ticket_key->key_name, name, S2N_TICKET_KEY_NAME_LEN) == 0) { @@ -482,107 +727,104 @@ int s2n_encrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer * uint8_t iv_data[S2N_TLS_GCM_IV_LEN] = { 0 }; struct s2n_blob iv = {0}; - GUARD(s2n_blob_init(&iv, iv_data, sizeof(iv_data))); + POSIX_GUARD(s2n_blob_init(&iv, iv_data, sizeof(iv_data))); uint8_t aad_data[S2N_TICKET_AAD_LEN] = { 0 }; struct s2n_blob aad_blob = {0}; - GUARD(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data))); + POSIX_GUARD(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data))); struct s2n_stuffer aad = {0}; - uint8_t s_data[S2N_STATE_SIZE_IN_BYTES + S2N_TLS_GCM_TAG_LEN] = { 0 }; - struct s2n_blob state_blob = {0}; - GUARD(s2n_blob_init(&state_blob, s_data, sizeof(s_data))); - struct s2n_stuffer state = {0}; - key = s2n_get_ticket_encrypt_decrypt_key(conn->config); /* No keys loaded by the user or the keys are either in decrypt-only or expired state */ S2N_ERROR_IF(!key, S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY); - GUARD(s2n_stuffer_write_bytes(to, key->key_name, S2N_TICKET_KEY_NAME_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(to, key->key_name, S2N_TICKET_KEY_NAME_LEN)); - GUARD_AS_POSIX(s2n_get_public_random_data(&iv)); - GUARD(s2n_stuffer_write(to, &iv)); + POSIX_GUARD_RESULT(s2n_get_public_random_data(&iv)); + POSIX_GUARD(s2n_stuffer_write(to, &iv)); - GUARD(s2n_blob_init(&aes_key_blob, key->aes_key, S2N_AES256_KEY_LEN)); - GUARD(s2n_session_key_alloc(&aes_ticket_key)); - GUARD(s2n_aes256_gcm.init(&aes_ticket_key)); - GUARD(s2n_aes256_gcm.set_encryption_key(&aes_ticket_key, &aes_key_blob)); + POSIX_GUARD(s2n_blob_init(&aes_key_blob, key->aes_key, S2N_AES256_KEY_LEN)); + POSIX_GUARD(s2n_session_key_alloc(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.init(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.set_encryption_key(&aes_ticket_key, &aes_key_blob)); - GUARD(s2n_stuffer_init(&aad, &aad_blob)); - GUARD(s2n_stuffer_write_bytes(&aad, key->implicit_aad, S2N_TICKET_AAD_IMPLICIT_LEN)); - GUARD(s2n_stuffer_write_bytes(&aad, key->key_name, S2N_TICKET_KEY_NAME_LEN)); + POSIX_GUARD(s2n_stuffer_init(&aad, &aad_blob)); + POSIX_GUARD(s2n_stuffer_write_bytes(&aad, key->implicit_aad, S2N_TICKET_AAD_IMPLICIT_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&aad, key->key_name, S2N_TICKET_KEY_NAME_LEN)); - GUARD(s2n_stuffer_init(&state, &state_blob)); - GUARD(s2n_serialize_resumption_state(conn, &state)); + uint32_t plaintext_header_size = s2n_stuffer_data_available(to); + POSIX_GUARD_RESULT(s2n_serialize_resumption_state(conn, to)); + POSIX_GUARD(s2n_stuffer_skip_write(to, S2N_TLS_GCM_TAG_LEN)); - GUARD(s2n_aes256_gcm.io.aead.encrypt(&aes_ticket_key, &iv, &aad_blob, &state_blob, &state_blob)); + struct s2n_blob state_blob = { 0 }; + struct s2n_stuffer copy_for_encryption = *to; + POSIX_GUARD(s2n_stuffer_skip_read(©_for_encryption, plaintext_header_size)); + uint32_t state_blob_size = s2n_stuffer_data_available(©_for_encryption); + uint8_t *state_blob_data = s2n_stuffer_raw_read(©_for_encryption, state_blob_size); + POSIX_ENSURE_REF(state_blob_data); + POSIX_GUARD(s2n_blob_init(&state_blob, state_blob_data, state_blob_size)); - GUARD(s2n_stuffer_write(to, &state_blob)); + POSIX_GUARD(s2n_aes256_gcm.io.aead.encrypt(&aes_ticket_key, &iv, &aad_blob, &state_blob, &state_blob)); - GUARD(s2n_aes256_gcm.destroy_key(&aes_ticket_key)); - GUARD(s2n_session_key_free(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.destroy_key(&aes_ticket_key)); + POSIX_GUARD(s2n_session_key_free(&aes_ticket_key)); return 0; } -int s2n_decrypt_session_ticket(struct s2n_connection *conn) +int s2n_decrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *from) { struct s2n_ticket_key *key; DEFER_CLEANUP(struct s2n_session_key aes_ticket_key = {0}, s2n_session_key_free); struct s2n_blob aes_key_blob = {0}; - struct s2n_stuffer *from; uint8_t key_name[S2N_TICKET_KEY_NAME_LEN]; uint8_t iv_data[S2N_TLS_GCM_IV_LEN] = { 0 }; struct s2n_blob iv = { 0 }; - GUARD(s2n_blob_init(&iv, iv_data, sizeof(iv_data))); + POSIX_GUARD(s2n_blob_init(&iv, iv_data, sizeof(iv_data))); uint8_t aad_data[S2N_TICKET_AAD_LEN] = { 0 }; struct s2n_blob aad_blob = {0}; - GUARD(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data))); + POSIX_GUARD(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data))); struct s2n_stuffer aad = {0}; - uint8_t s_data[S2N_STATE_SIZE_IN_BYTES] = { 0 }; - struct s2n_blob state_blob = {0}; - GUARD(s2n_blob_init(&state_blob, s_data, sizeof(s_data))); - struct s2n_stuffer state = {0}; - - uint8_t en_data[S2N_STATE_SIZE_IN_BYTES + S2N_TLS_GCM_TAG_LEN] = {0}; - struct s2n_blob en_blob = {0}; - GUARD(s2n_blob_init(&en_blob, en_data, sizeof(en_data))); - - from = &conn->client_ticket_to_decrypt; - GUARD(s2n_stuffer_read_bytes(from, key_name, S2N_TICKET_KEY_NAME_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(from, key_name, S2N_TICKET_KEY_NAME_LEN)); key = s2n_find_ticket_key(conn->config, key_name); /* Key has expired; do full handshake with New Session Ticket (NST) */ S2N_ERROR_IF(!key, S2N_ERR_KEY_USED_IN_SESSION_TICKET_NOT_FOUND); - GUARD(s2n_stuffer_read(from, &iv)); + POSIX_GUARD(s2n_stuffer_read(from, &iv)); s2n_blob_init(&aes_key_blob, key->aes_key, S2N_AES256_KEY_LEN); - GUARD(s2n_session_key_alloc(&aes_ticket_key)); - GUARD(s2n_aes256_gcm.init(&aes_ticket_key)); - GUARD(s2n_aes256_gcm.set_decryption_key(&aes_ticket_key, &aes_key_blob)); - - GUARD(s2n_stuffer_init(&aad, &aad_blob)); - GUARD(s2n_stuffer_write_bytes(&aad, key->implicit_aad, S2N_TICKET_AAD_IMPLICIT_LEN)); - GUARD(s2n_stuffer_write_bytes(&aad, key->key_name, S2N_TICKET_KEY_NAME_LEN)); - - GUARD(s2n_stuffer_read(from, &en_blob)); - - GUARD(s2n_aes256_gcm.io.aead.decrypt(&aes_ticket_key, &iv, &aad_blob, &en_blob, &en_blob)); - - GUARD(s2n_stuffer_init(&state, &state_blob)); - GUARD(s2n_stuffer_write_bytes(&state, en_data, S2N_STATE_SIZE_IN_BYTES)); - - GUARD(s2n_deserialize_resumption_state(conn, &state)); + POSIX_GUARD(s2n_session_key_alloc(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.init(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.set_decryption_key(&aes_ticket_key, &aes_key_blob)); + + POSIX_GUARD(s2n_stuffer_init(&aad, &aad_blob)); + POSIX_GUARD(s2n_stuffer_write_bytes(&aad, key->implicit_aad, S2N_TICKET_AAD_IMPLICIT_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&aad, key->key_name, S2N_TICKET_KEY_NAME_LEN)); + + struct s2n_blob en_blob = { 0 }; + uint32_t en_blob_size = s2n_stuffer_data_available(from); + uint8_t *en_blob_data = s2n_stuffer_raw_read(from, en_blob_size); + POSIX_ENSURE_REF(en_blob_data); + POSIX_GUARD(s2n_blob_init(&en_blob, en_blob_data, en_blob_size)); + POSIX_GUARD(s2n_aes256_gcm.io.aead.decrypt(&aes_ticket_key, &iv, &aad_blob, &en_blob, &en_blob)); + + struct s2n_blob state_blob = { 0 }; + uint32_t state_blob_size = en_blob_size - S2N_TLS_GCM_TAG_LEN; + POSIX_GUARD(s2n_blob_init(&state_blob, en_blob.data, state_blob_size)); + struct s2n_stuffer state_stuffer = { 0 }; + POSIX_GUARD(s2n_stuffer_init(&state_stuffer, &state_blob)); + POSIX_GUARD(s2n_stuffer_skip_write(&state_stuffer, state_blob_size)); + POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, &from->blob, &state_stuffer)); uint64_t now; - GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, &now)); + POSIX_GUARD(conn->config->wall_clock(conn->config->sys_clock_ctx, &now)); /* If the key is in decrypt-only state, then a new key is assigned * for the ticket. @@ -591,13 +833,11 @@ int s2n_decrypt_session_ticket(struct s2n_connection *conn) /* Check if a key in encrypt-decrypt state is available */ if (s2n_config_is_encrypt_decrypt_key_available(conn->config) == 1) { conn->session_ticket_status = S2N_NEW_TICKET; - conn->handshake.handshake_type |= WITH_SESSION_TICKET; - - return 0; + POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, WITH_SESSION_TICKET)); + return S2N_SUCCESS; } } - - return 0; + return S2N_SUCCESS; } int s2n_encrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *to) @@ -605,7 +845,6 @@ int s2n_encrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *t return s2n_encrypt_session_ticket(conn, to); } - int s2n_decrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *from) { struct s2n_ticket_key *key; @@ -616,51 +855,50 @@ int s2n_decrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *f uint8_t iv_data[S2N_TLS_GCM_IV_LEN] = { 0 }; struct s2n_blob iv = {0}; - GUARD(s2n_blob_init(&iv, iv_data, sizeof(iv_data))); + POSIX_GUARD(s2n_blob_init(&iv, iv_data, sizeof(iv_data))); uint8_t aad_data[S2N_TICKET_AAD_LEN] = { 0 }; struct s2n_blob aad_blob = {0}; - GUARD(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data))); + POSIX_GUARD(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data))); struct s2n_stuffer aad = {0}; - uint8_t s_data[S2N_STATE_SIZE_IN_BYTES] = { 0 }; + uint8_t s_data[S2N_TLS12_STATE_SIZE_IN_BYTES] = { 0 }; struct s2n_blob state_blob = {0}; - GUARD(s2n_blob_init(&state_blob, s_data, sizeof(s_data))); + POSIX_GUARD(s2n_blob_init(&state_blob, s_data, sizeof(s_data))); struct s2n_stuffer state = {0}; - uint8_t en_data[S2N_STATE_SIZE_IN_BYTES + S2N_TLS_GCM_TAG_LEN] = {0}; + uint8_t en_data[S2N_TLS12_STATE_SIZE_IN_BYTES + S2N_TLS_GCM_TAG_LEN] = {0}; struct s2n_blob en_blob = {0}; - GUARD(s2n_blob_init(&en_blob, en_data, sizeof(en_data))); + POSIX_GUARD(s2n_blob_init(&en_blob, en_data, sizeof(en_data))); - GUARD(s2n_stuffer_read_bytes(from, key_name, S2N_TICKET_KEY_NAME_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(from, key_name, S2N_TICKET_KEY_NAME_LEN)); key = s2n_find_ticket_key(conn->config, key_name); /* Key has expired; do full handshake with New Session Ticket (NST) */ S2N_ERROR_IF(!key, S2N_ERR_KEY_USED_IN_SESSION_TICKET_NOT_FOUND); - GUARD(s2n_stuffer_read(from, &iv)); + POSIX_GUARD(s2n_stuffer_read(from, &iv)); s2n_blob_init(&aes_key_blob, key->aes_key, S2N_AES256_KEY_LEN); - GUARD(s2n_session_key_alloc(&aes_ticket_key)); - GUARD(s2n_aes256_gcm.init(&aes_ticket_key)); - GUARD(s2n_aes256_gcm.set_decryption_key(&aes_ticket_key, &aes_key_blob)); - - GUARD(s2n_stuffer_init(&aad, &aad_blob)); - GUARD(s2n_stuffer_write_bytes(&aad, key->implicit_aad, S2N_TICKET_AAD_IMPLICIT_LEN)); - GUARD(s2n_stuffer_write_bytes(&aad, key->key_name, S2N_TICKET_KEY_NAME_LEN)); + POSIX_GUARD(s2n_session_key_alloc(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.init(&aes_ticket_key)); + POSIX_GUARD(s2n_aes256_gcm.set_decryption_key(&aes_ticket_key, &aes_key_blob)); - GUARD(s2n_stuffer_read(from, &en_blob)); + POSIX_GUARD(s2n_stuffer_init(&aad, &aad_blob)); + POSIX_GUARD(s2n_stuffer_write_bytes(&aad, key->implicit_aad, S2N_TICKET_AAD_IMPLICIT_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&aad, key->key_name, S2N_TICKET_KEY_NAME_LEN)); - GUARD(s2n_aes256_gcm.io.aead.decrypt(&aes_ticket_key, &iv, &aad_blob, &en_blob, &en_blob)); + POSIX_GUARD(s2n_stuffer_read(from, &en_blob)); - GUARD(s2n_stuffer_init(&state, &state_blob)); - GUARD(s2n_stuffer_write_bytes(&state, en_data, S2N_STATE_SIZE_IN_BYTES)); + POSIX_GUARD(s2n_aes256_gcm.io.aead.decrypt(&aes_ticket_key, &iv, &aad_blob, &en_blob, &en_blob)); + POSIX_GUARD(s2n_aes256_gcm.destroy_key(&aes_ticket_key)); + POSIX_GUARD(s2n_session_key_free(&aes_ticket_key)); - GUARD(s2n_deserialize_resumption_state(conn, &state)); + POSIX_GUARD(s2n_stuffer_init(&state, &state_blob)); + POSIX_GUARD(s2n_stuffer_write_bytes(&state, en_data, S2N_TLS12_STATE_SIZE_IN_BYTES)); - GUARD(s2n_aes256_gcm.destroy_key(&aes_ticket_key)); - GUARD(s2n_session_key_free(&aes_ticket_key)); + POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, NULL, &state)); return 0; } @@ -680,14 +918,14 @@ int s2n_config_wipe_expired_ticket_crypto_keys(struct s2n_config *config, int8_t } uint64_t now; - GUARD(config->wall_clock(config->sys_clock_ctx, &now)); - notnull_check(config->ticket_keys); + POSIX_GUARD(config->wall_clock(config->sys_clock_ctx, &now)); + POSIX_ENSURE_REF(config->ticket_keys); uint32_t ticket_keys_len = 0; - GUARD_AS_POSIX(s2n_set_len(config->ticket_keys, &ticket_keys_len)); + POSIX_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len)); for (uint32_t i = 0; i < ticket_keys_len; i++) { - GUARD_AS_POSIX(s2n_set_get(config->ticket_keys, i, (void **)&ticket_key)); + POSIX_GUARD_RESULT(s2n_set_get(config->ticket_keys, i, (void **)&ticket_key)); if (now >= ticket_key->intro_timestamp + config->encrypt_decrypt_key_lifetime_in_nanos + config->decrypt_key_lifetime_in_nanos) { expired_keys_index[num_of_expired_keys] = i; @@ -697,7 +935,7 @@ int s2n_config_wipe_expired_ticket_crypto_keys(struct s2n_config *config, int8_t end: for (int j = 0; j < num_of_expired_keys; j++) { - GUARD_AS_POSIX(s2n_set_remove(config->ticket_keys, expired_keys_index[j] - j)); + POSIX_GUARD_RESULT(s2n_set_remove(config->ticket_keys, expired_keys_index[j] - j)); } return 0; @@ -707,6 +945,83 @@ end: int s2n_config_store_ticket_key(struct s2n_config *config, struct s2n_ticket_key *key) { /* Keys are stored from oldest to newest */ - GUARD_AS_POSIX(s2n_set_add(config->ticket_keys, key)); + POSIX_GUARD_RESULT(s2n_set_add(config->ticket_keys, key)); + return S2N_SUCCESS; +} + +int s2n_config_set_initial_ticket_count(struct s2n_config *config, uint8_t num) +{ + POSIX_ENSURE_REF(config); + + config->initial_tickets_to_send = num; + POSIX_GUARD(s2n_config_set_session_tickets_onoff(config, true)); + + return S2N_SUCCESS; +} + +int s2n_connection_add_new_tickets_to_send(struct s2n_connection *conn, uint8_t num) +{ + POSIX_ENSURE_REF(conn); + POSIX_GUARD_RESULT(s2n_psk_validate_keying_material(conn)); + + uint32_t out = conn->tickets_to_send + num; + POSIX_ENSURE(out <= UINT16_MAX, S2N_ERR_INTEGER_OVERFLOW); + conn->tickets_to_send = out; + + return S2N_SUCCESS; +} + +int s2n_connection_get_tickets_sent(struct s2n_connection *conn, uint16_t *num) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(num); + POSIX_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_CLIENT_MODE); + *num = conn->tickets_sent; + return S2N_SUCCESS; +} + +int s2n_connection_set_server_keying_material_lifetime(struct s2n_connection *conn, uint32_t lifetime_in_secs) +{ + POSIX_ENSURE_REF(conn); + conn->server_keying_material_lifetime = lifetime_in_secs; + return S2N_SUCCESS; +} + +int s2n_config_set_session_ticket_cb(struct s2n_config *config, s2n_session_ticket_fn callback, void *ctx) +{ + POSIX_ENSURE_MUT(config); + + config->session_ticket_cb = callback; + config->session_ticket_ctx = ctx; + return S2N_SUCCESS; +} + +int s2n_session_ticket_get_data_len(struct s2n_session_ticket *ticket, size_t *data_len) +{ + POSIX_ENSURE_REF(ticket); + POSIX_ENSURE_MUT(data_len); + + *data_len = ticket->ticket_data.size; + return S2N_SUCCESS; +} + +int s2n_session_ticket_get_data(struct s2n_session_ticket *ticket, size_t max_data_len, uint8_t *data) +{ + POSIX_ENSURE_REF(ticket); + POSIX_ENSURE_MUT(data); + + POSIX_ENSURE(ticket->ticket_data.size <= max_data_len, S2N_ERR_SERIALIZED_SESSION_STATE_TOO_LONG); + POSIX_CHECKED_MEMCPY(data, ticket->ticket_data.data, ticket->ticket_data.size); + + return S2N_SUCCESS; +} + +int s2n_session_ticket_get_lifetime(struct s2n_session_ticket *ticket, uint32_t *session_lifetime) +{ + POSIX_ENSURE_REF(ticket); + POSIX_ENSURE_REF(session_lifetime); + + *session_lifetime = ticket->session_lifetime; + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_resume.h b/contrib/restricted/aws/s2n/tls/s2n_resume.h index c58025e41f..2d104d6b4c 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_resume.h +++ b/contrib/restricted/aws/s2n/tls/s2n_resume.h @@ -19,16 +19,22 @@ #include "stuffer/s2n_stuffer.h" -#define S2N_SERIALIZED_FORMAT_VERSION 1 #define S2N_STATE_LIFETIME_IN_NANOS 54000000000000 /* 15 hours */ -#define S2N_STATE_SIZE_IN_BYTES (1 + 8 + 1 + S2N_TLS_CIPHER_SUITE_LEN + S2N_TLS_SECRET_LEN) +#define S2N_TLS12_STATE_SIZE_IN_BYTES (1 + 8 + 1 + S2N_TLS_CIPHER_SUITE_LEN + S2N_TLS_SECRET_LEN + 1) +#define S2N_TLS13_FIXED_STATE_SIZE 21 +#define S2N_TLS13_FIXED_EARLY_DATA_STATE_SIZE 3 + #define S2N_TLS_SESSION_CACHE_TTL (6 * 60 * 60) #define S2N_TICKET_KEY_NAME_LEN 16 #define S2N_TICKET_AAD_IMPLICIT_LEN 12 #define S2N_TICKET_AAD_LEN (S2N_TICKET_AAD_IMPLICIT_LEN + S2N_TICKET_KEY_NAME_LEN) #define S2N_AES256_KEY_LEN 32 #define ONE_SEC_IN_NANOS 1000000000 -#define S2N_TICKET_SIZE_IN_BYTES (S2N_TICKET_KEY_NAME_LEN + S2N_TLS_GCM_IV_LEN + S2N_STATE_SIZE_IN_BYTES + S2N_TLS_GCM_TAG_LEN) +#define ONE_MILLISEC_IN_NANOS 1000000 +#define ONE_WEEK_IN_SEC 604800 +#define S2N_TLS12_TICKET_SIZE_IN_BYTES (S2N_TICKET_KEY_NAME_LEN + S2N_TLS_GCM_IV_LEN + \ + S2N_TLS12_STATE_SIZE_IN_BYTES + S2N_TLS_GCM_TAG_LEN) + #define S2N_TICKET_ENCRYPT_DECRYPT_KEY_LIFETIME_IN_NANOS 7200000000000 /* 2 hours */ #define S2N_TICKET_DECRYPT_KEY_LIFETIME_IN_NANOS 46800000000000 /* 13 hours */ #define S2N_STATE_FORMAT_LEN 1 @@ -37,6 +43,11 @@ #define S2N_GREATER_OR_EQUAL 1 #define S2N_LESS_THAN -1 +#define S2N_TLS12_SESSION_SIZE S2N_STATE_FORMAT_LEN + \ + S2N_SESSION_TICKET_SIZE_LEN + \ + S2N_TLS12_TICKET_SIZE_IN_BYTES + \ + S2N_TLS12_STATE_SIZE_IN_BYTES + struct s2n_connection; struct s2n_config; @@ -52,9 +63,19 @@ struct s2n_ticket_key_weight { uint8_t key_index; }; +struct s2n_ticket_fields { + struct s2n_blob session_secret; + uint32_t ticket_age_add; +}; + +struct s2n_session_ticket { + struct s2n_blob ticket_data; + uint32_t session_lifetime; +}; + extern struct s2n_ticket_key *s2n_find_ticket_key(struct s2n_config *config, const uint8_t *name); extern int s2n_encrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *to); -extern int s2n_decrypt_session_ticket(struct s2n_connection *conn); +extern int s2n_decrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *from); extern int s2n_encrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *to); extern int s2n_decrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *from); extern int s2n_config_is_encrypt_decrypt_key_available(struct s2n_config *config); @@ -67,6 +88,14 @@ typedef enum { S2N_STATE_WITH_SESSION_TICKET } s2n_client_tls_session_state_format; +typedef enum { + S2N_SERIALIZED_FORMAT_TLS12_V1 = 1, + S2N_SERIALIZED_FORMAT_TLS13_V1, + S2N_SERIALIZED_FORMAT_TLS12_V2, + S2N_SERIALIZED_FORMAT_TLS12_V3, +} s2n_serial_format_version; + extern int s2n_allowed_to_cache_connection(struct s2n_connection *conn); extern int s2n_resume_from_cache(struct s2n_connection *conn); -extern int s2n_store_to_cache(struct s2n_connection *conn); +S2N_RESULT s2n_store_to_cache(struct s2n_connection *conn); +S2N_RESULT s2n_connection_get_session_state_size(struct s2n_connection *conn, size_t *state_size); diff --git a/contrib/restricted/aws/s2n/tls/s2n_security_policies.c b/contrib/restricted/aws/s2n/tls/s2n_security_policies.c index 388fb25b56..90c0cb16a3 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_security_policies.c +++ b/contrib/restricted/aws/s2n/tls/s2n_security_policies.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "tls/s2n_security_policies.h" #include "tls/s2n_connection.h" @@ -27,9 +27,9 @@ const struct s2n_security_policy security_policy_20170210 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; -const struct s2n_security_policy security_policy_20201110 = { +const struct s2n_security_policy security_policy_default_tls13 = { .minimum_protocol_version = S2N_TLS10, - .cipher_preferences = &cipher_preferences_20190801, + .cipher_preferences = &cipher_preferences_20210831, .kem_preferences = &kem_preferences_null, .signature_preferences = &s2n_signature_preferences_20200207, .certificate_signature_preferences = &s2n_certificate_signature_preferences_20201110, @@ -70,6 +70,14 @@ const struct s2n_security_policy security_policy_20170405 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_20170405_gcm = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_20170405_gcm, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20140601, +}; + const struct s2n_security_policy security_policy_elb_2015_04 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &elb_security_policy_2015_04, @@ -281,6 +289,46 @@ const struct s2n_security_policy security_policy_cloudfront_tls_1_2_2019_legacy .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_aws_crt_sdk_ssl_v3 = { + .minimum_protocol_version = S2N_SSLv3, + .cipher_preferences = &cipher_preferences_aws_crt_sdk_ssl_v3, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_aws_crt_sdk_tls_10 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_aws_crt_sdk_default, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_aws_crt_sdk_tls_11 = { + .minimum_protocol_version = S2N_TLS11, + .cipher_preferences = &cipher_preferences_aws_crt_sdk_default, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_aws_crt_sdk_tls_12 = { + .minimum_protocol_version = S2N_TLS12, + .cipher_preferences = &cipher_preferences_aws_crt_sdk_default, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_aws_crt_sdk_tls_13 = { + .minimum_protocol_version = S2N_TLS13, + .cipher_preferences = &cipher_preferences_aws_crt_sdk_tls_13, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + const struct s2n_security_policy security_policy_kms_tls_1_0_2018_10 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_kms_tls_1_0_2018_10, @@ -289,6 +337,14 @@ const struct s2n_security_policy security_policy_kms_tls_1_0_2018_10 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_kms_tls_1_0_2021_08 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_kms_tls_1_0_2021_08, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + const struct s2n_security_policy security_policy_kms_pq_tls_1_0_2019_06 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_kms_pq_tls_1_0_2019_06, @@ -337,6 +393,88 @@ const struct s2n_security_policy security_policy_pq_tls_1_0_2020_12 = { .ecc_preferences = &s2n_ecc_preferences_20200310, }; +const struct s2n_security_policy security_policy_pq_tls_1_1_2021_05_17 = { + .minimum_protocol_version = S2N_TLS11, + .cipher_preferences = &cipher_preferences_pq_tls_1_1_2021_05_17, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_18 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_18, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_19 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_19, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_20 = { + .minimum_protocol_version = S2N_TLS10, + /* Yes, this is the same cipher_preferences as kms_pq_tls_1_0_2020_07. Both allow Kyber, BIKE, SIKE. The difference + * between these policies is the kem_preferences, which have been updated to prefer Round 3 over Round 2. */ + .cipher_preferences = &cipher_preferences_kms_pq_tls_1_0_2020_07, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_1_2021_05_21 = { + .minimum_protocol_version = S2N_TLS11, + .cipher_preferences = &cipher_preferences_pq_tls_1_1_2021_05_21, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_22 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_22, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_23 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_23, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_24 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_24, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_25 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_25, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_26 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_pq_tls_1_0_2021_05_26, + .kem_preferences = &kem_preferences_pq_tls_1_0_2021_05, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + const struct s2n_security_policy security_policy_kms_fips_tls_1_2_2018_10 = { .minimum_protocol_version = S2N_TLS12, .cipher_preferences = &cipher_preferences_kms_fips_tls_1_2_2018_10, @@ -345,6 +483,14 @@ const struct s2n_security_policy security_policy_kms_fips_tls_1_2_2018_10 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_kms_fips_tls_1_2_2021_08 = { + .minimum_protocol_version = S2N_TLS12, + .cipher_preferences = &cipher_preferences_kms_fips_tls_1_2_2021_08, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20140601, +}; + const struct s2n_security_policy security_policy_20140601 = { .minimum_protocol_version = S2N_SSLv3, .cipher_preferences = &cipher_preferences_20140601, @@ -441,6 +587,30 @@ const struct s2n_security_policy security_policy_20190214 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_20190214_gcm = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_20190214_gcm, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20140601, +}; + +const struct s2n_security_policy security_policy_20210825 = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_20210825, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + +const struct s2n_security_policy security_policy_20210825_gcm = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_20210825_gcm, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20200207, + .ecc_preferences = &s2n_ecc_preferences_20200310, +}; + const struct s2n_security_policy security_policy_20170328 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_20170328, @@ -449,6 +619,14 @@ const struct s2n_security_policy security_policy_20170328 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_20170328_gcm = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_20170328_gcm, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20140601, +}; + const struct s2n_security_policy security_policy_20170718 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_20170718, @@ -457,6 +635,14 @@ const struct s2n_security_policy security_policy_20170718 = { .ecc_preferences = &s2n_ecc_preferences_20140601, }; +const struct s2n_security_policy security_policy_20170718_gcm = { + .minimum_protocol_version = S2N_TLS10, + .cipher_preferences = &cipher_preferences_20170718_gcm, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20140601, + .ecc_preferences = &s2n_ecc_preferences_20140601, +}; + const struct s2n_security_policy security_policy_20201021 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_20190122, @@ -465,6 +651,22 @@ const struct s2n_security_policy security_policy_20201021 = { .ecc_preferences = &s2n_ecc_preferences_20201021, }; +const struct s2n_security_policy security_policy_20210816 = { + .minimum_protocol_version = S2N_TLS12, + .cipher_preferences = &cipher_preferences_20210816, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20210816, + .ecc_preferences = &s2n_ecc_preferences_20210816, +}; + +const struct s2n_security_policy security_policy_20210816_gcm = { + .minimum_protocol_version = S2N_TLS12, + .cipher_preferences = &cipher_preferences_20210816_gcm, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_20210816, + .ecc_preferences = &s2n_ecc_preferences_20210816, +}; + const struct s2n_security_policy security_policy_test_all = { .minimum_protocol_version = S2N_SSLv3, .cipher_preferences = &cipher_preferences_test_all, @@ -531,7 +733,7 @@ const struct s2n_security_policy security_policy_null = { struct s2n_security_policy_selection security_policy_selection[] = { { .version="default", .security_policy=&security_policy_20170210, .ecc_extension_required=0, .pq_kem_extension_required=0 }, - { .version="default_tls13", .security_policy=&security_policy_20201110, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="default_tls13", .security_policy=&security_policy_default_tls13, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="default_fips", .security_policy=&security_policy_20170405, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="ELBSecurityPolicy-TLS-1-0-2015-04", .security_policy=&security_policy_elb_2015_04, .ecc_extension_required=0, .pq_kem_extension_required=0 }, /* Not a mistake. TLS-1-0-2015-05 and 2016-08 are equivalent */ @@ -563,14 +765,32 @@ struct s2n_security_policy_selection security_policy_selection[] = { { .version="CloudFront-TLS-1-1-2016-Legacy", .security_policy=&security_policy_cloudfront_tls_1_1_2016_legacy, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="CloudFront-TLS-1-2-2018-Legacy", .security_policy=&security_policy_cloudfront_tls_1_2_2018_legacy, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="CloudFront-TLS-1-2-2019-Legacy", .security_policy=&security_policy_cloudfront_tls_1_2_2019_legacy, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="AWS-CRT-SDK-SSLv3.0", .security_policy=&security_policy_aws_crt_sdk_ssl_v3, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="AWS-CRT-SDK-TLSv1.0", .security_policy=&security_policy_aws_crt_sdk_tls_10, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="AWS-CRT-SDK-TLSv1.1", .security_policy=&security_policy_aws_crt_sdk_tls_11, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="AWS-CRT-SDK-TLSv1.2", .security_policy=&security_policy_aws_crt_sdk_tls_12, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="AWS-CRT-SDK-TLSv1.3", .security_policy=&security_policy_aws_crt_sdk_tls_13, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + /* KMS TLS Policies*/ { .version="KMS-TLS-1-0-2018-10", .security_policy=&security_policy_kms_tls_1_0_2018_10, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="KMS-TLS-1-0-2021-08", .security_policy=&security_policy_kms_tls_1_0_2021_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="KMS-FIPS-TLS-1-2-2018-10", .security_policy=&security_policy_kms_fips_tls_1_2_2018_10, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="KMS-FIPS-TLS-1-2-2021-08", .security_policy=&security_policy_kms_fips_tls_1_2_2021_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="KMS-PQ-TLS-1-0-2019-06", .security_policy=&security_policy_kms_pq_tls_1_0_2019_06, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="KMS-PQ-TLS-1-0-2020-02", .security_policy=&security_policy_kms_pq_tls_1_0_2020_02, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="KMS-PQ-TLS-1-0-2020-07", .security_policy=&security_policy_kms_pq_tls_1_0_2020_07, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="PQ-SIKE-TEST-TLS-1-0-2019-11", .security_policy=&security_policy_pq_sike_test_tls_1_0_2019_11, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="PQ-SIKE-TEST-TLS-1-0-2020-02", .security_policy=&security_policy_pq_sike_test_tls_1_0_2020_02, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="PQ-TLS-1-0-2020-12", .security_policy=&security_policy_pq_tls_1_0_2020_12, .ecc_extension_required=0, .pq_kem_extension_required=0 }, - { .version="KMS-FIPS-TLS-1-2-2018-10", .security_policy=&security_policy_kms_fips_tls_1_2_2018_10, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-1-2021-05-17", .security_policy=&security_policy_pq_tls_1_1_2021_05_17, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-18", .security_policy=&security_policy_pq_tls_1_0_2021_05_18, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-19", .security_policy=&security_policy_pq_tls_1_0_2021_05_19, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-20", .security_policy=&security_policy_pq_tls_1_0_2021_05_20, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-1-2021-05-21", .security_policy=&security_policy_pq_tls_1_1_2021_05_21, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-22", .security_policy=&security_policy_pq_tls_1_0_2021_05_22, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-23", .security_policy=&security_policy_pq_tls_1_0_2021_05_23, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-24", .security_policy=&security_policy_pq_tls_1_0_2021_05_24, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-25", .security_policy=&security_policy_pq_tls_1_0_2021_05_25, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="PQ-TLS-1-0-2021-05-26", .security_policy=&security_policy_pq_tls_1_0_2021_05_26, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20140601", .security_policy=&security_policy_20140601, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20141001", .security_policy=&security_policy_20141001, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20150202", .security_policy=&security_policy_20150202, .ecc_extension_required=0, .pq_kem_extension_required=0 }, @@ -581,9 +801,15 @@ struct s2n_security_policy_selection security_policy_selection[] = { { .version="20160824", .security_policy=&security_policy_20160824, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20170210", .security_policy=&security_policy_20170210, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20170328", .security_policy=&security_policy_20170328, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20170328_gcm", .security_policy=&security_policy_20170328_gcm, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20190214", .security_policy=&security_policy_20190214, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20190214_gcm", .security_policy=&security_policy_20190214_gcm, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20210825", .security_policy=&security_policy_20210825, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20210825_gcm", .security_policy=&security_policy_20210825_gcm, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20170405", .security_policy=&security_policy_20170405, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20170405_gcm", .security_policy=&security_policy_20170405_gcm, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20170718", .security_policy=&security_policy_20170718, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20170718_gcm", .security_policy=&security_policy_20170718_gcm, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20190120", .security_policy=&security_policy_20190120, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20190121", .security_policy=&security_policy_20190121, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20190122", .security_policy=&security_policy_20190122, .ecc_extension_required=0, .pq_kem_extension_required=0 }, @@ -591,6 +817,8 @@ struct s2n_security_policy_selection security_policy_selection[] = { { .version="20190802", .security_policy=&security_policy_20190802, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20200207", .security_policy=&security_policy_test_all_tls13, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="20201021", .security_policy=&security_policy_20201021, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20210816", .security_policy=&security_policy_20210816, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="20210816_GCM", .security_policy=&security_policy_20210816_gcm, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="test_all", .security_policy=&security_policy_test_all, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="test_all_fips", .security_policy=&security_policy_test_all_fips, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="test_all_ecdsa", .security_policy=&security_policy_test_all_ecdsa, .ecc_extension_required=0, .pq_kem_extension_required=0 }, @@ -604,8 +832,8 @@ struct s2n_security_policy_selection security_policy_selection[] = { int s2n_find_security_policy_from_version(const char *version, const struct s2n_security_policy **security_policy) { - notnull_check(version); - notnull_check(security_policy); + POSIX_ENSURE_REF(version); + POSIX_ENSURE_REF(security_policy); for (int i = 0; security_policy_selection[i].version != NULL; i++) { if (!strcasecmp(version, security_policy_selection[i].version)) { @@ -614,18 +842,21 @@ int s2n_find_security_policy_from_version(const char *version, const struct s2n_ } } - S2N_ERROR(S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_BAIL(S2N_ERR_INVALID_SECURITY_POLICY); } int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version) { const struct s2n_security_policy *security_policy = NULL; - GUARD(s2n_find_security_policy_from_version(version, &security_policy)); - ENSURE_POSIX_REF(security_policy); - ENSURE_POSIX_REF(security_policy->cipher_preferences); - ENSURE_POSIX_REF(security_policy->kem_preferences); - ENSURE_POSIX_REF(security_policy->signature_preferences); - ENSURE_POSIX_REF(security_policy->ecc_preferences); + POSIX_GUARD(s2n_find_security_policy_from_version(version, &security_policy)); + POSIX_ENSURE_REF(security_policy); + POSIX_ENSURE_REF(security_policy->cipher_preferences); + POSIX_ENSURE_REF(security_policy->kem_preferences); + POSIX_ENSURE_REF(security_policy->signature_preferences); + POSIX_ENSURE_REF(security_policy->ecc_preferences); + + /* If the security policy's minimum version is higher than what libcrypto supports, return an error. */ + POSIX_ENSURE((security_policy->minimum_protocol_version <= s2n_get_highest_fully_supported_tls_version()), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); config->security_policy = security_policy; return 0; @@ -634,12 +865,15 @@ int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *ver int s2n_connection_set_cipher_preferences(struct s2n_connection *conn, const char *version) { const struct s2n_security_policy *security_policy = NULL; - GUARD(s2n_find_security_policy_from_version(version, &security_policy)); - ENSURE_POSIX_REF(security_policy); - ENSURE_POSIX_REF(security_policy->cipher_preferences); - ENSURE_POSIX_REF(security_policy->kem_preferences); - ENSURE_POSIX_REF(security_policy->signature_preferences); - ENSURE_POSIX_REF(security_policy->ecc_preferences); + POSIX_GUARD(s2n_find_security_policy_from_version(version, &security_policy)); + POSIX_ENSURE_REF(security_policy); + POSIX_ENSURE_REF(security_policy->cipher_preferences); + POSIX_ENSURE_REF(security_policy->kem_preferences); + POSIX_ENSURE_REF(security_policy->signature_preferences); + POSIX_ENSURE_REF(security_policy->ecc_preferences); + + /* If the security policy's minimum version is higher than what libcrypto supports, return an error. */ + POSIX_ENSURE((security_policy->minimum_protocol_version <= s2n_get_highest_fully_supported_tls_version()), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); conn->security_policy_override = security_policy; return 0; @@ -649,33 +883,30 @@ int s2n_security_policies_init() { for (int i = 0; security_policy_selection[i].version != NULL; i++) { const struct s2n_security_policy *security_policy = security_policy_selection[i].security_policy; - notnull_check(security_policy); + POSIX_ENSURE_REF(security_policy); const struct s2n_cipher_preferences *cipher_preference = security_policy->cipher_preferences; - notnull_check(cipher_preference); + POSIX_ENSURE_REF(cipher_preference); const struct s2n_kem_preferences *kem_preference = security_policy->kem_preferences; - notnull_check(kem_preference); + POSIX_ENSURE_REF(kem_preference); const struct s2n_ecc_preferences *ecc_preference = security_policy->ecc_preferences; - notnull_check(ecc_preference); - GUARD(s2n_check_ecc_preferences_curves_list(ecc_preference)); + POSIX_ENSURE_REF(ecc_preference); + POSIX_GUARD(s2n_check_ecc_preferences_curves_list(ecc_preference)); const struct s2n_signature_preferences *certificate_signature_preference = security_policy->certificate_signature_preferences; if (certificate_signature_preference != NULL) { - GUARD_AS_POSIX(s2n_validate_certificate_signature_preferences(certificate_signature_preference)); + POSIX_GUARD_RESULT(s2n_validate_certificate_signature_preferences(certificate_signature_preference)); } if (security_policy != &security_policy_null) { - /* catch any offending security policy that does not support P-256 */ - S2N_ERROR_IF(!s2n_ecc_preferences_includes_curve(ecc_preference, TLS_EC_CURVE_SECP_256_R1), S2N_ERR_INVALID_SECURITY_POLICY); + /* All policies must have at least one ecc curve configured. */ + S2N_ERROR_IF(ecc_preference->count == 0, S2N_ERR_INVALID_SECURITY_POLICY); } for (int j = 0; j < cipher_preference->count; j++) { struct s2n_cipher_suite *cipher = cipher_preference->suites[j]; - notnull_check(cipher); + POSIX_ENSURE_REF(cipher); - /* TLS1.3 does not include key exchange algorithms in its cipher suites, - * but the elliptic curves extension is always required. */ if (cipher->minimum_required_tls_version >= S2N_TLS13) { - security_policy_selection[i].ecc_extension_required = 1; security_policy_selection[i].supports_tls13 = 1; } @@ -683,16 +914,16 @@ int s2n_security_policies_init() S2N_ERROR_IF(s2n_is_valid_tls13_cipher(cipher->iana_value) ^ (cipher->minimum_required_tls_version >= S2N_TLS13), S2N_ERR_INVALID_SECURITY_POLICY); - if (s2n_kex_includes(cipher->key_exchange_alg, &s2n_ecdhe)) { + if (s2n_cipher_suite_requires_ecc_extension(cipher)) { security_policy_selection[i].ecc_extension_required = 1; } - if (s2n_kex_includes(cipher->key_exchange_alg, &s2n_kem)) { + if (s2n_cipher_suite_requires_pq_extension(cipher)) { security_policy_selection[i].pq_kem_extension_required = 1; } } - GUARD(s2n_validate_kem_preferences(kem_preference, security_policy_selection[i].pq_kem_extension_required)); + POSIX_GUARD(s2n_validate_kem_preferences(kem_preference, security_policy_selection[i].pq_kem_extension_required)); } return 0; } @@ -708,6 +939,18 @@ bool s2n_ecc_is_extension_required(const struct s2n_security_policy *security_po return 1 == security_policy_selection[i].ecc_extension_required; } } + + /* If cipher preference is not in the official list, compute the result */ + const struct s2n_cipher_preferences *cipher_preferences = security_policy->cipher_preferences; + if (cipher_preferences == NULL) { + return false; + } + for (uint8_t i = 0; i < cipher_preferences->count; i++) { + if (s2n_cipher_suite_requires_ecc_extension(cipher_preferences->suites[i])) { + return true; + } + } + return false; } @@ -722,6 +965,17 @@ bool s2n_pq_kem_is_extension_required(const struct s2n_security_policy *security return 1 == security_policy_selection[i].pq_kem_extension_required; } } + + /* If cipher preference is not in the official list, compute the result */ + const struct s2n_cipher_preferences *cipher_preferences = security_policy->cipher_preferences; + if (cipher_preferences == NULL) { + return false; + } + for (uint8_t i = 0; i < cipher_preferences->count; i++) { + if (s2n_cipher_suite_requires_pq_extension(cipher_preferences->suites[i])) { + return true; + } + } return false; } @@ -747,7 +1001,7 @@ bool s2n_security_policy_supports_tls13(const struct s2n_security_policy *securi } for (uint8_t i = 0; i < cipher_preferences->count; i++) { - if (s2n_is_valid_tls13_cipher(cipher_preferences->suites[i]->iana_value)) { + if (cipher_preferences->suites[i]->minimum_required_tls_version >= S2N_TLS13) { return true; } } @@ -757,13 +1011,13 @@ bool s2n_security_policy_supports_tls13(const struct s2n_security_policy *securi int s2n_connection_is_valid_for_cipher_preferences(struct s2n_connection *conn, const char *version) { - notnull_check(conn); - notnull_check(version); - notnull_check(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(version); + POSIX_ENSURE_REF(conn->secure.cipher_suite); const struct s2n_security_policy *security_policy = NULL; - GUARD(s2n_find_security_policy_from_version(version, &security_policy)); - notnull_check(security_policy); + POSIX_GUARD(s2n_find_security_policy_from_version(version, &security_policy)); + POSIX_ENSURE_REF(security_policy); /* make sure we dont use a tls version lower than that configured by the version */ if (s2n_connection_get_actual_protocol_version(conn) < security_policy->minimum_protocol_version) { @@ -771,7 +1025,7 @@ int s2n_connection_is_valid_for_cipher_preferences(struct s2n_connection *conn, } struct s2n_cipher_suite *cipher = conn->secure.cipher_suite; - notnull_check(cipher); + POSIX_ENSURE_REF(cipher); for (int i = 0; i < security_policy->cipher_preferences->count; ++i) { if (0 == memcmp(security_policy->cipher_preferences->suites[i]->iana_value, cipher->iana_value, S2N_TLS_CIPHER_SUITE_LEN)) { return 1; @@ -782,21 +1036,22 @@ int s2n_connection_is_valid_for_cipher_preferences(struct s2n_connection *conn, } int s2n_validate_kem_preferences(const struct s2n_kem_preferences *kem_preferences, bool pq_kem_extension_required) { - notnull_check(kem_preferences); + POSIX_ENSURE_REF(kem_preferences); /* Basic sanity checks to assert that the count is 0 if and only if the associated list is NULL */ - ENSURE_POSIX(S2N_IFF(kem_preferences->tls13_kem_group_count == 0, kem_preferences->tls13_kem_groups == NULL), + POSIX_ENSURE(S2N_IFF(kem_preferences->tls13_kem_group_count == 0, kem_preferences->tls13_kem_groups == NULL), S2N_ERR_INVALID_SECURITY_POLICY); - ENSURE_POSIX(S2N_IFF(kem_preferences->kem_count == 0, kem_preferences->kems == NULL), + POSIX_ENSURE(S2N_IFF(kem_preferences->kem_count == 0, kem_preferences->kems == NULL), S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_ENSURE(kem_preferences->tls13_kem_group_count <= S2N_SUPPORTED_KEM_GROUPS_COUNT, S2N_ERR_ARRAY_INDEX_OOB); /* The PQ KEM extension is applicable only to TLS 1.2 */ if (pq_kem_extension_required) { - ENSURE_POSIX(kem_preferences->kem_count > 0, S2N_ERR_INVALID_SECURITY_POLICY); - ENSURE_POSIX(kem_preferences->kems != NULL, S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_ENSURE(kem_preferences->kem_count > 0, S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_ENSURE(kem_preferences->kems != NULL, S2N_ERR_INVALID_SECURITY_POLICY); } else { - ENSURE_POSIX(kem_preferences->kem_count == 0, S2N_ERR_INVALID_SECURITY_POLICY); - ENSURE_POSIX(kem_preferences->kems == NULL, S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_ENSURE(kem_preferences->kem_count == 0, S2N_ERR_INVALID_SECURITY_POLICY); + POSIX_ENSURE(kem_preferences->kems == NULL, S2N_ERR_INVALID_SECURITY_POLICY); } return S2N_SUCCESS; @@ -804,7 +1059,7 @@ int s2n_validate_kem_preferences(const struct s2n_kem_preferences *kem_preferenc S2N_RESULT s2n_validate_certificate_signature_preferences(const struct s2n_signature_preferences *certificate_signature_preferences) { - ENSURE_REF(certificate_signature_preferences); + RESULT_ENSURE_REF(certificate_signature_preferences); size_t rsa_pss_scheme_count = 0; @@ -817,6 +1072,6 @@ S2N_RESULT s2n_validate_certificate_signature_preferences(const struct s2n_signa /* The Openssl function used to parse signatures off certificates does not differentiate between any rsa pss * signature schemes. Therefore a security policy with a certificate signatures preference list must include * all rsa_pss signature schemes. */ - ENSURE(rsa_pss_scheme_count == NUM_RSA_PSS_SCHEMES || rsa_pss_scheme_count == 0, S2N_ERR_INVALID_SECURITY_POLICY); + RESULT_ENSURE(rsa_pss_scheme_count == NUM_RSA_PSS_SCHEMES || rsa_pss_scheme_count == 0, S2N_ERR_INVALID_SECURITY_POLICY); return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_security_policies.h b/contrib/restricted/aws/s2n/tls/s2n_security_policies.h index f724eb1934..be28fb584a 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_security_policies.h +++ b/contrib/restricted/aws/s2n/tls/s2n_security_policies.h @@ -53,12 +53,16 @@ extern const struct s2n_security_policy security_policy_20160804; extern const struct s2n_security_policy security_policy_20160824; extern const struct s2n_security_policy security_policy_20170210; extern const struct s2n_security_policy security_policy_20170328; +extern const struct s2n_security_policy security_policy_20170328_gcm; extern const struct s2n_security_policy security_policy_20170405; +extern const struct s2n_security_policy security_policy_20170405_gcm; extern const struct s2n_security_policy security_policy_20170718; +extern const struct s2n_security_policy security_policy_20170718_gcm; extern const struct s2n_security_policy security_policy_20190214; +extern const struct s2n_security_policy security_policy_20190214_gcm; extern const struct s2n_security_policy security_policy_20190801; extern const struct s2n_security_policy security_policy_20190802; -extern const struct s2n_security_policy security_policy_20201110; +extern const struct s2n_security_policy security_policy_default_tls13; extern const struct s2n_security_policy security_policy_test_all; extern const struct s2n_security_policy security_policy_test_all_tls12; @@ -79,12 +83,28 @@ extern const struct s2n_security_policy security_policy_elb_fs_1_2_2019_08; extern const struct s2n_security_policy security_policy_elb_fs_1_1_2019_08; extern const struct s2n_security_policy security_policy_elb_fs_1_2_res_2019_08; +extern const struct s2n_security_policy security_policy_aws_crt_sdk_ssl_v3; +extern const struct s2n_security_policy security_policy_aws_crt_sdk_tls_10; +extern const struct s2n_security_policy security_policy_aws_crt_sdk_tls_11; +extern const struct s2n_security_policy security_policy_aws_crt_sdk_tls_12; +extern const struct s2n_security_policy security_policy_aws_crt_sdk_tls_13; + extern const struct s2n_security_policy security_policy_kms_pq_tls_1_0_2019_06; extern const struct s2n_security_policy security_policy_kms_pq_tls_1_0_2020_02; extern const struct s2n_security_policy security_policy_kms_pq_tls_1_0_2020_07; extern const struct s2n_security_policy security_policy_pq_sike_test_tls_1_0_2019_11; extern const struct s2n_security_policy security_policy_pq_sike_test_tls_1_0_2020_02; extern const struct s2n_security_policy security_policy_pq_tls_1_0_2020_12; +extern const struct s2n_security_policy security_policy_pq_tls_1_1_2021_05_17; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_18; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_19; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_20; +extern const struct s2n_security_policy security_policy_pq_tls_1_1_2021_05_21; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_22; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_23; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_24; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_25; +extern const struct s2n_security_policy security_policy_pq_tls_1_0_2021_05_26; extern const struct s2n_security_policy security_policy_cloudfront_upstream; extern const struct s2n_security_policy security_policy_cloudfront_upstream_tls10; diff --git a/contrib/restricted/aws/s2n/tls/s2n_send.c b/contrib/restricted/aws/s2n/tls/s2n_send.c index 4f59054845..013fa28b66 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_send.c +++ b/contrib/restricted/aws/s2n/tls/s2n_send.c @@ -15,7 +15,7 @@ #include <sys/param.h> #include <errno.h> -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -45,9 +45,9 @@ int s2n_flush(struct s2n_connection *conn, s2n_blocked_status * blocked) w = s2n_connection_send_stuffer(&conn->out, conn, s2n_stuffer_data_available(&conn->out)); if (w < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) { - S2N_ERROR(S2N_ERR_IO_BLOCKED); + POSIX_BAIL(S2N_ERR_IO_BLOCKED); } - S2N_ERROR(S2N_ERR_IO); + POSIX_BAIL(S2N_ERR_IO); } conn->wire_bytes_out += w; } @@ -55,15 +55,15 @@ int s2n_flush(struct s2n_connection *conn, s2n_blocked_status * blocked) if (conn->closing) { conn->closed = 1; } - GUARD(s2n_stuffer_rewrite(&conn->out)); + POSIX_GUARD(s2n_stuffer_rewrite(&conn->out)); /* If there's an alert pending out, send that */ if (s2n_stuffer_data_available(&conn->reader_alert_out) == 2) { struct s2n_blob alert = {0}; alert.data = conn->reader_alert_out.blob.data; alert.size = 2; - GUARD(s2n_record_write(conn, TLS_ALERT, &alert)); - GUARD(s2n_stuffer_rewrite(&conn->reader_alert_out)); + POSIX_GUARD(s2n_record_write(conn, TLS_ALERT, &alert)); + POSIX_GUARD(s2n_stuffer_rewrite(&conn->reader_alert_out)); conn->closing = 1; /* Actually write it ... */ @@ -75,8 +75,8 @@ int s2n_flush(struct s2n_connection *conn, s2n_blocked_status * blocked) struct s2n_blob alert = {0}; alert.data = conn->writer_alert_out.blob.data; alert.size = 2; - GUARD(s2n_record_write(conn, TLS_ALERT, &alert)); - GUARD(s2n_stuffer_rewrite(&conn->writer_alert_out)); + POSIX_GUARD(s2n_record_write(conn, TLS_ALERT, &alert)); + POSIX_GUARD(s2n_stuffer_rewrite(&conn->writer_alert_out)); conn->closing = 1; /* Actually write it ... */ @@ -92,11 +92,11 @@ ssize_t s2n_sendv_with_offset_impl(struct s2n_connection *conn, const struct iov { ssize_t user_data_sent, total_size = 0; - S2N_ERROR_IF(conn->closed, S2N_ERR_CLOSED); - S2N_ERROR_IF(conn->config->quic_enabled, S2N_ERR_UNSUPPORTED_WITH_QUIC); + POSIX_ENSURE(!conn->closed, S2N_ERR_CLOSED); + POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_UNSUPPORTED_WITH_QUIC); /* Flush any pending I/O */ - GUARD(s2n_flush(conn, blocked)); + POSIX_GUARD(s2n_flush(conn, blocked)); /* Acknowledge consumed and flushed user data as sent */ user_data_sent = conn->current_user_data_consumed; @@ -104,7 +104,7 @@ ssize_t s2n_sendv_with_offset_impl(struct s2n_connection *conn, const struct iov *blocked = S2N_BLOCKED_ON_WRITE; uint16_t max_payload_size = 0; - GUARD_AS_POSIX(s2n_record_max_write_payload_size(conn, &max_payload_size)); + POSIX_GUARD_RESULT(s2n_record_max_write_payload_size(conn, &max_payload_size)); /* TLS 1.0 and SSLv3 are vulnerable to the so-called Beast attack. Work * around this by splitting messages into one byte records, and then @@ -129,15 +129,16 @@ ssize_t s2n_sendv_with_offset_impl(struct s2n_connection *conn, const struct iov bufs = _bufs; count = _count; } - for (int i = 0; i < count; i++) { + for (ssize_t i = 0; i < count; i++) { total_size += bufs[i].iov_len; } total_size -= offs; S2N_ERROR_IF(conn->current_user_data_consumed > total_size, S2N_ERR_SEND_SIZE); + POSIX_GUARD_RESULT(s2n_early_data_validate_send(conn, total_size)); if (conn->dynamic_record_timeout_threshold > 0) { uint64_t elapsed; - GUARD_AS_POSIX(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); + POSIX_GUARD_RESULT(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); /* Reset record size back to a single segment after threshold seconds of inactivity */ if (elapsed - conn->last_write_elapsed > (uint64_t) conn->dynamic_record_timeout_threshold * 1000000000) { conn->active_application_bytes_consumed = 0; @@ -154,7 +155,7 @@ ssize_t s2n_sendv_with_offset_impl(struct s2n_connection *conn, const struct iov */ if (conn->active_application_bytes_consumed < (uint64_t) conn->dynamic_record_resize_threshold) { uint16_t min_payload_size = 0; - GUARD_AS_POSIX(s2n_record_min_write_payload_size(conn, &min_payload_size)); + POSIX_GUARD_RESULT(s2n_record_min_write_payload_size(conn, &min_payload_size)); to_write = MIN(min_payload_size, to_write); } @@ -168,12 +169,12 @@ ssize_t s2n_sendv_with_offset_impl(struct s2n_connection *conn, const struct iov } } - GUARD(s2n_stuffer_rewrite(&conn->out)); + POSIX_GUARD(s2n_stuffer_rewrite(&conn->out)); - GUARD(s2n_post_handshake_send(conn, blocked)); + POSIX_GUARD(s2n_post_handshake_send(conn, blocked)); /* Write and encrypt the record */ - GUARD(s2n_record_writev(conn, TLS_APPLICATION_DATA, bufs, count, + POSIX_GUARD(s2n_record_writev(conn, TLS_APPLICATION_DATA, bufs, count, conn->current_user_data_consumed + offs, to_write)); conn->current_user_data_consumed += to_write; conn->active_application_bytes_consumed += to_write; @@ -200,12 +201,13 @@ ssize_t s2n_sendv_with_offset_impl(struct s2n_connection *conn, const struct iov *blocked = S2N_NOT_BLOCKED; + POSIX_GUARD_RESULT(s2n_early_data_record_bytes(conn, total_size)); return total_size; } ssize_t s2n_sendv_with_offset(struct s2n_connection *conn, const struct iovec *bufs, ssize_t count, ssize_t offs, s2n_blocked_status *blocked) { - ENSURE_POSIX(!conn->send_in_use, S2N_ERR_REENTRANCY); + POSIX_ENSURE(!conn->send_in_use, S2N_ERR_REENTRANCY); conn->send_in_use = true; ssize_t result = s2n_sendv_with_offset_impl(conn, bufs, count, offs, blocked); conn->send_in_use = false; diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_cert.c b/contrib/restricted/aws/s2n/tls/s2n_server_cert.c index 0188505ae1..6be1ac6202 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_cert.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_cert.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" @@ -27,30 +27,30 @@ int s2n_server_cert_recv(struct s2n_connection *conn) { if (conn->actual_protocol_version == S2N_TLS13) { uint8_t certificate_request_context_len; - GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &certificate_request_context_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &certificate_request_context_len)); S2N_ERROR_IF(certificate_request_context_len != 0, S2N_ERR_BAD_MESSAGE); } uint32_t size_of_all_certificates; - GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &size_of_all_certificates)); + POSIX_GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &size_of_all_certificates)); S2N_ERROR_IF(size_of_all_certificates > s2n_stuffer_data_available(&conn->handshake.io) || size_of_all_certificates < 3, S2N_ERR_BAD_MESSAGE); s2n_cert_public_key public_key; - GUARD(s2n_pkey_zero_init(&public_key)); + POSIX_GUARD(s2n_pkey_zero_init(&public_key)); s2n_pkey_type actual_cert_pkey_type; struct s2n_blob cert_chain = {0}; cert_chain.size = size_of_all_certificates; cert_chain.data = s2n_stuffer_raw_read(&conn->handshake.io, size_of_all_certificates); - notnull_check(cert_chain.data); + POSIX_ENSURE_REF(cert_chain.data); - GUARD(s2n_x509_validator_validate_cert_chain(&conn->x509_validator, conn, cert_chain.data, - cert_chain.size, &actual_cert_pkey_type, &public_key)); + POSIX_ENSURE(s2n_x509_validator_validate_cert_chain(&conn->x509_validator, conn, cert_chain.data, + cert_chain.size, &actual_cert_pkey_type, &public_key) == S2N_CERT_OK, S2N_ERR_CERT_UNTRUSTED); - GUARD(s2n_is_cert_type_valid_for_auth(conn, actual_cert_pkey_type)); - GUARD(s2n_pkey_setup_for_type(&public_key, actual_cert_pkey_type)); - conn->secure.server_public_key = public_key; + POSIX_GUARD(s2n_is_cert_type_valid_for_auth(conn, actual_cert_pkey_type)); + POSIX_GUARD(s2n_pkey_setup_for_type(&public_key, actual_cert_pkey_type)); + conn->handshake_params.server_public_key = public_key; return 0; } @@ -62,10 +62,10 @@ int s2n_server_cert_send(struct s2n_connection *conn) /* server's certificate request context should always be of zero length */ /* https://tools.ietf.org/html/rfc8446#section-4.4.2 */ uint8_t certificate_request_context_len = 0; - GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, certificate_request_context_len)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, certificate_request_context_len)); } - GUARD(s2n_send_cert_chain(conn, &conn->handshake.io, conn->handshake_params.our_chain_and_key)); + POSIX_GUARD(s2n_send_cert_chain(conn, &conn->handshake.io, conn->handshake_params.our_chain_and_key)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_cert_request.c b/contrib/restricted/aws/s2n/tls/s2n_server_cert_request.c index 26dcecc56c..45790f0645 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_cert_request.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_cert_request.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "crypto/s2n_certificate.h" #include "error/s2n_errno.h" @@ -60,26 +60,13 @@ static uint8_t s2n_cert_type_preference_list_legacy_dss[] = { S2N_CERT_TYPE_ECDSA_SIGN }; -static int s2n_cert_type_to_pkey_type(s2n_cert_type cert_type_in, s2n_pkey_type *pkey_type_out) { - switch(cert_type_in) { - case S2N_CERT_TYPE_RSA_SIGN: - *pkey_type_out = S2N_PKEY_TYPE_RSA; - return 0; - case S2N_CERT_TYPE_ECDSA_SIGN: - *pkey_type_out = S2N_PKEY_TYPE_ECDSA; - return 0; - default: - S2N_ERROR(S2N_CERT_ERR_TYPE_UNSUPPORTED); - } -} - static int s2n_recv_client_cert_preferences(struct s2n_stuffer *in, s2n_cert_type *chosen_cert_type_out) { uint8_t cert_types_len; - GUARD(s2n_stuffer_read_uint8(in, &cert_types_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &cert_types_len)); uint8_t *their_cert_type_pref_list = s2n_stuffer_raw_read(in, cert_types_len); - notnull_check(their_cert_type_pref_list); + POSIX_ENSURE_REF(their_cert_type_pref_list); /* Iterate through our preference list from most to least preferred, and return the first match that we find. */ for (int our_cert_pref_idx = 0; our_cert_pref_idx < sizeof(s2n_cert_type_preference_list); our_cert_pref_idx++) { @@ -91,18 +78,19 @@ static int s2n_recv_client_cert_preferences(struct s2n_stuffer *in, s2n_cert_typ } } - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); + POSIX_BAIL(S2N_ERR_CERT_TYPE_UNSUPPORTED); } static int s2n_set_cert_chain_as_client(struct s2n_connection *conn) { if (s2n_config_get_num_default_certs(conn->config) > 0) { - GUARD(s2n_choose_sig_scheme_from_peer_preference_list(conn, &conn->handshake_params.server_sig_hash_algs, - &conn->secure.client_cert_sig_scheme)); + POSIX_GUARD(s2n_choose_sig_scheme_from_peer_preference_list(conn, &conn->handshake_params.server_sig_hash_algs, + &conn->handshake_params.client_cert_sig_scheme)); struct s2n_cert_chain_and_key *cert = s2n_config_get_single_default_cert(conn->config); - notnull_check(cert); + POSIX_ENSURE_REF(cert); conn->handshake_params.our_chain_and_key = cert; + conn->handshake_params.client_cert_pkey_type = s2n_cert_chain_and_key_get_pkey_type(cert); } return 0; @@ -114,13 +102,13 @@ int s2n_tls13_cert_req_recv(struct s2n_connection *conn) /* read request context length */ uint8_t request_context_length; - GUARD(s2n_stuffer_read_uint8(in, &request_context_length)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &request_context_length)); /* RFC 8446: This field SHALL be zero length unless used for the post-handshake authentication */ S2N_ERROR_IF(request_context_length != 0, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_extension_list_recv(S2N_EXTENSION_LIST_CERT_REQ, conn, in)); + POSIX_GUARD(s2n_extension_list_recv(S2N_EXTENSION_LIST_CERT_REQ, conn, in)); - GUARD(s2n_set_cert_chain_as_client(conn)); + POSIX_GUARD(s2n_set_cert_chain_as_client(conn)); return S2N_SUCCESS; } @@ -130,26 +118,25 @@ int s2n_cert_req_recv(struct s2n_connection *conn) struct s2n_stuffer *in = &conn->handshake.io; s2n_cert_type cert_type = 0; - GUARD(s2n_recv_client_cert_preferences(in, &cert_type)); - GUARD(s2n_cert_type_to_pkey_type(cert_type, &conn->secure.client_cert_pkey_type)); + POSIX_GUARD(s2n_recv_client_cert_preferences(in, &cert_type)); if (conn->actual_protocol_version == S2N_TLS12) { - GUARD(s2n_recv_supported_sig_scheme_list(in, &conn->handshake_params.server_sig_hash_algs)); + POSIX_GUARD(s2n_recv_supported_sig_scheme_list(in, &conn->handshake_params.server_sig_hash_algs)); } uint16_t cert_authorities_len = 0; - GUARD(s2n_stuffer_read_uint16(in, &cert_authorities_len)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &cert_authorities_len)); /* For now we don't parse X.501 encoded CA Distinguished Names. * Don't fail just yet as we still may succeed if we provide * right certificate or if ClientAuth is optional. */ - GUARD(s2n_stuffer_skip_read(in, cert_authorities_len)); + POSIX_GUARD(s2n_stuffer_skip_read(in, cert_authorities_len)); /* In the future we may have more advanced logic to match a set of configured certificates against * The cert authorities extension and the signature algorithms advertised. * For now, this will just set the only certificate configured. */ - GUARD(s2n_set_cert_chain_as_client(conn)); + POSIX_GUARD(s2n_set_cert_chain_as_client(conn)); return 0; } @@ -159,9 +146,9 @@ int s2n_tls13_cert_req_send(struct s2n_connection *conn) struct s2n_stuffer *out = &conn->handshake.io; /* Write 0 length request context https://tools.ietf.org/html/rfc8446#section-4.3.2 */ - GUARD(s2n_stuffer_write_uint8(out, 0)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, 0)); - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERT_REQ, conn, out)); + POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERT_REQ, conn, out)); return S2N_SUCCESS; } @@ -174,24 +161,24 @@ int s2n_cert_req_send(struct s2n_connection *conn) if (conn->config->cert_req_dss_legacy_compat_enabled) { client_cert_preference_list_size = sizeof(s2n_cert_type_preference_list_legacy_dss); } - GUARD(s2n_stuffer_write_uint8(out, client_cert_preference_list_size)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, client_cert_preference_list_size)); for (int i = 0; i < client_cert_preference_list_size; i++) { if (conn->config->cert_req_dss_legacy_compat_enabled) { - GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list_legacy_dss[i])); + POSIX_GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list_legacy_dss[i])); } else { - GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list[i])); + POSIX_GUARD(s2n_stuffer_write_uint8(out, s2n_cert_type_preference_list[i])); } } if (conn->actual_protocol_version == S2N_TLS12) { - GUARD(s2n_send_supported_sig_scheme_list(conn, out)); + POSIX_GUARD(s2n_send_supported_sig_scheme_list(conn, out)); } /* RFC 5246 7.4.4 - If the certificate_authorities list is empty, then the * client MAY send any certificate of the appropriate ClientCertificateType */ uint16_t acceptable_cert_authorities_len = 0; - GUARD(s2n_stuffer_write_uint16(out, acceptable_cert_authorities_len)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, acceptable_cert_authorities_len)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c b/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c index 0fc8f6bb15..b604556009 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c @@ -29,10 +29,12 @@ int s2n_server_extensions_send(struct s2n_connection *conn, struct s2n_stuffer * { uint32_t data_available_before_extensions = s2n_stuffer_data_available(out); - if (conn->actual_protocol_version >= S2N_TLS13) { - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_SERVER_HELLO_TLS13, conn, out)); + if (s2n_is_hello_retry_message(conn)) { + POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_HELLO_RETRY_REQUEST, conn, out)); + } else if (conn->actual_protocol_version >= S2N_TLS13) { + POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_SERVER_HELLO_TLS13, conn, out)); } else { - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_SERVER_HELLO_DEFAULT, conn, out)); + POSIX_GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_SERVER_HELLO_DEFAULT, conn, out)); } /* The ServerHello extension list size (uint16_t) is NOT written if the list is empty. @@ -45,7 +47,7 @@ int s2n_server_extensions_send(struct s2n_connection *conn, struct s2n_stuffer * * so will never produce an empty list. */ if(s2n_stuffer_data_available(out) - data_available_before_extensions == S2N_EMPTY_EXTENSION_LIST_SIZE) { - GUARD(s2n_stuffer_wipe_n(out, S2N_EMPTY_EXTENSION_LIST_SIZE)); + POSIX_GUARD(s2n_stuffer_wipe_n(out, S2N_EMPTY_EXTENSION_LIST_SIZE)); } return S2N_SUCCESS; @@ -54,18 +56,20 @@ int s2n_server_extensions_send(struct s2n_connection *conn, struct s2n_stuffer * int s2n_server_extensions_recv(struct s2n_connection *conn, struct s2n_stuffer *in) { s2n_parsed_extensions_list parsed_extension_list = { 0 }; - GUARD(s2n_extension_list_parse(in, &parsed_extension_list)); + POSIX_GUARD(s2n_extension_list_parse(in, &parsed_extension_list)); /* Process supported_versions first so that we know which extensions list to use. * - If the supported_versions extension exists, then it will set server_protocol_version. * - If the supported_versions extension does not exist, then the server_protocol_version will remain * unknown and we will use the default list of allowed extension types. */ - GUARD(s2n_extension_process(&s2n_server_supported_versions_extension, conn, &parsed_extension_list)); + POSIX_GUARD(s2n_extension_process(&s2n_server_supported_versions_extension, conn, &parsed_extension_list)); - if (conn->server_protocol_version >= S2N_TLS13) { - GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_SERVER_HELLO_TLS13, conn, &parsed_extension_list)); + if (s2n_is_hello_retry_message(conn)) { + POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_HELLO_RETRY_REQUEST, conn, &parsed_extension_list)); + } else if (conn->server_protocol_version >= S2N_TLS13) { + POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_SERVER_HELLO_TLS13, conn, &parsed_extension_list)); } else { - GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_SERVER_HELLO_DEFAULT, conn, &parsed_extension_list)); + POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_SERVER_HELLO_DEFAULT, conn, &parsed_extension_list)); } return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_finished.c b/contrib/restricted/aws/s2n/tls/s2n_server_finished.c index 156641dd14..d7e57a222b 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_finished.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_finished.c @@ -37,7 +37,7 @@ int s2n_server_finished_recv(struct s2n_connection *conn) } uint8_t *their_version = s2n_stuffer_raw_read(&conn->handshake.io, length); - notnull_check(their_version); + POSIX_ENSURE_REF(their_version); S2N_ERROR_IF(!s2n_constant_time_equals(our_version, their_version, length), S2N_ERR_BAD_MESSAGE); @@ -50,7 +50,7 @@ int s2n_server_finished_send(struct s2n_connection *conn) int length = S2N_TLS_FINISHED_LEN; /* Compute the finished message */ - GUARD(s2n_prf_server_finished(conn)); + POSIX_GUARD(s2n_prf_server_finished(conn)); our_version = conn->handshake.server_finished; @@ -58,17 +58,17 @@ int s2n_server_finished_send(struct s2n_connection *conn) length = S2N_SSL_FINISHED_LEN; } - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, length)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, length)); /* Zero the sequence number */ struct s2n_blob seq = {.data = conn->secure.server_sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; - GUARD(s2n_blob_zero(&seq)); + POSIX_GUARD(s2n_blob_zero(&seq)); /* Update the secure state to active, and point the client at the active state */ conn->server = &conn->secure; - if (IS_RESUMPTION_HANDSHAKE(conn->handshake.handshake_type)) { - GUARD(s2n_prf_key_expansion(conn)); + if (s2n_connection_is_session_resumed(conn)) { + POSIX_GUARD(s2n_prf_key_expansion(conn)); } return 0; @@ -76,7 +76,7 @@ int s2n_server_finished_send(struct s2n_connection *conn) int s2n_tls13_server_finished_recv(struct s2n_connection *conn) { - eq_check(conn->actual_protocol_version, S2N_TLS13); + POSIX_ENSURE_EQ(conn->actual_protocol_version, S2N_TLS13); uint8_t length = s2n_stuffer_data_available(&conn->handshake.io); S2N_ERROR_IF(length == 0, S2N_ERR_BAD_MESSAGE); @@ -89,43 +89,45 @@ int s2n_tls13_server_finished_recv(struct s2n_connection *conn) { s2n_tls13_connection_keys(keys, conn); /* get transcript hash */ - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, keys.hash_algorithm, hash_state)); /* look up finished secret key */ struct s2n_blob finished_key = {0}; - GUARD(s2n_blob_init(&finished_key, conn->handshake.server_finished, keys.size)); + POSIX_GUARD(s2n_blob_init(&finished_key, conn->handshake.server_finished, keys.size)); /* generate the hashed message authenticated code */ s2n_tls13_key_blob(server_finished_mac, keys.size); - GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, &hash_state, &server_finished_mac)); + POSIX_GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, hash_state, &server_finished_mac)); /* compare mac with received message */ - GUARD(s2n_tls13_mac_verify(&keys, &server_finished_mac, &wire_finished_mac)); + POSIX_GUARD(s2n_tls13_mac_verify(&keys, &server_finished_mac, &wire_finished_mac)); return 0; } int s2n_tls13_server_finished_send(struct s2n_connection *conn) { - eq_check(conn->actual_protocol_version, S2N_TLS13); + POSIX_ENSURE_EQ(conn->actual_protocol_version, S2N_TLS13); /* get tls13 keys */ s2n_tls13_connection_keys(keys, conn); /* get transcript hash */ - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, keys.hash_algorithm, hash_state)); /* look up finished secret key */ struct s2n_blob finished_key = {0}; - GUARD(s2n_blob_init(&finished_key, conn->handshake.server_finished, keys.size)); + POSIX_GUARD(s2n_blob_init(&finished_key, conn->handshake.server_finished, keys.size)); /* generate the hashed message authenticated code */ s2n_tls13_key_blob(server_finished_mac, keys.size); - GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, &hash_state, &server_finished_mac)); + POSIX_GUARD(s2n_tls13_calculate_finished_mac(&keys, &finished_key, hash_state, &server_finished_mac)); /* write to handshake io */ - GUARD(s2n_stuffer_write(&conn->handshake.io, &server_finished_mac)); + POSIX_GUARD(s2n_stuffer_write(&conn->handshake.io, &server_finished_mac)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_hello.c b/contrib/restricted/aws/s2n/tls/s2n_server_hello.c index 010c06547a..632f745478 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_hello.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_hello.c @@ -15,7 +15,7 @@ #include <sys/param.h> -#include <s2n.h> +#include "api/s2n.h" #include <time.h> #include "crypto/s2n_fips.h" @@ -31,6 +31,7 @@ #include "tls/s2n_tls13.h" #include "tls/s2n_security_policies.h" #include "tls/s2n_tls13_handshake.h" +#include "tls/s2n_tls13_key_schedule.h" #include "stuffer/s2n_stuffer.h" @@ -51,26 +52,26 @@ const uint8_t tls11_downgrade_protection_bytes[] = { }; static int s2n_hello_retry_validate(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - ENSURE_POSIX(memcmp(hello_retry_req_random, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN) == 0, + POSIX_ENSURE(memcmp(hello_retry_req_random, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN) == 0, S2N_ERR_INVALID_HELLO_RETRY); return S2N_SUCCESS; } static int s2n_client_detect_downgrade_mechanism(struct s2n_connection *conn) { - notnull_check(conn); - uint8_t *downgrade_bytes = &conn->secure.server_random[S2N_TLS_RANDOM_DATA_LEN - S2N_DOWNGRADE_PROTECTION_SIZE]; + POSIX_ENSURE_REF(conn); + uint8_t *downgrade_bytes = &conn->handshake_params.server_random[S2N_TLS_RANDOM_DATA_LEN - S2N_DOWNGRADE_PROTECTION_SIZE]; /* Detect downgrade attacks according to RFC 8446 section 4.1.3 */ if (conn->client_protocol_version == S2N_TLS13 && conn->server_protocol_version == S2N_TLS12) { if (s2n_constant_time_equals(downgrade_bytes, tls12_downgrade_protection_bytes, S2N_DOWNGRADE_PROTECTION_SIZE)) { - S2N_ERROR(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); + POSIX_BAIL(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); } } else if (conn->client_protocol_version == S2N_TLS13 && conn->server_protocol_version <= S2N_TLS11) { if (s2n_constant_time_equals(downgrade_bytes, tls11_downgrade_protection_bytes, S2N_DOWNGRADE_PROTECTION_SIZE)) { - S2N_ERROR(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); + POSIX_BAIL(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); } } @@ -78,16 +79,16 @@ static int s2n_client_detect_downgrade_mechanism(struct s2n_connection *conn) { } static int s2n_server_add_downgrade_mechanism(struct s2n_connection *conn) { - notnull_check(conn); - uint8_t *downgrade_bytes = &conn->secure.server_random[S2N_TLS_RANDOM_DATA_LEN - S2N_DOWNGRADE_PROTECTION_SIZE]; + POSIX_ENSURE_REF(conn); + uint8_t *downgrade_bytes = &conn->handshake_params.server_random[S2N_TLS_RANDOM_DATA_LEN - S2N_DOWNGRADE_PROTECTION_SIZE]; /* Protect against downgrade attacks according to RFC 8446 section 4.1.3 */ if (conn->server_protocol_version >= S2N_TLS13 && conn->actual_protocol_version == S2N_TLS12) { /* TLS1.3 servers MUST use a special random value when negotiating TLS1.2 */ - memcpy_check(downgrade_bytes, tls12_downgrade_protection_bytes, S2N_DOWNGRADE_PROTECTION_SIZE); + POSIX_CHECKED_MEMCPY(downgrade_bytes, tls12_downgrade_protection_bytes, S2N_DOWNGRADE_PROTECTION_SIZE); } else if (conn->server_protocol_version >= S2N_TLS13 && conn->actual_protocol_version <= S2N_TLS11) { /* TLS1.3 servers MUST, use a special random value when negotiating TLS1.1 or below */ - memcpy_check(downgrade_bytes, tls11_downgrade_protection_bytes, S2N_DOWNGRADE_PROTECTION_SIZE); + POSIX_CHECKED_MEMCPY(downgrade_bytes, tls11_downgrade_protection_bytes, S2N_DOWNGRADE_PROTECTION_SIZE); } return 0; @@ -95,7 +96,7 @@ static int s2n_server_add_downgrade_mechanism(struct s2n_connection *conn) { static int s2n_server_hello_parse(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_stuffer *in = &conn->handshake.io; uint8_t compression_method; @@ -103,50 +104,70 @@ static int s2n_server_hello_parse(struct s2n_connection *conn) uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; uint8_t session_id[S2N_TLS_SESSION_ID_MAX_LEN]; - GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); - GUARD(s2n_stuffer_read_bytes(in, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN)); /* If the client receives a second HelloRetryRequest in the same connection, it MUST send an error. */ if (s2n_hello_retry_validate(conn) == S2N_SUCCESS) { - ENSURE_POSIX(!s2n_is_hello_retry_handshake(conn), S2N_ERR_INVALID_HELLO_RETRY); - GUARD(s2n_set_hello_retry_required(conn)); + POSIX_ENSURE(!s2n_is_hello_retry_handshake(conn), S2N_ERR_INVALID_HELLO_RETRY); + POSIX_GUARD(s2n_set_hello_retry_required(conn)); } - GUARD(s2n_stuffer_read_uint8(in, &session_id_len)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &session_id_len)); S2N_ERROR_IF(session_id_len > S2N_TLS_SESSION_ID_MAX_LEN, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_read_bytes(in, session_id, session_id_len)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, session_id, session_id_len)); uint8_t *cipher_suite_wire = s2n_stuffer_raw_read(in, S2N_TLS_CIPHER_SUITE_LEN); - notnull_check(cipher_suite_wire); + POSIX_ENSURE_REF(cipher_suite_wire); - GUARD(s2n_stuffer_read_uint8(in, &compression_method)); + POSIX_GUARD(s2n_stuffer_read_uint8(in, &compression_method)); S2N_ERROR_IF(compression_method != S2N_TLS_COMPRESSION_METHOD_NULL, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_server_extensions_recv(conn, in)); + bool session_ids_match = session_id_len != 0 && session_id_len == conn->session_id_len + && memcmp(session_id, conn->session_id, session_id_len) == 0; + if (!session_ids_match) { + conn->ems_negotiated = false; + } + + POSIX_GUARD(s2n_server_extensions_recv(conn, in)); if (conn->server_protocol_version >= S2N_TLS13) { - S2N_ERROR_IF(session_id_len != conn->session_id_len || memcmp(session_id, conn->session_id, session_id_len), S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(session_ids_match || (session_id_len == 0 && conn->session_id_len == 0), S2N_ERR_BAD_MESSAGE); conn->actual_protocol_version = conn->server_protocol_version; - GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); + POSIX_GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); } else { conn->server_protocol_version = (uint8_t)(protocol_version[0] * 10) + protocol_version[1]; - S2N_ERROR_IF(s2n_client_detect_downgrade_mechanism(conn), S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); - ENSURE_POSIX(!conn->config->quic_enabled, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + POSIX_ENSURE(!s2n_client_detect_downgrade_mechanism(conn), S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); + POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + + /* + *= https://tools.ietf.org/rfc/rfc8446#appendix-D.3 + *# A client that attempts to send 0-RTT data MUST fail a connection if + *# it receives a ServerHello with TLS 1.2 or older. + */ + POSIX_ENSURE(conn->early_data_state != S2N_EARLY_DATA_REQUESTED, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); const struct s2n_security_policy *security_policy; - GUARD(s2n_connection_get_security_policy(conn, &security_policy)); + POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); if (conn->server_protocol_version < security_policy->minimum_protocol_version || conn->server_protocol_version > conn->client_protocol_version) { - GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); - S2N_ERROR(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + POSIX_GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn)); + POSIX_BAIL(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); } uint8_t actual_protocol_version = MIN(conn->server_protocol_version, conn->client_protocol_version); - /* Use the session state if server sent same session id as client sent in client hello */ - if (session_id_len != 0 && session_id_len == conn->session_id_len - && !memcmp(session_id, conn->session_id, session_id_len)) { + + /* + *= https://tools.ietf.org/rfc/rfc5077#section-3.4 + *# If the server accepts the ticket + *# and the Session ID is not empty, then it MUST respond with the same + *# Session ID present in the ClientHello. This allows the client to + *# easily differentiate when the server is resuming a session from when + *# it is falling back to a full handshake. + */ + if (session_ids_match) { /* check if the resumed session state is valid */ S2N_ERROR_IF(conn->actual_protocol_version != actual_protocol_version, S2N_ERR_BAD_MESSAGE); S2N_ERROR_IF(memcmp(conn->secure.cipher_suite->iana_value, cipher_suite_wire, S2N_TLS_CIPHER_SUITE_LEN) != 0, S2N_ERR_BAD_MESSAGE); @@ -155,54 +176,64 @@ static int s2n_server_hello_parse(struct s2n_connection *conn) conn->client_session_resumed = 1; } else { conn->session_id_len = session_id_len; - memcpy_check(conn->session_id, session_id, session_id_len); + POSIX_CHECKED_MEMCPY(conn->session_id, session_id, session_id_len); conn->actual_protocol_version = actual_protocol_version; - GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); + POSIX_GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); /* Erase master secret which might have been set for session resumption */ - memset_check((uint8_t *)conn->secure.master_secret, 0, S2N_TLS_SECRET_LEN); + POSIX_CHECKED_MEMSET((uint8_t *)conn->secrets.tls12.master_secret, 0, S2N_TLS_SECRET_LEN); /* Erase client session ticket which might have been set for session resumption */ - GUARD(s2n_free(&conn->client_ticket)); + POSIX_GUARD(s2n_free(&conn->client_ticket)); } } + /* If it is not possible to accept early data on this connection + * (for example, because no PSK was negotiated) we need to reject early data now. + * Otherwise, early data logic may make certain invalid assumptions about the + * state of the connection (for example, that the prf is the early data prf). + */ + POSIX_GUARD_RESULT(s2n_early_data_accept_or_reject(conn)); + if (conn->early_data_state == S2N_EARLY_DATA_REJECTED) { + POSIX_GUARD_RESULT(s2n_tls13_key_schedule_reset(conn)); + } + return 0; } int s2n_server_hello_recv(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); /* Read the message off the wire */ - GUARD(s2n_server_hello_parse(conn)); + POSIX_GUARD(s2n_server_hello_parse(conn)); conn->actual_protocol_version_established = 1; - GUARD(s2n_conn_set_handshake_type(conn)); + POSIX_GUARD(s2n_conn_set_handshake_type(conn)); /* If this is a HelloRetryRequest, we don't process the ServerHello. * Instead we proceed with retry logic. */ if (s2n_is_hello_retry_message(conn)) { - GUARD(s2n_server_hello_retry_recv(conn)); + POSIX_GUARD(s2n_server_hello_retry_recv(conn)); return 0; } - if (IS_RESUMPTION_HANDSHAKE(conn->handshake.handshake_type)) { - GUARD(s2n_prf_key_expansion(conn)); + if (conn->actual_protocol_version < S2N_TLS13 && s2n_connection_is_session_resumed(conn)) { + POSIX_GUARD(s2n_prf_key_expansion(conn)); } /* Choose a default signature scheme */ - GUARD(s2n_choose_default_sig_scheme(conn, &conn->secure.conn_sig_scheme)); + POSIX_GUARD(s2n_choose_default_sig_scheme(conn, &conn->handshake_params.conn_sig_scheme, S2N_SERVER)); /* Update the required hashes for this connection */ - GUARD(s2n_conn_update_required_handshake_hashes(conn)); + POSIX_GUARD(s2n_conn_update_required_handshake_hashes(conn)); return 0; } int s2n_server_hello_write_message(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); /* The actual_protocol_version is set while processing the CLIENT_HELLO message, so * it could be S2N_TLS13. SERVER_HELLO should always respond with the legacy version. @@ -212,38 +243,38 @@ int s2n_server_hello_write_message(struct s2n_connection *conn) protocol_version[0] = (uint8_t)(legacy_protocol_version / 10); protocol_version[1] = (uint8_t)(legacy_protocol_version % 10); - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); - GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, conn->session_id_len)); - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, conn->session_id, conn->session_id_len)); - GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, conn->secure.cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); - GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, S2N_TLS_COMPRESSION_METHOD_NULL)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, conn->session_id_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, conn->session_id, conn->session_id_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, conn->secure.cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN)); + POSIX_GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, S2N_TLS_COMPRESSION_METHOD_NULL)); return 0; } int s2n_server_hello_send(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); struct s2n_stuffer server_random = {0}; struct s2n_blob b = {0}; - GUARD(s2n_blob_init(&b, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_blob_init(&b, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN)); /* Create the server random data */ - GUARD(s2n_stuffer_init(&server_random, &b)); + POSIX_GUARD(s2n_stuffer_init(&server_random, &b)); struct s2n_blob rand_data = {0}; - GUARD(s2n_blob_init(&rand_data, s2n_stuffer_raw_write(&server_random, S2N_TLS_RANDOM_DATA_LEN), S2N_TLS_RANDOM_DATA_LEN)); - notnull_check(rand_data.data); - GUARD_AS_POSIX(s2n_get_public_random_data(&rand_data)); + POSIX_GUARD(s2n_blob_init(&rand_data, s2n_stuffer_raw_write(&server_random, S2N_TLS_RANDOM_DATA_LEN), S2N_TLS_RANDOM_DATA_LEN)); + POSIX_ENSURE_REF(rand_data.data); + POSIX_GUARD_RESULT(s2n_get_public_random_data(&rand_data)); /* Add a downgrade detection mechanism if required */ - GUARD(s2n_server_add_downgrade_mechanism(conn)); + POSIX_GUARD(s2n_server_add_downgrade_mechanism(conn)); - GUARD(s2n_server_hello_write_message(conn)); + POSIX_GUARD(s2n_server_hello_write_message(conn)); - GUARD(s2n_server_extensions_send(conn, &conn->handshake.io)); + POSIX_GUARD(s2n_server_extensions_send(conn, &conn->handshake.io)); conn->actual_protocol_version_established = 1; diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c b/contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c index a6dda9edf8..c305289100 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c @@ -35,50 +35,50 @@ uint8_t hello_retry_req_random[S2N_TLS_RANDOM_DATA_LEN] = { static int s2n_conn_reset_retry_values(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); /* Reset handshake values */ conn->handshake.client_hello_received = 0; /* Reset client hello state */ - GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message)); - GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0)); - GUARD(s2n_client_hello_free(&conn->client_hello)); - GUARD(s2n_stuffer_growable_alloc(&conn->client_hello.raw_message, 0)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message)); + POSIX_GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0)); + POSIX_GUARD(s2n_client_hello_free(&conn->client_hello)); + POSIX_GUARD(s2n_stuffer_growable_alloc(&conn->client_hello.raw_message, 0)); return 0; } int s2n_server_hello_retry_send(struct s2n_connection *conn) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); - memcpy_check(conn->secure.server_random, hello_retry_req_random, S2N_TLS_RANDOM_DATA_LEN); + POSIX_CHECKED_MEMCPY(conn->handshake_params.server_random, hello_retry_req_random, S2N_TLS_RANDOM_DATA_LEN); - GUARD(s2n_server_hello_write_message(conn)); + POSIX_GUARD(s2n_server_hello_write_message(conn)); /* Write the extensions */ - GUARD(s2n_server_extensions_send(conn, &conn->handshake.io)); + POSIX_GUARD(s2n_server_extensions_send(conn, &conn->handshake.io)); /* Update transcript */ - GUARD(s2n_server_hello_retry_recreate_transcript(conn)); - GUARD(s2n_conn_reset_retry_values(conn)); + POSIX_GUARD(s2n_server_hello_retry_recreate_transcript(conn)); + POSIX_GUARD(s2n_conn_reset_retry_values(conn)); return 0; } int s2n_server_hello_retry_recv(struct s2n_connection *conn) { - notnull_check(conn); - ENSURE_POSIX(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_INVALID_HELLO_RETRY); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_INVALID_HELLO_RETRY); const struct s2n_ecc_preferences *ecc_pref = NULL; - GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); - notnull_check(ecc_pref); + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); + POSIX_ENSURE_REF(ecc_pref); const struct s2n_kem_preferences *kem_pref = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); - notnull_check(kem_pref); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); + POSIX_ENSURE_REF(kem_pref); /* Upon receipt of the HelloRetryRequest, the client MUST verify that: * (1) the selected_group field corresponds to a group @@ -88,44 +88,34 @@ int s2n_server_hello_retry_recv(struct s2n_connection *conn) * in the "key_share" extension in the original ClientHello. * If either of these checks fails, then the client MUST abort the handshake. */ - bool match_found = false; - - const struct s2n_ecc_named_curve *named_curve = conn->secure.server_ecc_evp_params.negotiated_curve; - const struct s2n_kem_group *kem_group = conn->secure.server_kem_group_params.kem_group; + const struct s2n_ecc_named_curve *named_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve; + const struct s2n_kem_group *kem_group = conn->kex_params.server_kem_group_params.kem_group; /* Boolean XOR check: exactly one of {named_curve, kem_group} should be non-null. */ - ENSURE_POSIX( (named_curve != NULL) != (kem_group != NULL), S2N_ERR_INVALID_HELLO_RETRY); + POSIX_ENSURE( (named_curve != NULL) != (kem_group != NULL), S2N_ERR_INVALID_HELLO_RETRY); + bool new_key_share_requested = false; if (named_curve != NULL) { - for (size_t i = 0; i < ecc_pref->count; i++) { - if (ecc_pref->ecc_curves[i] == named_curve) { - match_found = true; - ENSURE_POSIX(conn->secure.client_ecc_evp_params[i].evp_pkey == NULL, S2N_ERR_INVALID_HELLO_RETRY); - break; - } - } + new_key_share_requested = (named_curve != conn->kex_params.client_ecc_evp_params.negotiated_curve); } - if (kem_group != NULL) { /* If PQ is disabled, the client should not have sent any PQ IDs * in the supported_groups list of the initial ClientHello */ - ENSURE_POSIX(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); - - for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { - if (kem_pref->tls13_kem_groups[i] == kem_group) { - match_found = true; - ENSURE_POSIX(conn->secure.client_kem_group_params[i].kem_params.private_key.data == NULL, - S2N_ERR_INVALID_HELLO_RETRY); - ENSURE_POSIX(conn->secure.client_kem_group_params[i].ecc_params.evp_pkey == NULL, - S2N_ERR_INVALID_HELLO_RETRY); - } - } + POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); + new_key_share_requested = (kem_group != conn->kex_params.client_kem_group_params.kem_group); } - ENSURE_POSIX(match_found, S2N_ERR_INVALID_HELLO_RETRY); + /* + *= https://tools.ietf.org/rfc/rfc8446#section-4.1.4 + *# Clients MUST abort the handshake with an + *# "illegal_parameter" alert if the HelloRetryRequest would not result + *# in any change in the ClientHello. + */ + POSIX_ENSURE((conn->early_data_state == S2N_EARLY_DATA_REJECTED) || new_key_share_requested, + S2N_ERR_INVALID_HELLO_RETRY); /* Update transcript hash */ - GUARD(s2n_server_hello_retry_recreate_transcript(conn)); + POSIX_GUARD(s2n_server_hello_retry_recreate_transcript(conn)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_key_exchange.c b/contrib/restricted/aws/s2n/tls/s2n_server_key_exchange.c index 9116868110..b10b300e57 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_key_exchange.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_key_exchange.c @@ -13,12 +13,11 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "error/s2n_errno.h" #include "tls/s2n_async_pkey.h" -#include "tls/s2n_tls_digest_preferences.h" #include "tls/s2n_kem.h" #include "tls/s2n_kex.h" #include "tls/s2n_cipher_suites.h" @@ -38,50 +37,50 @@ static int s2n_server_key_send_write_signature(struct s2n_connection *conn, stru int s2n_server_key_recv(struct s2n_connection *conn) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); - notnull_check(conn->secure.cipher_suite->key_exchange_alg); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn->secure.cipher_suite->key_exchange_alg); + POSIX_ENSURE_REF(conn->handshake.hashes); - struct s2n_hash_state *signature_hash = &conn->secure.signature_hash; + struct s2n_hash_state *signature_hash = &conn->handshake.hashes->hash_workspace; const struct s2n_kex *key_exchange = conn->secure.cipher_suite->key_exchange_alg; struct s2n_stuffer *in = &conn->handshake.io; struct s2n_blob data_to_verify = {0}; /* Read the KEX data */ struct s2n_kex_raw_server_data kex_data = {0}; - GUARD_AS_POSIX(s2n_kex_server_key_recv_read_data(key_exchange, conn, &data_to_verify, &kex_data)); + POSIX_GUARD_RESULT(s2n_kex_server_key_recv_read_data(key_exchange, conn, &data_to_verify, &kex_data)); /* Add common signature data */ - struct s2n_signature_scheme active_sig_scheme; + struct s2n_signature_scheme *active_sig_scheme = &conn->handshake_params.conn_sig_scheme; if (conn->actual_protocol_version == S2N_TLS12) { /* Verify the SigScheme picked by the Server was in the preference list we sent (or is the default SigScheme) */ - GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, in, &active_sig_scheme)); - } else { - active_sig_scheme = conn->secure.conn_sig_scheme; + POSIX_GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, in, active_sig_scheme)); } - GUARD(s2n_hash_init(signature_hash, active_sig_scheme.hash_alg)); - GUARD(s2n_hash_update(signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); - GUARD(s2n_hash_update(signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); + + POSIX_GUARD(s2n_hash_init(signature_hash, active_sig_scheme->hash_alg)); + POSIX_GUARD(s2n_hash_update(signature_hash, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_hash_update(signature_hash, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN)); /* Add KEX specific data */ - GUARD(s2n_hash_update(signature_hash, data_to_verify.data, data_to_verify.size)); + POSIX_GUARD(s2n_hash_update(signature_hash, data_to_verify.data, data_to_verify.size)); /* Verify the signature */ uint16_t signature_length; - GUARD(s2n_stuffer_read_uint16(in, &signature_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &signature_length)); struct s2n_blob signature = {.size = signature_length, .data = s2n_stuffer_raw_read(in, signature_length)}; - notnull_check(signature.data); - gt_check(signature_length, 0); + POSIX_ENSURE_REF(signature.data); + POSIX_ENSURE_GT(signature_length, 0); - S2N_ERROR_IF(s2n_pkey_verify(&conn->secure.server_public_key, active_sig_scheme.sig_alg,signature_hash, &signature) < 0, + S2N_ERROR_IF(s2n_pkey_verify(&conn->handshake_params.server_public_key, active_sig_scheme->sig_alg, signature_hash, &signature) < 0, S2N_ERR_BAD_MESSAGE); /* We don't need the key any more, so free it */ - GUARD(s2n_pkey_free(&conn->secure.server_public_key)); + POSIX_GUARD(s2n_pkey_free(&conn->handshake_params.server_public_key)); /* Parse the KEX data into whatever form needed and save it to the connection object */ - GUARD_AS_POSIX(s2n_kex_server_key_recv_parse_data(key_exchange, conn, &kex_data)); + POSIX_GUARD_RESULT(s2n_kex_server_key_recv_parse_data(key_exchange, conn, &kex_data)); return 0; } @@ -89,13 +88,13 @@ int s2n_ecdhe_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_ { struct s2n_stuffer *in = &conn->handshake.io; - GUARD(s2n_ecc_evp_read_params(in, data_to_verify, &raw_server_data->ecdhe_data)); + POSIX_GUARD(s2n_ecc_evp_read_params(in, data_to_verify, &raw_server_data->ecdhe_data)); return 0; } int s2n_ecdhe_server_key_recv_parse_data(struct s2n_connection *conn, struct s2n_kex_raw_server_data *raw_server_data) { - GUARD(s2n_ecc_evp_parse_params(&raw_server_data->ecdhe_data, &conn->secure.server_ecc_evp_params)); + POSIX_GUARD(s2n_ecc_evp_parse_params(&raw_server_data->ecdhe_data, &conn->kex_params.server_ecc_evp_params)); return 0; } @@ -111,23 +110,23 @@ int s2n_dhe_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_bl /* Keep a copy to the start of the whole structure for the signature check */ data_to_verify->data = s2n_stuffer_raw_read(in, 0); - notnull_check(data_to_verify->data); + POSIX_ENSURE_REF(data_to_verify->data); /* Read each of the three elements in */ - GUARD(s2n_stuffer_read_uint16(in, &p_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &p_length)); dhe_data->p.size = p_length; dhe_data->p.data = s2n_stuffer_raw_read(in, p_length); - notnull_check(dhe_data->p.data); + POSIX_ENSURE_REF(dhe_data->p.data); - GUARD(s2n_stuffer_read_uint16(in, &g_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &g_length)); dhe_data->g.size = g_length; dhe_data->g.data = s2n_stuffer_raw_read(in, g_length); - notnull_check(dhe_data->g.data); + POSIX_ENSURE_REF(dhe_data->g.data); - GUARD(s2n_stuffer_read_uint16(in, &Ys_length)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &Ys_length)); dhe_data->Ys.size = Ys_length; dhe_data->Ys.data = s2n_stuffer_raw_read(in, Ys_length); - notnull_check(dhe_data->Ys.data); + POSIX_ENSURE_REF(dhe_data->Ys.data); /* Now we know the total size of the structure */ data_to_verify->size = 2 + p_length + 2 + g_length + 2 + Ys_length; @@ -139,7 +138,7 @@ int s2n_dhe_server_key_recv_parse_data(struct s2n_connection *conn, struct s2n_k struct s2n_dhe_raw_server_points dhe_data = raw_server_data->dhe_data; /* Copy the DH details */ - GUARD(s2n_dh_p_g_Ys_to_dh_params(&conn->secure.server_dh_params, &dhe_data.p, &dhe_data.g, &dhe_data.Ys)); + POSIX_GUARD(s2n_dh_p_g_Ys_to_dh_params(&conn->kex_params.server_dh_params, &dhe_data.p, &dhe_data.g, &dhe_data.Ys)); return 0; } @@ -150,26 +149,26 @@ int s2n_kem_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_bl /* Keep a copy to the start of the whole structure for the signature check */ data_to_verify->data = s2n_stuffer_raw_read(in, 0); - notnull_check(data_to_verify->data); + POSIX_ENSURE_REF(data_to_verify->data); /* the server sends the KEM ID */ kem_data->kem_name.data = s2n_stuffer_raw_read(in, 2); - notnull_check(kem_data->kem_name.data); + POSIX_ENSURE_REF(kem_data->kem_name.data); kem_data->kem_name.size = 2; struct s2n_stuffer kem_id_stuffer = { 0 }; uint8_t kem_id_arr[2]; kem_extension_size kem_id; struct s2n_blob kem_id_blob = { .data = kem_id_arr, .size = s2n_array_len(kem_id_arr) }; - GUARD(s2n_stuffer_init(&kem_id_stuffer, &kem_id_blob)); - GUARD(s2n_stuffer_write(&kem_id_stuffer, &(kem_data->kem_name))); - GUARD(s2n_stuffer_read_uint16(&kem_id_stuffer, &kem_id)); + POSIX_GUARD(s2n_stuffer_init(&kem_id_stuffer, &kem_id_blob)); + POSIX_GUARD(s2n_stuffer_write(&kem_id_stuffer, &(kem_data->kem_name))); + POSIX_GUARD(s2n_stuffer_read_uint16(&kem_id_stuffer, &kem_id)); - GUARD(s2n_get_kem_from_extension_id(kem_id, &(conn->secure.kem_params.kem))); - GUARD(s2n_kem_recv_public_key(in, &(conn->secure.kem_params))); + POSIX_GUARD(s2n_get_kem_from_extension_id(kem_id, &(conn->kex_params.kem_params.kem))); + POSIX_GUARD(s2n_kem_recv_public_key(in, &(conn->kex_params.kem_params))); - kem_data->raw_public_key.data = conn->secure.kem_params.public_key.data; - kem_data->raw_public_key.size = conn->secure.kem_params.public_key.size; + kem_data->raw_public_key.data = conn->kex_params.kem_params.public_key.data; + kem_data->raw_public_key.size = conn->kex_params.kem_params.public_key.size; data_to_verify->size = sizeof(kem_extension_size) + sizeof(kem_public_key_size) + kem_data->raw_public_key.size; @@ -182,37 +181,37 @@ int s2n_kem_server_key_recv_parse_data(struct s2n_connection *conn, struct s2n_k /* Check that the server's requested kem is supported by the client */ const struct s2n_kem_preferences *kem_preferences = NULL; - GUARD(s2n_connection_get_kem_preferences(conn, &kem_preferences)); - notnull_check(kem_preferences); + POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_preferences)); + POSIX_ENSURE_REF(kem_preferences); const struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite; const struct s2n_kem *match = NULL; S2N_ERROR_IF(s2n_choose_kem_with_peer_pref_list(cipher_suite->iana_value, &kem_data->kem_name, kem_preferences->kems, kem_preferences->kem_count, &match) != 0, S2N_ERR_KEM_UNSUPPORTED_PARAMS); - conn->secure.kem_params.kem = match; + conn->kex_params.kem_params.kem = match; - S2N_ERROR_IF(kem_data->raw_public_key.size != conn->secure.kem_params.kem->public_key_length, S2N_ERR_BAD_MESSAGE); + S2N_ERROR_IF(kem_data->raw_public_key.size != conn->kex_params.kem_params.kem->public_key_length, S2N_ERR_BAD_MESSAGE); return 0; } int s2n_hybrid_server_key_recv_read_data(struct s2n_connection *conn, struct s2n_blob *total_data_to_verify, struct s2n_kex_raw_server_data *raw_server_data) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); const struct s2n_kex *kex = conn->secure.cipher_suite->key_exchange_alg; const struct s2n_kex *hybrid_kex_0 = kex->hybrid[0]; const struct s2n_kex *hybrid_kex_1 = kex->hybrid[1]; /* Keep a copy to the start of the whole structure for the signature check */ total_data_to_verify->data = s2n_stuffer_raw_read(&conn->handshake.io, 0); - notnull_check(total_data_to_verify->data); + POSIX_ENSURE_REF(total_data_to_verify->data); struct s2n_blob data_to_verify_0 = {0}; - GUARD_AS_POSIX(s2n_kex_server_key_recv_read_data(hybrid_kex_0, conn, &data_to_verify_0, raw_server_data)); + POSIX_GUARD_RESULT(s2n_kex_server_key_recv_read_data(hybrid_kex_0, conn, &data_to_verify_0, raw_server_data)); struct s2n_blob data_to_verify_1 = {0}; - GUARD_AS_POSIX(s2n_kex_server_key_recv_read_data(hybrid_kex_1, conn, &data_to_verify_1, raw_server_data)); + POSIX_GUARD_RESULT(s2n_kex_server_key_recv_read_data(hybrid_kex_1, conn, &data_to_verify_1, raw_server_data)); total_data_to_verify->size = data_to_verify_0.size + data_to_verify_1.size; return 0; @@ -220,43 +219,46 @@ int s2n_hybrid_server_key_recv_read_data(struct s2n_connection *conn, struct s2n int s2n_hybrid_server_key_recv_parse_data(struct s2n_connection *conn, struct s2n_kex_raw_server_data *raw_server_data) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); const struct s2n_kex *kex = conn->secure.cipher_suite->key_exchange_alg; const struct s2n_kex *hybrid_kex_0 = kex->hybrid[0]; const struct s2n_kex *hybrid_kex_1 = kex->hybrid[1]; - GUARD_AS_POSIX(s2n_kex_server_key_recv_parse_data(hybrid_kex_0, conn, raw_server_data)); - GUARD_AS_POSIX(s2n_kex_server_key_recv_parse_data(hybrid_kex_1, conn, raw_server_data)); + POSIX_GUARD_RESULT(s2n_kex_server_key_recv_parse_data(hybrid_kex_0, conn, raw_server_data)); + POSIX_GUARD_RESULT(s2n_kex_server_key_recv_parse_data(hybrid_kex_1, conn, raw_server_data)); return 0; } int s2n_server_key_send(struct s2n_connection *conn) { + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->handshake.hashes); + S2N_ASYNC_PKEY_GUARD(conn); - struct s2n_hash_state *signature_hash = &conn->secure.signature_hash; + struct s2n_hash_state *signature_hash = &conn->handshake.hashes->hash_workspace; const struct s2n_kex *key_exchange = conn->secure.cipher_suite->key_exchange_alg; struct s2n_stuffer *out = &conn->handshake.io; struct s2n_blob data_to_sign = {0}; /* Call the negotiated key exchange method to send it's data */ - GUARD_AS_POSIX(s2n_kex_server_key_send(key_exchange, conn, &data_to_sign)); + POSIX_GUARD_RESULT(s2n_kex_server_key_send(key_exchange, conn, &data_to_sign)); /* Add common signature data */ if (conn->actual_protocol_version == S2N_TLS12) { - GUARD(s2n_stuffer_write_uint16(out, conn->secure.conn_sig_scheme.iana_value)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, conn->handshake_params.conn_sig_scheme.iana_value)); } /* Add the random data to the hash */ - GUARD(s2n_hash_init(signature_hash, conn->secure.conn_sig_scheme.hash_alg)); - GUARD(s2n_hash_update(signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN)); - GUARD(s2n_hash_update(signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_hash_init(signature_hash, conn->handshake_params.conn_sig_scheme.hash_alg)); + POSIX_GUARD(s2n_hash_update(signature_hash, conn->handshake_params.client_random, S2N_TLS_RANDOM_DATA_LEN)); + POSIX_GUARD(s2n_hash_update(signature_hash, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN)); /* Add KEX specific data to the hash */ - GUARD(s2n_hash_update(signature_hash, data_to_sign.data, data_to_sign.size)); + POSIX_GUARD(s2n_hash_update(signature_hash, data_to_sign.data, data_to_sign.size)); - S2N_ASYNC_PKEY_SIGN(conn, conn->secure.conn_sig_scheme.sig_alg, signature_hash, s2n_server_key_send_write_signature); + S2N_ASYNC_PKEY_SIGN(conn, conn->handshake_params.conn_sig_scheme.sig_alg, signature_hash, s2n_server_key_send_write_signature); } int s2n_ecdhe_server_key_send(struct s2n_connection *conn, struct s2n_blob *data_to_sign) @@ -264,10 +266,10 @@ int s2n_ecdhe_server_key_send(struct s2n_connection *conn, struct s2n_blob *data struct s2n_stuffer *out = &conn->handshake.io; /* Generate an ephemeral key and */ - GUARD(s2n_ecc_evp_generate_ephemeral_key(&conn->secure.server_ecc_evp_params)); + POSIX_GUARD(s2n_ecc_evp_generate_ephemeral_key(&conn->kex_params.server_ecc_evp_params)); /* Write it out and calculate the data to sign later */ - GUARD(s2n_ecc_evp_write_params(&conn->secure.server_ecc_evp_params, out, data_to_sign)); + POSIX_GUARD(s2n_ecc_evp_write_params(&conn->kex_params.server_ecc_evp_params, out, data_to_sign)); return 0; } @@ -276,26 +278,26 @@ int s2n_dhe_server_key_send(struct s2n_connection *conn, struct s2n_blob *data_t struct s2n_stuffer *out = &conn->handshake.io; /* Duplicate the DH key from the config */ - GUARD(s2n_dh_params_copy(conn->config->dhparams, &conn->secure.server_dh_params)); + POSIX_GUARD(s2n_dh_params_copy(conn->config->dhparams, &conn->kex_params.server_dh_params)); /* Generate an ephemeral key */ - GUARD(s2n_dh_generate_ephemeral_key(&conn->secure.server_dh_params)); + POSIX_GUARD(s2n_dh_generate_ephemeral_key(&conn->kex_params.server_dh_params)); /* Write it out and calculate the data to sign later */ - GUARD(s2n_dh_params_to_p_g_Ys(&conn->secure.server_dh_params, out, data_to_sign)); + POSIX_GUARD(s2n_dh_params_to_p_g_Ys(&conn->kex_params.server_dh_params, out, data_to_sign)); return 0; } int s2n_kem_server_key_send(struct s2n_connection *conn, struct s2n_blob *data_to_sign) { struct s2n_stuffer *out = &conn->handshake.io; - const struct s2n_kem *kem = conn->secure.kem_params.kem; + const struct s2n_kem *kem = conn->kex_params.kem_params.kem; data_to_sign->data = s2n_stuffer_raw_write(out, 0); - notnull_check(data_to_sign->data); + POSIX_ENSURE_REF(data_to_sign->data); - GUARD(s2n_stuffer_write_uint16(out, kem->kem_extension_id)); - GUARD(s2n_kem_send_public_key(out, &(conn->secure.kem_params))); + POSIX_GUARD(s2n_stuffer_write_uint16(out, kem->kem_extension_id)); + POSIX_GUARD(s2n_kem_send_public_key(out, &(conn->kex_params.kem_params))); data_to_sign->size = sizeof(kem_extension_size) + sizeof(kem_public_key_size) + kem->public_key_length; @@ -304,21 +306,21 @@ int s2n_kem_server_key_send(struct s2n_connection *conn, struct s2n_blob *data_t int s2n_hybrid_server_key_send(struct s2n_connection *conn, struct s2n_blob *total_data_to_sign) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(conn->secure.cipher_suite); const struct s2n_kex *kex = conn->secure.cipher_suite->key_exchange_alg; const struct s2n_kex *hybrid_kex_0 = kex->hybrid[0]; const struct s2n_kex *hybrid_kex_1 = kex->hybrid[1]; /* Keep a copy to the start of the whole structure for the signature check */ total_data_to_sign->data = s2n_stuffer_raw_write(&conn->handshake.io, 0); - notnull_check(total_data_to_sign->data); + POSIX_ENSURE_REF(total_data_to_sign->data); struct s2n_blob data_to_verify_0 = {0}; - GUARD_AS_POSIX(s2n_kex_server_key_send(hybrid_kex_0, conn, &data_to_verify_0)); + POSIX_GUARD_RESULT(s2n_kex_server_key_send(hybrid_kex_0, conn, &data_to_verify_0)); struct s2n_blob data_to_verify_1 = {0}; - GUARD_AS_POSIX(s2n_kex_server_key_send(hybrid_kex_1, conn, &data_to_verify_1)); + POSIX_GUARD_RESULT(s2n_kex_server_key_send(hybrid_kex_1, conn, &data_to_verify_1)); total_data_to_sign->size = data_to_verify_0.size + data_to_verify_1.size; return 0; @@ -328,8 +330,8 @@ int s2n_server_key_send_write_signature(struct s2n_connection *conn, struct s2n_ { struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_stuffer_write_uint16(out, signature->size)); - GUARD(s2n_stuffer_write_bytes(out, signature->data, signature->size)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, signature->size)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, signature->data, signature->size)); return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_new_session_ticket.c b/contrib/restricted/aws/s2n/tls/s2n_server_new_session_ticket.c index a42c5029d2..a0af0e56ac 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_new_session_ticket.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_new_session_ticket.c @@ -15,7 +15,7 @@ #include <sys/param.h> -#include <s2n.h> +#include "api/s2n.h" #include <time.h> #include "error/s2n_errno.h" @@ -24,53 +24,376 @@ #include "tls/s2n_alerts.h" #include "tls/s2n_tls.h" #include "tls/s2n_resume.h" +#include "tls/s2n_tls13_handshake.h" +#include "tls/s2n_record.h" #include "stuffer/s2n_stuffer.h" #include "utils/s2n_safety.h" #include "utils/s2n_random.h" +/* + * The maximum size of the NewSessionTicket message, not taking into account the + * ticket itself. + * + * To get the actual maximum size required for the NewSessionTicket message, we'll need + * to add the size of the ticket, which is much less predictable. + * + * This constant is enforced via unit tests. + */ +#define S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE 79 + int s2n_server_nst_recv(struct s2n_connection *conn) { - GUARD(s2n_stuffer_read_uint32(&conn->handshake.io, &conn->ticket_lifetime_hint)); + POSIX_GUARD(s2n_stuffer_read_uint32(&conn->handshake.io, &conn->ticket_lifetime_hint)); uint16_t session_ticket_len; - GUARD(s2n_stuffer_read_uint16(&conn->handshake.io, &session_ticket_len)); + POSIX_GUARD(s2n_stuffer_read_uint16(&conn->handshake.io, &session_ticket_len)); if (session_ticket_len > 0) { - GUARD(s2n_realloc(&conn->client_ticket, session_ticket_len)); + POSIX_GUARD(s2n_realloc(&conn->client_ticket, session_ticket_len)); + + POSIX_GUARD(s2n_stuffer_read(&conn->handshake.io, &conn->client_ticket)); + + if (conn->config->session_ticket_cb != NULL) { + size_t session_len = s2n_connection_get_session_length(conn); + + /* Alloc some memory for the serialized session ticket */ + DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free); + POSIX_GUARD(s2n_alloc(&mem, S2N_STATE_FORMAT_LEN + S2N_SESSION_TICKET_SIZE_LEN + \ + conn->client_ticket.size + S2N_TLS12_STATE_SIZE_IN_BYTES)); + + POSIX_GUARD(s2n_connection_get_session(conn, mem.data, session_len)); + uint32_t session_lifetime = s2n_connection_get_session_ticket_lifetime_hint(conn); + + struct s2n_session_ticket ticket = { .ticket_data = mem, .session_lifetime = session_lifetime }; - GUARD(s2n_stuffer_read(&conn->handshake.io, &conn->client_ticket)); + POSIX_GUARD(conn->config->session_ticket_cb(conn, conn->config->session_ticket_ctx, &ticket)); + } } - return 0; + return S2N_SUCCESS; } int s2n_server_nst_send(struct s2n_connection *conn) { - uint16_t session_ticket_len = S2N_TICKET_SIZE_IN_BYTES; - uint8_t data[S2N_TICKET_SIZE_IN_BYTES]; + uint16_t session_ticket_len = S2N_TLS12_TICKET_SIZE_IN_BYTES; + uint8_t data[S2N_TLS12_TICKET_SIZE_IN_BYTES] = { 0 }; struct s2n_blob entry = { .data = data, .size = sizeof(data) }; struct s2n_stuffer to; uint32_t lifetime_hint_in_secs = (conn->config->encrypt_decrypt_key_lifetime_in_nanos + conn->config->decrypt_key_lifetime_in_nanos) / ONE_SEC_IN_NANOS; /* When server changes it's mind mid handshake send lifetime hint and session ticket length as zero */ if (!conn->config->use_tickets) { - GUARD(s2n_stuffer_write_uint32(&conn->handshake.io, 0)); - GUARD(s2n_stuffer_write_uint16(&conn->handshake.io, 0)); + POSIX_GUARD(s2n_stuffer_write_uint32(&conn->handshake.io, 0)); + POSIX_GUARD(s2n_stuffer_write_uint16(&conn->handshake.io, 0)); return 0; } if (!s2n_server_sending_nst(conn)) { - S2N_ERROR(S2N_ERR_SENDING_NST); + POSIX_BAIL(S2N_ERR_SENDING_NST); + } + + POSIX_GUARD(s2n_stuffer_init(&to, &entry)); + POSIX_GUARD(s2n_stuffer_write_uint32(&conn->handshake.io, lifetime_hint_in_secs)); + POSIX_GUARD(s2n_stuffer_write_uint16(&conn->handshake.io, session_ticket_len)); + + POSIX_GUARD(s2n_encrypt_session_ticket(conn, &to)); + POSIX_GUARD(s2n_stuffer_write(&conn->handshake.io, &to.blob)); + + /* For parity with TLS1.3, track the single ticket sent. + * This simplifies s2n_connection_get_tickets_sent. + */ + conn->tickets_sent++; + return S2N_SUCCESS; +} + +S2N_RESULT s2n_tls13_server_nst_send(struct s2n_connection *conn, s2n_blocked_status *blocked) +{ + RESULT_ENSURE_REF(conn); + + /* Usually tickets are sent immediately after the handshake. + * If possible, reuse the handshake IO stuffer before it's wiped. + * + * Note: handshake.io isn't explicitly dedicated to only reading or only writing, + * so we have to be careful using it outside of s2n_negotiate. + * If we use it for writing here, we CAN'T use it for reading any post-handshake messages. + */ + struct s2n_stuffer *nst_stuffer = &conn->handshake.io; + + if (conn->mode != S2N_SERVER || conn->actual_protocol_version < S2N_TLS13 || !conn->config->use_tickets) { + return S2N_RESULT_OK; + } + + /* No-op if all tickets already sent. + * Clean up the stuffer used for the ticket to conserve memory. */ + if (conn->tickets_to_send == conn->tickets_sent) { + RESULT_GUARD_POSIX(s2n_stuffer_resize(nst_stuffer, 0)); + return S2N_RESULT_OK; + } + + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# Note that in principle it is possible to continue issuing new tickets + *# which indefinitely extend the lifetime of the keying material + *# originally derived from an initial non-PSK handshake (which was most + *# likely tied to the peer's certificate). It is RECOMMENDED that + *# implementations place limits on the total lifetime of such keying + *# material; these limits should take into account the lifetime of the + *# peer's certificate, the likelihood of intervening revocation, and the + *# time since the peer's online CertificateVerify signature. + */ + if (s2n_result_is_error(s2n_psk_validate_keying_material(conn))) { + conn->tickets_to_send = conn->tickets_sent; + return S2N_RESULT_OK; + } + + RESULT_ENSURE(conn->tickets_sent <= conn->tickets_to_send, S2N_ERR_INTEGER_OVERFLOW); + + size_t session_state_size = 0; + RESULT_GUARD(s2n_connection_get_session_state_size(conn, &session_state_size)); + const size_t maximum_nst_size = session_state_size + S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE; + if (s2n_stuffer_space_remaining(nst_stuffer) < maximum_nst_size) { + RESULT_GUARD_POSIX(s2n_stuffer_resize(nst_stuffer, maximum_nst_size)); + } + + while (conn->tickets_to_send - conn->tickets_sent > 0) { + if (s2n_result_is_error(s2n_tls13_server_nst_write(conn, nst_stuffer))) { + return S2N_RESULT_OK; + } + + struct s2n_blob nst_blob = { 0 }; + uint16_t nst_size = s2n_stuffer_data_available(nst_stuffer); + uint8_t *nst_data = s2n_stuffer_raw_read(nst_stuffer, nst_size); + RESULT_ENSURE_REF(nst_data); + RESULT_GUARD_POSIX(s2n_blob_init(&nst_blob, nst_data, nst_size)); + + RESULT_GUARD_POSIX(s2n_record_write(conn, TLS_HANDSHAKE, &nst_blob)); + RESULT_GUARD_POSIX(s2n_flush(conn, blocked)); + RESULT_GUARD_POSIX(s2n_stuffer_wipe(nst_stuffer)); + } + + RESULT_GUARD_POSIX(s2n_stuffer_resize(nst_stuffer, 0)); + return S2N_RESULT_OK; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# Indicates the lifetime in seconds as a 32-bit + *# unsigned integer in network byte order from the time of ticket + *# issuance. + **/ +static S2N_RESULT s2n_generate_ticket_lifetime(struct s2n_connection *conn, uint32_t *ticket_lifetime) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_MUT(ticket_lifetime); + + uint32_t key_lifetime_in_secs = + (conn->config->encrypt_decrypt_key_lifetime_in_nanos + conn->config->decrypt_key_lifetime_in_nanos) / ONE_SEC_IN_NANOS; + uint32_t session_lifetime_in_secs = conn->config->session_state_lifetime_in_nanos / ONE_SEC_IN_NANOS; + uint32_t key_and_session_min_lifetime = MIN(key_lifetime_in_secs, session_lifetime_in_secs); + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# Servers MUST NOT use any value greater than + *# 604800 seconds (7 days). + **/ + *ticket_lifetime = MIN(key_and_session_min_lifetime, ONE_WEEK_IN_SEC); + + return S2N_RESULT_OK; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# A per-ticket value that is unique across all tickets + *# issued on this connection. + **/ +static S2N_RESULT s2n_generate_ticket_nonce(uint16_t value, struct s2n_blob *output) +{ + RESULT_ENSURE_MUT(output); + + struct s2n_stuffer stuffer = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_init(&stuffer, output)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint16(&stuffer, value)); + + return S2N_RESULT_OK; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# A securely generated, random 32-bit value that is + *# used to obscure the age of the ticket that the client includes in + *# the "pre_shared_key" extension. + **/ +static S2N_RESULT s2n_generate_ticket_age_add(struct s2n_blob *random_data, uint32_t *ticket_age_add) +{ + RESULT_ENSURE_REF(random_data); + RESULT_ENSURE_REF(ticket_age_add); + + struct s2n_stuffer stuffer = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_init(&stuffer, random_data)); + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&stuffer, random_data->size)); + RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(&stuffer, ticket_age_add)); + + return S2N_RESULT_OK; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# The PSK associated with the ticket is computed as: + *# + *# HKDF-Expand-Label(resumption_master_secret, + *# "resumption", ticket_nonce, Hash.length) + **/ +static int s2n_generate_session_secret(struct s2n_connection *conn, struct s2n_blob *nonce, struct s2n_blob *output) +{ + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(nonce); + POSIX_ENSURE_REF(output); + + s2n_tls13_connection_keys(secrets, conn); + struct s2n_blob master_secret = { 0 }; + POSIX_GUARD(s2n_blob_init(&master_secret, conn->secrets.tls13.resumption_master_secret, secrets.size)); + POSIX_GUARD(s2n_realloc(output, secrets.size)); + POSIX_GUARD_RESULT(s2n_tls13_derive_session_ticket_secret(&secrets, &master_secret, nonce, output)); + + return S2N_SUCCESS; +} + +S2N_RESULT s2n_tls13_server_nst_write(struct s2n_connection *conn, struct s2n_stuffer *output) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(output); + + struct s2n_ticket_fields *ticket_fields = &conn->tls13_ticket_fields; + + /* Write message type because session resumption in TLS13 is a post-handshake message */ + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(output, TLS_SERVER_NEW_SESSION_TICKET)); + + struct s2n_stuffer_reservation message_size = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_reserve_uint24(output, &message_size)); + + uint32_t ticket_lifetime_in_secs = 0; + RESULT_GUARD(s2n_generate_ticket_lifetime(conn, &ticket_lifetime_in_secs)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint32(output, ticket_lifetime_in_secs)); + + /* Get random data to use as ticket_age_add value */ + uint8_t data[sizeof(uint32_t)] = { 0 }; + struct s2n_blob random_data = { 0 }; + RESULT_GUARD_POSIX(s2n_blob_init(&random_data, data, sizeof(data))); + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# The server MUST generate a fresh value + *# for each ticket it sends. + **/ + RESULT_GUARD(s2n_get_private_random_data(&random_data)); + RESULT_GUARD(s2n_generate_ticket_age_add(&random_data, &ticket_fields->ticket_age_add)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint32(output, ticket_fields->ticket_age_add)); + + /* Write ticket nonce */ + uint8_t nonce_data[sizeof(uint16_t)] = { 0 }; + struct s2n_blob nonce = { 0 }; + RESULT_GUARD_POSIX(s2n_blob_init(&nonce, nonce_data, sizeof(nonce_data))); + RESULT_GUARD(s2n_generate_ticket_nonce(conn->tickets_sent, &nonce)); + RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(output, nonce.size)); + RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(output, nonce.data, nonce.size)); + + /* Derive individual session ticket secret */ + RESULT_GUARD_POSIX(s2n_generate_session_secret(conn, &nonce, &ticket_fields->session_secret)); + + /* Write ticket */ + struct s2n_stuffer_reservation ticket_size = { 0 }; + RESULT_GUARD_POSIX(s2n_stuffer_reserve_uint16(output, &ticket_size)); + RESULT_GUARD_POSIX(s2n_encrypt_session_ticket(conn, output)); + RESULT_GUARD_POSIX(s2n_stuffer_write_vector_size(&ticket_size)); + + RESULT_GUARD_POSIX(s2n_extension_list_send(S2N_EXTENSION_LIST_NST, conn, output)); + + RESULT_GUARD_POSIX(s2n_stuffer_write_vector_size(&message_size)); + + RESULT_ENSURE(conn->tickets_sent < UINT16_MAX, S2N_ERR_INTEGER_OVERFLOW); + conn->tickets_sent++; + + return S2N_RESULT_OK; +} + +/** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# struct { + *# uint32 ticket_lifetime; + *# uint32 ticket_age_add; + *# opaque ticket_nonce<0..255>; + *# opaque ticket<1..2^16-1>; + *# Extension extensions<0..2^16-2>; + *# } NewSessionTicket; +**/ +S2N_RESULT s2n_tls13_server_nst_recv(struct s2n_connection *conn, struct s2n_stuffer *input) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(input); + RESULT_ENSURE_REF(conn->config); + + RESULT_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE); + RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_BAD_MESSAGE); + + if (!conn->config->use_tickets) { + return S2N_RESULT_OK; + } + struct s2n_ticket_fields *ticket_fields = &conn->tls13_ticket_fields; + + /* Handle `ticket_lifetime` field */ + uint32_t ticket_lifetime = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(input, &ticket_lifetime)); + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# Servers MUST NOT use any value greater than + *# 604800 seconds (7 days). + */ + RESULT_ENSURE(ticket_lifetime <= ONE_WEEK_IN_SEC, S2N_ERR_BAD_MESSAGE); + /** + *= https://tools.ietf.org/rfc/rfc8446#section-4.6.1 + *# The value of zero indicates that the + *# ticket should be discarded immediately. + */ + if (ticket_lifetime == 0) { + return S2N_RESULT_OK; } + conn->ticket_lifetime_hint = ticket_lifetime; - GUARD(s2n_stuffer_init(&to, &entry)); - GUARD(s2n_stuffer_write_uint32(&conn->handshake.io, lifetime_hint_in_secs)); - GUARD(s2n_stuffer_write_uint16(&conn->handshake.io, session_ticket_len)); + /* Handle `ticket_age_add` field */ + RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(input, &ticket_fields->ticket_age_add)); - GUARD(s2n_encrypt_session_ticket(conn, &to)); - GUARD(s2n_stuffer_write(&conn->handshake.io, &to.blob)); + /* Handle `ticket_nonce` field */ + uint8_t ticket_nonce_len = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(input, &ticket_nonce_len)); + uint8_t nonce_data[UINT8_MAX] = { 0 }; + struct s2n_blob nonce = { 0 }; + RESULT_GUARD_POSIX(s2n_blob_init(&nonce, nonce_data, ticket_nonce_len)); + RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(input, nonce.data, ticket_nonce_len)); + RESULT_GUARD_POSIX(s2n_generate_session_secret(conn, &nonce, &ticket_fields->session_secret)); + + /* Handle `ticket` field */ + uint16_t session_ticket_len = 0; + RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(input, &session_ticket_len)); + RESULT_ENSURE(session_ticket_len > 0, S2N_ERR_SAFETY); + RESULT_GUARD_POSIX(s2n_realloc(&conn->client_ticket, session_ticket_len)); + RESULT_GUARD_POSIX(s2n_stuffer_read(input, &conn->client_ticket)); + + /* Handle `extensions` field */ + RESULT_GUARD_POSIX(s2n_extension_list_recv(S2N_EXTENSION_LIST_NST, conn, input)); + + if (conn->config->session_ticket_cb != NULL) { + /* Retrieve serialized session data */ + const uint16_t session_state_size = s2n_connection_get_session_length(conn); + DEFER_CLEANUP(struct s2n_blob session_state = { 0 }, s2n_free); + RESULT_GUARD_POSIX(s2n_realloc(&session_state, session_state_size)); + RESULT_GUARD_POSIX(s2n_connection_get_session(conn, session_state.data, session_state.size)); + + struct s2n_session_ticket ticket = { + .ticket_data = session_state, + .session_lifetime = ticket_lifetime + }; + RESULT_GUARD_POSIX(conn->config->session_ticket_cb(conn, conn->config->session_ticket_ctx, &ticket)); + } - return 0; + return S2N_RESULT_OK; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_shutdown.c b/contrib/restricted/aws/s2n/tls/s2n_shutdown.c index 700d94b1d1..383d3026a5 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_shutdown.c +++ b/contrib/restricted/aws/s2n/tls/s2n_shutdown.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "tls/s2n_alerts.h" #include "tls/s2n_connection.h" @@ -23,8 +23,8 @@ int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status * more) { - notnull_check(conn); - notnull_check(more); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(more); /* Treat this call as a no-op if already wiped */ if (conn->send == NULL && conn->recv == NULL) { @@ -32,24 +32,27 @@ int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status * more) } uint64_t elapsed; - GUARD_AS_POSIX(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); + POSIX_GUARD_RESULT(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed)); S2N_ERROR_IF(elapsed < conn->delay, S2N_ERR_SHUTDOWN_PAUSED); /* Queue our close notify, once. Use warning level so clients don't give up */ - GUARD(s2n_queue_writer_close_alert_warning(conn)); + POSIX_GUARD(s2n_queue_writer_close_alert_warning(conn)); /* Write it */ - GUARD(s2n_flush(conn, more)); + POSIX_GUARD(s2n_flush(conn, more)); /* Assume caller isn't interested in pending incoming data */ if (conn->in_status == PLAINTEXT) { - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); + POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; } - /* Fails with S2N_ERR_SHUTDOWN_RECORD_TYPE or S2N_ERR_ALERT on receipt of anything but a close_notify */ - GUARD(s2n_recv_close_notify(conn, more)); + /* Dont expect to receive another close notify alert if we have already received it */ + if (!conn->close_notify_received) { + /* Fails with S2N_ERR_SHUTDOWN_RECORD_TYPE or S2N_ERR_ALERT on receipt of anything but a close_notify */ + POSIX_GUARD(s2n_recv_close_notify(conn, more)); + } return 0; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.c b/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.c index 4645eae5f1..ae367e9670 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.c +++ b/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.c @@ -21,7 +21,6 @@ #include "tls/s2n_auth_selection.h" #include "tls/s2n_cipher_suites.h" #include "tls/s2n_kex.h" -#include "tls/s2n_tls_digest_preferences.h" #include "tls/s2n_signature_algorithms.h" #include "tls/s2n_signature_scheme.h" #include "tls/s2n_security_policies.h" @@ -31,14 +30,19 @@ static int s2n_signature_scheme_valid_to_offer(struct s2n_connection *conn, const struct s2n_signature_scheme *scheme) { /* We don't know what protocol version we will eventually negotiate, but we know that it won't be any higher. */ - gte_check(conn->actual_protocol_version, scheme->minimum_protocol_version); + POSIX_ENSURE_GTE(conn->actual_protocol_version, scheme->minimum_protocol_version); + + /* QUIC only supports TLS1.3 */ + if (s2n_connection_is_quic_enabled(conn) && scheme->maximum_protocol_version) { + POSIX_ENSURE_GTE(scheme->maximum_protocol_version, S2N_TLS13); + } if (!s2n_is_rsa_pss_signing_supported()) { - ne_check(scheme->sig_alg, S2N_SIGNATURE_RSA_PSS_RSAE); + POSIX_ENSURE_NE(scheme->sig_alg, S2N_SIGNATURE_RSA_PSS_RSAE); } if (!s2n_is_rsa_pss_certs_supported()) { - ne_check(scheme->sig_alg, S2N_SIGNATURE_RSA_PSS_PSS); + POSIX_ENSURE_NE(scheme->sig_alg, S2N_SIGNATURE_RSA_PSS_PSS); } return 0; @@ -46,23 +50,23 @@ static int s2n_signature_scheme_valid_to_offer(struct s2n_connection *conn, cons static int s2n_signature_scheme_valid_to_accept(struct s2n_connection *conn, const struct s2n_signature_scheme *scheme) { - notnull_check(scheme); + POSIX_ENSURE_REF(scheme); - GUARD(s2n_signature_scheme_valid_to_offer(conn, scheme)); + POSIX_GUARD(s2n_signature_scheme_valid_to_offer(conn, scheme)); if (scheme->maximum_protocol_version != S2N_UNKNOWN_PROTOCOL_VERSION) { - lte_check(conn->actual_protocol_version, scheme->maximum_protocol_version); + POSIX_ENSURE_LTE(conn->actual_protocol_version, scheme->maximum_protocol_version); } return 0; } static int s2n_is_signature_scheme_usable(struct s2n_connection *conn, const struct s2n_signature_scheme *candidate) { - notnull_check(conn); - notnull_check(candidate); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(candidate); - GUARD(s2n_signature_scheme_valid_to_accept(conn, candidate)); - GUARD(s2n_is_sig_scheme_valid_for_auth(conn, candidate)); + POSIX_GUARD(s2n_signature_scheme_valid_to_accept(conn, candidate)); + POSIX_GUARD(s2n_is_sig_scheme_valid_for_auth(conn, candidate)); return S2N_SUCCESS; } @@ -70,13 +74,13 @@ static int s2n_is_signature_scheme_usable(struct s2n_connection *conn, const str static int s2n_choose_sig_scheme(struct s2n_connection *conn, struct s2n_sig_scheme_list *peer_wire_prefs, struct s2n_signature_scheme *chosen_scheme_out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_signature_preferences *signature_preferences = NULL; - GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); - notnull_check(signature_preferences); + POSIX_GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); + POSIX_ENSURE_REF(signature_preferences); struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite; - notnull_check(cipher_suite); + POSIX_ENSURE_REF(cipher_suite); for (size_t i = 0; i < signature_preferences->count; i++) { const struct s2n_signature_scheme *candidate = signature_preferences->signature_schemes[i]; @@ -100,15 +104,15 @@ static int s2n_choose_sig_scheme(struct s2n_connection *conn, struct s2n_sig_sch } /* similar to s2n_choose_sig_scheme() without matching client's preference */ -static int s2n_tls13_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *chosen_scheme_out) +int s2n_tls13_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *chosen_scheme_out) { - notnull_check(conn); + POSIX_ENSURE_REF(conn); const struct s2n_signature_preferences *signature_preferences = NULL; - GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); - notnull_check(signature_preferences); + POSIX_GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); + POSIX_ENSURE_REF(signature_preferences); struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite; - notnull_check(cipher_suite); + POSIX_ENSURE_REF(cipher_suite); for (size_t i = 0; i < signature_preferences->count; i++) { const struct s2n_signature_scheme *candidate = signature_preferences->signature_schemes[i]; @@ -121,18 +125,18 @@ static int s2n_tls13_default_sig_scheme(struct s2n_connection *conn, struct s2n_ return S2N_SUCCESS; } - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_SCHEME); + POSIX_BAIL(S2N_ERR_INVALID_SIGNATURE_SCHEME); } int s2n_get_and_validate_negotiated_signature_scheme(struct s2n_connection *conn, struct s2n_stuffer *in, struct s2n_signature_scheme *chosen_sig_scheme) { uint16_t actual_iana_val; - GUARD(s2n_stuffer_read_uint16(in, &actual_iana_val)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &actual_iana_val)); const struct s2n_signature_preferences *signature_preferences = NULL; - GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); - notnull_check(signature_preferences); + POSIX_GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); + POSIX_ENSURE_REF(signature_preferences); for (size_t i = 0; i < signature_preferences->count; i++) { const struct s2n_signature_scheme *candidate = signature_preferences->signature_schemes[i]; @@ -150,8 +154,8 @@ int s2n_get_and_validate_negotiated_signature_scheme(struct s2n_connection *conn /* We require an exact match in TLS 1.3, but all previous versions can fall back to the default SignatureScheme. * This means that an s2n client will accept the default SignatureScheme from a TLS server, even if the client did * not send it in it's ClientHello. This pre-TLS1.3 behavior is an intentional choice to maximize support. */ - struct s2n_signature_scheme default_scheme; - GUARD(s2n_choose_default_sig_scheme(conn, &default_scheme)); + struct s2n_signature_scheme default_scheme = { 0 }; + POSIX_GUARD(s2n_choose_default_sig_scheme(conn, &default_scheme, S2N_PEER_MODE(conn->mode))); if ((conn->actual_protocol_version <= S2N_TLS12) && (s2n_signature_scheme_valid_to_accept(conn, &default_scheme) == S2N_SUCCESS) @@ -161,16 +165,21 @@ int s2n_get_and_validate_negotiated_signature_scheme(struct s2n_connection *conn return S2N_SUCCESS; } - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_SCHEME); + POSIX_BAIL(S2N_ERR_INVALID_SIGNATURE_SCHEME); } -int s2n_choose_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *sig_scheme_out) +int s2n_choose_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *sig_scheme_out, s2n_mode signer) { - notnull_check(conn); - notnull_check(conn->secure.cipher_suite); - notnull_check(sig_scheme_out); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(sig_scheme_out); - s2n_authentication_method cipher_suite_auth_method = conn->secure.cipher_suite->auth_method; + s2n_authentication_method auth_method = 0; + if (signer == S2N_CLIENT) { + POSIX_GUARD(s2n_get_auth_method_for_cert_type(conn->handshake_params.client_cert_pkey_type, &auth_method)); + } else { + POSIX_ENSURE_REF(conn->secure.cipher_suite); + auth_method = conn->secure.cipher_suite->auth_method; + } /* Default our signature digest algorithms. For TLS 1.2 this default is different and may be * overridden by the signature_algorithms extension. If the server chooses an ECDHE_ECDSA @@ -178,13 +187,11 @@ int s2n_choose_default_sig_scheme(struct s2n_connection *conn, struct s2n_signat */ *sig_scheme_out = s2n_rsa_pkcs1_md5_sha1; - if (cipher_suite_auth_method == S2N_AUTHENTICATION_ECDSA) { + if (auth_method == S2N_AUTHENTICATION_ECDSA) { *sig_scheme_out = s2n_ecdsa_sha1; - } - - /* Default RSA Hash Algorithm is SHA1 (instead of MD5_SHA1) if TLS 1.2 or FIPS mode */ - if ((conn->actual_protocol_version >= S2N_TLS12 || s2n_is_in_fips_mode()) - && (sig_scheme_out->sig_alg == S2N_SIGNATURE_RSA)) { + } else if (conn->actual_protocol_version >= S2N_TLS12) { + *sig_scheme_out = s2n_rsa_pkcs1_sha1; + } else if (s2n_is_in_fips_mode() && signer == S2N_SERVER) { *sig_scheme_out = s2n_rsa_pkcs1_sha1; } @@ -194,41 +201,39 @@ int s2n_choose_default_sig_scheme(struct s2n_connection *conn, struct s2n_signat int s2n_choose_sig_scheme_from_peer_preference_list(struct s2n_connection *conn, struct s2n_sig_scheme_list *peer_wire_prefs, struct s2n_signature_scheme *sig_scheme_out) { - notnull_check(conn); - notnull_check(sig_scheme_out); - - struct s2n_signature_scheme chosen_scheme; + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(sig_scheme_out); + struct s2n_signature_scheme chosen_scheme = { 0 }; if (conn->actual_protocol_version < S2N_TLS13) { - GUARD(s2n_choose_default_sig_scheme(conn, &chosen_scheme)); + POSIX_GUARD(s2n_choose_default_sig_scheme(conn, &chosen_scheme, conn->mode)); } else { /* Pick a default signature algorithm in TLS 1.3 https://tools.ietf.org/html/rfc8446#section-4.4.2.2 */ - GUARD(s2n_tls13_default_sig_scheme(conn, &chosen_scheme)); + POSIX_GUARD(s2n_tls13_default_sig_scheme(conn, &chosen_scheme)); } /* SignatureScheme preference list was first added in TLS 1.2. It will be empty in older TLS versions. */ if (peer_wire_prefs != NULL && peer_wire_prefs->len > 0) { /* Use a best effort approach to selecting a signature scheme matching client's preferences */ - GUARD(s2n_choose_sig_scheme(conn, peer_wire_prefs, &chosen_scheme)); + POSIX_GUARD(s2n_choose_sig_scheme(conn, peer_wire_prefs, &chosen_scheme)); } *sig_scheme_out = chosen_scheme; - return S2N_SUCCESS; } int s2n_send_supported_sig_scheme_list(struct s2n_connection *conn, struct s2n_stuffer *out) { const struct s2n_signature_preferences *signature_preferences = NULL; - GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); - notnull_check(signature_preferences); + POSIX_GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); + POSIX_ENSURE_REF(signature_preferences); - GUARD(s2n_stuffer_write_uint16(out, s2n_supported_sig_scheme_list_size(conn))); + POSIX_GUARD(s2n_stuffer_write_uint16(out, s2n_supported_sig_scheme_list_size(conn))); for (size_t i = 0; i < signature_preferences->count; i++) { const struct s2n_signature_scheme *const scheme = signature_preferences->signature_schemes[i]; if (0 == s2n_signature_scheme_valid_to_offer(conn, scheme)) { - GUARD(s2n_stuffer_write_uint16(out, scheme->iana_value)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, scheme->iana_value)); } } @@ -243,8 +248,8 @@ int s2n_supported_sig_scheme_list_size(struct s2n_connection *conn) int s2n_supported_sig_schemes_count(struct s2n_connection *conn) { const struct s2n_signature_preferences *signature_preferences = NULL; - GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); - notnull_check(signature_preferences); + POSIX_GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences)); + POSIX_ENSURE_REF(signature_preferences); uint8_t count = 0; for (size_t i = 0; i < signature_preferences->count; i++) { @@ -258,7 +263,7 @@ int s2n_supported_sig_schemes_count(struct s2n_connection *conn) int s2n_recv_supported_sig_scheme_list(struct s2n_stuffer *in, struct s2n_sig_scheme_list *sig_hash_algs) { uint16_t length_of_all_pairs; - GUARD(s2n_stuffer_read_uint16(in, &length_of_all_pairs)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &length_of_all_pairs)); if (length_of_all_pairs > s2n_stuffer_data_available(in)) { /* Malformed length, ignore the extension */ return 0; @@ -266,21 +271,21 @@ int s2n_recv_supported_sig_scheme_list(struct s2n_stuffer *in, struct s2n_sig_sc if (length_of_all_pairs % 2) { /* Pairs occur in two byte lengths. Malformed length, ignore the extension and skip ahead */ - GUARD(s2n_stuffer_skip_read(in, length_of_all_pairs)); + POSIX_GUARD(s2n_stuffer_skip_read(in, length_of_all_pairs)); return 0; } int pairs_available = length_of_all_pairs / 2; if (pairs_available > TLS_SIGNATURE_SCHEME_LIST_MAX_LEN) { - S2N_ERROR(S2N_ERR_TOO_MANY_SIGNATURE_SCHEMES); + POSIX_BAIL(S2N_ERR_TOO_MANY_SIGNATURE_SCHEMES); } sig_hash_algs->len = 0; for (size_t i = 0; i < pairs_available; i++) { uint16_t sig_scheme = 0; - GUARD(s2n_stuffer_read_uint16(in, &sig_scheme)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &sig_scheme)); sig_hash_algs->iana_list[sig_hash_algs->len] = sig_scheme; sig_hash_algs->len += 1; diff --git a/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.h b/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.h index b400977a16..f1533335ba 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.h +++ b/contrib/restricted/aws/s2n/tls/s2n_signature_algorithms.h @@ -15,7 +15,7 @@ #pragma once -#include <s2n.h> +#include "api/s2n.h" #include "crypto/s2n_hash.h" #include "crypto/s2n_signature.h" @@ -29,7 +29,9 @@ struct s2n_sig_scheme_list { uint8_t len; }; -int s2n_choose_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *sig_scheme_out); +int s2n_choose_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *sig_scheme_out, s2n_mode signer); +int s2n_tls13_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *sig_scheme_out); + int s2n_choose_sig_scheme_from_peer_preference_list(struct s2n_connection *conn, struct s2n_sig_scheme_list *sig_hash_algs, struct s2n_signature_scheme *sig_scheme_out); int s2n_get_and_validate_negotiated_signature_scheme(struct s2n_connection *conn, struct s2n_stuffer *in, diff --git a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c index 911e717127..6ccddacab6 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c +++ b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -#include <s2n.h> +#include "api/s2n.h" #include "crypto/s2n_hash.h" #include "crypto/s2n_signature.h" @@ -339,3 +339,19 @@ const struct s2n_signature_preferences s2n_certificate_signature_preferences_202 .count = s2n_array_len(s2n_sig_scheme_pref_list_20201110), .signature_schemes = s2n_sig_scheme_pref_list_20201110, }; + +/* Based on s2n_sig_scheme_pref_list_20140601 but with all hashes < SHA-384 removed */ +const struct s2n_signature_scheme* const s2n_sig_scheme_pref_list_20210816[] = { + /* RSA PKCS1 */ + &s2n_rsa_pkcs1_sha384, + &s2n_rsa_pkcs1_sha512, + + /* ECDSA - TLS 1.2 */ + &s2n_ecdsa_sha384, /* same iana value as TLS 1.3 s2n_ecdsa_secp384r1_sha384 */ + &s2n_ecdsa_sha512, +}; + +const struct s2n_signature_preferences s2n_signature_preferences_20210816 = { + .count = s2n_array_len(s2n_sig_scheme_pref_list_20210816), + .signature_schemes = s2n_sig_scheme_pref_list_20210816 +}; diff --git a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h index 416f936a6d..3f78d8a500 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h +++ b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h @@ -15,7 +15,7 @@ #pragma once -#include <s2n.h> +#include "api/s2n.h" #include <strings.h> #include "crypto/s2n_hash.h" @@ -76,6 +76,7 @@ extern const struct s2n_signature_scheme s2n_rsa_pss_rsae_sha512; extern const struct s2n_signature_preferences s2n_signature_preferences_20140601; extern const struct s2n_signature_preferences s2n_signature_preferences_20200207; extern const struct s2n_signature_preferences s2n_signature_preferences_20201021; +extern const struct s2n_signature_preferences s2n_signature_preferences_20210816; extern const struct s2n_signature_preferences s2n_signature_preferences_null; extern const struct s2n_signature_preferences s2n_certificate_signature_preferences_20201110; diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls.h b/contrib/restricted/aws/s2n/tls/s2n_tls.h index d74822a236..7f17c8bc7c 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls.h +++ b/contrib/restricted/aws/s2n/tls/s2n_tls.h @@ -24,6 +24,7 @@ extern uint8_t s2n_unknown_protocol_version; extern uint8_t s2n_highest_protocol_version; extern int s2n_flush(struct s2n_connection *conn, s2n_blocked_status * more); +int s2n_client_hello_request_recv(struct s2n_connection *conn); extern int s2n_client_hello_send(struct s2n_connection *conn); extern int s2n_client_hello_recv(struct s2n_connection *conn); extern int s2n_establish_session(struct s2n_connection *conn); @@ -57,6 +58,9 @@ extern int s2n_tls13_cert_verify_recv(struct s2n_connection *conn); extern int s2n_tls13_cert_verify_send(struct s2n_connection *conn); extern int s2n_server_nst_send(struct s2n_connection *conn); extern int s2n_server_nst_recv(struct s2n_connection *conn); +S2N_RESULT s2n_tls13_server_nst_send(struct s2n_connection *conn, s2n_blocked_status *blocked); +S2N_RESULT s2n_tls13_server_nst_write(struct s2n_connection *conn, struct s2n_stuffer *output); +S2N_RESULT s2n_tls13_server_nst_recv(struct s2n_connection *conn, struct s2n_stuffer *input); extern int s2n_ccs_send(struct s2n_connection *conn); extern int s2n_basic_ccs_recv(struct s2n_connection *conn); extern int s2n_server_ccs_recv(struct s2n_connection *conn); @@ -69,6 +73,8 @@ extern int s2n_tls13_client_finished_send(struct s2n_connection *conn); extern int s2n_tls13_client_finished_recv(struct s2n_connection *conn); extern int s2n_tls13_server_finished_send(struct s2n_connection *conn); extern int s2n_tls13_server_finished_recv(struct s2n_connection *conn); +extern int s2n_end_of_early_data_send(struct s2n_connection *conn); +extern int s2n_end_of_early_data_recv(struct s2n_connection *conn); extern int s2n_process_client_hello(struct s2n_connection *conn); extern int s2n_handshake_write_header(struct s2n_stuffer *out, uint8_t message_type); extern int s2n_handshake_finish_header(struct s2n_stuffer *out); diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13.c b/contrib/restricted/aws/s2n/tls/s2n_tls13.c index 52dd99a86a..790ad8cadc 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls13.c +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13.c @@ -16,6 +16,7 @@ #include "api/s2n.h" #include "tls/s2n_tls.h" #include "tls/s2n_tls13.h" +#include "crypto/s2n_rsa_pss.h" #include "crypto/s2n_rsa_signing.h" bool s2n_use_default_tls13_config_flag = false; @@ -25,6 +26,17 @@ bool s2n_use_default_tls13_config() return s2n_use_default_tls13_config_flag; } +bool s2n_is_tls13_fully_supported() +{ + /* Older versions of Openssl (eg 1.0.2) do not support RSA PSS, which is required for TLS 1.3. */ + return s2n_is_rsa_pss_signing_supported() && s2n_is_rsa_pss_certs_supported(); +} + +int s2n_get_highest_fully_supported_tls_version() +{ + return s2n_is_tls13_fully_supported() ? S2N_TLS13 : S2N_TLS12; +} + /* Allow TLS1.3 to be negotiated, and use the default TLS1.3 security policy. * This is NOT the default behavior, and this method is deprecated. * @@ -33,6 +45,17 @@ bool s2n_use_default_tls13_config() */ int s2n_enable_tls13() { + return s2n_enable_tls13_in_test(); +} + +/* Allow TLS1.3 to be negotiated, and use the default TLS1.3 security policy. + * This is NOT the default behavior, and this method is deprecated. + * + * Please consider using the default behavior and configuring + * TLS1.2/TLS1.3 via explicit security policy instead. + */ +int s2n_enable_tls13_in_test() +{ s2n_highest_protocol_version = S2N_TLS13; s2n_use_default_tls13_config_flag = true; return S2N_SUCCESS; @@ -44,9 +67,9 @@ int s2n_enable_tls13() * Please consider using the default behavior and configuring * TLS1.2/TLS1.3 via explicit security policy instead. */ -int s2n_disable_tls13() +int s2n_disable_tls13_in_test() { - ENSURE_POSIX(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); + POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); s2n_highest_protocol_version = S2N_TLS12; s2n_use_default_tls13_config_flag = false; return S2N_SUCCESS; @@ -57,9 +80,9 @@ int s2n_disable_tls13() * This method is intended for use in existing unit tests when the APIs * to enable/disable TLS1.3 have already been called. */ -int s2n_reset_tls13() +int s2n_reset_tls13_in_test() { - ENSURE_POSIX(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); + POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); s2n_highest_protocol_version = S2N_TLS13; s2n_use_default_tls13_config_flag = false; return S2N_SUCCESS; @@ -73,3 +96,53 @@ bool s2n_is_valid_tls13_cipher(const uint8_t version[2]) { */ return version[0] == 0x13 && version[1] >= 0x01 && version[1] <= 0x05; } + +/* Use middlebox compatibility mode for TLS1.3 by default. + * For now, only disable it when QUIC support is enabled. + */ +bool s2n_is_middlebox_compat_enabled(struct s2n_connection *conn) +{ + return s2n_connection_get_protocol_version(conn) >= S2N_TLS13 + && !s2n_connection_is_quic_enabled(conn); +} + +S2N_RESULT s2n_connection_validate_tls13_support(struct s2n_connection *conn) +{ + RESULT_ENSURE_REF(conn); + + /* If the underlying libcrypto supports all features of TLS1.3 + * (including RSA-PSS, which is unsupported by some libraries), + * then we can always support TLS1.3. + */ + if (s2n_is_tls13_fully_supported()) { + return S2N_RESULT_OK; + } + + /* + * If the underlying libcrypto doesn't support all features... + */ + + /* There are some TLS servers in the wild that will choose options not offered by the client. + * So a server might choose to use RSA-PSS even if even if the client does not advertise support for RSA-PSS. + * Therefore, only servers can perform TLS1.3 without full feature support. + */ + RESULT_ENSURE(conn->mode == S2N_SERVER, S2N_RSA_PSS_NOT_SUPPORTED); + + /* RSA signatures must use RSA-PSS in TLS1.3. + * So RSA-PSS is required for TLS1.3 servers if an RSA certificate is used. + */ + RESULT_ENSURE(!conn->config->is_rsa_cert_configured, S2N_RSA_PSS_NOT_SUPPORTED); + + /* RSA-PSS is also required for TLS1.3 servers if client auth is requested, because the + * client might offer an RSA certificate. + */ + s2n_cert_auth_type client_auth_status = S2N_CERT_AUTH_NONE; + RESULT_GUARD_POSIX(s2n_connection_get_client_auth_type(conn, &client_auth_status)); + RESULT_ENSURE(client_auth_status == S2N_CERT_AUTH_NONE, S2N_RSA_PSS_NOT_SUPPORTED); + + return S2N_RESULT_OK; +} + +bool s2n_connection_supports_tls13(struct s2n_connection *conn) { + return s2n_result_is_ok(s2n_connection_validate_tls13_support(conn)); +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13.h b/contrib/restricted/aws/s2n/tls/s2n_tls13.h index 53dedaf02e..7ad815bd71 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls13.h +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13.h @@ -42,9 +42,16 @@ extern "C" { extern uint8_t hello_retry_req_random[S2N_TLS_RANDOM_DATA_LEN]; bool s2n_use_default_tls13_config(); -int s2n_disable_tls13(); -int s2n_reset_tls13(); +bool s2n_is_tls13_fully_supported(); +int s2n_get_highest_fully_supported_tls_version(); +int s2n_enable_tls13_in_test(); +int s2n_disable_tls13_in_test(); +int s2n_reset_tls13_in_test(); bool s2n_is_valid_tls13_cipher(const uint8_t version[2]); +S2N_RESULT s2n_connection_validate_tls13_support(struct s2n_connection *conn); +bool s2n_connection_supports_tls13(struct s2n_connection *conn); + +bool s2n_is_middlebox_compat_enabled(struct s2n_connection *conn); bool s2n_is_hello_retry_handshake(struct s2n_connection *conn); bool s2n_is_hello_retry_message(struct s2n_connection *conn); diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_certificate_verify.c b/contrib/restricted/aws/s2n/tls/s2n_tls13_certificate_verify.c index 74654f33cf..abc96b8b21 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls13_certificate_verify.c +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_certificate_verify.c @@ -60,10 +60,10 @@ int s2n_tls13_cert_verify_send(struct s2n_connection *conn) if (conn->mode == S2N_SERVER) { /* Write digital signature */ - GUARD(s2n_tls13_write_cert_verify_signature(conn, &conn->secure.conn_sig_scheme)); + POSIX_GUARD(s2n_tls13_write_cert_verify_signature(conn, &conn->handshake_params.conn_sig_scheme)); } else { /* Write digital signature */ - GUARD(s2n_tls13_write_cert_verify_signature(conn, &conn->secure.client_cert_sig_scheme)); + POSIX_GUARD(s2n_tls13_write_cert_verify_signature(conn, &conn->handshake_params.client_cert_sig_scheme)); } @@ -72,20 +72,20 @@ int s2n_tls13_cert_verify_send(struct s2n_connection *conn) int s2n_tls13_write_cert_verify_signature(struct s2n_connection *conn, struct s2n_signature_scheme *chosen_sig_scheme) { - notnull_check(conn->handshake_params.our_chain_and_key); + POSIX_ENSURE_REF(conn->handshake_params.our_chain_and_key); /* Write the SignatureScheme out */ struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_stuffer_write_uint16(out, chosen_sig_scheme->iana_value)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, chosen_sig_scheme->iana_value)); DEFER_CLEANUP(struct s2n_hash_state message_hash = {0}, s2n_hash_free); - GUARD(s2n_hash_new(&message_hash)); - GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg)); + POSIX_GUARD(s2n_hash_new(&message_hash)); + POSIX_GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg)); DEFER_CLEANUP(struct s2n_stuffer unsigned_content = {0}, s2n_stuffer_free); - GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, conn->mode)); + POSIX_GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, conn->mode)); - GUARD(s2n_hash_update(&message_hash, unsigned_content.blob.data, s2n_stuffer_data_available(&unsigned_content))); + POSIX_GUARD(s2n_hash_update(&message_hash, unsigned_content.blob.data, s2n_stuffer_data_available(&unsigned_content))); S2N_ASYNC_PKEY_SIGN(conn, chosen_sig_scheme->sig_alg, &message_hash, s2n_tls13_write_signature); } @@ -94,8 +94,8 @@ int s2n_tls13_write_signature(struct s2n_connection *conn, struct s2n_blob *sign { struct s2n_stuffer *out = &conn->handshake.io; - GUARD(s2n_stuffer_write_uint16(out, signature->size)); - GUARD(s2n_stuffer_write_bytes(out, signature->data, signature->size)); + POSIX_GUARD(s2n_stuffer_write_uint16(out, signature->size)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, signature->data, signature->size)); return 0; } @@ -104,30 +104,26 @@ int s2n_tls13_generate_unsigned_cert_verify_content(struct s2n_connection *conn, { s2n_tls13_connection_keys(tls13_ctx, conn); - struct s2n_hash_state handshake_hash, hash_copy; uint8_t hash_digest_length = tls13_ctx.size; uint8_t digest_out[S2N_MAX_DIGEST_LEN]; /* Get current handshake hash */ - GUARD(s2n_handshake_get_hash_state(conn, tls13_ctx.hash_algorithm, &handshake_hash)); - - /* Copy current hash content */ - GUARD(s2n_hash_new(&hash_copy)); - GUARD(s2n_hash_copy(&hash_copy, &handshake_hash)); - GUARD(s2n_hash_digest(&hash_copy, digest_out, hash_digest_length)); - GUARD(s2n_hash_free(&hash_copy)); + POSIX_ENSURE_REF(conn->handshake.hashes); + struct s2n_hash_state *hash_state = &conn->handshake.hashes->hash_workspace; + POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, tls13_ctx.hash_algorithm, hash_state)); + POSIX_GUARD(s2n_hash_digest(hash_state, digest_out, hash_digest_length)); /* Concatenate the content to be signed/verified */ - GUARD(s2n_stuffer_alloc(unsigned_content, hash_digest_length + s2n_tls13_cert_verify_header_length(mode))); - GUARD(s2n_stuffer_write_bytes(unsigned_content, S2N_CERT_VERIFY_PREFIX, sizeof(S2N_CERT_VERIFY_PREFIX))); + POSIX_GUARD(s2n_stuffer_alloc(unsigned_content, hash_digest_length + s2n_tls13_cert_verify_header_length(mode))); + POSIX_GUARD(s2n_stuffer_write_bytes(unsigned_content, S2N_CERT_VERIFY_PREFIX, sizeof(S2N_CERT_VERIFY_PREFIX))); if (mode == S2N_CLIENT) { - GUARD(s2n_stuffer_write_bytes(unsigned_content, S2N_CLIENT_CERT_VERIFY_CONTEXT, sizeof(S2N_CLIENT_CERT_VERIFY_CONTEXT))); + POSIX_GUARD(s2n_stuffer_write_bytes(unsigned_content, S2N_CLIENT_CERT_VERIFY_CONTEXT, sizeof(S2N_CLIENT_CERT_VERIFY_CONTEXT))); } else { - GUARD(s2n_stuffer_write_bytes(unsigned_content, S2N_SERVER_CERT_VERIFY_CONTEXT, sizeof(S2N_SERVER_CERT_VERIFY_CONTEXT))); + POSIX_GUARD(s2n_stuffer_write_bytes(unsigned_content, S2N_SERVER_CERT_VERIFY_CONTEXT, sizeof(S2N_SERVER_CERT_VERIFY_CONTEXT))); } - GUARD(s2n_stuffer_write_bytes(unsigned_content, digest_out, hash_digest_length)); + POSIX_GUARD(s2n_stuffer_write_bytes(unsigned_content, digest_out, hash_digest_length)); return 0; } @@ -144,16 +140,16 @@ int s2n_tls13_cert_verify_recv(struct s2n_connection *conn) { if (conn->mode == S2N_SERVER) { /* Read the algorithm and update sig_scheme */ - GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, &conn->handshake.io, &conn->secure.client_cert_sig_scheme)); + POSIX_GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, &conn->handshake.io, &conn->handshake_params.client_cert_sig_scheme)); /* Read the rest of the signature and verify */ - GUARD(s2n_tls13_cert_read_and_verify_signature(conn, &conn->secure.client_cert_sig_scheme)); + POSIX_GUARD(s2n_tls13_cert_read_and_verify_signature(conn, &conn->handshake_params.client_cert_sig_scheme)); } else { /* Read the algorithm and update sig_scheme */ - GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, &conn->handshake.io, &conn->secure.conn_sig_scheme)); + POSIX_GUARD(s2n_get_and_validate_negotiated_signature_scheme(conn, &conn->handshake.io, &conn->handshake_params.conn_sig_scheme)); /* Read the rest of the signature and verify */ - GUARD(s2n_tls13_cert_read_and_verify_signature(conn, &conn->secure.conn_sig_scheme)); + POSIX_GUARD(s2n_tls13_cert_read_and_verify_signature(conn, &conn->handshake_params.conn_sig_scheme)); } return 0; @@ -165,32 +161,32 @@ int s2n_tls13_cert_read_and_verify_signature(struct s2n_connection *conn, struct DEFER_CLEANUP(struct s2n_blob signed_content = {0}, s2n_free); DEFER_CLEANUP(struct s2n_stuffer unsigned_content = {0}, s2n_stuffer_free); DEFER_CLEANUP(struct s2n_hash_state message_hash = {0}, s2n_hash_free); - GUARD(s2n_hash_new(&message_hash)); + POSIX_GUARD(s2n_hash_new(&message_hash)); /* Get signature size */ uint16_t signature_size; - GUARD(s2n_stuffer_read_uint16(in, &signature_size)); + POSIX_GUARD(s2n_stuffer_read_uint16(in, &signature_size)); S2N_ERROR_IF(signature_size > s2n_stuffer_data_available(in), S2N_ERR_BAD_MESSAGE); /* Get wire signature */ - GUARD(s2n_alloc(&signed_content, signature_size)); + POSIX_GUARD(s2n_alloc(&signed_content, signature_size)); signed_content.size = signature_size; - GUARD(s2n_stuffer_read_bytes(in, signed_content.data, signature_size)); + POSIX_GUARD(s2n_stuffer_read_bytes(in, signed_content.data, signature_size)); /* Verify signature. We send the opposite mode as we are trying to verify what was sent to us */ if (conn->mode == S2N_CLIENT) { - GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, S2N_SERVER)); + POSIX_GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, S2N_SERVER)); } else { - GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, S2N_CLIENT)); + POSIX_GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, S2N_CLIENT)); } - GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg)); - GUARD(s2n_hash_update(&message_hash, unsigned_content.blob.data, s2n_stuffer_data_available(&unsigned_content))); + POSIX_GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg)); + POSIX_GUARD(s2n_hash_update(&message_hash, unsigned_content.blob.data, s2n_stuffer_data_available(&unsigned_content))); if (conn->mode == S2N_CLIENT) { - GUARD(s2n_pkey_verify(&conn->secure.server_public_key, chosen_sig_scheme->sig_alg, &message_hash, &signed_content)); + POSIX_GUARD(s2n_pkey_verify(&conn->handshake_params.server_public_key, chosen_sig_scheme->sig_alg, &message_hash, &signed_content)); } else { - GUARD(s2n_pkey_verify(&conn->secure.client_public_key, chosen_sig_scheme->sig_alg, &message_hash, &signed_content)); + POSIX_GUARD(s2n_pkey_verify(&conn->handshake_params.client_public_key, chosen_sig_scheme->sig_alg, &message_hash, &signed_content)); } return 0; diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c b/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c index 4382c02382..e5b2bd3202 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.c @@ -15,358 +15,143 @@ #include "tls/s2n_tls13_handshake.h" #include "tls/s2n_cipher_suites.h" +#include "tls/s2n_key_log.h" #include "tls/s2n_security_policies.h" static int s2n_zero_sequence_number(struct s2n_connection *conn, s2n_mode mode) { - notnull_check(conn); + POSIX_ENSURE_REF(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))); + POSIX_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))); + POSIX_GUARD(s2n_blob_init(&sequence_number, conn->secure.server_sequence_number, sizeof(conn->secure.server_sequence_number))); } - GUARD(s2n_blob_zero(&sequence_number)); + POSIX_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); + POSIX_ENSURE_REF(wire_verify->data); + POSIX_ENSURE_EQ(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; + return S2N_SUCCESS; } 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; + POSIX_GUARD(s2n_tls13_keys_init(keys, conn->secure.cipher_suite->prf_alg)); + return S2N_SUCCESS; } int s2n_tls13_compute_ecc_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) { - notnull_check(conn); + POSIX_ENSURE_REF(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; - } - } + POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_preferences)); + POSIX_ENSURE_REF(ecc_preferences); - 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); + struct s2n_ecc_evp_params *server_key = &conn->kex_params.server_ecc_evp_params; + POSIX_ENSURE_REF(server_key); + POSIX_ENSURE_REF(server_key->negotiated_curve); + + struct s2n_ecc_evp_params *client_key = &conn->kex_params.client_ecc_evp_params; + POSIX_ENSURE_REF(client_key); + POSIX_ENSURE_REF(client_key->negotiated_curve); + + POSIX_ENSURE_EQ(server_key->negotiated_curve, client_key->negotiated_curve); if (conn->mode == S2N_CLIENT) { - GUARD(s2n_ecc_evp_compute_shared_secret_from_params(client_key, server_key, shared_secret)); + POSIX_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)); + POSIX_GUARD(s2n_ecc_evp_compute_shared_secret_from_params(server_key, client_key, shared_secret)); } - return 0; + return S2N_SUCCESS; } /* 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); + POSIX_ENSURE_REF(conn); + POSIX_ENSURE_REF(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); + /* conn->kex_params.server_ecc_evp_params should be set only during a classic/non-hybrid handshake */ + POSIX_ENSURE_EQ(NULL, conn->kex_params.server_ecc_evp_params.negotiated_curve); + POSIX_ENSURE_EQ(NULL, conn->kex_params.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_kem_group_params *server_kem_group_params = &conn->kex_params.server_kem_group_params; + POSIX_ENSURE_REF(server_kem_group_params); struct s2n_ecc_evp_params *server_ecc_params = &server_kem_group_params->ecc_params; - notnull_check(server_ecc_params); + POSIX_ENSURE_REF(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_kem_group_params *client_kem_group_params = &conn->kex_params.client_kem_group_params; + POSIX_ENSURE_REF(client_kem_group_params); struct s2n_ecc_evp_params *client_ecc_params = &client_kem_group_params->ecc_params; - notnull_check(client_ecc_params); + POSIX_ENSURE_REF(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)); + POSIX_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)); + POSIX_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); + POSIX_ENSURE_REF(pq_shared_secret); + POSIX_ENSURE_REF(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); + const struct s2n_kem_group *negotiated_kem_group = conn->kex_params.server_kem_group_params.kem_group; + POSIX_ENSURE_REF(negotiated_kem_group); + POSIX_ENSURE_REF(negotiated_kem_group->kem); - eq_check(pq_shared_secret->size, negotiated_kem_group->kem->shared_secret_key_length); + POSIX_ENSURE_EQ(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)); + POSIX_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)); + POSIX_GUARD(s2n_stuffer_init(&stuffer_combiner, shared_secret)); + POSIX_GUARD(s2n_stuffer_write(&stuffer_combiner, &ecdhe_shared_secret)); + POSIX_GUARD(s2n_stuffer_write(&stuffer_combiner, pq_shared_secret)); return S2N_SUCCESS; } static int s2n_tls13_pq_hybrid_supported(struct s2n_connection *conn) { - return conn->secure.server_kem_group_params.kem_group != NULL; + return conn->kex_params.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); + POSIX_ENSURE_REF(conn); if (s2n_tls13_pq_hybrid_supported(conn)) { - GUARD(s2n_tls13_compute_pq_hybrid_shared_secret(conn, shared_secret)); + POSIX_GUARD(s2n_tls13_compute_pq_hybrid_shared_secret(conn, shared_secret)); } else { - GUARD(s2n_tls13_compute_ecc_shared_secret(conn, shared_secret)); + POSIX_GUARD(s2n_tls13_compute_ecc_shared_secret(conn, shared_secret)); } - return S2N_SUCCESS; -} + POSIX_GUARD_RESULT(s2n_connection_wipe_all_keyshares(conn)); -/* - * 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, conn->psk_params.chosen_psk)); - /* since early secrets have been computed, PSKs are no longer needed and can be cleaned up */ - GUARD_AS_POSIX(s2n_psk_parameters_wipe(&conn->psk_params)); - - /* 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)); - } + /* It would make more sense to wipe the PSK secrets in s2n_tls13_handle_early_secret, + * but at that point we don't know whether or not the server will request a HRR request + * and we'll have to use the secrets again. + * + * Instead, wipe them here when we wipe all the other connection secrets. */ + POSIX_GUARD_RESULT(s2n_psk_parameters_wipe_secrets(&conn->psk_params)); - /* 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; -} - -static int s2n_tls13_handle_resumption_master_secret(struct s2n_connection *conn) -{ - s2n_tls13_connection_keys(keys, conn); - - struct s2n_hash_state hash_state = {0}; - GUARD(s2n_handshake_get_hash_state(conn, keys.hash_algorithm, &hash_state)); - - struct s2n_blob resumption_master_secret = {0}; - GUARD(s2n_blob_init(&resumption_master_secret, conn->resumption_master_secret, keys.size)); - GUARD(s2n_tls13_derive_resumption_master_secret(&keys, &hash_state, &resumption_master_secret)); - 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)); - GUARD(s2n_tls13_handle_resumption_master_secret(conn)); - 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); + POSIX_ENSURE_REF(conn); /* get tls13 key context */ s2n_tls13_connection_keys(keys, conn); @@ -377,28 +162,28 @@ int s2n_update_application_traffic_keys(struct s2n_connection *conn, s2n_mode mo 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)); + POSIX_GUARD(s2n_blob_init(&old_app_secret, conn->secrets.tls13.client_app_secret, keys.size)); + POSIX_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)); + POSIX_GUARD(s2n_blob_init(&old_app_secret, conn->secrets.tls13.server_app_secret, keys.size)); + POSIX_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)); + POSIX_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)); + POSIX_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)); + POSIX_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)); + POSIX_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: @@ -406,12 +191,12 @@ int s2n_update_application_traffic_keys(struct s2n_connection *conn, s2n_mode mo * 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)); + POSIX_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)); + POSIX_GUARD(s2n_stuffer_init(&old_secret_stuffer, &old_app_secret)); + POSIX_GUARD(s2n_stuffer_write_bytes(&old_secret_stuffer, app_secret_update.data, keys.size)); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.h b/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.h index f496677a09..e9785de6d0 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.h +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_handshake.h @@ -25,16 +25,16 @@ int s2n_tls13_mac_verify(struct s2n_tls13_keys *keys, struct s2n_blob *finished_ #define s2n_get_hash_state(hash_state, alg, conn) \ struct s2n_hash_state hash_state = {0}; \ - GUARD(s2n_handshake_get_hash_state(conn, alg, &hash_state)); + POSIX_GUARD(s2n_handshake_get_hash_state(conn, alg, &hash_state)); /* Creates a reference to tls13_keys from connection */ #define s2n_tls13_connection_keys(keys, conn) \ DEFER_CLEANUP(struct s2n_tls13_keys keys = {0}, s2n_tls13_keys_free);\ - GUARD(s2n_tls13_keys_from_conn(&keys, conn)); + POSIX_GUARD(s2n_tls13_keys_from_conn(&keys, conn)); int s2n_tls13_keys_from_conn(struct s2n_tls13_keys *keys, struct s2n_connection *conn); -int s2n_tls13_handle_secrets(struct s2n_connection *conn); +int s2n_tls13_compute_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret); int s2n_update_application_traffic_keys(struct s2n_connection *conn, s2n_mode mode, keyupdate_status status); int s2n_server_hello_retry_recreate_transcript(struct s2n_connection *conn); 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; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.h b/contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.h new file mode 100644 index 0000000000..0991be9c06 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_key_schedule.h @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#pragma once + +#include "utils/s2n_result.h" + +S2N_RESULT s2n_tls13_key_schedule_update(struct s2n_connection *conn); +S2N_RESULT s2n_tls13_key_schedule_reset(struct s2n_connection *conn); + diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_secrets.c b/contrib/restricted/aws/s2n/tls/s2n_tls13_secrets.c new file mode 100644 index 0000000000..9bbe24ec84 --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_secrets.c @@ -0,0 +1,626 @@ +/* + * 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.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_ENSURE_REF(conn->secure.cipher_suite); + RESULT_GUARD_POSIX(s2n_hmac_hash_alg(conn->secure.cipher_suite->prf_alg, &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(CONN_SECRETS(conn).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(CONN_SECRETS(conn).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) + **/ +S2N_RESULT s2n_tls13_compute_finished_key(s2n_hmac_algorithm hmac_alg, + const struct s2n_blob *base_key, struct s2n_blob *output) +{ + /* + * 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, hmac_alg, + base_key, &s2n_tls13_label_finished, &(struct s2n_blob){0}, output)); + 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) +{ + 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]; + + 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, callback_secret_type, + secret->data, secret->size)); + } + s2n_result_ignore(s2n_key_log_tls13_secret(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) +{ + 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) +{ + 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) +{ + 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_blob_zeroize_free); + 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_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_HMAC_ALG(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_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_HMAC_ALG(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) +{ + 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_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; +} + +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.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(conn).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(conn).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.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); + 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.tls13.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; + } + 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))); + 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); + + 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(conn).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; +} diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls13_secrets.h b/contrib/restricted/aws/s2n/tls/s2n_tls13_secrets.h new file mode 100644 index 0000000000..37c50a117c --- /dev/null +++ b/contrib/restricted/aws/s2n/tls/s2n_tls13_secrets.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#pragma once + +#include "tls/s2n_crypto_constants.h" +#include "tls/s2n_quic_support.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +/* tls/s2n_tls13_secrets should eventually replace crypto/s2n_tls13_keys.h */ +#include "crypto/s2n_tls13_keys.h" + +typedef enum { + S2N_NONE_SECRET = 0, + S2N_EARLY_SECRET, + S2N_HANDSHAKE_SECRET, + S2N_MASTER_SECRET +} s2n_extract_secret_type_t; + +struct s2n_tls13_secrets { + uint8_t extract_secret[S2N_TLS13_SECRET_MAX_LEN]; + s2n_extract_secret_type_t extract_secret_type; + + uint8_t client_early_secret[S2N_TLS13_SECRET_MAX_LEN]; + uint8_t client_handshake_secret[S2N_TLS13_SECRET_MAX_LEN]; + uint8_t server_handshake_secret[S2N_TLS13_SECRET_MAX_LEN]; + + uint8_t client_app_secret[S2N_TLS13_SECRET_MAX_LEN]; + uint8_t server_app_secret[S2N_TLS13_SECRET_MAX_LEN]; + uint8_t resumption_master_secret[S2N_TLS13_SECRET_MAX_LEN]; +}; + +S2N_RESULT s2n_tls13_empty_transcripts_init(); + +S2N_RESULT s2n_tls13_secrets_update(struct s2n_connection *conn); +S2N_RESULT s2n_tls13_secrets_get(struct s2n_connection *conn, s2n_extract_secret_type_t secret_type, + s2n_mode mode, struct s2n_blob *secret); +S2N_RESULT s2n_tls13_secrets_clean(struct s2n_connection *conn); + +S2N_RESULT s2n_derive_binder_key(struct s2n_psk *psk, struct s2n_blob *output); +S2N_RESULT s2n_derive_resumption_master_secret(struct s2n_connection *conn); + diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls_digest_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_tls_digest_preferences.h deleted file mode 100644 index 9b856cf481..0000000000 --- a/contrib/restricted/aws/s2n/tls/s2n_tls_digest_preferences.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ -#pragma once - -#include "tls/s2n_tls_parameters.h" - -#include "crypto/s2n_hash.h" - -/* Table to translate TLS numbers to s2n algorithms */ -static const s2n_hash_algorithm s2n_hash_tls_to_alg[] = { - [TLS_HASH_ALGORITHM_MD5] = S2N_HASH_MD5, - [TLS_HASH_ALGORITHM_SHA1] = S2N_HASH_SHA1, - [TLS_HASH_ALGORITHM_SHA224] = S2N_HASH_SHA224, - [TLS_HASH_ALGORITHM_SHA256] = S2N_HASH_SHA256, - [TLS_HASH_ALGORITHM_SHA384] = S2N_HASH_SHA384, - [TLS_HASH_ALGORITHM_SHA512] = S2N_HASH_SHA512 }; - -/* Table to translate from s2n algorithm numbers to TLS numbers */ -static const uint8_t s2n_hash_alg_to_tls[] = { - [S2N_HASH_MD5] = TLS_HASH_ALGORITHM_MD5, - [S2N_HASH_SHA1] = TLS_HASH_ALGORITHM_SHA1, - [S2N_HASH_SHA224] = TLS_HASH_ALGORITHM_SHA224, - [S2N_HASH_SHA256] = TLS_HASH_ALGORITHM_SHA256, - [S2N_HASH_SHA384] = TLS_HASH_ALGORITHM_SHA384, - [S2N_HASH_SHA512] = TLS_HASH_ALGORITHM_SHA512 }; - diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls_parameters.h b/contrib/restricted/aws/s2n/tls/s2n_tls_parameters.h index 7bce43d0b2..c998d6b1c8 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls_parameters.h +++ b/contrib/restricted/aws/s2n/tls/s2n_tls_parameters.h @@ -65,20 +65,27 @@ #define TLS_EXTENSION_PQ_KEM_PARAMETERS 0xFE01 #define TLS_PQ_KEM_EXTENSION_ID_BIKE1_L1_R1 1 #define TLS_PQ_KEM_EXTENSION_ID_BIKE1_L1_R2 13 +#define TLS_PQ_KEM_EXTENSION_ID_BIKE1_L1_R3 25 #define TLS_PQ_KEM_EXTENSION_ID_SIKE_P503_R1 10 -#define TLS_PQ_KEM_EXTENSION_ID_SIKE_P434_R2 19 +#define TLS_PQ_KEM_EXTENSION_ID_SIKE_P434_R3 19 #define TLS_PQ_KEM_EXTENSION_ID_KYBER_512_R2 23 #define TLS_PQ_KEM_EXTENSION_ID_KYBER_512_90S_R2 24 +#define TLS_PQ_KEM_EXTENSION_ID_KYBER_512_R3 28 /* TLS 1.3 hybrid post-quantum definitions are from the proposed reserved range defined - * in https://tools.ietf.org/html/draft-stebila-tls-hybrid-design. Values for interoperability - * are defined in https://docs.google.com/spreadsheets/d/12YarzaNv3XQNLnvDsWLlRKwtZFhRrDdWf36YlzwrPeg/edit#gid=0. */ -#define TLS_PQ_KEM_GROUP_ID_X25519_SIKE_P434_R2 0x2F27 -#define TLS_PQ_KEM_GROUP_ID_SECP256R1_SIKE_P434_R2 0x2F1F -#define TLS_PQ_KEM_GROUP_ID_X25519_BIKE1_L1_R2 0x2F28 -#define TLS_PQ_KEM_GROUP_ID_SECP256R1_BIKE1_L1_R2 0x2F23 -#define TLS_PQ_KEM_GROUP_ID_X25519_KYBER_512_R2 0x2F26 -#define TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_512_R2 0x2F0F + * in https://tools.ietf.org/html/draft-stebila-tls-hybrid-design. Values for interoperability are defined in + * https://github.com/open-quantum-safe/openssl/blob/OQS-OpenSSL_1_1_1-stable/oqs-template/oqs-kem-info.md */ +#define TLS_PQ_KEM_GROUP_ID_X25519_SIKE_P434_R3 0x2F27 +#define TLS_PQ_KEM_GROUP_ID_SECP256R1_SIKE_P434_R3 0x2F1F +#define TLS_PQ_KEM_GROUP_ID_X25519_BIKE1_L1_R2 0x2F28 +#define TLS_PQ_KEM_GROUP_ID_SECP256R1_BIKE1_L1_R2 0x2F23 +#define TLS_PQ_KEM_GROUP_ID_X25519_KYBER_512_R2 0x2F26 +#define TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_512_R2 0x2F0F +#define TLS_PQ_KEM_GROUP_ID_X25519_BIKE_L1_R3 0x2F37 +#define TLS_PQ_KEM_GROUP_ID_SECP256R1_BIKE_L1_R3 0x2F38 +#define TLS_PQ_KEM_GROUP_ID_X25519_KYBER_512_R3 0x2F39 +#define TLS_PQ_KEM_GROUP_ID_SECP256R1_KYBER_512_R3 0x2F3A + /* From https://tools.ietf.org/html/rfc7507 */ #define TLS_FALLBACK_SCSV 0x56, 0x00 @@ -100,12 +107,14 @@ #define TLS_EXTENSION_SIGNATURE_ALGORITHMS 13 #define TLS_EXTENSION_ALPN 16 #define TLS_EXTENSION_SCT_LIST 18 +#define TLS_EXTENSION_EMS 23 #define TLS_EXTENSION_SESSION_TICKET 35 #define TLS_EXTENSION_PRE_SHARED_KEY 41 #define TLS_EXTENSION_CERT_AUTHORITIES 47 #define TLS_EXTENSION_RENEGOTIATION_INFO 65281 /* TLS 1.3 extensions from https://tools.ietf.org/html/rfc8446#section-4.2 */ +#define TLS_EXTENSION_EARLY_DATA 42 #define TLS_EXTENSION_SUPPORTED_VERSIONS 43 #define TLS_EXTENSION_COOKIE 44 #define TLS_EXTENSION_PSK_KEY_EXCHANGE_MODES 45 @@ -116,33 +125,12 @@ #define TLS_PSK_DHE_KE_MODE 1 /** - *= https://tools.ietf.org/id/draft-ietf-quic-tls-32.txt#8.2 + *= https://tools.ietf.org/rfc/rfc9001.txt#8.2 *# enum { - *# quic_transport_parameters(0xffa5), (65535) + *# quic_transport_parameters(0x39), (65535) *# } ExtensionType; */ -#define TLS_QUIC_TRANSPORT_PARAMETERS 0xffa5 - -/* TLS Signature Algorithms - RFC 5246 7.4.1.4.1 */ -/* https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16 */ -#define TLS_SIGNATURE_ALGORITHM_ANONYMOUS 0 -#define TLS_SIGNATURE_ALGORITHM_RSA 1 -#define TLS_SIGNATURE_ALGORITHM_DSA 2 -#define TLS_SIGNATURE_ALGORITHM_ECDSA 3 -#define TLS_SIGNATURE_ALGORITHM_PRIVATE 224 - -#define TLS_SIGNATURE_ALGORITHM_COUNT 4 - -/* TLS Hash Algorithm - https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -/* https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18 */ -#define TLS_HASH_ALGORITHM_ANONYMOUS 0 -#define TLS_HASH_ALGORITHM_MD5 1 -#define TLS_HASH_ALGORITHM_SHA1 2 -#define TLS_HASH_ALGORITHM_SHA224 3 -#define TLS_HASH_ALGORITHM_SHA256 4 -#define TLS_HASH_ALGORITHM_SHA384 5 -#define TLS_HASH_ALGORITHM_SHA512 6 -#define TLS_HASH_ALGORITHM_COUNT 7 +#define TLS_QUIC_TRANSPORT_PARAMETERS 0x39 /* TLS SignatureScheme (Backwards compatible with SigHash and SigAlg values above) */ /* Defined here: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme */ @@ -201,6 +189,7 @@ #define TLS_EC_CURVE_SECP_384_R1 24 #define TLS_EC_CURVE_SECP_521_R1 25 #define TLS_EC_CURVE_ECDH_X25519 29 +#define TLS_EC_CURVE_ECDH_X448 30 /* Ethernet maximum transmission unit (MTU) * MTU is usually associated with the Ethernet protocol, @@ -214,21 +203,8 @@ #define TCP_HEADER_LENGTH 20 #define TCP_OPTIONS_LENGTH 40 -/* The maximum size of a TLS record is 16389 bytes. This is; 1 byte for content - * type, 2 bytes for the protocol version, 2 bytes for the length field, - * and then up to 2^14 for the encrypted+compressed payload data. - */ -#define S2N_TLS_RECORD_HEADER_LENGTH 5 -#define S2N_TLS_MAXIMUM_FRAGMENT_LENGTH 16384 -/* Maximum TLS record length allows for 2048 octets of compression expansion and padding */ -#define S2N_TLS_MAXIMUM_RECORD_LENGTH (S2N_TLS_MAXIMUM_FRAGMENT_LENGTH + S2N_TLS_RECORD_HEADER_LENGTH + 2048) #define S2N_TLS_MAX_FRAG_LEN_EXT_NONE 0 -/* TLS1.3 has a max fragment length of 2^14 + 1 byte for the content type */ -#define S2N_TLS13_MAXIMUM_FRAGMENT_LENGTH 16385 -/* Max encryption overhead is 255 for AEAD padding */ -#define S2N_TLS13_MAXIMUM_RECORD_LENGTH (S2N_TLS13_MAXIMUM_FRAGMENT_LENGTH + S2N_TLS_RECORD_HEADER_LENGTH + 255) - /* The maximum size of an SSL2 message is 2^14 - 1, as neither of the first two * bits in the length field are usable. Per; * http://www-archive.mozilla.org/projects/security/pki/nss/ssl/draft02.html @@ -258,7 +234,6 @@ */ #define S2N_LARGE_RECORD_LENGTH S2N_TLS_MAXIMUM_RECORD_LENGTH #define S2N_LARGE_FRAGMENT_LENGTH S2N_TLS_MAXIMUM_FRAGMENT_LENGTH -#define S2N_TLS13_LARGE_FRAGMENT_LENGTH S2N_TLS13_MAXIMUM_FRAGMENT_LENGTH /* Cap dynamic record resize threshold to 8M */ #define S2N_TLS_MAX_RESIZE_THRESHOLD (1024 * 1024 * 8) diff --git a/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c b/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c index da2eea8be6..4506878ced 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c +++ b/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c @@ -30,7 +30,7 @@ #include <openssl/asn1.h> #include <openssl/x509.h> -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +#if !defined(OPENSSL_IS_BORINGSSL) #include <openssl/ocsp.h> #endif @@ -42,13 +42,6 @@ /* Time used by default for nextUpdate if none provided in OCSP: 1 hour since thisUpdate. */ #define DEFAULT_OCSP_NEXT_UPDATE_PERIOD 3600000000000 -typedef enum { - UNINIT, - INIT, - VALIDATED, - OCSP_VALIDATED, -} validator_state; - uint8_t s2n_x509_ocsp_stapling_supported(void) { return S2N_OCSP_STAPLING_SUPPORTED; } @@ -64,13 +57,13 @@ uint8_t s2n_x509_trust_store_has_certs(struct s2n_x509_trust_store *store) { int s2n_x509_trust_store_from_system_defaults(struct s2n_x509_trust_store *store) { if (!store->trust_store) { store->trust_store = X509_STORE_new(); - notnull_check(store->trust_store); + POSIX_ENSURE_REF(store->trust_store); } int err_code = X509_STORE_set_default_paths(store->trust_store); if (!err_code) { s2n_x509_trust_store_wipe(store); - S2N_ERROR(S2N_ERR_X509_TRUST_STORE); + POSIX_BAIL(S2N_ERR_X509_TRUST_STORE); } X509_STORE_set_flags(store->trust_store, X509_VP_FLAG_DEFAULT); @@ -80,8 +73,8 @@ int s2n_x509_trust_store_from_system_defaults(struct s2n_x509_trust_store *store int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char *pem) { - notnull_check(store); - notnull_check(pem); + POSIX_ENSURE_REF(store); + POSIX_ENSURE_REF(pem); if (!store->trust_store) { store->trust_store = X509_STORE_new(); @@ -90,21 +83,24 @@ int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char DEFER_CLEANUP(struct s2n_stuffer pem_in_stuffer = {0}, s2n_stuffer_free); DEFER_CLEANUP(struct s2n_stuffer der_out_stuffer = {0}, s2n_stuffer_free); - GUARD(s2n_stuffer_alloc_ro_from_string(&pem_in_stuffer, pem)); - GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, 2048)); + POSIX_GUARD(s2n_stuffer_alloc_ro_from_string(&pem_in_stuffer, pem)); + POSIX_GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, 2048)); do { DEFER_CLEANUP(struct s2n_blob next_cert = {0}, s2n_free); - GUARD(s2n_stuffer_certificate_from_pem(&pem_in_stuffer, &der_out_stuffer)); - GUARD(s2n_alloc(&next_cert, s2n_stuffer_data_available(&der_out_stuffer))); - GUARD(s2n_stuffer_read(&der_out_stuffer, &next_cert)); + POSIX_GUARD(s2n_stuffer_certificate_from_pem(&pem_in_stuffer, &der_out_stuffer)); + POSIX_GUARD(s2n_alloc(&next_cert, s2n_stuffer_data_available(&der_out_stuffer))); + POSIX_GUARD(s2n_stuffer_read(&der_out_stuffer, &next_cert)); const uint8_t *data = next_cert.data; DEFER_CLEANUP(X509 *ca_cert = d2i_X509(NULL, &data, next_cert.size), X509_free_pointer); S2N_ERROR_IF(ca_cert == NULL, S2N_ERR_DECODE_CERTIFICATE); - GUARD_OSSL(X509_STORE_add_cert(store->trust_store, ca_cert), S2N_ERR_DECODE_CERTIFICATE); + if (!X509_STORE_add_cert(store->trust_store, ca_cert)) { + unsigned long error = ERR_get_error(); + POSIX_ENSURE(ERR_GET_REASON(error) == X509_R_CERT_ALREADY_IN_HASH_TABLE, S2N_ERR_DECODE_CERTIFICATE); + } } while (s2n_stuffer_data_available(&pem_in_stuffer)); return 0; @@ -113,13 +109,13 @@ int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char int s2n_x509_trust_store_from_ca_file(struct s2n_x509_trust_store *store, const char *ca_pem_filename, const char *ca_dir) { if (!store->trust_store) { store->trust_store = X509_STORE_new(); - notnull_check(store->trust_store); + POSIX_ENSURE_REF(store->trust_store); } int err_code = X509_STORE_load_locations(store->trust_store, ca_pem_filename, ca_dir); if (!err_code) { s2n_x509_trust_store_wipe(store); - S2N_ERROR(S2N_ERR_X509_TRUST_STORE); + POSIX_BAIL(S2N_ERR_X509_TRUST_STORE); } /* It's a likely scenario if this function is called, a self-signed certificate is used, and that is was generated @@ -141,7 +137,7 @@ void s2n_x509_trust_store_wipe(struct s2n_x509_trust_store *store) { } int s2n_x509_validator_init_no_x509_validation(struct s2n_x509_validator *validator) { - notnull_check(validator); + POSIX_ENSURE_REF(validator); validator->trust_store = NULL; validator->store_ctx = NULL; validator->skip_cert_validation = 1; @@ -154,7 +150,7 @@ int s2n_x509_validator_init_no_x509_validation(struct s2n_x509_validator *valida } int s2n_x509_validator_init(struct s2n_x509_validator *validator, struct s2n_x509_trust_store *trust_store, uint8_t check_ocsp) { - notnull_check(trust_store); + POSIX_ENSURE_REF(trust_store); validator->trust_store = trust_store; validator->skip_cert_validation = 0; validator->check_stapled_ocsp = check_ocsp; @@ -162,7 +158,7 @@ int s2n_x509_validator_init(struct s2n_x509_validator *validator, struct s2n_x50 validator->store_ctx = NULL; if (validator->trust_store->trust_store) { validator->store_ctx = X509_STORE_CTX_new(); - notnull_check(validator->store_ctx); + POSIX_ENSURE_REF(validator->store_ctx); } validator->cert_chain_from_wire = sk_X509_new_null(); validator->state = INIT; @@ -190,7 +186,7 @@ void s2n_x509_validator_wipe(struct s2n_x509_validator *validator) { } int s2n_x509_validator_set_max_chain_depth(struct s2n_x509_validator *validator, uint16_t max_depth) { - notnull_check(validator); + POSIX_ENSURE_REF(validator); S2N_ERROR_IF(max_depth == 0, S2N_ERR_INVALID_ARGUMENT); validator->max_chain_depth = max_depth; @@ -265,7 +261,7 @@ static uint8_t s2n_verify_host_information(struct s2n_x509_validator *validator, if (common_name) { char peer_cn[255]; static size_t peer_cn_size = sizeof(peer_cn); - memset_check(&peer_cn, 0, peer_cn_size); + POSIX_CHECKED_MEMSET(&peer_cn, 0, peer_cn_size); /* X520CommonName allows the following ANSI string types per RFC 5280 Appendix A.1 */ if (ASN1_STRING_type(common_name) == V_ASN1_TELETEXSTRING || @@ -276,8 +272,8 @@ static uint8_t s2n_verify_host_information(struct s2n_x509_validator *validator, size_t len = (size_t) ASN1_STRING_length(common_name); - lte_check(len, sizeof(peer_cn) - 1); - memcpy_check(peer_cn, ASN1_STRING_data(common_name), len); + POSIX_ENSURE_LTE(len, sizeof(peer_cn) - 1); + POSIX_CHECKED_MEMCPY(peer_cn, ASN1_STRING_data(common_name), len); verified = conn->verify_host_fn(peer_cn, len, conn->data_for_verify_host); } } @@ -291,7 +287,7 @@ static uint8_t s2n_verify_host_information(struct s2n_x509_validator *validator, s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn, uint8_t *cert_chain_in, uint32_t cert_chain_len, s2n_pkey_type *pkey_type, struct s2n_pkey *public_key_out) { S2N_ERROR_IF(!validator->skip_cert_validation && !s2n_x509_trust_store_has_certs(validator->trust_store), S2N_ERR_CERT_UNTRUSTED); - S2N_ERROR_IF(validator->state != INIT, S2N_ERR_INVALID_STATE); + S2N_ERROR_IF(validator->state != INIT, S2N_ERR_INVALID_CERT_STATE); struct s2n_blob cert_chain_blob = {.data = cert_chain_in, .size = cert_chain_len}; DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = {0}, s2n_stuffer_free); @@ -315,7 +311,7 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_ struct s2n_blob asn1cert = {0}; asn1cert.size = certificate_size; asn1cert.data = s2n_stuffer_raw_read(&cert_chain_in_stuffer, certificate_size); - notnull_check(asn1cert.data); + POSIX_ENSURE_REF(asn1cert.data); const uint8_t *data = asn1cert.data; @@ -326,11 +322,11 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_ /* add the cert to the chain. */ if (!sk_X509_push(validator->cert_chain_from_wire, server_cert)) { X509_free(server_cert); - S2N_ERROR(S2N_ERR_CERT_UNTRUSTED); + POSIX_BAIL(S2N_ERR_CERT_UNTRUSTED); } if (!validator->skip_cert_validation) { - GUARD_AS_POSIX(s2n_validate_certificate_signature(conn, server_cert)); + POSIX_GUARD_RESULT(s2n_validate_certificate_signature(conn, server_cert)); } /* Pull the public key from the first certificate */ @@ -341,7 +337,7 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_ /* certificate extensions is a field in TLS 1.3 - https://tools.ietf.org/html/rfc8446#section-4.4.2 */ if (conn->actual_protocol_version >= S2N_TLS13) { s2n_parsed_extensions_list parsed_extensions_list = { 0 }; - GUARD(s2n_extension_list_parse(&cert_chain_in_stuffer, &parsed_extensions_list)); + POSIX_GUARD(s2n_extension_list_parse(&cert_chain_in_stuffer, &parsed_extensions_list)); /* RFC 8446: if an extension applies to the entire chain, it SHOULD be included in the first CertificateEntry */ if (sk_X509_num(validator->cert_chain_from_wire) == 1) { @@ -379,7 +375,7 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_ } if (conn->actual_protocol_version >= S2N_TLS13) { - GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CERTIFICATE, conn, &first_certificate_extensions)); + POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CERTIFICATE, conn, &first_certificate_extensions)); } *public_key_out = public_key; @@ -398,7 +394,7 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_stapled_ocsp_response( return S2N_CERT_OK; } - S2N_ERROR_IF(validator->state != VALIDATED, S2N_ERR_INVALID_STATE); + S2N_ERROR_IF(validator->state != VALIDATED, S2N_ERR_INVALID_CERT_STATE); #if !S2N_OCSP_STAPLING_SUPPORTED /* Default to safety */ @@ -467,13 +463,15 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_stapled_ocsp_response( } /* Important: this checks that the stapled ocsp response CAN be verified, not that it has been verified. */ - const int ocsp_verify_err = OCSP_basic_verify(basic_response, cert_chain, validator->trust_store->trust_store, 0); - /* do the crypto checks on the response.*/ - if (!ocsp_verify_err) { - ret_val = S2N_CERT_ERR_UNTRUSTED; + const int ocsp_verify_res = OCSP_basic_verify(basic_response, cert_chain, validator->trust_store->trust_store, 0); + + /* OCSP_basic_verify() returns 1 on success, 0 on error, or -1 on fatal error such as malloc failure. */ + if (ocsp_verify_res != _OSSL_SUCCESS) { + ret_val = ocsp_verify_res == 0 ? S2N_CERT_ERR_UNTRUSTED : S2N_CERT_ERR_INTERNAL_ERROR; goto clean_up; } + /* do the crypto checks on the response.*/ int status = 0; int reason = 0; @@ -557,42 +555,42 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_stapled_ocsp_response( S2N_RESULT s2n_validate_certificate_signature(struct s2n_connection *conn, X509 *x509_cert) { - ENSURE_REF(conn); - ENSURE_REF(x509_cert); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(x509_cert); const struct s2n_security_policy *security_policy; - GUARD_AS_RESULT(s2n_connection_get_security_policy(conn, &security_policy)); + RESULT_GUARD_POSIX(s2n_connection_get_security_policy(conn, &security_policy)); if (security_policy->certificate_signature_preferences == NULL) { return S2N_RESULT_OK; } X509_NAME *issuer_name = X509_get_issuer_name(x509_cert); - ENSURE_REF(issuer_name); + RESULT_ENSURE_REF(issuer_name); X509_NAME *subject_name = X509_get_subject_name(x509_cert); - ENSURE_REF(subject_name); + RESULT_ENSURE_REF(subject_name); /* Do not validate any self-signed certificates */ if (X509_NAME_cmp(issuer_name, subject_name) == 0) { return S2N_RESULT_OK; } - GUARD_RESULT(s2n_validate_sig_scheme_supported(conn, x509_cert, security_policy->certificate_signature_preferences)); + RESULT_GUARD(s2n_validate_sig_scheme_supported(conn, x509_cert, security_policy->certificate_signature_preferences)); return S2N_RESULT_OK; } S2N_RESULT s2n_validate_sig_scheme_supported(struct s2n_connection *conn, X509 *x509_cert, const struct s2n_signature_preferences *cert_sig_preferences) { - ENSURE_REF(conn); - ENSURE_REF(x509_cert); - ENSURE_REF(cert_sig_preferences); + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(x509_cert); + RESULT_ENSURE_REF(cert_sig_preferences); int nid = 0; #if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x02070000f) - ENSURE_REF(x509_cert->sig_alg); + RESULT_ENSURE_REF(x509_cert->sig_alg); nid = OBJ_obj2nid(x509_cert->sig_alg->algorithm); #else nid = X509_get_signature_nid(x509_cert); @@ -602,12 +600,17 @@ S2N_RESULT s2n_validate_sig_scheme_supported(struct s2n_connection *conn, X509 * if (cert_sig_preferences->signature_schemes[i]->libcrypto_nid == nid) { /* SHA-1 algorithms are not supported in certificate signatures in TLS1.3 */ - ENSURE(!(conn->actual_protocol_version >= S2N_TLS13 && + RESULT_ENSURE(!(conn->actual_protocol_version >= S2N_TLS13 && cert_sig_preferences->signature_schemes[i]->hash_alg == S2N_HASH_SHA1), S2N_ERR_CERT_UNTRUSTED); return S2N_RESULT_OK; } } - BAIL(S2N_ERR_CERT_UNTRUSTED); + RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED); +} + +bool s2n_x509_validator_is_cert_chain_validated(const struct s2n_x509_validator *validator) +{ + return validator && (validator->state == VALIDATED || validator->state == OCSP_VALIDATED); } diff --git a/contrib/restricted/aws/s2n/tls/s2n_x509_validator.h b/contrib/restricted/aws/s2n/tls/s2n_x509_validator.h index 9e57bb4d34..b35d535141 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_x509_validator.h +++ b/contrib/restricted/aws/s2n/tls/s2n_x509_validator.h @@ -21,13 +21,13 @@ #include <openssl/x509v3.h> -/* one day, BoringSSL/AWS-LC, may add ocsp stapling support. Let's future proof this a bit by grabbing a definition +/* one day, BoringSSL may add ocsp stapling support. Let's future proof this a bit by grabbing a definition * that would have to be there when they add support */ -#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && !defined(OCSP_RESPONSE_STATUS_SUCCESSFUL) +#if defined(OPENSSL_IS_BORINGSSL) && !defined(OCSP_RESPONSE_STATUS_SUCCESSFUL) #define S2N_OCSP_STAPLING_SUPPORTED 0 #else #define S2N_OCSP_STAPLING_SUPPORTED 1 -#endif /* (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && !defined(OCSP_RESPONSE_STATUS_SUCCESSFUL) */ +#endif /* defined(OPENSSL_IS_BORINGSSL) && !defined(OCSP_RESPONSE_STATUS_SUCCESSFUL) */ typedef enum { S2N_CERT_OK = 0, @@ -36,9 +36,17 @@ typedef enum { S2N_CERT_ERR_EXPIRED = -3, S2N_CERT_ERR_TYPE_UNSUPPORTED = -4, S2N_CERT_ERR_INVALID = -5, - S2N_CERT_ERR_MAX_CHAIN_DEPTH_EXCEEDED = -6 + S2N_CERT_ERR_MAX_CHAIN_DEPTH_EXCEEDED = -6, + S2N_CERT_ERR_INTERNAL_ERROR = -7 } s2n_cert_validation_code; +typedef enum { + UNINIT, + INIT, + VALIDATED, + OCSP_VALIDATED, +} validator_state; + /** Return TRUE for trusted, FALSE for untrusted **/ typedef uint8_t (*verify_host) (const char *host_name, size_t host_name_len, void *data); struct s2n_connection; @@ -125,6 +133,12 @@ s2n_cert_validation_code s2n_x509_validator_validate_cert_stapled_ocsp_response( const uint8_t *ocsp_response, uint32_t size); /** + * Checks whether the peer's certificate chain has been received and validated. + * Should be verified before any use of the peer's certificate data. + */ +bool s2n_x509_validator_is_cert_chain_validated(const struct s2n_x509_validator *validator); + +/** * Validates that each certificate in a peer's cert chain contains only signature algorithms in a security policy's * certificate_signatures_preference list. */ |