From 5ab656ab61842332435eafc86517f392c65a3f45 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Wed, 22 Jul 2026 07:31:35 +0900 Subject: [PATCH] add WOLFSSL_STRICT_CIPHER_LIST for TLS 1.3-only cipher lists on a non-TLS1.3 ctx/ssl --- .wolfssl_known_macro_extras | 1 + src/internal.c | 4 ++++ src/ssl.c | 9 +++++++++ tests/api/test_tls13.c | 25 +++++++++++++++++++++++++ tests/api/test_tls13.h | 2 ++ 5 files changed, 41 insertions(+) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 3c3879c33f..4e45de41f6 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -1013,6 +1013,7 @@ WOLFSSL_STM32F427_RNG WOLFSSL_STM32U0 WOLFSSL_STM32_DHUK_UNWRAP WOLFSSL_STM32_USE_SAES +WOLFSSL_STRICT_CIPHER_LIST WOLFSSL_STRONGEST_HASH_SIG WOLFSSL_STSAFE_TAKES_SLOT WOLFSSL_TELIT_M2MB diff --git a/src/internal.c b/src/internal.c index 5914aa4203..5f809bb622 100644 --- a/src/internal.c +++ b/src/internal.c @@ -41,6 +41,10 @@ * Enable SHA-2 cipher suites for pre-TLS 1.2 default: off * WOLFSSL_NO_STRICT_CIPHER_SUITE: * Relax strict cipher suite validation default: off + * WOLFSSL_STRICT_CIPHER_LIST: Fail wolfSSL_CTX/SSL_set_cipher_list() + * when given a TLS 1.3-only suite list but TLS 1.3 + * is not negotiable, instead of leaving the prior + * suites untouched and returning success default: off * NO_RESUME_SUITE_CHECK: Skip cipher suite check on resume default: off * NO_FORCE_SCR_SAME_SUITE: Allow different suite in renegotiation default: off * CIPHER_NONCE: Per-record cipher nonce for AEAD default: off diff --git a/src/ssl.c b/src/ssl.c index 445720d997..0fa4d4948f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3895,8 +3895,17 @@ static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, tls13Only = 1; if ((ctx != NULL && !IsAtLeastTLSv1_3(ctx->method->version)) || (ssl != NULL && !IsAtLeastTLSv1_3(ssl->version))) { +#ifdef WOLFSSL_STRICT_CIPHER_LIST + /* TLS 1.3 is not negotiable on this ctx/ssl: fail instead of + * leaving the previously configured <= TLS 1.2 suites + * untouched while reporting success. */ + WOLFSSL_MSG("Cipher list has only TLS 1.3 suites but TLS 1.3 " + "is not negotiable"); + return WOLFSSL_FAILURE; +#else /* Silently ignore TLS 1.3 ciphers if we don't support it. */ return WOLFSSL_SUCCESS; +#endif } } diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index fe311bf548..0f4215dbb3 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -2463,6 +2463,31 @@ int test_tls13_cipher_suites(void) return EXPECT_RESULT(); } +int test_tls13_cipher_list_no_tls13_ctx(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ + defined(BUILD_TLS_AES_128_GCM_SHA256) + WOLFSSL_CTX* ctx = NULL; + + /* ctx->method caps the connection at TLS 1.2, so a cipher list that + * names only TLS 1.3 suites can never take effect on it. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); +#ifdef WOLFSSL_STRICT_CIPHER_LIST + ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx, "TLS13-AES128-GCM-SHA256"), + WOLFSSL_FAILURE); +#else + /* Default OpenSSL-compat behavior: succeed but leave ctx->suites + * untouched since the TLS 1.3-only list is unusable on this ctx. */ + ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx, "TLS13-AES128-GCM-SHA256"), + WOLFSSL_SUCCESS); +#endif + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + #if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)\ && !defined(NO_PSK) diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index 05f2be54f2..06f636b33b 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -26,6 +26,7 @@ int test_tls13_apis(void); int test_tls13_cipher_suites(void); +int test_tls13_cipher_list_no_tls13_ctx(void); int test_tls13_bad_psk_binder(void); int test_tls13_rpk_handshake(void); int test_tls13_rpk_handshake_no_negotiation(void); @@ -108,6 +109,7 @@ int test_tls13_pqc_hybrid_async_server(void); #define TEST_TLS13_DECLS \ TEST_DECL_GROUP("tls13", test_tls13_apis), \ TEST_DECL_GROUP("tls13", test_tls13_cipher_suites), \ + TEST_DECL_GROUP("tls13", test_tls13_cipher_list_no_tls13_ctx), \ TEST_DECL_GROUP("tls13", test_tls13_bad_psk_binder), \ TEST_DECL_GROUP("tls13", test_tls13_rpk_handshake), \ TEST_DECL_GROUP("tls13", test_tls13_rpk_handshake_no_negotiation), \