From 3c83c5ba4f6502c708b7a5f55c98a10e312668da Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Mon, 26 Nov 2018 13:58:52 -0800 Subject: [PATCH] Ignore cipher suites when setting cipher list set_cipher_list() sets TLSv1.2 (and below) ciphers, and its success or failure should not depend on whether set_ciphersuites() has been used to setup TLSv1.3 ciphers. Reviewed-by: Paul Dale Reviewed-by: Ben Kaduk Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/7759) --- ssl/ssl_lib.c | 24 ++++++++++++++++++-- test/cipherlist_test.c | 35 +++++++++++++++++++++++++++++ test/clienthellotest.c | 3 ++- test/ssltest_old.c | 51 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 105 insertions(+), 8 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index b001da75fc..322a4381b0 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2579,6 +2579,26 @@ STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) return NULL; } +/* + * Distinguish between ciphers controlled by set_ciphersuite() and + * set_cipher_list() when counting. + */ +static int cipher_list_tls12_num(STACK_OF(SSL_CIPHER) *sk) +{ + int i, num = 0; + const SSL_CIPHER *c; + + if (sk == NULL) + return 0; + for (i = 0; i < sk_SSL_CIPHER_num(sk); ++i) { + c = sk_SSL_CIPHER_value(sk, i); + if (c->min_tls >= TLS1_3_VERSION) + continue; + num++; + } + return num; +} + /** specify the ciphers to be used by default by the SSL_CTX */ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { @@ -2596,7 +2616,7 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) */ if (sk == NULL) return 0; - else if (sk_SSL_CIPHER_num(sk) == 0) { + else if (cipher_list_tls12_num(sk) == 0) { SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH); return 0; } @@ -2614,7 +2634,7 @@ int SSL_set_cipher_list(SSL *s, const char *str) /* see comment in SSL_CTX_set_cipher_list */ if (sk == NULL) return 0; - else if (sk_SSL_CIPHER_num(sk) == 0) { + else if (cipher_list_tls12_num(sk) == 0) { SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH); return 0; } diff --git a/test/cipherlist_test.c b/test/cipherlist_test.c index 89ef1b1546..b950411c38 100644 --- a/test/cipherlist_test.c +++ b/test/cipherlist_test.c @@ -215,9 +215,44 @@ static int test_default_cipherlist_explicit(void) return result; } +/* SSL_CTX_set_cipher_list() should fail if it clears all TLSv1.2 ciphers. */ +static int test_default_cipherlist_clear(void) +{ + SETUP_CIPHERLIST_TEST_FIXTURE(); + SSL *s = NULL; + + if (fixture == NULL) + return 0; + + if (!TEST_int_eq(SSL_CTX_set_cipher_list(fixture->server, "no-such"), 0)) + goto end; + + if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), SSL_R_NO_CIPHER_MATCH)) + goto end; + + s = SSL_new(fixture->client); + + if (!TEST_ptr(s)) + goto end; + + if (!TEST_int_eq(SSL_set_cipher_list(s, "no-such"), 0)) + goto end; + + if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), + SSL_R_NO_CIPHER_MATCH)) + goto end; + + result = 1; +end: + SSL_free(s); + tear_down(fixture); + return result; +} + int setup_tests(void) { ADD_TEST(test_default_cipherlist_implicit); ADD_TEST(test_default_cipherlist_explicit); + ADD_TEST(test_default_cipherlist_clear); return 1; } diff --git a/test/clienthellotest.c b/test/clienthellotest.c index 2c1110b13f..7fdb5bc6fe 100644 --- a/test/clienthellotest.c +++ b/test/clienthellotest.c @@ -99,8 +99,9 @@ static int test_client_hello(int currtest) * ClientHello is already going to be quite long. To avoid getting one * that is too long for this test we use a restricted ciphersuite list */ - if (!TEST_true(SSL_CTX_set_cipher_list(ctx, ""))) + if (!TEST_false(SSL_CTX_set_cipher_list(ctx, ""))) goto end; + ERR_clear_error(); /* Fall through */ case TEST_ADD_PADDING: case TEST_PADDING_NOT_NEEDED: diff --git a/test/ssltest_old.c b/test/ssltest_old.c index f26bf85173..390ca88bb7 100644 --- a/test/ssltest_old.c +++ b/test/ssltest_old.c @@ -1382,11 +1382,52 @@ int main(int argc, char *argv[]) goto end; if (cipher != NULL) { - if (!SSL_CTX_set_cipher_list(c_ctx, cipher) - || !SSL_CTX_set_cipher_list(s_ctx, cipher) - || !SSL_CTX_set_cipher_list(s_ctx2, cipher)) { - ERR_print_errors(bio_err); - goto end; + if (strcmp(cipher, "") == 0) { + if (!SSL_CTX_set_cipher_list(c_ctx, cipher)) { + if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_NO_CIPHER_MATCH) { + ERR_clear_error(); + } else { + ERR_print_errors(bio_err); + goto end; + } + } else { + /* Should have failed when clearing all TLSv1.2 ciphers. */ + fprintf(stderr, "CLEARING ALL TLSv1.2 CIPHERS SHOULD FAIL\n"); + goto end; + } + + if (!SSL_CTX_set_cipher_list(s_ctx, cipher)) { + if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_NO_CIPHER_MATCH) { + ERR_clear_error(); + } else { + ERR_print_errors(bio_err); + goto end; + } + } else { + /* Should have failed when clearing all TLSv1.2 ciphers. */ + fprintf(stderr, "CLEARING ALL TLSv1.2 CIPHERS SHOULD FAIL\n"); + goto end; + } + + if (!SSL_CTX_set_cipher_list(s_ctx2, cipher)) { + if (ERR_GET_REASON(ERR_peek_error()) == SSL_R_NO_CIPHER_MATCH) { + ERR_clear_error(); + } else { + ERR_print_errors(bio_err); + goto end; + } + } else { + /* Should have failed when clearing all TLSv1.2 ciphers. */ + fprintf(stderr, "CLEARING ALL TLSv1.2 CIPHERS SHOULD FAIL\n"); + goto end; + } + } else { + if (!SSL_CTX_set_cipher_list(c_ctx, cipher) + || !SSL_CTX_set_cipher_list(s_ctx, cipher) + || !SSL_CTX_set_cipher_list(s_ctx2, cipher)) { + ERR_print_errors(bio_err); + goto end; + } } } if (ciphersuites != NULL) {