Commit afaa70c1a6 for openssl.org
commit afaa70c1a60f9e682a9b00323fc9bc7116d41614
Author: mat <mateiignat03@gmail.com>
Date: Wed Apr 29 09:09:24 2026 +0300
test: add regression test for ciphersuite_cb() with empty list elements
Cover the three cases where CONF_parse_list() produces a NULL/empty
element: leading separator, trailing separator, and consecutive
separators (double colon). Before the fix these would crash via a
NULL memcpy inside ciphersuite_cb().
Each case also verifies via SSL_CTX_get_ciphers() that the valid
ciphersuite(s) in the same string were actually applied, not just
that the call returned without crashing.
Reviewed-by: Daniel Kubec <kubec@openssl.foundation>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
MergeDate: Tue May 26 08:56:53 2026
(Merged from https://github.com/openssl/openssl/pull/31023)
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 80fa976f47..61e8c4abbe 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1234,7 +1234,7 @@ static int ciphersuite_cb(const char *elem, int len, void *arg)
/* Arbitrary sized temp buffer for the cipher name. Should be big enough */
char name[80];
- /* CONF_parse_list signals empty elements with elem==NULL; skip them */
+ /* CONF_parse_list signals empty elements with elem == NULL; skip them */
if (elem == NULL || len == 0)
return 1;
diff --git a/test/cipherlist_test.c b/test/cipherlist_test.c
index 9874e6bad6..a0e1704d49 100644
--- a/test/cipherlist_test.c
+++ b/test/cipherlist_test.c
@@ -258,11 +258,66 @@ end:
return result;
}
+/*
+ * SSL_CTX_set_ciphersuites() must not crash on empty list elements.
+ * CONF_parse_list() signals them with elem=NULL; ciphersuite_cb() must skip
+ * such entries rather than passing NULL to memcpy().
+ */
+#ifndef OPENSSL_NO_TLS1_3
+static int cipher_in_ctx(const SSL_CTX *ctx, uint32_t id)
+{
+ const STACK_OF(SSL_CIPHER) *sk = SSL_CTX_get_ciphers(ctx);
+ int i;
+
+ for (i = 0; i < sk_SSL_CIPHER_num(sk); i++)
+ if (SSL_CIPHER_get_id(sk_SSL_CIPHER_value(sk, i)) == id)
+ return 1;
+ return 0;
+}
+
+static int test_set_ciphersuites_empty_elem(void)
+{
+ SSL_CTX *ctx = NULL;
+ int result = 0;
+
+ if (!TEST_ptr(ctx = SSL_CTX_new(TLS_method())))
+ goto end;
+
+ /* Double colon: both surrounding valid suites must be applied */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(ctx,
+ "TLS_AES_128_GCM_SHA256::TLS_AES_256_GCM_SHA384")))
+ goto end;
+ if (!TEST_true(cipher_in_ctx(ctx, TLS1_3_CK_AES_128_GCM_SHA256))
+ || !TEST_true(cipher_in_ctx(ctx, TLS1_3_CK_AES_256_GCM_SHA384)))
+ goto end;
+
+ /* Leading separator: empty first element, one valid suite must apply */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(ctx, ":TLS_AES_128_GCM_SHA256")))
+ goto end;
+ if (!TEST_true(cipher_in_ctx(ctx, TLS1_3_CK_AES_128_GCM_SHA256)))
+ goto end;
+
+ /* Trailing separator: empty last element, one valid suite must apply */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(ctx, "TLS_AES_128_GCM_SHA256:")))
+ goto end;
+ if (!TEST_true(cipher_in_ctx(ctx, TLS1_3_CK_AES_128_GCM_SHA256)))
+ goto end;
+
+ result = 1;
+end:
+ SSL_CTX_free(ctx);
+ return result;
+}
+#endif
+
int setup_tests(void)
{
ADD_TEST(test_default_cipherlist_implicit);
ADD_TEST(test_default_cipherlist_explicit);
ADD_TEST(test_default_cipherlist_clear);
+#ifndef OPENSSL_NO_TLS1_3
+ ADD_TEST(test_set_ciphersuites_empty_elem);
+#endif
ADD_TEST(test_stdname_cipherlist);
return 1;
}