Commit 59a62db65b for openssl.org

commit 59a62db65bd643ade3cbe1a2f74021c38ca9a2da
Author: Tommy Chiang <ototot@google.com>
Date:   Sun Jan 25 21:12:28 2026 +0800

    SSL_CONF_FLAG: Prevent setting both CMDLINE and FILE flags

    The `SSL_CONF_CTX_set_flags` function did not prevent setting both
    `SSL_CONF_FLAG_CMDLINE` and `SSL_CONF_FLAG_FILE` flags, which is an
    invalid combination. This commit adds a check to prevent this and
    updates the documentation to clarify that only one of these flags
    can be set.

    A new test case is also added to verify the correct behavior.

    Fixes https://github.com/openssl/openssl/issues/15508

    Reviewed-by: Matt Caswell <matt@openssl.org>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    MergeDate: Tue Feb  3 09:40:04 2026
    (Merged from https://github.com/openssl/openssl/pull/29752)

diff --git a/doc/man3/SSL_CONF_CTX_set_flags.pod b/doc/man3/SSL_CONF_CTX_set_flags.pod
index 78c3ce7585..117575e7d5 100644
--- a/doc/man3/SSL_CONF_CTX_set_flags.pod
+++ b/doc/man3/SSL_CONF_CTX_set_flags.pod
@@ -28,8 +28,9 @@ Currently the following B<flags> values are recognised:

 =item SSL_CONF_FLAG_CMDLINE, SSL_CONF_FLAG_FILE

-recognise options intended for command line or configuration file use. At
-least one of these flags must be set.
+recognise options intended for command line or configuration file use. One of
+these flags, but not both, must be set. If an attempt is made to set one of
+these flags when the other is already set then the new flag is ignored.

 =item SSL_CONF_FLAG_CLIENT, SSL_CONF_FLAG_SERVER

diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index 0d61def3dd..f113d59c71 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -1123,6 +1123,14 @@ void SSL_CONF_CTX_free(SSL_CONF_CTX *cctx)

 unsigned int SSL_CONF_CTX_set_flags(SSL_CONF_CTX *cctx, unsigned int flags)
 {
+    if ((cctx->flags & SSL_CONF_FLAG_CMDLINE)
+        && (flags & SSL_CONF_FLAG_FILE))
+        flags &= ~SSL_CONF_FLAG_FILE;
+
+    if ((cctx->flags & SSL_CONF_FLAG_FILE)
+        && (flags & SSL_CONF_FLAG_CMDLINE))
+        flags &= ~SSL_CONF_FLAG_CMDLINE;
+
     cctx->flags |= flags;
     return cctx->flags;
 }
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 30dc17ce3c..1db7bddac3 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -13843,6 +13843,66 @@ err:
 }
 #endif

+static int test_ssl_conf_flags(void)
+{
+    SSL_CONF_CTX *cctx = NULL;
+    int ret = 0;
+
+    if (!TEST_ptr(cctx = SSL_CONF_CTX_new()))
+        goto err;
+
+    /* Initial flags should be 0 */
+    if (!TEST_uint_eq(SSL_CONF_CTX_set_flags(cctx, 0), 0))
+        goto err;
+
+    /* Setting CMDLINE should succeed */
+    if (!TEST_uint_eq(SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CMDLINE),
+            SSL_CONF_FLAG_CMDLINE))
+        goto err;
+
+    /*
+     * Setting FILE when CMDLINE is set should fail to set the flag but return
+     * success (return the original flags value).
+     * If we also try to set a non-conflicting flag at the same time it should
+     * succeed.
+     */
+    if (!TEST_uint_eq(SSL_CONF_CTX_set_flags(cctx,
+                          SSL_CONF_FLAG_FILE
+                              | SSL_CONF_FLAG_SHOW_ERRORS),
+            SSL_CONF_FLAG_CMDLINE | SSL_CONF_FLAG_SHOW_ERRORS))
+        goto err;
+
+    SSL_CONF_CTX_free(cctx);
+    cctx = NULL;
+
+    /* Retry in reverse */
+    if (!TEST_ptr(cctx = SSL_CONF_CTX_new()))
+        goto err;
+
+    /* Setting FILE should succeed */
+    if (!TEST_uint_eq(SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE),
+            SSL_CONF_FLAG_FILE))
+        goto err;
+
+    /*
+     * Setting CMDLINE when FILE is set should fail to set the flag but return
+     * success (return the original flags value)
+     * If we also try to set a non-conflicting flag at the same time it should
+     * succeed.
+     */
+    if (!TEST_uint_eq(SSL_CONF_CTX_set_flags(cctx,
+                          SSL_CONF_FLAG_CMDLINE
+                              | SSL_CONF_FLAG_SHOW_ERRORS),
+            SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_SHOW_ERRORS))
+        goto err;
+
+    ret = 1;
+
+err:
+    SSL_CONF_CTX_free(cctx);
+    return ret;
+}
+
 /*
  * Test that SSL_CTX_set1_groups() when called with a list where the first
  * entry is unsupported, will send a key_share that uses the next usable entry.
@@ -14244,6 +14304,7 @@ int setup_tests(void)
         ADD_TEST(test_ssl_trace);
 #endif
     ADD_ALL_TESTS(test_ssl_set_groups_unsupported_keyshare, 2);
+    ADD_TEST(test_ssl_conf_flags);
     return 1;

 err: