Skip to content

Commit

Permalink
Merge branch 'main' into blinding_c
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstewart authored Jan 18, 2024
2 parents cfb90ac + 7f84701 commit ea9b764
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 27 deletions.
29 changes: 29 additions & 0 deletions api/s2n.h
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,35 @@ struct s2n_client_hello;
*/
S2N_API extern struct s2n_client_hello *s2n_connection_get_client_hello(struct s2n_connection *conn);

/**
* Creates an s2n_client_hello from bytes representing a ClientHello message.
*
* The input bytes should include the message header (message type and length),
* but not the record header.
*
* Unlike s2n_connection_get_client_hello, the s2n_client_hello returned by this
* method is owned by the application and must be freed with s2n_client_hello_free.
*
* This method does not support SSLv2 ClientHellos.
*
* @param bytes The raw bytes representing the ClientHello.
* @param size The size of raw_message.
* @returns A new s2n_client_hello on success, or NULL on failure.
*/
S2N_API extern struct s2n_client_hello *s2n_client_hello_parse_message(const uint8_t *bytes, uint32_t size);

/**
* Frees an s2n_client_hello structure.
*
* This method should be called to free s2n_client_hellos returned by
* s2n_client_hello_parse_message. It will error if passed an s2n_client_hello
* returned by s2n_connection_get_client_hello and owned by the connection.
*
* @param ch The structure to be freed.
* @returns S2N_SUCCESS on success, S2N_FAILURE on failure.
*/
S2N_API extern int s2n_client_hello_free(struct s2n_client_hello **ch);

/**
* Function to determine the size of the raw Client Hello buffer.
*
Expand Down
26 changes: 0 additions & 26 deletions api/unstable/fingerprint.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,3 @@ S2N_API int s2n_client_hello_get_fingerprint_hash(struct s2n_client_hello *ch,
S2N_API int s2n_client_hello_get_fingerprint_string(struct s2n_client_hello *ch,
s2n_fingerprint_type type, uint32_t max_size,
uint8_t *output, uint32_t *output_size);

/**
* Creates an s2n_client_hello from bytes representing a ClientHello message.
*
* Unlike s2n_connection_get_client_hello, the s2n_client_hello returned by this
* method is owned by the application and must be freed with s2n_client_hello_free.
*
* This method does not support SSLv2 ClientHellos.
*
* @param bytes The raw bytes representing the ClientHello.
* @param size The size of raw_message.
* @returns A new s2n_client_hello on success, or NULL on failure.
*/
S2N_API struct s2n_client_hello *s2n_client_hello_parse_message(const uint8_t *bytes, uint32_t size);

/**
* Frees an s2n_client_hello structure.
*
* This method should be called to free s2n_client_hellos returned by
* s2n_client_hello_parse_message. It will error if passed an s2n_client_hello
* returned by s2n_connection_get_client_hello and owned by the connection.
*
* @param ch The structure to be freed.
* @returns S2N_SUCCESS on success, S2N_FAILURE on failure.
*/
S2N_API int s2n_client_hello_free(struct s2n_client_hello **ch);
18 changes: 18 additions & 0 deletions api/unstable/ktls.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ S2N_API int s2n_connection_ktls_enable_recv(struct s2n_connection *conn);
*
* Enabling TLS1.3 with this method is considered "unsafe" because the kernel
* currently doesn't support updating encryption keys, which is required in TLS1.3.
* s2n_connection_get_key_update_counts can be used to gather metrics on whether
* key updates are occurring on your connections before enabling TLS1.3.
*
* In order to safely enable TLS1.3, an application must ensure that its peer will
* not send any KeyUpdate messages. If s2n-tls receives a KeyUpdate message while
Expand All @@ -119,6 +121,22 @@ S2N_API int s2n_connection_ktls_enable_recv(struct s2n_connection *conn);
*/
S2N_API int s2n_config_ktls_enable_unsafe_tls13(struct s2n_config *config);

/**
* Reports the number of times sending and receiving keys have been updated.
*
* This only applies to TLS1.3. Earlier versions do not support key updates.
*
* @warning s2n-tls only tracks up to UINT8_MAX (255) key updates. If this method
* reports 255 updates, then more than 255 updates may have occurred.
*
* @param conn A pointer to the connection.
* @param send_key_updates Number of times the sending key was updated.
* @param recv_key_updates Number of times the receiving key was updated.
* @returns S2N_SUCCESS if successful, S2N_FAILURE otherwise.
*/
S2N_API int s2n_connection_get_key_update_counts(struct s2n_connection *conn,
uint8_t *send_key_updates, uint8_t *recv_key_updates);

/**
* Sends the contents of a file as application data.
*
Expand Down
18 changes: 17 additions & 1 deletion docs/usage-guide/topics/ch10-client-hello.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
# Examining the Client Hello

## Getting a Client Hello

### From a connection
s2n-tls stores the received Client Hello and makes it available to the application. Call `s2n_connection_get_client_hello()` to get a pointer to the `s2n_client_hello` struct storing the Client Hello message. A NULL value will be returned if the connection has not yet received the Client Hello. The earliest point in the handshake when this struct is available is during the [Client Hello Callback](#client-hello-callback). The stored Client Hello message will not be available after calling `s2n_connection_free_handshake()`.

### From raw bytes
s2n-tls can parse a Client Hello from raw bytes. Call `s2n_client_hello_parse_message()`
with raw bytes representing a Client Hello message (including the message header, but excluding
the record header). The returned pointer to a `s2n_client_hello` struct behaves
the same as a pointer returned from `s2n_connection_get_client_hello()`, except
that the memory is owned by the application and must be freed with `s2n_client_hello_free()`.

## Examining the message

Call `s2n_client_hello_get_raw_message()` to retrieve the complete Client Hello message with the random bytes on it zeroed out.

Call `s2n_client_hello_get_cipher_suites()` to retrieve the list of cipher suites sent by the client.

Call `s2n_client_hello_get_session_id()` to retrieve the session ID sent by the client in the ClientHello message. Note that this value may not be the session ID eventually associated with this particular connection since the session ID can change when the server sends the Server Hello. The official session ID can be retrieved with `s2n_connection_get_session_id()`after the handshake completes.

Call `s2n_client_hello_get_extensions()` to retrieve the entire list of extensions sent in the Client Hello. Calling `s2n_client_hello_get_extension_by_id()` allows you to interrogate the `s2n_client_hello` struct for a specific extension.
Call `s2n_client_hello_get_extensions()` to retrieve the entire list of extensions sent in the Client Hello. Call `s2n_client_hello_get_extension_by_id()` to retrieve a specific extension. Because `s2n_client_hello_get_extension_by_id()` doesn't distinguish between zero-length extensions and missing extensions,
`s2n_client_hello_has_extension()` should be used to check for the existence of an extension.

Call `s2n_client_hello_get_supported_groups()` to retrieve the entire list of
supported groups sent by the client.

## SSLv2
s2n-tls will not negotiate SSLv2, but will accept SSLv2 ClientHellos advertising a
Expand Down
28 changes: 28 additions & 0 deletions tests/unit/s2n_connection_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "tls/s2n_connection.h"

#include "api/unstable/ktls.h"
#include "crypto/s2n_hash.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
Expand Down Expand Up @@ -878,6 +879,33 @@ int main(int argc, char **argv)
};
};

/* Test s2n_connection_get_key_update_counts */
{
/* Safety */
DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT),
s2n_connection_ptr_free);
EXPECT_NOT_NULL(conn);
uint8_t send_count = 0, recv_count = 0;
EXPECT_FAILURE_WITH_ERRNO(
s2n_connection_get_key_update_counts(NULL, &send_count, &recv_count),
S2N_ERR_NULL);
EXPECT_FAILURE_WITH_ERRNO(
s2n_connection_get_key_update_counts(conn, NULL, &recv_count),
S2N_ERR_NULL);
EXPECT_FAILURE_WITH_ERRNO(
s2n_connection_get_key_update_counts(conn, &send_count, NULL),
S2N_ERR_NULL);

/* Returns counts */
const uint8_t expected_send_count = 10;
conn->send_key_updated = expected_send_count;
const uint8_t expected_recv_count = 255;
conn->recv_key_updated = expected_recv_count;
EXPECT_SUCCESS(s2n_connection_get_key_update_counts(conn, &send_count, &recv_count));
EXPECT_EQUAL(send_count, expected_send_count);
EXPECT_EQUAL(recv_count, expected_recv_count);
}

EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_chain_and_key));
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(rsa_chain_and_key));
END_TEST();
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/s2n_key_update_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ int main(int argc, char **argv)
EXPECT_SUCCESS(s2n_key_update_recv(server_conn, &input));
EXPECT_EQUAL(server_conn->secure->client_sequence_number[0], 0);
EXPECT_FALSE(s2n_atomic_flag_test(&server_conn->key_update_pending));
EXPECT_EQUAL(server_conn->recv_key_updated, 1);

EXPECT_SUCCESS(s2n_connection_free(server_conn));
};
Expand All @@ -243,6 +244,7 @@ int main(int argc, char **argv)
EXPECT_SUCCESS(s2n_key_update_recv(client_conn, &input));
EXPECT_EQUAL(client_conn->secure->server_sequence_number[0], 0);
EXPECT_FALSE(s2n_atomic_flag_test(&client_conn->key_update_pending));
EXPECT_EQUAL(client_conn->recv_key_updated, 1);

EXPECT_SUCCESS(s2n_connection_free(client_conn));
};
Expand Down Expand Up @@ -294,6 +296,26 @@ int main(int argc, char **argv)
/* KeyUpdate still pending */
EXPECT_TRUE(s2n_atomic_flag_test(&conn->key_update_pending));
};

/* Receiving a KeyUpdate doesn't overflow the key update count */
{
DEFER_CLEANUP(struct s2n_stuffer input, s2n_stuffer_free);
EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, 0));

DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
EXPECT_NOT_NULL(conn);
conn->actual_protocol_version = S2N_TLS13;
conn->secure->cipher_suite = cipher_suite_with_limit;
conn->recv_key_updated = UINT8_MAX;

conn->secure->client_sequence_number[0] = 1;
EXPECT_SUCCESS(s2n_stuffer_write_uint8(&input, S2N_KEY_UPDATE_NOT_REQUESTED));
EXPECT_SUCCESS(s2n_key_update_recv(conn, &input));
EXPECT_EQUAL(conn->secure->client_sequence_number[0], 0);
EXPECT_EQUAL(conn->recv_key_updated, UINT8_MAX);
EXPECT_EQUAL(conn->send_key_updated, 0);
};
};

/* s2n_key_update_send */
Expand All @@ -319,6 +341,7 @@ int main(int argc, char **argv)
EXPECT_EQUAL(s2n_atomic_flag_test(&client_conn->key_update_pending), false);
EXPECT_BYTEARRAY_EQUAL(client_conn->secure->client_sequence_number, zeroed_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN);
EXPECT_TRUE(s2n_stuffer_data_available(&stuffer) > 0);
EXPECT_EQUAL(client_conn->send_key_updated, 1);

EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
EXPECT_SUCCESS(s2n_connection_free(client_conn));
Expand Down Expand Up @@ -346,6 +369,7 @@ int main(int argc, char **argv)
EXPECT_EQUAL(s2n_atomic_flag_test(&client_conn->key_update_pending), false);
EXPECT_BYTEARRAY_EQUAL(client_conn->secure->client_sequence_number, zeroed_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN);
EXPECT_TRUE(s2n_stuffer_data_available(&stuffer) > 0);
EXPECT_EQUAL(client_conn->send_key_updated, 1);

EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
EXPECT_SUCCESS(s2n_connection_free(client_conn));
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/s2n_security_rules_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,15 @@ int main(int argc, char **argv)
.signature_preferences = &valid_sig_prefs,
.certificate_signature_preferences = &valid_sig_prefs,
.ecc_preferences = &valid_ecc_prefs,
.kem_preferences = &kem_preferences_null,
.minimum_protocol_version = VALID_VERSION,
};
const struct s2n_security_policy invalid_policy = {
.cipher_preferences = &invalid_cipher_prefs,
.signature_preferences = &invalid_sig_prefs,
.certificate_signature_preferences = &invalid_sig_prefs,
.ecc_preferences = &invalid_ecc_prefs,
.kem_preferences = &kem_preferences_null,
.minimum_protocol_version = EXAMPLE_INVALID_VERSION,
};

Expand Down
40 changes: 40 additions & 0 deletions tls/s2n_cipher_preferences.c
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,46 @@ const struct s2n_cipher_preferences cipher_preferences_pq_tls_1_3_2023_06_01 = {
.allow_chacha20_boosting = false,
};

struct s2n_cipher_suite *cipher_suites_20231213[] = {
&s2n_tls13_aes_128_gcm_sha256,
&s2n_tls13_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_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_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,
};

const struct s2n_cipher_preferences cipher_preferences_20231213 = {
.count = s2n_array_len(cipher_suites_20231213),
.suites = cipher_suites_20231213,
};

struct s2n_cipher_suite *cipher_suites_20231214[] = {
&s2n_tls13_aes_128_gcm_sha256,
&s2n_tls13_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_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,
};

const struct s2n_cipher_preferences cipher_preferences_20231214 = {
.count = s2n_array_len(cipher_suites_20231214),
.suites = cipher_suites_20231214,
};

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,
Expand Down
3 changes: 3 additions & 0 deletions tls/s2n_cipher_preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ 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_20231213;
extern const struct s2n_cipher_preferences cipher_preferences_20231214;

extern const struct s2n_cipher_preferences cipher_preferences_default_fips;

extern const struct s2n_cipher_preferences cipher_preferences_test_all;
Expand Down
13 changes: 13 additions & 0 deletions tls/s2n_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <unistd.h>

#include "api/s2n.h"
/* Required for s2n_connection_get_key_update_counts */
#include "api/unstable/ktls.h"
#include "crypto/s2n_certificate.h"
#include "crypto/s2n_cipher.h"
#include "crypto/s2n_crypto.h"
Expand Down Expand Up @@ -1689,3 +1691,14 @@ S2N_RESULT s2n_connection_get_sequence_number(struct s2n_connection *conn,

return S2N_RESULT_OK;
}

int s2n_connection_get_key_update_counts(struct s2n_connection *conn,
uint8_t *send_key_updates, uint8_t *recv_key_updates)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(send_key_updates);
POSIX_ENSURE_REF(recv_key_updates);
*send_key_updates = conn->send_key_updated;
*recv_key_updates = conn->recv_key_updated;
return S2N_SUCCESS;
}
4 changes: 4 additions & 0 deletions tls/s2n_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ struct s2n_connection {
* The writer clears it after a KeyUpdate is sent.
*/
s2n_atomic_flag key_update_pending;

/* Track KeyUpdates for metrics */
uint8_t send_key_updated;
uint8_t recv_key_updated;
};

S2N_CLEANUP_RESULT s2n_connection_ptr_free(struct s2n_connection **s2n_connection);
Expand Down
16 changes: 16 additions & 0 deletions tls/s2n_kem_preferences.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ const struct s2n_kem_group *pq_kem_groups_r3_2023_06[] = {
&s2n_x25519_kyber_512_r3,
};

const struct s2n_kem_group *pq_kem_groups_r3_2023_12[] = {
&s2n_secp256r1_kyber_768_r3,
&s2n_secp384r1_kyber_768_r3,
&s2n_secp521r1_kyber_1024_r3,
&s2n_secp256r1_kyber_512_r3,
};

const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2021_05 = {
.kem_count = s2n_array_len(pq_kems_r3_2021_05),
.kems = pq_kems_r3_2021_05,
Expand All @@ -59,6 +66,15 @@ const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_06 = {
.tls13_pq_hybrid_draft_revision = 5
};

/* Same as kem_preferences_pq_tls_1_3_2023_06, but without x25519 */
const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_12 = {
.kem_count = 0,
.kems = NULL,
.tls13_kem_group_count = s2n_array_len(pq_kem_groups_r3_2023_12),
.tls13_kem_groups = pq_kem_groups_r3_2023_12,
.tls13_pq_hybrid_draft_revision = 5
};

const struct s2n_kem_preferences kem_preferences_all = {
.kem_count = s2n_array_len(pq_kems_r3_2021_05),
.kems = pq_kems_r3_2021_05,
Expand Down
1 change: 1 addition & 0 deletions tls/s2n_kem_preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ extern const struct s2n_kem_group *pq_kem_groups_r3_2023_06[];
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2021_05;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_0_2023_01;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_06;
extern const struct s2n_kem_preferences kem_preferences_pq_tls_1_3_2023_12;
extern const struct s2n_kem_preferences kem_preferences_all;
extern const struct s2n_kem_preferences kem_preferences_null;

Expand Down
Loading

0 comments on commit ea9b764

Please sign in to comment.