aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2023-02-15 10:12:58 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2023-02-15 10:12:58 +0300
commitb6379c4bd7f5c5daa7a24989d00c8579ebb6caeb (patch)
treefb4b0bad9fe1fcb399c0ecbba039ebee15999f1e
parent13218a75e88b9127fd5da4c3216237dcc2ace935 (diff)
downloadydb-b6379c4bd7f5c5daa7a24989d00c8579ebb6caeb.tar.gz
Update contrib/restricted/aws/s2n to 1.3.35
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_recv.c19
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_shutdown.c39
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_tls.h1
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_x509_validator.c226
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,