]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
test: add regression test for ciphersuite_cb() with empty list elements
authormat <mateiignat03@gmail.com>
Wed, 29 Apr 2026 06:09:24 +0000 (09:09 +0300)
committerTomas Mraz <tomas@openssl.foundation>
Tue, 26 May 2026 08:56:32 +0000 (10:56 +0200)
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)

ssl/ssl_ciph.c
test/cipherlist_test.c

index 80fa976f47488a87ac14552378538f69cfa7ec90..61e8c4abbe4ab356f31a9398d48bcb23c4d889a1 100644 (file)
@@ -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;
 
index 9874e6bad6413bc07893823f7022f9f3675cdde3..a0e1704d49284572542e9d06f2ec55830e4914a7 100644 (file)
@@ -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;
 }