Skip to content

Commit

Permalink
Clean up receiving supported sig algs
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstewart committed Oct 31, 2023
1 parent 95753f0 commit e088cb7
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 268 deletions.
4 changes: 2 additions & 2 deletions tests/unit/s2n_client_signature_algorithms_extension_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ int main(int argc, char **argv)
conn->actual_protocol_version = S2N_TLS13;
EXPECT_SUCCESS(s2n_client_signature_algorithms_extension.recv(conn, &signature_algorithms_extension));
EXPECT_EQUAL(conn->handshake_params.client_sig_hash_algs.len, sig_hash_algs.len);
EXPECT_FAILURE(s2n_choose_sig_scheme_from_peer_preference_list(conn, &conn->handshake_params.client_sig_hash_algs,
EXPECT_FAILURE(s2n_process_peer_signature_preference_list(conn, &conn->handshake_params.client_sig_hash_algs,
&conn->handshake_params.server_cert_sig_scheme));

EXPECT_SUCCESS(s2n_stuffer_free(&signature_algorithms_extension));
Expand Down Expand Up @@ -119,7 +119,7 @@ int main(int argc, char **argv)
/* If a valid algorithm is offered among unknown algorithms, the valid one should be chosen */
EXPECT_SUCCESS(s2n_client_signature_algorithms_extension.recv(conn, &signature_algorithms_extension));
EXPECT_EQUAL(conn->handshake_params.client_sig_hash_algs.len, sig_hash_algs.len);
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &conn->handshake_params.client_sig_hash_algs,
EXPECT_SUCCESS(s2n_process_peer_signature_preference_list(conn, &conn->handshake_params.client_sig_hash_algs,
&conn->handshake_params.server_cert_sig_scheme));
EXPECT_EQUAL(conn->handshake_params.server_cert_sig_scheme->iana_value, TLS_SIGNATURE_SCHEME_RSA_PKCS1_SHA384);

Expand Down
144 changes: 95 additions & 49 deletions tests/unit/s2n_signature_algorithms_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@
#define ECDSA_CIPHER_SUITE &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha
#define TLS13_CIPHER_SUITE &s2n_tls13_aes_128_gcm_sha256

#define S2N_IANA_TO_BYTES(iana) (iana) >> 8, (iana) & 0xFF

const struct s2n_signature_scheme *const test_signature_schemes[] = {
&s2n_ecdsa_secp384r1_sha384,
&s2n_ecdsa_sha256,
&s2n_rsa_pkcs1_sha256,
&s2n_rsa_pkcs1_sha224,
&s2n_rsa_pkcs1_sha1,
Expand Down Expand Up @@ -116,28 +119,6 @@ int main(int argc, char **argv)
EXPECT_EQUAL(s2n_stuffer_data_available(&result), 0);
};

/* Test: written signatures readable */
{
DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT),
s2n_connection_ptr_free);
EXPECT_NOT_NULL(conn);
conn->security_policy_override = &test_security_policy;
conn->actual_protocol_version = S2N_TLS13;

DEFER_CLEANUP(struct s2n_stuffer result = { 0 }, s2n_stuffer_free);
EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&result, 0));
EXPECT_OK(s2n_signature_algorithms_supported_list_send(conn, &result));

struct s2n_sig_scheme_list signatures = { 0 };
EXPECT_SUCCESS(s2n_recv_supported_sig_scheme_list(&result, &signatures));
EXPECT_EQUAL(s2n_stuffer_data_available(&result), 0);

EXPECT_EQUAL(signatures.len, s2n_array_len(test_signature_schemes));
for (size_t i = 0; i < s2n_array_len(test_signature_schemes); i++) {
EXPECT_EQUAL(signatures.iana_list[i], test_signature_schemes[i]->iana_value);
}
};

/* Test: do not send TLS1.2 signature schemes if QUIC enabled */
{
DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT),
Expand Down Expand Up @@ -197,7 +178,7 @@ int main(int argc, char **argv)
EXPECT_EQUAL(conn->handshake_params.client_cert_sig_scheme, &s2n_rsa_pkcs1_sha256);
};

/* Test: algorithm not included in message */
/* Test: no algorithm provided */
{
struct s2n_stuffer empty = { 0 };

Expand Down Expand Up @@ -316,6 +297,72 @@ int main(int argc, char **argv)
};
};

/* s2n_signature_algorithms_supported_list_process */
{
DEFER_CLEANUP(struct s2n_config *server_config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, rsa_cert_chain));
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert_chain));

DEFER_CLEANUP(struct s2n_config *client_ecdsa_config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(client_ecdsa_config, ecdsa_cert_chain));

struct s2n_security_policy test_security_policy = *s2n_fetch_default_config()->security_policy;
test_security_policy.signature_preferences = &test_preferences;
server_config->security_policy = &test_security_policy;
client_ecdsa_config->security_policy = &test_security_policy;

/* Test: successfully choose server signature scheme */
{
const struct s2n_signature_scheme *expected = &s2n_ecdsa_sha256;
uint8_t ianas[] = {
S2N_IANA_TO_BYTES(expected->iana_value)
};
struct s2n_blob peer_ianas = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&peer_ianas, ianas, sizeof(ianas)));

DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT),
s2n_connection_ptr_free);
EXPECT_SUCCESS(s2n_connection_set_config(conn, client_ecdsa_config));

EXPECT_OK(s2n_signature_algorithms_supported_list_process(conn, &peer_ianas));
EXPECT_EQUAL(conn->handshake_params.client_cert_sig_scheme, expected);
};

/* Test: successfully choose client signature scheme */
{
const struct s2n_signature_scheme *expected = &s2n_ecdsa_sha256;
uint8_t ianas[] = {
S2N_IANA_TO_BYTES(expected->iana_value)
};
struct s2n_blob peer_ianas = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&peer_ianas, ianas, sizeof(ianas)));

DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
conn->actual_protocol_version = S2N_TLS12;
conn->secure->cipher_suite = ECDSA_CIPHER_SUITE;
EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));

EXPECT_OK(s2n_signature_algorithms_supported_list_process(conn, &peer_ianas));
EXPECT_EQUAL(conn->handshake_params.server_cert_sig_scheme, expected);
};

/* Test: choose server most preferred, not client most preferred */
/* Test: choose legacy default for <TLS1.2 */
/* Test: no / empty peer list */
/* Test: legacy defaults supported */
/* Test: legacy defaults not supported */
/* Test: no shared signature schemes */
/* Test: only invalid shared signature schemes */
};

/* s2n_signature_algorithms_supported_list_recv */
{
/* Test: successfully choose signature scheme */
/* Test: malformed supported list is ignored */

};

/* Test: choose correct signature for duplicate iana values.
* Some signature schemes have the same iana, but are different for
* different protocol versions. */
Expand Down Expand Up @@ -814,19 +861,20 @@ int main(int argc, char **argv)
conn->actual_protocol_version = S2N_TLS13;
EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

struct s2n_sig_scheme_list peer_list = {
.len = 1,
.iana_list = { s2n_rsa_pss_rsae_sha256.iana_value },
uint8_t ianas[] = {
S2N_IANA_TO_BYTES(s2n_rsa_pss_rsae_sha256.iana_value)
};

const struct s2n_signature_scheme *result = NULL;
struct s2n_blob peer_list = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&peer_list, ianas, sizeof(ianas)));

if (s2n_is_rsa_pss_signing_supported()) {
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result));
EXPECT_EQUAL(result, &s2n_rsa_pss_rsae_sha256);
EXPECT_OK(s2n_signature_algorithms_supported_list_process(
conn, &peer_list));
EXPECT_EQUAL(conn->handshake_params.client_cert_sig_scheme,
&s2n_rsa_pss_rsae_sha256);
} else {
EXPECT_FAILURE_WITH_ERRNO(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result),
S2N_ERR_INVALID_SIGNATURE_SCHEME);
EXPECT_ERROR_WITH_ERRNO(s2n_signature_algorithms_supported_list_process(
conn, &peer_list), S2N_ERR_INVALID_SIGNATURE_SCHEME);
}
};
};
Expand Down Expand Up @@ -863,39 +911,37 @@ int main(int argc, char **argv)

/* Test: no shared valid signature schemes, using TLS1.3. Server cant pick preferred */
{
const struct s2n_signature_scheme *result = NULL;
conn->secure->cipher_suite = TLS13_CIPHER_SUITE;
conn->actual_protocol_version = S2N_TLS13;

struct s2n_sig_scheme_list peer_list = {
.len = 1,
.iana_list = {
s2n_rsa_pkcs1_sha224.iana_value, /* Invalid (wrong protocol version) */
},
uint8_t ianas[] = {
/* Invalid (PKCS1 not allowed by TLS1.3) */
S2N_IANA_TO_BYTES(s2n_rsa_pkcs1_sha224.iana_value)
};
struct s2n_blob peer_list = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&peer_list, ianas, sizeof(ianas)));

EXPECT_FAILURE_WITH_ERRNO(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result),
EXPECT_ERROR_WITH_ERRNO(s2n_signature_algorithms_supported_list_process(conn, &peer_list),
S2N_ERR_INVALID_SIGNATURE_SCHEME);
};

EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, rsa_cert_chain));

/* Test: no shared valid signature schemes, using TLS1.3. Server picks a preferred */
{
const struct s2n_signature_scheme *result = NULL;
conn->secure->cipher_suite = TLS13_CIPHER_SUITE;
conn->actual_protocol_version = S2N_TLS13;

struct s2n_sig_scheme_list peer_list = {
.len = 1,
.iana_list = {
s2n_rsa_pkcs1_sha224.iana_value, /* Invalid (wrong protocol version) */
},
uint8_t ianas[] = {
/* Invalid (PKCS1 not allowed by TLS1.3) */
S2N_IANA_TO_BYTES(s2n_rsa_pkcs1_sha224.iana_value)
};
struct s2n_blob peer_list = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&peer_list, ianas, sizeof(ianas)));

/* behavior is that we fallback to a preferred signature algorithm */
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result));
EXPECT_EQUAL(result, &s2n_rsa_pss_rsae_sha256);
/* behavior is that we fallback to a preferred PSS signature algorithm */
EXPECT_OK(s2n_signature_algorithms_supported_list_process(conn, &peer_list));
EXPECT_EQUAL(conn->handshake_params.server_cert_sig_scheme, &s2n_rsa_pss_rsae_sha256);
};

s2n_connection_free(conn);
Expand Down Expand Up @@ -1014,7 +1060,7 @@ int main(int argc, char **argv)
server_conn->security_policy_override = &sha384_policy;

EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate_test_server_and_client(server_conn, client_conn),
S2N_ERR_INVALID_SIGNATURE_ALGORITHM);
S2N_ERR_INVALID_SIGNATURE_SCHEME);
EXPECT_EQUAL(client_conn->actual_protocol_version, S2N_TLS12);
EXPECT_EQUAL(server_conn->actual_protocol_version, S2N_TLS12);
};
Expand Down
13 changes: 11 additions & 2 deletions tls/extensions/s2n_client_signature_algorithms.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "utils/s2n_safety.h"

static bool s2n_client_signature_algorithms_should_send(struct s2n_connection *conn);
static int s2n_client_signature_algorithms_if_missing(struct s2n_connection *conn);
static int s2n_client_signature_algorithms_send(struct s2n_connection *conn, struct s2n_stuffer *extension);
static int s2n_client_signature_algorithms_recv(struct s2n_connection *conn, struct s2n_stuffer *extension);

Expand All @@ -33,14 +34,21 @@ const s2n_extension_type s2n_client_signature_algorithms_extension = {
.send = s2n_client_signature_algorithms_send,
.recv = s2n_client_signature_algorithms_recv,
.should_send = s2n_client_signature_algorithms_should_send,
.if_missing = s2n_extension_noop_if_missing,
.if_missing = s2n_client_signature_algorithms_if_missing,
};

static bool s2n_client_signature_algorithms_should_send(struct s2n_connection *conn)
{
return s2n_connection_get_protocol_version(conn) >= S2N_TLS12;
}

static int s2n_client_signature_algorithms_if_missing(struct s2n_connection *conn)
{
struct s2n_blob empty_list = { 0 };
POSIX_GUARD_RESULT(s2n_signature_algorithms_supported_list_process(conn, &empty_list));
return S2N_SUCCESS;
}

static int s2n_client_signature_algorithms_send(struct s2n_connection *conn, struct s2n_stuffer *extension)
{
POSIX_GUARD_RESULT(s2n_signature_algorithms_supported_list_send(conn, extension));
Expand All @@ -49,5 +57,6 @@ static int s2n_client_signature_algorithms_send(struct s2n_connection *conn, str

static int s2n_client_signature_algorithms_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
{
return s2n_recv_supported_sig_scheme_list(extension, &conn->handshake_params.client_sig_hash_algs);
POSIX_GUARD_RESULT(s2n_signature_algorithms_supported_list_recv(conn, extension));
return S2N_SUCCESS;
}
51 changes: 40 additions & 11 deletions tls/extensions/s2n_extension_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,38 @@ int s2n_extension_list_recv(s2n_extension_list_id list_type, struct s2n_connecti
return S2N_SUCCESS;
}

static S2N_RESULT s2n_extension_get_parsed(const s2n_extension_type *extension_type,
s2n_parsed_extensions_list *parsed_extension_list, s2n_parsed_extension **parsed_extension)
{
RESULT_ENSURE_REF(extension_type);
RESULT_ENSURE_REF(parsed_extension_list);
RESULT_ENSURE_REF(parsed_extension);

s2n_extension_type_id extension_id = 0;
RESULT_GUARD_POSIX(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id));

*parsed_extension = &parsed_extension_list->parsed_extensions[extension_id];
return S2N_RESULT_OK;
}

S2N_RESULT s2n_extension_skip(const s2n_extension_type *extension_type,
s2n_parsed_extensions_list *parsed_extension_list)
{
s2n_parsed_extension *parsed_extension = NULL;
RESULT_GUARD(s2n_extension_get_parsed(extension_type, parsed_extension_list,
&parsed_extension));
RESULT_ENSURE_REF(parsed_extension);

parsed_extension->processed = true;
return S2N_RESULT_OK;
}

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_extension);

if (parsed_extension->processed) {
return S2N_SUCCESS;
}

if (s2n_parsed_extension_is_empty(parsed_extension)) {
POSIX_GUARD(s2n_extension_is_missing(extension_type, conn));
return S2N_SUCCESS;
Expand All @@ -70,7 +92,7 @@ static int s2n_extension_process_impl(const s2n_extension_type *extension_type,
POSIX_GUARD(s2n_stuffer_skip_write(&extension_stuffer, parsed_extension->extension.size));

POSIX_GUARD(s2n_extension_recv(extension_type, conn, &extension_stuffer));

parsed_extension->processed = true;
return S2N_SUCCESS;
}

Expand All @@ -80,12 +102,11 @@ int s2n_extension_process(const s2n_extension_type *extension_type, struct s2n_c
POSIX_ENSURE_REF(parsed_extension_list);
POSIX_ENSURE_REF(extension_type);

s2n_extension_type_id extension_id;
POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id));
s2n_parsed_extension *parsed_extension = NULL;
POSIX_GUARD_RESULT(s2n_extension_get_parsed(extension_type, parsed_extension_list,
&parsed_extension));

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;
}

Expand All @@ -98,8 +119,16 @@ int s2n_extension_list_process(s2n_extension_list_id list_type, struct s2n_conne
POSIX_GUARD(s2n_extension_type_list_get(list_type, &extension_type_list));

for (int i = 0; i < extension_type_list->count; i++) {
POSIX_GUARD(s2n_extension_process(extension_type_list->extension_types[i],
conn, parsed_extension_list));
const s2n_extension_type *extension_type = extension_type_list->extension_types[i];

s2n_parsed_extension *parsed_extension = NULL;
POSIX_GUARD_RESULT(s2n_extension_get_parsed(extension_type, parsed_extension_list,
&parsed_extension));

if (parsed_extension->processed) {
continue;
}
POSIX_GUARD(s2n_extension_process(extension_type, conn, parsed_extension_list));
}

/**
Expand Down
2 changes: 2 additions & 0 deletions tls/extensions/s2n_extension_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ typedef enum {
int s2n_extension_list_send(s2n_extension_list_id list_type, struct s2n_connection *conn, struct s2n_stuffer *out);
int s2n_extension_list_recv(s2n_extension_list_id list_type, struct s2n_connection *conn, struct s2n_stuffer *in);

S2N_RESULT s2n_extension_skip(const s2n_extension_type *extension_type,
s2n_parsed_extensions_list *parsed_extension_list);
int s2n_extension_process(const s2n_extension_type *extension_type, struct s2n_connection *conn,
s2n_parsed_extensions_list *parsed_extension_list);
int s2n_extension_list_process(s2n_extension_list_id list_type, struct s2n_connection *conn,
Expand Down
3 changes: 2 additions & 1 deletion tls/extensions/s2n_server_signature_algorithms.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ static int s2n_signature_algorithms_send(struct s2n_connection *conn, struct s2n

static int s2n_signature_algorithms_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
{
return s2n_recv_supported_sig_scheme_list(extension, &conn->handshake_params.server_sig_hash_algs);
POSIX_GUARD_RESULT(s2n_signature_algorithms_supported_list_recv(conn, extension));
return S2N_SUCCESS;
}
6 changes: 1 addition & 5 deletions tls/s2n_client_cert_verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,9 @@ int s2n_client_cert_verify_send(struct s2n_connection *conn)
S2N_ASYNC_PKEY_GUARD(conn);
struct s2n_stuffer *out = &conn->handshake.io;

if (conn->actual_protocol_version < S2N_TLS12) {
POSIX_GUARD(s2n_choose_default_sig_scheme(conn, &conn->handshake_params.client_cert_sig_scheme, S2N_CLIENT));
} else {
POSIX_GUARD(s2n_stuffer_write_uint16(out, conn->handshake_params.client_cert_sig_scheme->iana_value));
}
const struct s2n_signature_scheme *chosen_sig_scheme = conn->handshake_params.client_cert_sig_scheme;
POSIX_ENSURE_REF(chosen_sig_scheme);
POSIX_GUARD(s2n_stuffer_write_uint16(out, chosen_sig_scheme->iana_value));

/* Use a copy of the hash state since the verify digest computation may modify the running hash state we need later. */
struct s2n_hash_state *hash_state = &hashes->hash_workspace;
Expand Down

0 comments on commit e088cb7

Please sign in to comment.