diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-11-07 16:54:51 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-11-07 16:54:51 +0300 |
commit | 9ca5282bca79550f17a48f7aef639f0e6d477b2c (patch) | |
tree | 6b03d26c014c76bea0c1743e7f03dd066023b72e /contrib/restricted/aws/s2n/tls/extensions | |
parent | 964584075fe8d2284078222e1e7e2e424c8bd9a1 (diff) | |
download | ydb-9ca5282bca79550f17a48f7aef639f0e6d477b2c.tar.gz |
Update contrib/restricted/aws/s2n to 1.3.25
Diffstat (limited to 'contrib/restricted/aws/s2n/tls/extensions')
7 files changed, 283 insertions, 23 deletions
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 ac11ad22e2..187d5603dc 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 @@ -24,6 +24,7 @@ static int s2n_client_renegotiation_send(struct s2n_connection *conn, struct s2n_stuffer *out); static int s2n_client_renegotiation_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); static bool s2n_client_renegotiation_should_send(struct s2n_connection *conn); +static int s2n_client_renegotiation_if_missing(struct s2n_connection *conn); const s2n_extension_type s2n_client_renegotiation_info_extension = { .iana_value = TLS_EXTENSION_RENEGOTIATION_INFO, @@ -31,21 +32,7 @@ const s2n_extension_type s2n_client_renegotiation_info_extension = { .send = s2n_client_renegotiation_send, .recv = s2n_client_renegotiation_recv, .should_send = s2n_client_renegotiation_should_send, - - /** - *= https://tools.ietf.org/rfc/rfc5746#3.6 - *# o If neither the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV nor the - *# "renegotiation_info" extension was included, set the - *# secure_renegotiation flag to FALSE. In this case, some servers - *# may want to terminate the handshake instead of continuing - * - * The conn->secure_renegotiation flag defaults to false, so this is a no-op. - * We do not terminate the handshake, although missing messaging for secure - * renegotiation degrades client security. - * - * We could introduce an option to fail in this case in the future. - */ - .if_missing = s2n_extension_noop_if_missing, + .if_missing = s2n_client_renegotiation_if_missing, }; /** @@ -75,6 +62,7 @@ static int s2n_client_renegotiation_send(struct s2n_connection *conn, struct s2n POSIX_ENSURE(conn->secure_renegotiation, S2N_ERR_NO_RENEGOTIATION); uint8_t renegotiated_connection_len = conn->handshake.finished_len; + POSIX_ENSURE_GT(renegotiated_connection_len, 0); POSIX_GUARD(s2n_stuffer_write_uint8(out, renegotiated_connection_len)); POSIX_GUARD(s2n_stuffer_write_bytes(out, conn->handshake.client_finished, renegotiated_connection_len)); @@ -85,8 +73,14 @@ static int s2n_client_renegotiation_send(struct s2n_connection *conn, struct s2n *= https://tools.ietf.org/rfc/rfc5746#3.6 *# o The server MUST check if the "renegotiation_info" extension is *# included in the ClientHello. + * + * Note that this extension must also work for SSLv3: + *= https://tools.ietf.org/rfc/rfc5746#4.5 + *# TLS servers that support secure renegotiation and support SSLv3 MUST accept SCSV or the + *# "renegotiation_info" extension and respond as described in this + *# specification even if the offered client version is {0x03, 0x00}. */ -static int s2n_client_renegotiation_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) +static int s2n_client_renegotiation_recv_initial(struct s2n_connection *conn, struct s2n_stuffer *extension) { /** *= https://tools.ietf.org/rfc/rfc5746#3.6 @@ -108,6 +102,94 @@ static int s2n_client_renegotiation_recv(struct s2n_connection *conn, struct s2n return S2N_SUCCESS; } +static int s2n_client_renegotiation_recv_renegotiation(struct s2n_connection *conn, struct s2n_stuffer *extension) +{ + POSIX_ENSURE_REF(conn); + + /* s2n-tls servers do not support renegotiation. + * We add the renegotiation version of this logic only for testing. + */ + POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); + + /** + *= https://tools.ietf.org/rfc/rfc5746#3.7 + *# This text applies if the connection's "secure_renegotiation" flag is + *# set to TRUE (if it is set to FALSE, see Section 4.4). + */ + POSIX_ENSURE(conn->secure_renegotiation, S2N_ERR_NO_RENEGOTIATION); + + /** + *= https://tools.ietf.org/rfc/rfc5746#3.7 + *# o The server MUST verify that the value of the + *# "renegotiated_connection" field is equal to the saved + *# client_verify_data value; if it is not, the server MUST abort the + *# handshake. + */ + + uint8_t verify_data_len = conn->handshake.finished_len; + POSIX_ENSURE_GT(verify_data_len, 0); + + uint8_t renegotiated_connection_len = 0; + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &renegotiated_connection_len)); + POSIX_ENSURE(verify_data_len == renegotiated_connection_len, S2N_ERR_BAD_MESSAGE); + + uint8_t *renegotiated_connection = s2n_stuffer_raw_read(extension, verify_data_len); + POSIX_ENSURE_REF(renegotiated_connection); + POSIX_ENSURE(s2n_constant_time_equals(renegotiated_connection, conn->handshake.client_finished, verify_data_len), + S2N_ERR_BAD_MESSAGE); + + return S2N_SUCCESS; +} + +static int s2n_client_renegotiation_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) +{ + if (s2n_handshake_is_renegotiation(conn)) { + POSIX_GUARD(s2n_client_renegotiation_recv_renegotiation(conn, extension)); + } else { + POSIX_GUARD(s2n_client_renegotiation_recv_initial(conn, extension)); + } + POSIX_ENSURE(s2n_stuffer_data_available(extension) == 0, S2N_ERR_BAD_MESSAGE); + return S2N_SUCCESS; +} + +static int s2n_client_renegotiation_if_missing(struct s2n_connection *conn) +{ + POSIX_ENSURE_REF(conn); + if (s2n_handshake_is_renegotiation(conn)) { + /* s2n-tls servers do not support renegotiation. + * We add the renegotiation version of this logic only for testing. + */ + POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); + + /** + *= https://tools.ietf.org/rfc/rfc5746#3.7 + *# This text applies if the connection's "secure_renegotiation" flag is + *# set to TRUE (if it is set to FALSE, see Section 4.4). + */ + POSIX_ENSURE(conn->secure_renegotiation, S2N_ERR_NO_RENEGOTIATION); + + /** + *= https://tools.ietf.org/rfc/rfc5746#3.7 + *# o The server MUST verify that the "renegotiation_info" extension is + *# present; if it is not, the server MUST abort the handshake. + */ + POSIX_BAIL(S2N_ERR_MISSING_EXTENSION); + } else { + /** + *= https://tools.ietf.org/rfc/rfc5746#3.6 + *# o If neither the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV nor the + *# "renegotiation_info" extension was included, set the + *# secure_renegotiation flag to FALSE. In this case, some servers + *# may want to terminate the handshake instead of continuing + * + * We do not terminate the handshake for compatibility reasons. + * See https://github.com/aws/s2n-tls/issues/3528 + */ + conn->secure_renegotiation = false; + return S2N_SUCCESS; + } +} + /* Old-style extension functions -- remove after extensions refactor is complete */ int s2n_recv_client_renegotiation_info(struct s2n_connection *conn, struct s2n_stuffer *extension) 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 00245dacec..cddddf4135 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h @@ -42,6 +42,7 @@ typedef enum { S2N_EXTENSION_LIST_CERT_REQ, S2N_EXTENSION_LIST_CERTIFICATE, S2N_EXTENSION_LIST_NST, + S2N_EXTENSION_LIST_ENCRYPTED_EXTENSIONS_TLS12, 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.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h index f3ccf58730..a5ecb36ce4 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.h @@ -67,6 +67,7 @@ static const uint16_t s2n_supported_extensions[] = { TLS_EXTENSION_PRE_SHARED_KEY, TLS_EXTENSION_EARLY_DATA, TLS_EXTENSION_EMS, + TLS_EXTENSION_NPN, }; 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 e28e774acc..d8505894cd 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 @@ -49,6 +49,7 @@ #include "tls/extensions/s2n_server_supported_versions.h" #include "tls/extensions/s2n_server_key_share.h" #include "tls/extensions/s2n_server_psk.h" +#include "tls/extensions/s2n_npn.h" static const s2n_extension_type *const client_hello_extensions[] = { &s2n_client_supported_versions_extension, @@ -74,6 +75,7 @@ static const s2n_extension_type *const client_hello_extensions[] = { &s2n_psk_key_exchange_modes_extension, &s2n_client_early_data_indication_extension, &s2n_client_ems_extension, + &s2n_client_npn_extension, &s2n_client_psk_extension /* MUST be last */ }; @@ -88,6 +90,7 @@ static const s2n_extension_type *const tls12_server_hello_extensions[] = { &s2n_server_max_fragment_length_extension, &s2n_server_session_ticket_extension, &s2n_server_ems_extension, + &s2n_server_npn_extension, }; /** @@ -121,6 +124,10 @@ static const s2n_extension_type *const encrypted_extensions[] = { &s2n_server_early_data_indication_extension, }; +static const s2n_extension_type *const tls12_encrypted_extensions[] = { + &s2n_npn_encrypted_extension, +}; + static const s2n_extension_type *const cert_req_extensions[] = { &s2n_server_signature_algorithms_extension, }; @@ -145,6 +152,7 @@ static s2n_extension_type_list extension_lists[] = { [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_ENCRYPTED_EXTENSIONS_TLS12] = S2N_EXTENSION_LIST(tls12_encrypted_extensions), [S2N_EXTENSION_LIST_EMPTY] = { .extension_types = NULL, .count = 0 }, }; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.c index 61c5b3a6d1..4731f97ffb 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.c @@ -66,7 +66,33 @@ int s2n_server_npn_recv(struct s2n_connection *conn, struct s2n_stuffer *extensi return S2N_SUCCESS; } - POSIX_GUARD_RESULT(s2n_select_server_preference_protocol(conn, extension, supported_protocols)); + /* + *= https://datatracker.ietf.org/doc/id/draft-agl-tls-nextprotoneg-04#section-3 + *# The "extension_data" field of a "next_protocol_negotiation" extension + *# in a "ServerHello" contains an optional list of protocols advertised + *# by the server. + */ + if (s2n_stuffer_data_available(extension)) { + POSIX_GUARD_RESULT(s2n_select_server_preference_protocol(conn, extension, supported_protocols)); + } + + /* + *= https://datatracker.ietf.org/doc/id/draft-agl-tls-nextprotoneg-04#section-4 + *# In the event that the client doesn't support any of server's protocols, or + *# the server doesn't advertise any, it SHOULD select the first protocol + *# that it supports. + */ + if (s2n_get_application_protocol(conn) == NULL) { + struct s2n_stuffer stuffer = { 0 }; + POSIX_GUARD(s2n_stuffer_init(&stuffer, supported_protocols)); + POSIX_GUARD(s2n_stuffer_skip_write(&stuffer, supported_protocols->size)); + struct s2n_blob protocol = { 0 }; + POSIX_GUARD_RESULT(s2n_protocol_preferences_read(&stuffer, &protocol)); + + POSIX_ENSURE_LT(protocol.size, sizeof(conn->application_protocol)); + POSIX_CHECKED_MEMCPY(conn->application_protocol, protocol.data, protocol.size); + conn->application_protocol[protocol.size] = '\0'; + } return S2N_SUCCESS; } @@ -79,3 +105,73 @@ const s2n_extension_type s2n_server_npn_extension = { .should_send = s2n_server_npn_should_send, .if_missing = s2n_extension_noop_if_missing, }; + +bool s2n_npn_encrypted_should_send(struct s2n_connection *conn) +{ + return s2n_server_alpn_should_send(conn); +} + +S2N_RESULT s2n_calculate_padding(uint8_t protocol_len, uint8_t *padding_len) +{ + RESULT_ENSURE_REF(padding_len); + + /* + *= https://datatracker.ietf.org/doc/id/draft-agl-tls-nextprotoneg-04#section-3 + *# The length of "padding" SHOULD be 32 - ((len(selected_protocol) + 2) % 32). + */ + *padding_len = 32 - ((protocol_len + 2) % 32); + return S2N_RESULT_OK; +} + +int s2n_npn_encrypted_extension_send(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + uint8_t protocol_len = strlen(conn->application_protocol); + POSIX_GUARD(s2n_stuffer_write_uint8(out, protocol_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, (uint8_t*) conn->application_protocol, protocol_len)); + + uint8_t padding_len = 0; + POSIX_GUARD_RESULT(s2n_calculate_padding(protocol_len, &padding_len)); + POSIX_GUARD(s2n_stuffer_write_uint8(out, padding_len)); + for (size_t i = 0; i < padding_len; i++) { + POSIX_GUARD(s2n_stuffer_write_uint8(out, 0)); + } + + return S2N_SUCCESS; +} + +int s2n_npn_encrypted_extension_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) +{ + uint8_t protocol_len = 0; + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &protocol_len)); + + uint8_t *protocol = s2n_stuffer_raw_read(extension, protocol_len); + POSIX_ENSURE_REF(protocol); + POSIX_CHECKED_MEMCPY(conn->application_protocol, protocol, protocol_len); + conn->application_protocol[protocol_len] = '\0'; + + uint8_t expected_padding_len = 0; + POSIX_GUARD_RESULT(s2n_calculate_padding(protocol_len, &expected_padding_len)); + uint8_t padding_len = 0; + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &padding_len)); + POSIX_ENSURE_EQ(padding_len, expected_padding_len); + + for (size_t i = 0; i < padding_len; i++) { + uint8_t byte = 0; + POSIX_GUARD(s2n_stuffer_read_uint8(extension, &byte)); + POSIX_ENSURE_EQ(byte, 0); + } + POSIX_ENSURE_EQ(s2n_stuffer_data_available(extension), 0); + + return S2N_SUCCESS; +} + +const s2n_extension_type s2n_npn_encrypted_extension = { + .iana_value = TLS_EXTENSION_NPN, + .is_response = true, + .send = s2n_npn_encrypted_extension_send, + .recv = s2n_npn_encrypted_extension_recv, + .should_send = s2n_npn_encrypted_should_send, + /* The NPN extension is the only one defined for TLS1.2 Encrypted Extensions. + * If it's missing, something has gone wrong. */ + .if_missing = s2n_extension_error_if_missing, +}; diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.h b/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.h index 0b03e5c1b4..81f0f60220 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.h +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_npn.h @@ -19,3 +19,4 @@ extern const s2n_extension_type s2n_client_npn_extension; extern const s2n_extension_type s2n_server_npn_extension; +extern const s2n_extension_type s2n_npn_encrypted_extension; 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 1052a41ab1..5834412e10 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 @@ -24,6 +24,17 @@ #include "tls/s2n_tls.h" #include "tls/extensions/s2n_server_renegotiation_info.h" +/** + * s2n-tls servers do NOT support renegotiation. + * + * We implement this extension to handle clients that require secure renegotiation support: + *= https://tools.ietf.org/rfc/rfc5746#4.3 + *# In order to enable clients to probe, even servers that do not support + *# renegotiation MUST implement the minimal version of the extension + *# described in this document for initial handshakes, thus signaling + *# that they have been upgraded. + */ + 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); static int s2n_renegotiation_info_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); @@ -69,12 +80,53 @@ static bool s2n_renegotiation_info_should_send(struct s2n_connection *conn) *# include an empty "renegotiation_info" extension in the ServerHello *# message. */ -static int s2n_renegotiation_info_send(struct s2n_connection *conn, struct s2n_stuffer *out) +static int s2n_renegotiation_info_send_initial(struct s2n_connection *conn, struct s2n_stuffer *out) { POSIX_GUARD(s2n_stuffer_write_uint8(out, 0)); return S2N_SUCCESS; } +static int s2n_renegotiation_info_send_renegotiation(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + POSIX_ENSURE_REF(conn); + + /* s2n-tls servers do not support renegotiation. + * We add the renegotiation version of this logic only for testing. + */ + POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); + + /** + *= https://tools.ietf.org/rfc/rfc5746#3.7 + *# This text applies if the connection's "secure_renegotiation" flag is + *# set to TRUE (if it is set to FALSE, see Section 4.4). + */ + POSIX_ENSURE(conn->secure_renegotiation, S2N_ERR_NO_RENEGOTIATION); + + /** + *= https://tools.ietf.org/rfc/rfc5746#3.7 + *# o The server MUST include a "renegotiation_info" extension + *# containing the saved client_verify_data and server_verify_data in + *# the ServerHello. + */ + const uint8_t verify_data_len = conn->handshake.finished_len; + POSIX_ENSURE_GT(verify_data_len, 0); + POSIX_GUARD(s2n_stuffer_write_uint8(out, verify_data_len * 2)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, conn->handshake.client_finished, verify_data_len)); + POSIX_GUARD(s2n_stuffer_write_bytes(out, conn->handshake.server_finished, verify_data_len)); + + return S2N_SUCCESS; +} + +static int s2n_renegotiation_info_send(struct s2n_connection *conn, struct s2n_stuffer *out) +{ + if (s2n_handshake_is_renegotiation(conn)) { + POSIX_GUARD(s2n_renegotiation_info_send_renegotiation(conn, out)); + } else { + POSIX_GUARD(s2n_renegotiation_info_send_initial(conn, out)); + } + return S2N_SUCCESS; +} + /** *= https://tools.ietf.org/rfc/rfc5746#3.4 *# o When a ServerHello is received, the client MUST check if it @@ -142,6 +194,14 @@ static int s2n_renegotiation_info_recv_renegotiation(struct s2n_connection *conn return S2N_SUCCESS; } +/** + * Note that this extension must also work for SSLv3: + *= https://tools.ietf.org/rfc/rfc5746#4.5 + *# Clients that support SSLv3 and offer secure renegotiation (either via SCSV or + *# "renegotiation_info") MUST accept the "renegotiation_info" extension + *# from the server, even if the server version is {0x03, 0x00}, and + *# behave as described in this specification. + */ static int s2n_renegotiation_info_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) { if (s2n_handshake_is_renegotiation(conn)) { @@ -170,13 +230,24 @@ static int s2n_renegotiation_info_if_missing(struct s2n_connection *conn) *# secure renegotiation; set secure_renegotiation flag to FALSE. *# In this case, some clients may want to terminate the handshake *# instead of continuing; see Section 4.1 for discussion. - * - * We do not terminate the handshake, although missing messaging for secure - * renegotiation degrades server security. - * - * We could introduce an option to fail in this case in the future. */ conn->secure_renegotiation = false; + + /** + *= https://tools.ietf.org/rfc/rfc5746#4.1 + *= type=exception + *= reason=Avoid interoperability problems + *# If clients wish to ensure that such attacks are impossible, they need + *# to terminate the connection immediately upon failure to receive the + *# extension without completing the handshake. Such clients MUST + *# generate a fatal "handshake_failure" alert prior to terminating the + *# connection. However, it is expected that many TLS servers that do + *# not support renegotiation (and thus are not vulnerable) will not + *# support this extension either, so in general, clients that implement + *# this behavior will encounter interoperability problems. + * + * TODO: https://github.com/aws/s2n-tls/issues/3528 + */ return S2N_SUCCESS; } } |