aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2022-07-21 15:48:40 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2022-07-21 15:48:40 +0300
commitd7bcd6c1debc3c73be1d9b096c22a4a7a8bd75d9 (patch)
tree00b0a76a27ea296b562bf8d1aad63ea59df02a88
parent4fc945f9177d94ae69c94276cc6f3277a0284f1f (diff)
downloadydb-d7bcd6c1debc3c73be1d9b096c22a4a7a8bd75d9.tar.gz
Update contrib/restricted/aws/s2n to 1.3.17
-rw-r--r--contrib/restricted/aws/s2n/api/s2n.h63
-rw-r--r--contrib/restricted/aws/s2n/crypto/s2n_certificate.c59
-rw-r--r--contrib/restricted/aws/s2n/crypto/s2n_certificate.h2
-rw-r--r--contrib/restricted/aws/s2n/error/s2n_errno.c1
-rw-r--r--contrib/restricted/aws/s2n/error/s2n_errno.h1
-rw-r--r--contrib/restricted/aws/s2n/tls/extensions/s2n_client_key_share.c35
-rw-r--r--contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c53
-rw-r--r--contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h1
-rw-r--r--contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c19
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_client_hello.c6
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_config.c98
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_config.h9
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_key_update.c18
-rw-r--r--contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c42
-rw-r--r--contrib/restricted/aws/s2n/utils/s2n_array.c2
-rw-r--r--contrib/restricted/aws/s2n/utils/s2n_array.h2
16 files changed, 282 insertions, 129 deletions
diff --git a/contrib/restricted/aws/s2n/api/s2n.h b/contrib/restricted/aws/s2n/api/s2n.h
index f1395151db..11df0c5f99 100644
--- a/contrib/restricted/aws/s2n/api/s2n.h
+++ b/contrib/restricted/aws/s2n/api/s2n.h
@@ -286,10 +286,8 @@ extern int s2n_config_free_cert_chain_and_key(struct s2n_config *config);
/**
* Callback function type used to get the system time.
*
- * Takes two arguments. A pointer to arbitrary data for use within the callback and a pointer to a 64 bit int.
- * the callback and a pointer to a 64 bit int. The 64 bit pointer should be set to the
- * number of nanoseconds since the Unix epoch.
- *
+ * @param void* A pointer to arbitrary data for use within the callback
+ * @param uint64_t* A pointer that the callback will set to the time in nanoseconds
* The function should return 0 on success and -1 on failure.
*/
typedef int (*s2n_clock_time_nanoseconds) (void *, uint64_t *);
@@ -345,7 +343,11 @@ typedef int (*s2n_cache_delete_callback) (struct s2n_connection *conn, void *,
/**
* Allows the caller to set a callback function that will be used to get the
- * system time.
+ * system time. The time returned should be the number of nanoseconds since the
+ * Unix epoch (Midnight, January 1st, 1970).
+ *
+ * s2n-tls uses this clock for timestamps.
+ *
* @param config The configuration object being updated
* @param clock_fn The wall clock time callback function
* @param ctx An opaque pointer that the callback will be invoked with
@@ -356,7 +358,11 @@ extern int s2n_config_set_wall_clock(struct s2n_config *config, s2n_clock_time_n
/**
* Allows the caller to set a callback function that will be used to get
- * monotonic time.
+ * monotonic time. The monotonic time is the time since an arbitrary, unspecified
+ * point. Unlike wall clock time, it MUST never move backwards.
+ *
+ * s2n-tls uses this clock for timers.
+ *
* @param config The configuration object being updated
* @param clock_fn The monotonic time callback function
* @param ctx An opaque pointer that the callback will be invoked with
@@ -712,6 +718,29 @@ S2N_API
extern s2n_cert_private_key *s2n_cert_chain_and_key_get_private_key(struct s2n_cert_chain_and_key *cert_and_key);
/**
+ * Set the raw OCSP stapling data for a certificate chain.
+ *
+ * @param chain_and_key The certificate chain handle
+ * @param data A pointer to the raw OCSP stapling data bytes. The data will be copied.
+ * @param length The length of the data bytes.
+ * @returns S2N_SUCCESS on success. S2N_FAILURE on failure
+ */
+S2N_API
+extern int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length);
+
+/**
+ * Set the signed certificate timestamp (SCT) for a certificate chain.
+ * This is used for Certificate Transparency.
+ *
+ * @param chain_and_key The certificate chain handle
+ * @param data A pointer to the SCT data. The data will be copied.
+ * @param length The length of the data bytes.
+ * @returns S2N_SUCCESS on success. S2N_FAILURE on failure
+ */
+S2N_API
+extern int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length);
+
+/**
* A callback function that is invoked if s2n-tls cannot resolve a conflict between
* two certificates with the same domain name. This function is invoked while certificates
* are added to an `s2n_config`.
@@ -738,16 +767,18 @@ S2N_API
extern int s2n_config_set_cert_tiebreak_callback(struct s2n_config *config, s2n_cert_tiebreak_callback cert_tiebreak_cb);
/**
- * Associates a certificate chain and a private key, with an `s2n_config` object.
- * At present, only one certificate-chain/key pair may be associated with a config.
+ * Associates a certificate chain and private key with an `s2n_config` object.
+ * Using this API, only one cert chain of each type (like ECDSA or RSA) may be associated with a config.
* `cert_chain_pem` should be a PEM encoded certificate chain, with the first certificate
- * in the chain being your servers certificate. `private_key_pem` should be a
+ * in the chain being your server's certificate. `private_key_pem` should be a
* PEM encoded private key corresponding to the server certificate.
*
+ * @deprecated Use s2n_config_add_cert_chain_and_key_to_store instead.
+ *
* @param config The configuration object being updated
* @param cert_chain_pem A byte array of a PEM encoded certificate chain.
* @param private_key_pem A byte array of a PEM encoded key.
- * @returns S2N_SUCCESS on success. S2N_FAILURE on failure
+ * @returns S2N_SUCCESS on success. S2N_FAILURE on failure.
*/
S2N_API
extern int s2n_config_add_cert_chain_and_key(struct s2n_config *config, const char *cert_chain_pem, const char *private_key_pem);
@@ -1023,6 +1054,8 @@ extern int s2n_config_set_alert_behavior(struct s2n_config *config, s2n_alert_be
* parameters are set to NULL, no new data is set in the `s2n_config` object,
* effectively clearing existing data.
*
+ * @deprecated Use s2n_cert_chain_and_key_set_ocsp_data and s2n_cert_chain_and_key_set_sct_list instead.
+ *
* @param config The configuration object being updated
* @param type The extension type
* @param data Data for the extension
@@ -1672,10 +1705,12 @@ S2N_API
extern int s2n_connection_set_protocol_preferences(struct s2n_connection *conn, const char * const *protocols, int protocol_count);
/**
- * Sets the server name for the connection.
+ * Sets the server name for the connection.
*
- * @note In the future, this can be used by clients who wish to use the TLS "Server Name indicator"
- * extension. At present, client functionality is disabled.
+ * It may be desirable for clients
+ * to provide this information to facilitate secure connections to
+ * servers that host multiple 'virtual' servers at a single underlying
+ * network address.
*
* @param conn The connection object being queried
* @param server_name A pointer to a string containing the desired server name
@@ -1707,7 +1742,7 @@ S2N_API
extern const char *s2n_get_application_protocol(struct s2n_connection *conn);
/**
- * Query the connection for a buffer containing the OCSP reponse.
+ * Query the connection for a buffer containing the OCSP response.
*
* @param conn The connection object being queried
* @param length A pointer that is set to the certificate transparency response buffer's size
diff --git a/contrib/restricted/aws/s2n/crypto/s2n_certificate.c b/contrib/restricted/aws/s2n/crypto/s2n_certificate.c
index f1a71a0332..9e3f4bc551 100644
--- a/contrib/restricted/aws/s2n/crypto/s2n_certificate.c
+++ b/contrib/restricted/aws/s2n/crypto/s2n_certificate.c
@@ -185,47 +185,38 @@ int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and
struct s2n_cert_chain_and_key *s2n_cert_chain_and_key_new(void)
{
- struct s2n_cert_chain_and_key *chain_and_key;
- struct s2n_blob chain_and_key_mem, cert_chain_mem, pkey_mem;
-
+ DEFER_CLEANUP(struct s2n_blob chain_and_key_mem = { 0 }, s2n_free);
PTR_GUARD_POSIX(s2n_alloc(&chain_and_key_mem, sizeof(struct s2n_cert_chain_and_key)));
- chain_and_key = (struct s2n_cert_chain_and_key *)(void *)chain_and_key_mem.data;
+ PTR_GUARD_POSIX(s2n_blob_zero(&chain_and_key_mem));
- /* Allocate the memory for the chain and key */
- if (s2n_alloc(&cert_chain_mem, sizeof(struct s2n_cert_chain)) != S2N_SUCCESS) {
- goto cleanup;
- }
- chain_and_key->cert_chain = (struct s2n_cert_chain *)(void *)cert_chain_mem.data;
+ DEFER_CLEANUP(struct s2n_blob cert_chain_mem = { 0 }, s2n_free);
+ PTR_GUARD_POSIX(s2n_alloc(&cert_chain_mem, sizeof(struct s2n_cert_chain)));
+ PTR_GUARD_POSIX(s2n_blob_zero(&cert_chain_mem));
- if (s2n_alloc(&pkey_mem, sizeof(s2n_cert_private_key)) != S2N_SUCCESS) {
- goto cleanup;
- }
- chain_and_key->private_key = (s2n_cert_private_key *)(void *)pkey_mem.data;
+ DEFER_CLEANUP(struct s2n_blob pkey_mem = { 0 }, s2n_free);
+ PTR_GUARD_POSIX(s2n_alloc(&pkey_mem, sizeof(s2n_cert_private_key)));
+ PTR_GUARD_POSIX(s2n_blob_zero(&pkey_mem));
- chain_and_key->cert_chain->head = NULL;
- if (s2n_pkey_zero_init(chain_and_key->private_key) != S2N_SUCCESS) {
- goto cleanup;
- }
- memset(&chain_and_key->ocsp_status, 0, sizeof(chain_and_key->ocsp_status));
- memset(&chain_and_key->sct_list, 0, sizeof(chain_and_key->sct_list));
- chain_and_key->cn_names = s2n_array_new(sizeof(struct s2n_blob));
- if (!chain_and_key->cn_names) {
- goto cleanup;
- }
-
- chain_and_key->san_names = s2n_array_new(sizeof(struct s2n_blob));
- if (!chain_and_key->san_names) {
- goto cleanup;
- }
+ DEFER_CLEANUP(struct s2n_array *cn_names = NULL, s2n_array_free_p);
+ cn_names = s2n_array_new(sizeof(struct s2n_blob));
+ PTR_ENSURE_REF(cn_names);
- chain_and_key->context = NULL;
+ DEFER_CLEANUP(struct s2n_array *san_names = NULL, s2n_array_free_p);
+ san_names = s2n_array_new(sizeof(struct s2n_blob));
+ PTR_ENSURE_REF(san_names);
+ struct s2n_cert_chain_and_key *chain_and_key = (struct s2n_cert_chain_and_key *)(void *)chain_and_key_mem.data;
+ chain_and_key->cert_chain = (struct s2n_cert_chain *)(void *)cert_chain_mem.data;
+ chain_and_key->private_key = (s2n_cert_private_key *)(void *)pkey_mem.data;
+ chain_and_key->cn_names = cn_names;
+ chain_and_key->san_names = san_names;
+
+ ZERO_TO_DISABLE_DEFER_CLEANUP(chain_and_key_mem);
+ ZERO_TO_DISABLE_DEFER_CLEANUP(cert_chain_mem);
+ ZERO_TO_DISABLE_DEFER_CLEANUP(pkey_mem);
+ ZERO_TO_DISABLE_DEFER_CLEANUP(cn_names);
+ ZERO_TO_DISABLE_DEFER_CLEANUP(san_names);
return chain_and_key;
- cleanup:
- s2n_free(&pkey_mem);
- s2n_free(&cert_chain_mem);
- s2n_free(&chain_and_key_mem);
- return NULL;
}
DEFINE_POINTER_CLEANUP_FUNC(GENERAL_NAMES *, GENERAL_NAMES_free);
diff --git a/contrib/restricted/aws/s2n/crypto/s2n_certificate.h b/contrib/restricted/aws/s2n/crypto/s2n_certificate.h
index e78601c1ae..c0cfad98da 100644
--- a/contrib/restricted/aws/s2n/crypto/s2n_certificate.h
+++ b/contrib/restricted/aws/s2n/crypto/s2n_certificate.h
@@ -60,8 +60,6 @@ struct certs_by_type {
struct s2n_cert_chain_and_key *certs[S2N_CERT_TYPE_COUNT];
};
-int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length);
-int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length);
/* Exposed for fuzzing */
int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert);
int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert);
diff --git a/contrib/restricted/aws/s2n/error/s2n_errno.c b/contrib/restricted/aws/s2n/error/s2n_errno.c
index 1ddc11b6e7..3ade2ea4ee 100644
--- a/contrib/restricted/aws/s2n/error/s2n_errno.c
+++ b/contrib/restricted/aws/s2n/error/s2n_errno.c
@@ -270,6 +270,7 @@ static const char *no_such_error = "Internal s2n error";
ERR_ENTRY(S2N_ERR_SECRET_SCHEDULE_STATE, "Correct inputs to secret calculation not available") \
ERR_ENTRY(S2N_ERR_LIBCRYPTO_VERSION_NUMBER_MISMATCH, "The libcrypto major version number seen at compile-time is different from the major version number seen at run-time") \
ERR_ENTRY(S2N_ERR_LIBCRYPTO_VERSION_NAME_MISMATCH, "The libcrypto major version name seen at compile-time is different from the major version name seen at run-time") \
+ ERR_ENTRY(S2N_ERR_CERT_OWNERSHIP, "The ownership of the certificate chain is incompatible with the operation")
/* clang-format on */
#define ERR_STR_CASE(ERR, str) case ERR: return str;
diff --git a/contrib/restricted/aws/s2n/error/s2n_errno.h b/contrib/restricted/aws/s2n/error/s2n_errno.h
index a02c7d5acc..a257500ef4 100644
--- a/contrib/restricted/aws/s2n/error/s2n_errno.h
+++ b/contrib/restricted/aws/s2n/error/s2n_errno.h
@@ -287,6 +287,7 @@ typedef enum {
S2N_ERR_INSUFFICIENT_MEM_SIZE,
S2N_ERR_KEYING_MATERIAL_EXPIRED,
S2N_ERR_SECRET_SCHEDULE_STATE,
+ S2N_ERR_CERT_OWNERSHIP,
S2N_ERR_T_USAGE_END,
} s2n_error;
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 6073263014..7e0ec41a82 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
@@ -84,6 +84,13 @@ static int s2n_generate_default_ecc_key_share(struct s2n_connection *conn, struc
POSIX_GUARD(s2n_ecc_evp_params_free(client_params));
}
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#4.2.8
+ *# Otherwise, when sending the new ClientHello, the client MUST
+ *# replace the original "key_share" extension with one containing only a
+ *# new KeyShareEntry for the group indicated in the selected_group field
+ *# of the triggering HelloRetryRequest.
+ **/
client_params->negotiated_curve = server_curve;
} else {
client_params->negotiated_curve = ecc_pref->ecc_curves[0];
@@ -164,6 +171,13 @@ static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn,
POSIX_GUARD(s2n_kem_group_free(client_params));
}
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#4.2.8
+ *# Otherwise, when sending the new ClientHello, the client MUST
+ *# replace the original "key_share" extension with one containing only a
+ *# new KeyShareEntry for the group indicated in the selected_group field
+ *# of the triggering HelloRetryRequest.
+ **/
client_params->kem_group = server_group;
} else {
client_params->kem_group = kem_pref->tls13_kem_groups[0];
@@ -175,6 +189,16 @@ static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn,
static int s2n_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out)
{
+ if (s2n_is_hello_retry_handshake(conn)) {
+ const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve;
+ const struct s2n_ecc_named_curve *client_curve = conn->kex_params.client_ecc_evp_params.negotiated_curve;
+ const struct s2n_kem_group *server_group = conn->kex_params.server_kem_group_params.kem_group;
+ const struct s2n_kem_group *client_group = conn->kex_params.client_kem_group_params.kem_group;
+
+ /* Ensure a new key share will be sent after a hello retry request */
+ POSIX_ENSURE(server_curve != client_curve || server_group != client_group, S2N_ERR_BAD_KEY_SHARE);
+ }
+
struct s2n_stuffer_reservation shares_size = {0};
POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &shares_size));
POSIX_GUARD(s2n_generate_default_pq_hybrid_key_share(conn, out));
@@ -397,8 +421,15 @@ static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stu
/* 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 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.
+ *
+ *= https://tools.ietf.org/rfc/rfc8446#4.1.1
+ *# If the server selects an (EC)DHE group and the client did not offer a
+ *# compatible "key_share" extension in the initial ClientHello, the
+ *# server MUST respond with a HelloRetryRequest (Section 4.1.4) message.
+ **/
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) {
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 25000e56a9..64b691abc3 100644
--- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c
+++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.c
@@ -24,8 +24,6 @@
#define s2n_parsed_extension_is_empty(parsed_extension) ((parsed_extension)->extension.data == NULL)
-static const s2n_parsed_extension empty_parsed_extensions[S2N_PARSED_EXTENSIONS_COUNT] = { 0 };
-
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;
@@ -50,23 +48,27 @@ int s2n_extension_list_recv(s2n_extension_list_id list_type, struct s2n_connecti
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)
+static int s2n_extension_process_impl(const s2n_extension_type *extension_type,
+ struct s2n_connection *conn, s2n_parsed_extension *parsed_extension)
{
POSIX_ENSURE_REF(extension_type);
- POSIX_ENSURE_REF(parsed_extensions);
+ POSIX_ENSURE_REF(parsed_extension);
+
+ if (parsed_extension->processed) {
+ return S2N_SUCCESS;
+ }
- if (s2n_parsed_extension_is_empty(&parsed_extensions[extension_id])) {
+ if (s2n_parsed_extension_is_empty(parsed_extension)) {
POSIX_GUARD(s2n_extension_is_missing(extension_type, conn));
return S2N_SUCCESS;
}
- POSIX_ENSURE(parsed_extensions[extension_id].extension_type == extension_type->iana_value,
+ POSIX_ENSURE(parsed_extension->extension_type == extension_type->iana_value,
S2N_ERR_INVALID_PARSED_EXTENSIONS);
- struct s2n_stuffer extension_stuffer;
- 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));
+ struct s2n_stuffer extension_stuffer = { 0 };
+ POSIX_GUARD(s2n_stuffer_init(&extension_stuffer, &parsed_extension->extension));
+ POSIX_GUARD(s2n_stuffer_skip_write(&extension_stuffer, parsed_extension->extension.size));
POSIX_GUARD(s2n_extension_recv(extension_type, conn, &extension_stuffer));
@@ -82,13 +84,10 @@ int s2n_extension_process(const s2n_extension_type *extension_type, struct s2n_c
s2n_extension_type_id 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);
-
- /* Wipe parsed_extension.
- * We can check for unprocessed extensions later by checking for non-blank parsed_extensions. */
- parsed_extension_list->parsed_extensions[extension_id] = empty_parsed_extensions[0];
-
- return result;
+ s2n_parsed_extension *parsed_extension = &parsed_extension_list->parsed_extensions[extension_id];
+ POSIX_GUARD(s2n_extension_process_impl(extension_type, conn, parsed_extension));
+ parsed_extension->processed = true;
+ return S2N_SUCCESS;
}
int s2n_extension_list_process(s2n_extension_list_id list_type, struct s2n_connection *conn,
@@ -104,17 +103,17 @@ int s2n_extension_list_process(s2n_extension_list_id list_type, struct s2n_conne
conn, parsed_extension_list));
}
- /* If parsed_extension_list.parsed_extensions is not completely wiped at this point,
- * then we have received an extension not allowed on this message type.
- *
- * According to the RFC, we should alert and close the connection.
- * From https://tools.ietf.org/html/rfc8446#section-4.2:
- * If an implementation receives an extension which it recognizes and which is not
- * specified for the message in which it appears, it MUST abort the handshake with an
- * "illegal_parameter" alert.
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#section-4.2
+ *= type=exception
+ *= reason=Incorrect implementations exist in the wild. Ignoring instead.
+ *# If an implementation receives an extension
+ *# which it recognizes and which is not specified for the message in
+ *# which it appears, it MUST abort the handshake with an
+ *# "illegal_parameter" alert.
*
- * However, to be more tolerant of non-compliant peers, we will just ignore and not
- * process the illegal extensions, treating them as if they are unsupported.
+ * If we want to enforce this restriction in the future, we can verify
+ * that no parsed extensions exist without the "processed" flag set.
*/
return S2N_SUCCESS;
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 a26eb3a89c..00245dacec 100644
--- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h
+++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_list.h
@@ -24,6 +24,7 @@ typedef struct {
uint16_t extension_type;
struct s2n_blob extension;
uint16_t wire_index;
+ unsigned processed:1;
} s2n_parsed_extension;
typedef struct {
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 02fa59ac3e..2df2ccd171 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
@@ -238,7 +238,24 @@ 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->kex_params.server_ecc_evp_params;
- server_ecc_evp_params->negotiated_curve = ecc_pref->ecc_curves[supported_curve_index];
+ const struct s2n_ecc_named_curve *negotiated_curve = ecc_pref->ecc_curves[supported_curve_index];
+
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#4.2.8
+ *# If using (EC)DHE key establishment and a HelloRetryRequest containing a
+ *# "key_share" extension was received by the client, the client MUST
+ *# verify that the selected NamedGroup in the ServerHello is the same as
+ *# that in the HelloRetryRequest. If this check fails, the client MUST
+ *# abort the handshake with an "illegal_parameter" alert.
+ **/
+ if (s2n_is_hello_retry_handshake(conn) && !s2n_is_hello_retry_message(conn)) {
+ POSIX_ENSURE_REF(server_ecc_evp_params->negotiated_curve);
+ const struct s2n_ecc_named_curve *previous_negotiated_curve = server_ecc_evp_params->negotiated_curve;
+ POSIX_ENSURE(negotiated_curve == previous_negotiated_curve,
+ S2N_ERR_BAD_MESSAGE);
+ }
+
+ server_ecc_evp_params->negotiated_curve = negotiated_curve;
/* If this is a HelloRetryRequest, we won't have a key share. We just have the selected group.
* Set the server negotiated curve and exit early so a proper keyshare can be generated. */
diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_hello.c b/contrib/restricted/aws/s2n/tls/s2n_client_hello.c
index 0553d1fe14..32506f495d 100644
--- a/contrib/restricted/aws/s2n/tls/s2n_client_hello.c
+++ b/contrib/restricted/aws/s2n/tls/s2n_client_hello.c
@@ -405,11 +405,7 @@ int s2n_process_client_hello(struct s2n_connection *conn)
conn->actual_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12);
}
- /* s2n_extension_list_process clears the parsed extensions as it processes them.
- * 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;
- POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, &copy_of_parsed_extensions));
+ POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, &conn->client_hello.extensions));
/* After parsing extensions, select a curve and corresponding keyshare to use */
if (conn->actual_protocol_version >= S2N_TLS13) {
diff --git a/contrib/restricted/aws/s2n/tls/s2n_config.c b/contrib/restricted/aws/s2n/tls/s2n_config.c
index 7c455bb642..dd8e06b0ad 100644
--- a/contrib/restricted/aws/s2n/tls/s2n_config.c
+++ b/contrib/restricted/aws/s2n/tls/s2n_config.c
@@ -314,15 +314,27 @@ int s2n_config_free_session_ticket_keys(struct s2n_config *config)
int s2n_config_free_cert_chain_and_key(struct s2n_config *config)
{
+ /* We track certificate ownership on the config itself because a config
+ * CANNOT use a combination of owned and unowned chains.
+ * If it does, and the unowned chains are freed before the config is,
+ * then iterating over the chains to determine which are owned and need to be freed
+ * will mean also reading the invalid, freed memory of any unowned certificates.
+ * As of now, some tests free chains before the config, so that pattern may also
+ * appear in application code.
+ */
+ if (config->cert_ownership != S2N_LIB_OWNED) {
+ return S2N_SUCCESS;
+ }
+
/* Free the cert_chain_and_key since the application has no reference
* to it. This is necessary until s2n_config_add_cert_chain_and_key is deprecated. */
- if (config->cert_allocated) {
- for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) {
- s2n_cert_chain_and_key_free(config->default_certs_by_type.certs[i]);
- }
+ for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) {
+ s2n_cert_chain_and_key_free(config->default_certs_by_type.certs[i]);
+ config->default_certs_by_type.certs[i] = NULL;
}
- return 0;
+ config->cert_ownership = S2N_NOT_OWNED;
+ return S2N_SUCCESS;
}
int s2n_config_free_dhparams(struct s2n_config *config)
@@ -466,19 +478,7 @@ int s2n_config_set_verification_ca_location(struct s2n_config *config, const cha
return err_code;
}
-/* Deprecated. Superseded by s2n_config_add_cert_chain_and_key_to_store */
-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;
- 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;
-}
-
-int s2n_config_add_cert_chain_and_key_to_store(struct s2n_config *config, struct s2n_cert_chain_and_key *cert_key_pair)
+static int s2n_config_add_cert_chain_and_key_impl(struct s2n_config *config, struct s2n_cert_chain_and_key *cert_key_pair)
{
POSIX_ENSURE_REF(config->domain_name_to_cert_map);
POSIX_ENSURE_REF(cert_key_pair);
@@ -491,6 +491,13 @@ int s2n_config_add_cert_chain_and_key_to_store(struct s2n_config *config, struct
* default, etc. */
if (config->default_certs_by_type.certs[cert_type] == NULL) {
config->default_certs_by_type.certs[cert_type] = cert_key_pair;
+ } else {
+ /* Because library-owned certificates are tracked and cleaned up via the
+ * default_certs_by_type mapping, library-owned chains MUST be set as the default
+ * to avoid a memory leak. If they're not the default, they're not freed.
+ */
+ POSIX_ENSURE(config->cert_ownership != S2N_LIB_OWNED,
+ S2N_ERR_MULTIPLE_DEFAULT_CERTIFICATES_PER_AUTH_TYPE);
}
}
@@ -501,6 +508,35 @@ int s2n_config_add_cert_chain_and_key_to_store(struct s2n_config *config, struct
return S2N_SUCCESS;
}
+/* Deprecated. Superseded by s2n_config_add_cert_chain_and_key_to_store */
+int s2n_config_add_cert_chain_and_key(struct s2n_config *config, const char *cert_chain_pem, const char *private_key_pem)
+{
+ POSIX_ENSURE_REF(config);
+ POSIX_ENSURE(config->cert_ownership != S2N_APP_OWNED, S2N_ERR_CERT_OWNERSHIP);
+
+ DEFER_CLEANUP(struct s2n_cert_chain_and_key *chain_and_key = s2n_cert_chain_and_key_new(),
+ s2n_cert_chain_and_key_ptr_free);
+ POSIX_ENSURE_REF(chain_and_key);
+ 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_impl(config, chain_and_key));
+ config->cert_ownership = S2N_LIB_OWNED;
+
+ ZERO_TO_DISABLE_DEFER_CLEANUP(chain_and_key);
+ return S2N_SUCCESS;
+}
+
+int s2n_config_add_cert_chain_and_key_to_store(struct s2n_config *config, struct s2n_cert_chain_and_key *cert_key_pair)
+{
+ POSIX_ENSURE_REF(config);
+ POSIX_ENSURE(config->cert_ownership != S2N_LIB_OWNED, S2N_ERR_CERT_OWNERSHIP);
+
+ POSIX_ENSURE_REF(cert_key_pair);
+ POSIX_GUARD(s2n_config_add_cert_chain_and_key_impl(config, cert_key_pair));
+ config->cert_ownership = S2N_APP_OWNED;
+
+ return S2N_SUCCESS;
+}
+
int s2n_config_set_async_pkey_callback(struct s2n_config *config, s2n_async_pkey_fn fn)
{
POSIX_ENSURE_REF(config);
@@ -510,12 +546,19 @@ int s2n_config_set_async_pkey_callback(struct s2n_config *config, s2n_async_pkey
return S2N_SUCCESS;
}
-int s2n_config_clear_default_certificates(struct s2n_config *config)
+static int s2n_config_clear_default_certificates(struct s2n_config *config)
{
POSIX_ENSURE_REF(config);
+
+ /* Clearing library-owned chains would lead to a memory leak.
+ * See s2n_config_free_cert_chain_and_key.
+ */
+ POSIX_ENSURE(config->cert_ownership != S2N_LIB_OWNED, S2N_ERR_CERT_OWNERSHIP);
+
for (int i = 0; i < S2N_CERT_TYPE_COUNT; i++) {
config->default_certs_by_type.certs[i] = NULL;
}
+ config->cert_ownership = S2N_NOT_OWNED;
return 0;
}
@@ -528,6 +571,11 @@ int s2n_config_set_cert_chain_and_key_defaults(struct s2n_config *config,
S2N_ERROR_IF(num_cert_key_pairs < 1 || num_cert_key_pairs > S2N_CERT_TYPE_COUNT,
S2N_ERR_NUM_DEFAULT_CERTIFICATES);
+ /* This method will set application-owned chains, so we must not already be using
+ * any library owned chains. See s2n_config_free_cert_chain_and_key.
+ */
+ POSIX_ENSURE(config->cert_ownership != S2N_LIB_OWNED, S2N_ERR_CERT_OWNERSHIP);
+
/* Validate certs being set before clearing auto-chosen defaults or previously set defaults */
struct certs_by_type new_defaults = {{ 0 }};
for (uint32_t i = 0; i < num_cert_key_pairs; i++) {
@@ -545,6 +593,7 @@ int s2n_config_set_cert_chain_and_key_defaults(struct s2n_config *config,
}
config->default_certs_are_explicit = 1;
+ config->cert_ownership = S2N_APP_OWNED;
return 0;
}
@@ -639,16 +688,15 @@ int s2n_config_set_extension_data(struct s2n_config *config, s2n_tls_extension_t
}
struct s2n_cert_chain_and_key *config_chain_and_key = s2n_config_get_single_default_cert(config);
POSIX_ENSURE_REF(config_chain_and_key);
+ POSIX_ENSURE(config->cert_ownership == S2N_LIB_OWNED, S2N_ERR_CERT_OWNERSHIP);
switch (type) {
case S2N_EXTENSION_CERTIFICATE_TRANSPARENCY:
- {
- POSIX_GUARD(s2n_cert_chain_and_key_set_sct_list(config_chain_and_key, data, length));
- } break;
+ POSIX_GUARD(s2n_cert_chain_and_key_set_sct_list(config_chain_and_key, data, length));
+ break;
case S2N_EXTENSION_OCSP_STAPLING:
- {
- POSIX_GUARD(s2n_cert_chain_and_key_set_ocsp_data(config_chain_and_key, data, length));
- } break;
+ POSIX_GUARD(s2n_cert_chain_and_key_set_ocsp_data(config_chain_and_key, data, length));
+ break;
default:
POSIX_BAIL(S2N_ERR_UNRECOGNIZED_EXTENSION);
}
diff --git a/contrib/restricted/aws/s2n/tls/s2n_config.h b/contrib/restricted/aws/s2n/tls/s2n_config.h
index c0068ce133..cfc7474c04 100644
--- a/contrib/restricted/aws/s2n/tls/s2n_config.h
+++ b/contrib/restricted/aws/s2n/tls/s2n_config.h
@@ -29,6 +29,12 @@
struct s2n_cipher_preferences;
+typedef enum {
+ S2N_NOT_OWNED = 0,
+ S2N_APP_OWNED,
+ S2N_LIB_OWNED,
+} s2n_cert_ownership;
+
struct s2n_config {
unsigned use_tickets:1;
@@ -36,7 +42,6 @@ struct s2n_config {
* See s2n_quic_support.h */
unsigned quic_enabled:1;
- unsigned cert_allocated:1;
unsigned default_certs_are_explicit:1;
unsigned use_session_cache:1;
/* if this is FALSE, server will ignore client's Maximum Fragment Length request */
@@ -142,6 +147,8 @@ struct s2n_config {
/* The user defined context associated with config */
void *context;
+
+ s2n_cert_ownership cert_ownership;
};
S2N_CLEANUP_RESULT s2n_config_ptr_free(struct s2n_config **config);
diff --git a/contrib/restricted/aws/s2n/tls/s2n_key_update.c b/contrib/restricted/aws/s2n/tls/s2n_key_update.c
index 86e933a1ac..3c862eb98e 100644
--- a/contrib/restricted/aws/s2n/tls/s2n_key_update.c
+++ b/contrib/restricted/aws/s2n/tls/s2n_key_update.c
@@ -107,10 +107,20 @@ int s2n_check_record_limit(struct s2n_connection *conn, struct s2n_blob *sequenc
POSIX_ENSURE_REF(conn->secure.cipher_suite);
POSIX_ENSURE_REF(conn->secure.cipher_suite->record_alg);
- uint64_t output = 0;
- POSIX_GUARD(s2n_sequence_number_to_uint64(sequence_number, &output));
-
- if (output + 1 > conn->secure.cipher_suite->record_alg->encryption_limit) {
+ /*
+ * This is the sequence number that will be used for the next record,
+ * because we incremented the sequence number after sending the last record.
+ */
+ uint64_t next_seq_num = 0;
+ POSIX_GUARD(s2n_sequence_number_to_uint64(sequence_number, &next_seq_num));
+
+ /*
+ * If the next record is the last record we can send, then the next record needs
+ * to contain a KeyUpdate message.
+ *
+ * This should always trigger on "==", but we use ">=" just in case.
+ */
+ if (next_seq_num >= conn->secure.cipher_suite->record_alg->encryption_limit) {
conn->key_update_pending = true;
}
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 ed80865998..4fbf2ca6a6 100644
--- a/contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c
+++ b/contrib/restricted/aws/s2n/tls/s2n_server_hello_retry.c
@@ -68,20 +68,33 @@ int s2n_server_hello_retry_recv(struct s2n_connection *conn)
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
- * which was provided in the "supported_groups" extension in the
- * original ClientHello and
- * (2) the selected_group field does not correspond to a group which was provided
- * in the "key_share" extension in the original ClientHello.
- * If either of these checks fails, then the client MUST abort the handshake. */
-
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. */
POSIX_ENSURE( (named_curve != NULL) != (kem_group != NULL), S2N_ERR_INVALID_HELLO_RETRY);
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#4.2.8
+ *# Upon receipt of this extension in a HelloRetryRequest, the client
+ *# MUST verify that (1) the selected_group field corresponds to a group
+ *# which was provided in the "supported_groups" extension in the
+ *# original ClientHello
+ **/
+ bool selected_group_in_supported_groups = false;
+ if (named_curve != NULL && s2n_ecc_preferences_includes_curve(ecc_pref, named_curve->iana_id)) {
+ selected_group_in_supported_groups = true;
+ }
+ if (kem_group != NULL && s2n_kem_preferences_includes_tls13_kem_group(kem_pref, kem_group->iana_id)) {
+ selected_group_in_supported_groups = true;
+ }
+
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#4.2.8
+ *# and (2) the selected_group field does not
+ *# correspond to a group which was provided in the "key_share" extension
+ *# in the original ClientHello.
+ **/
bool new_key_share_requested = false;
if (named_curve != NULL) {
new_key_share_requested = (named_curve != conn->kex_params.client_ecc_evp_params.negotiated_curve);
@@ -93,14 +106,19 @@ int s2n_server_hello_retry_recv(struct s2n_connection *conn)
new_key_share_requested = (kem_group != conn->kex_params.client_kem_group_params.kem_group);
}
- /*
+ /**
+ *= https://tools.ietf.org/rfc/rfc8446#4.2.8
+ *# If either of these checks fails, then
+ *# the client MUST abort the handshake with an "illegal_parameter"
+ *# alert.
+ *
*= 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);
+ **/
+ POSIX_ENSURE(new_key_share_requested, S2N_ERR_INVALID_HELLO_RETRY);
+ POSIX_ENSURE(selected_group_in_supported_groups, S2N_ERR_INVALID_HELLO_RETRY);
/* Update transcript hash */
POSIX_GUARD(s2n_server_hello_retry_recreate_transcript(conn));
diff --git a/contrib/restricted/aws/s2n/utils/s2n_array.c b/contrib/restricted/aws/s2n/utils/s2n_array.c
index 0ac2207e9a..0a7f185fc2 100644
--- a/contrib/restricted/aws/s2n/utils/s2n_array.c
+++ b/contrib/restricted/aws/s2n/utils/s2n_array.c
@@ -175,7 +175,7 @@ S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity)
return S2N_RESULT_OK;
}
-S2N_RESULT s2n_array_free_p(struct s2n_array **parray)
+S2N_CLEANUP_RESULT s2n_array_free_p(struct s2n_array **parray)
{
RESULT_ENSURE_REF(parray);
struct s2n_array *array = *parray;
diff --git a/contrib/restricted/aws/s2n/utils/s2n_array.h b/contrib/restricted/aws/s2n/utils/s2n_array.h
index 3e846ce4fd..a8f81325ee 100644
--- a/contrib/restricted/aws/s2n/utils/s2n_array.h
+++ b/contrib/restricted/aws/s2n/utils/s2n_array.h
@@ -41,5 +41,5 @@ extern S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t id
extern S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len);
extern S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity);
extern S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t idx);
-extern S2N_RESULT s2n_array_free_p(struct s2n_array **parray);
+extern S2N_CLEANUP_RESULT s2n_array_free_p(struct s2n_array **parray);
extern S2N_RESULT s2n_array_free(struct s2n_array *array);