diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2023-02-15 10:12:58 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2023-02-15 10:12:58 +0300 |
commit | b6379c4bd7f5c5daa7a24989d00c8579ebb6caeb (patch) | |
tree | fb4b0bad9fe1fcb399c0ecbba039ebee15999f1e | |
parent | 13218a75e88b9127fd5da4c3216237dcc2ace935 (diff) | |
download | ydb-b6379c4bd7f5c5daa7a24989d00c8579ebb6caeb.tar.gz |
Update contrib/restricted/aws/s2n to 1.3.35
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_recv.c | 19 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_shutdown.c | 39 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_tls.h | 1 | ||||
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_x509_validator.c | 226 |
4 files changed, 171 insertions, 114 deletions
diff --git a/contrib/restricted/aws/s2n/tls/s2n_recv.c b/contrib/restricted/aws/s2n/tls/s2n_recv.c index d90badaa99..cf267f1926 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_recv.c +++ b/contrib/restricted/aws/s2n/tls/s2n_recv.c @@ -251,22 +251,3 @@ uint32_t s2n_peek(struct s2n_connection *conn) return s2n_stuffer_data_available(&conn->in); } - -int s2n_recv_close_notify(struct s2n_connection *conn, s2n_blocked_status *blocked) -{ - uint8_t record_type; - int isSSLv2; - *blocked = S2N_BLOCKED_ON_READ; - - 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 */ - POSIX_GUARD(s2n_process_alert_fragment(conn)); - - *blocked = S2N_NOT_BLOCKED; - return 0; -} diff --git a/contrib/restricted/aws/s2n/tls/s2n_shutdown.c b/contrib/restricted/aws/s2n/tls/s2n_shutdown.c index b076991e47..3a89221375 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_shutdown.c +++ b/contrib/restricted/aws/s2n/tls/s2n_shutdown.c @@ -19,25 +19,27 @@ #include "tls/s2n_tls.h" #include "utils/s2n_safety.h" -int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status *more) +int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status *blocked) { POSIX_ENSURE_REF(conn); - POSIX_ENSURE_REF(more); + POSIX_ENSURE_REF(blocked); /* Treat this call as a no-op if already wiped */ if (conn->send == NULL && conn->recv == NULL) { - return 0; + return S2N_SUCCESS; } - uint64_t elapsed; + uint64_t elapsed = 0; 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 */ + /* Queue our close_notify alert. + * If we have already sent a close_notify, then this operation is a no-op. + */ POSIX_GUARD(s2n_queue_writer_close_alert_warning(conn)); - /* Write it */ - POSIX_GUARD(s2n_flush(conn, more)); + /* Flush any pending records, then send the queued close_notify. */ + POSIX_GUARD(s2n_flush(conn, blocked)); /* * The purpose of the peer responding to our close_notify @@ -52,18 +54,23 @@ int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status *more) return S2N_SUCCESS; } - /* Assume caller isn't interested in pending incoming data */ - if (conn->in_status == PLAINTEXT) { + /* Wait for the peer's close_notify. */ + uint8_t record_type = 0; + int isSSLv2 = false; + *blocked = S2N_BLOCKED_ON_READ; + while (!conn->close_notify_received) { + POSIX_GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2)); + POSIX_ENSURE(!isSSLv2, S2N_ERR_BAD_MESSAGE); + if (record_type == TLS_ALERT) { + POSIX_GUARD(s2n_process_alert_fragment(conn)); + } + + /* Wipe and keep trying */ POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in)); POSIX_GUARD(s2n_stuffer_wipe(&conn->in)); conn->in_status = ENCRYPTED; } - /* 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; + *blocked = S2N_NOT_BLOCKED; + return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/s2n_tls.h b/contrib/restricted/aws/s2n/tls/s2n_tls.h index b2d70ef564..b59378e971 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_tls.h +++ b/contrib/restricted/aws/s2n/tls/s2n_tls.h @@ -83,7 +83,6 @@ int s2n_handshake_write_header(struct s2n_stuffer *out, uint8_t message_type); int s2n_handshake_finish_header(struct s2n_stuffer *out); S2N_RESULT s2n_handshake_parse_header(struct s2n_stuffer *io, uint8_t *message_type, uint32_t *length); int s2n_read_full_record(struct s2n_connection *conn, uint8_t *record_type, int *isSSLv2); -int s2n_recv_close_notify(struct s2n_connection *conn, s2n_blocked_status *blocked); extern uint16_t mfl_code_to_length[5]; diff --git a/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c b/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c index 7e2c30c4c7..da32793643 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c +++ b/contrib/restricted/aws/s2n/tls/s2n_x509_validator.c @@ -45,6 +45,7 @@ DEFINE_POINTER_CLEANUP_FUNC(OCSP_BASICRESP *, OCSP_BASICRESP_free); #define DEFAULT_OCSP_NEXT_UPDATE_PERIOD 3600000000000 DEFINE_POINTER_CLEANUP_FUNC(STACK_OF(X509_CRL) *, sk_X509_CRL_free); +DEFINE_POINTER_CLEANUP_FUNC(STACK_OF(GENERAL_NAME) *, GENERAL_NAMES_free); uint8_t s2n_x509_ocsp_stapling_supported(void) { @@ -213,95 +214,164 @@ int s2n_x509_validator_set_max_chain_depth(struct s2n_x509_validator *validator, return 0; } +static S2N_RESULT s2n_verify_host_information_san_entry(struct s2n_connection *conn, GENERAL_NAME *current_name, bool *san_found) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(current_name); + RESULT_ENSURE_REF(san_found); + + if (current_name->type == GEN_DNS || current_name->type == GEN_URI) { + *san_found = true; + + const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5); + RESULT_ENSURE_REF(name); + int name_len = ASN1_STRING_length(current_name->d.ia5); + RESULT_ENSURE_GT(name_len, 0); + + RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_UNTRUSTED); + + return S2N_RESULT_OK; + } + + if (current_name->type == GEN_IPADD) { + *san_found = true; + + /* try to validate an IP address if it's in the subject alt name. */ + const unsigned char *ip_addr = current_name->d.iPAddress->data; + RESULT_ENSURE_REF(ip_addr); + int ip_addr_len = current_name->d.iPAddress->length; + RESULT_ENSURE_GT(ip_addr_len, 0); + + RESULT_STACK_BLOB(address, INET6_ADDRSTRLEN + 1, INET6_ADDRSTRLEN + 1); + + if (ip_addr_len == 4) { + RESULT_GUARD(s2n_inet_ntop(AF_INET, ip_addr, &address)); + } else if (ip_addr_len == 16) { + RESULT_GUARD(s2n_inet_ntop(AF_INET6, ip_addr, &address)); + } else { + /* we aren't able to parse this value so skip it */ + RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED); + } + + /* strlen should be safe here since we made sure we were null terminated AND that inet_ntop succeeded */ + const char *name = (const char *) address.data; + size_t name_len = strlen(name); + + RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_UNTRUSTED); + + return S2N_RESULT_OK; + } + + /* we don't understand this entry type so skip it */ + RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED); +} + +static S2N_RESULT s2n_verify_host_information_san(struct s2n_connection *conn, X509 *public_cert, bool *san_found) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(public_cert); + RESULT_ENSURE_REF(san_found); + + *san_found = false; + + DEFER_CLEANUP(STACK_OF(GENERAL_NAME) *names_list = NULL, GENERAL_NAMES_free_pointer); + names_list = X509_get_ext_d2i(public_cert, NID_subject_alt_name, NULL, NULL); + RESULT_ENSURE(names_list, S2N_ERR_CERT_UNTRUSTED); + + int n = sk_GENERAL_NAME_num(names_list); + RESULT_ENSURE(n > 0, S2N_ERR_CERT_UNTRUSTED); + + s2n_result result = S2N_RESULT_OK; + for (int i = 0; i < n; i++) { + GENERAL_NAME *current_name = sk_GENERAL_NAME_value(names_list, i); + + /* return success on the first entry that passes verification */ + result = s2n_verify_host_information_san_entry(conn, current_name, san_found); + if (s2n_result_is_ok(result)) { + return S2N_RESULT_OK; + } + } + + /* if an error was set by one of the entries, then just propagate the error from the last SAN entry call */ + RESULT_GUARD(result); + + RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED); +} + +static S2N_RESULT s2n_verify_host_information_common_name(struct s2n_connection *conn, X509 *public_cert, bool *cn_found) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE_REF(public_cert); + RESULT_ENSURE_REF(cn_found); + + X509_NAME *subject_name = X509_get_subject_name(public_cert); + RESULT_ENSURE(subject_name, S2N_ERR_CERT_UNTRUSTED); + + int curr_idx = -1; + while (true) { + int next_idx = X509_NAME_get_index_by_NID(subject_name, NID_commonName, curr_idx); + if (next_idx >= 0) { + curr_idx = next_idx; + } else { + break; + } + } + + RESULT_ENSURE(curr_idx >= 0, S2N_ERR_CERT_UNTRUSTED); + + ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, curr_idx)); + RESULT_ENSURE(common_name, S2N_ERR_CERT_UNTRUSTED); + + /* X520CommonName allows the following ANSI string types per RFC 5280 Appendix A.1 */ + RESULT_ENSURE(ASN1_STRING_type(common_name) == V_ASN1_TELETEXSTRING + || ASN1_STRING_type(common_name) == V_ASN1_PRINTABLESTRING + || ASN1_STRING_type(common_name) == V_ASN1_UNIVERSALSTRING + || ASN1_STRING_type(common_name) == V_ASN1_UTF8STRING + || ASN1_STRING_type(common_name) == V_ASN1_BMPSTRING, + S2N_ERR_CERT_UNTRUSTED); + + /* at this point we have a valid CN value */ + *cn_found = true; + + char peer_cn[255] = { 0 }; + int len = ASN1_STRING_length(common_name); + + RESULT_ENSURE_GT(len, 0); + RESULT_ENSURE_LTE(len, s2n_array_len(peer_cn) - 1); + RESULT_CHECKED_MEMCPY(peer_cn, ASN1_STRING_data(common_name), len); + RESULT_ENSURE(conn->verify_host_fn(peer_cn, len, conn->data_for_verify_host), S2N_ERR_CERT_UNTRUSTED); + + return S2N_RESULT_OK; +} + /* * For each name in the cert. Iterate them. Call the callback. If one returns true, then consider it validated, * if none of them return true, the cert is considered invalid. */ -static uint8_t s2n_verify_host_information(struct s2n_x509_validator *validator, struct s2n_connection *conn, X509 *public_cert) +static S2N_RESULT s2n_verify_host_information(struct s2n_connection *conn, X509 *public_cert) { - (void) validator; - uint8_t verified = 0; - uint8_t san_found = 0; + bool entry_found = false; /* Check SubjectAltNames before CommonName as per RFC 6125 6.4.4 */ - STACK_OF(GENERAL_NAME) *names_list = X509_get_ext_d2i(public_cert, NID_subject_alt_name, NULL, NULL); - int n = sk_GENERAL_NAME_num(names_list); - for (int i = 0; i < n && !verified; i++) { - GENERAL_NAME *current_name = sk_GENERAL_NAME_value(names_list, i); - if (current_name->type == GEN_DNS) { - san_found = 1; - - const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5); - size_t name_len = (size_t) ASN1_STRING_length(current_name->d.ia5); - - verified = conn->verify_host_fn(name, name_len, conn->data_for_verify_host); - } else if (current_name->type == GEN_URI) { - const char *name = (const char *) ASN1_STRING_data(current_name->d.ia5); - size_t name_len = (size_t) ASN1_STRING_length(current_name->d.ia5); - - verified = conn->verify_host_fn(name, name_len, conn->data_for_verify_host); - } else if (current_name->type == GEN_IPADD) { - san_found = 1; - /* try to validate an IP address if it's in the subject alt name. */ - const unsigned char *ip_addr = current_name->d.iPAddress->data; - size_t ip_addr_len = (size_t) current_name->d.iPAddress->length; - - s2n_result parse_result = S2N_RESULT_ERROR; - s2n_stack_blob(address, INET6_ADDRSTRLEN + 1, INET6_ADDRSTRLEN + 1); - if (ip_addr_len == 4) { - parse_result = s2n_inet_ntop(AF_INET, ip_addr, &address); - } else if (ip_addr_len == 16) { - parse_result = s2n_inet_ntop(AF_INET6, ip_addr, &address); - } - - /* strlen should be safe here since we made sure we were null terminated AND that inet_ntop succeeded */ - if (s2n_result_is_ok(parse_result)) { - verified = conn->verify_host_fn( - (const char *) address.data, - strlen((const char *) address.data), - conn->data_for_verify_host); - } - } + s2n_result result = s2n_verify_host_information_san(conn, public_cert, &entry_found); + if (entry_found) { + return result; } - GENERAL_NAMES_free(names_list); - /* if no SubjectAltNames of type DNS found, go to the common name. */ - if (!verified && !san_found) { - X509_NAME *subject_name = X509_get_subject_name(public_cert); - if (subject_name) { - int next_idx = 0, curr_idx = -1; - while ((next_idx = X509_NAME_get_index_by_NID(subject_name, NID_commonName, curr_idx)) >= 0) { - curr_idx = next_idx; - } - - if (curr_idx >= 0) { - ASN1_STRING *common_name = - X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, curr_idx)); - - if (common_name) { - char peer_cn[255]; - static size_t peer_cn_size = sizeof(peer_cn); - 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 - || ASN1_STRING_type(common_name) == V_ASN1_PRINTABLESTRING - || ASN1_STRING_type(common_name) == V_ASN1_UNIVERSALSTRING - || ASN1_STRING_type(common_name) == V_ASN1_UTF8STRING - || ASN1_STRING_type(common_name) == V_ASN1_BMPSTRING) { - size_t len = (size_t) ASN1_STRING_length(common_name); - - 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); - } - } - } - } + result = s2n_verify_host_information_common_name(conn, public_cert, &entry_found); + if (entry_found) { + return result; } - return verified; + /* make a null-terminated string in case the callback tries to use strlen */ + const char *name = ""; + size_t name_len = 0; + + /* at this point, we don't have anything to identify the certificate with so pass an empty string to the callback */ + RESULT_ENSURE(conn->verify_host_fn(name, name_len, conn->data_for_verify_host), S2N_ERR_CERT_UNTRUSTED); + + return S2N_RESULT_OK; } static S2N_RESULT s2n_x509_validator_read_asn1_cert(struct s2n_stuffer *cert_chain_in_stuffer, struct s2n_blob *asn1_cert) @@ -387,7 +457,7 @@ static S2N_RESULT s2n_x509_validator_process_cert_chain(struct s2n_x509_validato RESULT_ENSURE_REF(leaf); if (conn->verify_host_fn) { - RESULT_ENSURE(s2n_verify_host_information(validator, conn, leaf), S2N_ERR_CERT_UNTRUSTED); + RESULT_GUARD(s2n_verify_host_information(conn, leaf)); } RESULT_GUARD_OSSL(X509_STORE_CTX_init(validator->store_ctx, validator->trust_store->trust_store, leaf, |