This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 039af1c4c8f08631626d80c1dc6362ab023116f6
Author: opencode <[email protected]>
AuthorDate: Fri Oct 9 10:13:40 2026 +0200

    Do not store the runtime-derived OpenSSLConfCmd groups command
    
    When using the JNI OpenSSL implementation, creating the SSL context adds
    a
    "groups" OpenSSLConfCmd derived from the SSLHostConfig "groups"
    attribute
    directly into the configuration's command list. StoreConfig did not skip
    it
    (only the four internal OCSP commands were skipped), so saving the
    running
    configuration wrote a command that duplicated the persisted attribute.
    On
    the next start the stored command suppressed the derivation from the
    attribute, silently ignoring any later change of the attribute.
    
    SSLHostConfigSF now stores a copy of the OpenSSLConf without groups
    commands whose value is derived from the attribute. A user-written
    command
    with a different value is kept, and no filtering occurs when the
    attribute
    is not set, since the runtime cannot have injected a command then.
---
 .../catalina/storeconfig/SSLHostConfigSF.java      | 30 ++++++++++++
 .../catalina/storeconfig/TestStoreConfig.java      | 53 ++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/java/org/apache/catalina/storeconfig/SSLHostConfigSF.java 
b/java/org/apache/catalina/storeconfig/SSLHostConfigSF.java
index cc5d61ec2f..9676ec4d7f 100644
--- a/java/org/apache/catalina/storeconfig/SSLHostConfigSF.java
+++ b/java/org/apache/catalina/storeconfig/SSLHostConfigSF.java
@@ -25,6 +25,7 @@ import org.apache.tomcat.util.net.SSLHostConfig;
 import org.apache.tomcat.util.net.SSLHostConfigCertificate;
 import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
 import org.apache.tomcat.util.net.openssl.OpenSSLConf;
+import org.apache.tomcat.util.net.openssl.OpenSSLConfCmd;
 
 /**
  * Store SSLHostConfig
@@ -99,8 +100,37 @@ public class SSLHostConfigSF extends StoreFactoryBase {
             storeElementArray(aWriter, indent, hostConfigsCertificates);
             // Store nested <OpenSSLConf> element
             OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
+            openSslConf = removeRuntimeCommands(openSslConf, sslHostConfig);
             storeElement(aWriter, indent, openSslConf);
         }
     }
 
+    /*
+     * When the SSL context is created, the OpenSSL implementation adds a 
runtime "groups" command derived from the
+     * SSLHostConfig "groups" attribute. Store a copy of the configuration 
without such a command, since it duplicates
+     * the attribute and a stored command would shadow later changes of the 
attribute. A command whose value differs
+     * from the derived one was written by the user and is kept.
+     */
+    private OpenSSLConf removeRuntimeCommands(OpenSSLConf openSslConf, 
SSLHostConfig sslHostConfig) {
+        if (openSslConf == null || sslHostConfig.getGroups() == null) {
+            return openSslConf;
+        }
+        String derivedValue = sslHostConfig.getGroups().replace(',', ':');
+        ArrayList<OpenSSLConfCmd> retainedCommands = new ArrayList<>();
+        for (OpenSSLConfCmd command : openSslConf.getCommands()) {
+            if (OpenSSLConfCmd.GROUPS.equals(command.getName()) && 
derivedValue.equals(command.getValue())) {
+                continue;
+            }
+            retainedCommands.add(command);
+        }
+        if (retainedCommands.size() == openSslConf.getCommands().size()) {
+            return openSslConf;
+        }
+        OpenSSLConf filteredCommands = new OpenSSLConf();
+        for (OpenSSLConfCmd command : retainedCommands) {
+            filteredCommands.addCmd(command);
+        }
+        return filteredCommands;
+    }
+
 }
diff --git a/test/org/apache/catalina/storeconfig/TestStoreConfig.java 
b/test/org/apache/catalina/storeconfig/TestStoreConfig.java
index 383d0b2947..faba0f337d 100644
--- a/test/org/apache/catalina/storeconfig/TestStoreConfig.java
+++ b/test/org/apache/catalina/storeconfig/TestStoreConfig.java
@@ -42,6 +42,9 @@ import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.catalina.util.IOTools;
 import org.apache.catalina.util.SessionIdGeneratorBase;
 import org.apache.catalina.valves.AccessLogValve;
+import org.apache.tomcat.util.net.SSLHostConfig;
+import org.apache.tomcat.util.net.openssl.OpenSSLConf;
+import org.apache.tomcat.util.net.openssl.OpenSSLConfCmd;
 import org.xml.sax.InputSource;
 
 public class TestStoreConfig extends TomcatBaseTest {
@@ -558,6 +561,56 @@ public class TestStoreConfig extends TomcatBaseTest {
         Assert.assertTrue(serverXmlDump, 
serverXmlDump.contains("throwOnFailure=\"false\""));
     }
 
+    /**
+     * Verify that the "groups" OpenSSLConfCmd that the OpenSSL implementation 
derives at runtime from the
+     * SSLHostConfig "groups" attribute is not stored, since a stored command 
would shadow later changes of the
+     * attribute. A user-written groups command must be kept.
+     *
+     * @throws Exception if the test experiences an unexpected error
+     */
+    @Test
+    public void testOpenSSLConfGroupsCommandHandling() throws Exception {
+        StoreLoader loader = new StoreLoader();
+        loader.load(null);
+        StoreRegistry registry = loader.getRegistry();
+        StoreDescription desc = registry.findDescription(SSLHostConfig.class);
+        Assert.assertNotNull(desc);
+
+        // The runtime command that the OpenSSL implementation adds from the 
attribute must not be stored
+        SSLHostConfig derived = new SSLHostConfig();
+        derived.setGroups("secp256r1,secp384r1");
+        derived.setOpenSslConf(new OpenSSLConf());
+        derived.getOpenSslConf().addCmd(new 
OpenSSLConfCmd(OpenSSLConfCmd.GROUPS, "secp256r1:secp384r1"));
+        String dump = storeToString(desc, derived);
+        Assert.assertTrue(dump, 
dump.contains("groups=\"secp256r1,secp384r1\""));
+        Assert.assertFalse(dump, dump.contains("OpenSSLConfCmd"));
+
+        // A user-written command with a value different from the derived one 
must be kept
+        SSLHostConfig userCommand = new SSLHostConfig();
+        userCommand.setGroups("secp256r1,secp384r1");
+        userCommand.setOpenSslConf(new OpenSSLConf());
+        userCommand.getOpenSslConf().addCmd(new 
OpenSSLConfCmd(OpenSSLConfCmd.GROUPS, "X25519"));
+        dump = storeToString(desc, userCommand);
+        Assert.assertTrue(dump, dump.contains("OpenSSLConfCmd"));
+        Assert.assertTrue(dump, dump.contains("name=\"groups\""));
+        Assert.assertTrue(dump, dump.contains("value=\"X25519\""));
+
+        // Without the attribute, a groups command can only be user-written 
and must be kept
+        SSLHostConfig noAttribute = new SSLHostConfig();
+        noAttribute.setGroups(null);
+        noAttribute.setOpenSslConf(new OpenSSLConf());
+        noAttribute.getOpenSslConf().addCmd(new 
OpenSSLConfCmd(OpenSSLConfCmd.GROUPS, "secp256r1"));
+        dump = storeToString(desc, noAttribute);
+        Assert.assertTrue(dump, dump.contains("OpenSSLConfCmd"));
+        Assert.assertTrue(dump, dump.contains("name=\"groups\""));
+    }
+
+    private static String storeToString(StoreDescription desc, Object element) 
throws Exception {
+        StringWriter buffer = new StringWriter();
+        desc.getStoreFactory().store(new PrintWriter(buffer), -2, element);
+        return buffer.toString();
+    }
+
     public static class CustomTestManager extends StandardManager {
 
         public CustomTestManager() {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to