Skip to content

Commit 1616f31

Browse files
zz85baldwinmatt
andauthored
Support TLS 1.3 clients that do not specify signature algorithms (#2222)
* Pick a certificate signature algorithm in TLS 1.3 even if client does not indicate support. * int -> size_t * Tests * Use s2n_is_rsa_pss_signing_supported() * Simplify to GUARD, rename to s2n_tls13_preferred_sig_scheme for clarity * Add line break * Add s2n_is_signature_scheme_usable() to reduce duplication * S2N_ERR_EMPTY_SIGNATURE_SCHEME is no longer useful, remove it * Reorder TLS 1.3 default signature scheme selection * Update tls/s2n_signature_algorithms.c Co-authored-by: Matthew Baldwin <baldwinmatt@users.noreply.github.com>
1 parent cf1692b commit 1616f31

File tree

5 files changed

+128
-28
lines changed

5 files changed

+128
-28
lines changed

error/s2n_errno.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ static const char *no_such_error = "Internal s2n error";
7070
ERR_ENTRY(S2N_ERR_DECODE_PRIVATE_KEY, "error decoding private key") \
7171
ERR_ENTRY(S2N_ERR_INVALID_SIGNATURE_ALGORITHM, "Invalid signature algorithm") \
7272
ERR_ENTRY(S2N_ERR_INVALID_SIGNATURE_SCHEME, "Invalid signature scheme") \
73-
ERR_ENTRY(S2N_ERR_EMPTY_SIGNATURE_SCHEME, "Empty signature scheme") \
7473
ERR_ENTRY(S2N_ERR_CBC_VERIFY, "Failed CBC verification") \
7574
ERR_ENTRY(S2N_ERR_DH_COPYING_PUBLIC_KEY, "error copying Diffie-Hellman public key") \
7675
ERR_ENTRY(S2N_ERR_SIGN, "error signing data") \

error/s2n_errno.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ typedef enum {
8888
S2N_ERR_INVALID_HELLO_RETRY,
8989
S2N_ERR_INVALID_SIGNATURE_ALGORITHM,
9090
S2N_ERR_INVALID_SIGNATURE_SCHEME,
91-
S2N_ERR_EMPTY_SIGNATURE_SCHEME,
9291
S2N_ERR_CBC_VERIFY,
9392
S2N_ERR_DH_COPYING_PUBLIC_KEY,
9493
S2N_ERR_SIGN,

tests/unit/s2n_record_size_test.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static int destroy_server_keys(struct s2n_connection *server_conn)
4343
{
4444
GUARD(server_conn->initial.cipher_suite->record_alg->cipher->destroy_key(&server_conn->initial.server_key));
4545
GUARD(server_conn->initial.cipher_suite->record_alg->cipher->destroy_key(&server_conn->initial.client_key));
46+
4647
return S2N_SUCCESS;
4748
}
4849

tests/unit/s2n_signature_algorithms_test.c

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,14 +401,13 @@ int main(int argc, char **argv)
401401
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result));
402402
EXPECT_EQUAL(result.iana_value, default_scheme.iana_value);
403403

404-
/* TLS1.3 does not allow defaults */
404+
/* If we cannot find a match in TLS1.3, allow defaults for success */
405405
conn->secure.cipher_suite = TLS13_CIPHER_SUITE;
406406
conn->actual_protocol_version = S2N_TLS13;
407-
EXPECT_FAILURE_WITH_ERRNO(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result),
408-
S2N_ERR_EMPTY_SIGNATURE_SCHEME);
407+
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result));
409408
}
410409

411-
/* Test: no shared valid signature schemes, using TLS1.3 */
410+
/* Test: no shared valid signature schemes, using TLS1.3. Server picks preferred */
412411
{
413412
conn->secure.cipher_suite = TLS13_CIPHER_SUITE;
414413
conn->actual_protocol_version = S2N_TLS13;
@@ -420,8 +419,9 @@ int main(int argc, char **argv)
420419
},
421420
};
422421

423-
EXPECT_FAILURE_WITH_ERRNO(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result),
424-
S2N_ERR_INVALID_SIGNATURE_SCHEME);
422+
/* behavior is that we fallback to a preferred signature algorithm */
423+
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result));
424+
EXPECT_EQUAL(result.iana_value, s2n_ecdsa_sha384.iana_value);
425425
}
426426

427427
/* Test: no shared valid signature schemes, using TLS1.2 */
@@ -625,6 +625,76 @@ int main(int argc, char **argv)
625625
s2n_config_free(config);
626626
}
627627

628+
/* Test fallback of TLS 1.3 signature algorithms */
629+
if (s2n_is_rsa_pss_signing_supported())
630+
{
631+
struct s2n_config *config = s2n_config_new();
632+
633+
struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
634+
EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
635+
636+
const struct s2n_security_policy *security_policy = NULL;
637+
EXPECT_SUCCESS(s2n_connection_get_security_policy(conn, &security_policy));
638+
EXPECT_NOT_NULL(security_policy);
639+
640+
const struct s2n_signature_scheme *const test_rsae_signature_schemes[] = {
641+
&s2n_rsa_pss_rsae_sha256,
642+
};
643+
644+
const struct s2n_signature_preferences test_rsae_preferences = {
645+
.count = 1,
646+
.signature_schemes = test_rsae_signature_schemes,
647+
};
648+
649+
struct s2n_security_policy test_security_policy = {
650+
.minimum_protocol_version = security_policy->minimum_protocol_version,
651+
.cipher_preferences = security_policy->cipher_preferences,
652+
.kem_preferences = security_policy->kem_preferences,
653+
.signature_preferences = &test_rsae_preferences,
654+
.ecc_preferences = security_policy->ecc_preferences,
655+
};
656+
657+
config->security_policy = &test_security_policy;
658+
659+
struct s2n_signature_scheme result;
660+
661+
/* Test: no shared valid signature schemes, using TLS1.3. Server cant pick preferred */
662+
{
663+
conn->secure.cipher_suite = TLS13_CIPHER_SUITE;
664+
conn->actual_protocol_version = S2N_TLS13;
665+
666+
struct s2n_sig_scheme_list peer_list = {
667+
.len = 1, .iana_list = {
668+
s2n_rsa_pkcs1_sha224.iana_value, /* Invalid (wrong protocol version) */
669+
},
670+
};
671+
672+
EXPECT_FAILURE_WITH_ERRNO(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result),
673+
S2N_ERR_INVALID_SIGNATURE_SCHEME);
674+
}
675+
676+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, rsa_cert_chain));
677+
678+
/* Test: no shared valid signature schemes, using TLS1.3. Server picks a preferred */
679+
{
680+
conn->secure.cipher_suite = TLS13_CIPHER_SUITE;
681+
conn->actual_protocol_version = S2N_TLS13;
682+
683+
struct s2n_sig_scheme_list peer_list = {
684+
.len = 1, .iana_list = {
685+
s2n_rsa_pkcs1_sha224.iana_value, /* Invalid (wrong protocol version) */
686+
},
687+
};
688+
689+
/* behavior is that we fallback to a preferred signature algorithm */
690+
EXPECT_SUCCESS(s2n_choose_sig_scheme_from_peer_preference_list(conn, &peer_list, &result));
691+
EXPECT_EQUAL(result.iana_value, s2n_rsa_pss_rsae_sha256.iana_value);
692+
}
693+
694+
s2n_connection_free(conn);
695+
s2n_config_free(config);
696+
}
697+
628698
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(rsa_cert_chain));
629699
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_cert_chain));
630700

tls/s2n_signature_algorithms.c

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ static int s2n_signature_scheme_valid_to_accept(struct s2n_connection *conn, con
5757
return 0;
5858
}
5959

60+
static int s2n_is_signature_scheme_usable(struct s2n_connection *conn, const struct s2n_signature_scheme *candidate) {
61+
notnull_check(conn);
62+
notnull_check(candidate);
63+
64+
GUARD(s2n_signature_scheme_valid_to_accept(conn, candidate));
65+
GUARD(s2n_is_sig_scheme_valid_for_auth(conn, candidate));
66+
67+
return S2N_SUCCESS;
68+
}
69+
6070
static int s2n_choose_sig_scheme(struct s2n_connection *conn, struct s2n_sig_scheme_list *peer_wire_prefs,
6171
struct s2n_signature_scheme *chosen_scheme_out)
6272
{
@@ -68,18 +78,14 @@ static int s2n_choose_sig_scheme(struct s2n_connection *conn, struct s2n_sig_sch
6878
struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite;
6979
notnull_check(cipher_suite);
7080

71-
for (int i = 0; i < signature_preferences->count; i++) {
81+
for (size_t i = 0; i < signature_preferences->count; i++) {
7282
const struct s2n_signature_scheme *candidate = signature_preferences->signature_schemes[i];
7383

74-
if (s2n_signature_scheme_valid_to_accept(conn, candidate) != S2N_SUCCESS) {
75-
continue;
76-
}
77-
78-
if (s2n_is_sig_scheme_valid_for_auth(conn, candidate) != S2N_SUCCESS) {
84+
if (s2n_is_signature_scheme_usable(conn, candidate) != S2N_SUCCESS) {
7985
continue;
8086
}
8187

82-
for (int j = 0; j < peer_wire_prefs->len; j++) {
88+
for (size_t j = 0; j < peer_wire_prefs->len; j++) {
8389
uint16_t their_iana_val = peer_wire_prefs->iana_list[j];
8490

8591
if (candidate->iana_value == their_iana_val) {
@@ -89,6 +95,32 @@ static int s2n_choose_sig_scheme(struct s2n_connection *conn, struct s2n_sig_sch
8995
}
9096
}
9197

98+
/* do not error even if there's no match */
99+
return S2N_SUCCESS;
100+
}
101+
102+
/* similar to s2n_choose_sig_scheme() without matching client's preference */
103+
static int s2n_tls13_default_sig_scheme(struct s2n_connection *conn, struct s2n_signature_scheme *chosen_scheme_out)
104+
{
105+
notnull_check(conn);
106+
const struct s2n_signature_preferences *signature_preferences = NULL;
107+
GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences));
108+
notnull_check(signature_preferences);
109+
110+
struct s2n_cipher_suite *cipher_suite = conn->secure.cipher_suite;
111+
notnull_check(cipher_suite);
112+
113+
for (size_t i = 0; i < signature_preferences->count; i++) {
114+
const struct s2n_signature_scheme *candidate = signature_preferences->signature_schemes[i];
115+
116+
if (s2n_is_signature_scheme_usable(conn, candidate) != S2N_SUCCESS) {
117+
continue;
118+
}
119+
120+
*chosen_scheme_out = *candidate;
121+
return S2N_SUCCESS;
122+
}
123+
92124
S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_SCHEME);
93125
}
94126

@@ -102,7 +134,7 @@ int s2n_get_and_validate_negotiated_signature_scheme(struct s2n_connection *conn
102134
GUARD(s2n_connection_get_signature_preferences(conn, &signature_preferences));
103135
notnull_check(signature_preferences);
104136

105-
for (int i = 0; i < signature_preferences->count; i++) {
137+
for (size_t i = 0; i < signature_preferences->count; i++) {
106138
const struct s2n_signature_scheme *candidate = signature_preferences->signature_schemes[i];
107139

108140
if (0 != s2n_signature_scheme_valid_to_accept(conn, candidate)) {
@@ -167,18 +199,17 @@ int s2n_choose_sig_scheme_from_peer_preference_list(struct s2n_connection *conn,
167199

168200
struct s2n_signature_scheme chosen_scheme;
169201

170-
GUARD(s2n_choose_default_sig_scheme(conn, &chosen_scheme));
202+
if (conn->actual_protocol_version < S2N_TLS13) {
203+
GUARD(s2n_choose_default_sig_scheme(conn, &chosen_scheme));
204+
} else {
205+
/* Pick a default signature algorithm in TLS 1.3 https://tools.ietf.org/html/rfc8446#section-4.4.2.2 */
206+
GUARD(s2n_tls13_default_sig_scheme(conn, &chosen_scheme));
207+
}
171208

172209
/* SignatureScheme preference list was first added in TLS 1.2. It will be empty in older TLS versions. */
173210
if (peer_wire_prefs != NULL && peer_wire_prefs->len > 0) {
174-
int result = s2n_choose_sig_scheme(conn, peer_wire_prefs, &chosen_scheme);
175-
176-
/* We require an exact match in TLS 1.3, but all previous versions can fall back to the default.
177-
* The pre-TLS1.3 behavior is an intentional choice to maximize support. */
178-
S2N_ERROR_IF(result != S2N_SUCCESS && conn->actual_protocol_version == S2N_TLS13,
179-
S2N_ERR_INVALID_SIGNATURE_SCHEME);
180-
} else {
181-
S2N_ERROR_IF(conn->actual_protocol_version == S2N_TLS13, S2N_ERR_EMPTY_SIGNATURE_SCHEME);
211+
/* Use a best effort approach to selecting a signature scheme matching client's preferences */
212+
GUARD(s2n_choose_sig_scheme(conn, peer_wire_prefs, &chosen_scheme));
182213
}
183214

184215
*sig_scheme_out = chosen_scheme;
@@ -194,7 +225,7 @@ int s2n_send_supported_sig_scheme_list(struct s2n_connection *conn, struct s2n_s
194225

195226
GUARD(s2n_stuffer_write_uint16(out, s2n_supported_sig_scheme_list_size(conn)));
196227

197-
for (int i = 0; i < signature_preferences->count; i++) {
228+
for (size_t i = 0; i < signature_preferences->count; i++) {
198229
const struct s2n_signature_scheme *const scheme = signature_preferences->signature_schemes[i];
199230
if (0 == s2n_signature_scheme_valid_to_offer(conn, scheme)) {
200231
GUARD(s2n_stuffer_write_uint16(out, scheme->iana_value));
@@ -216,7 +247,7 @@ int s2n_supported_sig_schemes_count(struct s2n_connection *conn)
216247
notnull_check(signature_preferences);
217248

218249
uint8_t count = 0;
219-
for (int i = 0; i < signature_preferences->count; i++) {
250+
for (size_t i = 0; i < signature_preferences->count; i++) {
220251
if (0 == s2n_signature_scheme_valid_to_offer(conn, signature_preferences->signature_schemes[i])) {
221252
count ++;
222253
}
@@ -247,7 +278,7 @@ int s2n_recv_supported_sig_scheme_list(struct s2n_stuffer *in, struct s2n_sig_sc
247278

248279
sig_hash_algs->len = 0;
249280

250-
for (int i = 0; i < pairs_available; i++) {
281+
for (size_t i = 0; i < pairs_available; i++) {
251282
uint16_t sig_scheme = 0;
252283
GUARD(s2n_stuffer_read_uint16(in, &sig_scheme));
253284

0 commit comments

Comments
 (0)