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

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

commit 36a181413a4d601937fbeafd58734bd32fcc370f
Author: opencode <[email protected]>
AuthorDate: Fri Oct 16 08:54:06 2026 +0200

    Exclude unimplemented SSLv2 ciphers when converting OpenSSL cipher names to 
JSSE names
    
    openSSLToJsse() resolved an OpenSSL cipher name only when its alias
    mapped to exactly one Cipher constant, and returned that constant's
    first JSSE name otherwise. Two consequences of including the
    unimplemented SSLv2 constants of the Cipher enumeration in that
    resolution:
    
    - Genuine OpenSSL names shared with an SSLv2 constant (RC4-MD5,
      EXP-RC4-MD5, EXP-RC2-CBC-MD5) were ambiguous and resolved to
      null. The JNI SSLEngine implementation then added that null to the
      set returned by getSupportedCipherSuites(), violating the SSLEngine
      contract, and the Panama findCiphers() method could add null to the
      list later parsed by the cipher configuration parser, causing a null
      pointer exception when a PROFILE= expression resolved to one of these
      ciphers.
    - Aliases matching only an SSLv2 constant (RC2-CBC-MD5,
      DES-CBC3-MD5, the SSL_CK_*/SSL2_* constants) resolved to
      non-standard pseudo JSSE names derived from the enumeration.
    
    The conversion now excludes SSLv2 ciphers uniformly. Names shared with
    an SSLv2 constant resolve to the JSSE name of the modern cipher, names
    matching only SSLv2 ciphers, genuinely ambiguous names and unknown
    names resolve to null, and the two engine call sites that previously
    could propagate null now filter unmapped names.
---
 .../tomcat/util/net/openssl/OpenSSLEngine.java     |  7 +++++-
 .../ciphers/OpenSSLCipherConfigurationParser.java  | 29 ++++++++++++++++++----
 .../util/net/openssl/panama/OpenSSLLibrary.java    |  7 +++++-
 .../util/net/openssl/ciphers/TestCipher.java       | 27 ++++++++++++++++++++
 webapps/docs/changelog.xml                         | 11 ++++++++
 5 files changed, 74 insertions(+), 7 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java 
b/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
index 1322f42fcc..4d8d71f0b4 100644
--- a/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
+++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
@@ -90,7 +90,12 @@ public final class OpenSSLEngine extends SSLEngine 
implements SSLUtil.ProtocolIn
                         if (c == null || c.isEmpty() || 
availableCipherSuites.contains(c)) {
                             continue;
                         }
-                        
availableCipherSuites.add(OpenSSLCipherConfigurationParser.openSSLToJsse(c));
+                        String jsseName = 
OpenSSLCipherConfigurationParser.openSSLToJsse(c);
+                        // Ignore ciphers with no JSSE equivalent.
+                        if (jsseName == null) {
+                            continue;
+                        }
+                        availableCipherSuites.add(jsseName);
                     }
                 } finally {
                     SSL.freeSSL(ssl);
diff --git 
a/java/org/apache/tomcat/util/net/openssl/ciphers/OpenSSLCipherConfigurationParser.java
 
b/java/org/apache/tomcat/util/net/openssl/ciphers/OpenSSLCipherConfigurationParser.java
index 1805b6a2e7..cfeb7bced3 100644
--- 
a/java/org/apache/tomcat/util/net/openssl/ciphers/OpenSSLCipherConfigurationParser.java
+++ 
b/java/org/apache/tomcat/util/net/openssl/ciphers/OpenSSLCipherConfigurationParser.java
@@ -898,21 +898,40 @@ public class OpenSSLCipherConfigurationParser {
      *
      * @param opensslCipherName The OpenSSL name for a cipher
      *
-     * @return The first JSSE name for the specified OpenSSL cipher, or {@code 
null} if the name is not a known,
-     *             unambiguous OpenSSL cipher name
+     * @return The first JSSE name for the specified OpenSSL cipher, or {@code 
null} if the name is not a known
+     *             OpenSSL cipher name, if it remains ambiguous once 
unimplemented SSLv2 ciphers are excluded or if
+     *             only SSLv2 ciphers match
      */
     public static String openSSLToJsse(String opensslCipherName) {
         if (!initialized) {
             init();
         }
         List<Cipher> ciphers = aliases.get(opensslCipherName);
-        if (ciphers == null || ciphers.size() != 1) {
+        if (ciphers == null) {
             // Not an OpenSSL cipher name
             return null;
         }
-        Cipher cipher = ciphers.getFirst();
+        // OpenSSL has not supported SSLv2 for many years and the SSLv2
+        // ciphers here are unimplemented. Excluding them resolves the
+        // ambiguity for the OpenSSL names that an SSLv2 cipher shares with
+        // the equivalent modern cipher.
+        Cipher candidate = null;
+        for (Cipher cipher : ciphers) {
+            if (cipher.getProtocol() == Protocol.SSLv2) {
+                continue;
+            }
+            if (candidate != null) {
+                // Ambiguous name
+                return null;
+            }
+            candidate = cipher;
+        }
+        if (candidate == null) {
+            // Only SSLv2 ciphers matched
+            return null;
+        }
         // Each Cipher always has at least one JSSE name
-        return cipher.getJsseNames().iterator().next();
+        return candidate.getJsseNames().iterator().next();
     }
 
 
diff --git a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java 
b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
index 61baf56e99..2aa6c6addf 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
@@ -458,7 +458,12 @@ public class OpenSSLLibrary {
                         if (c == null || c.isEmpty() || 
ciphersList.contains(c)) {
                             continue;
                         }
-                        
ciphersList.add(OpenSSLCipherConfigurationParser.openSSLToJsse(c));
+                        String jsseName = 
OpenSSLCipherConfigurationParser.openSSLToJsse(c);
+                        // Ignore ciphers with no JSSE equivalent.
+                        if (jsseName == null) {
+                            continue;
+                        }
+                        ciphersList.add(jsseName);
                     }
                 } finally {
                     SSL_free(ssl);
diff --git a/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java 
b/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
index 46309bf581..3f224bacef 100644
--- a/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
+++ b/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
@@ -116,6 +116,33 @@ public class TestCipher {
     }
 
 
+    /**
+     * Check that OpenSSL aliases that are shared with unimplemented SSLv2
+     * ciphers resolve to the JSSE name of the modern cipher, while genuinely
+     * ambiguous aliases, aliases that only match SSLv2 ciphers and unknown
+     * names resolve to null.
+     */
+    @Test
+    public void testOpenSSLToJsseAmbiguousNames() {
+        Assert.assertEquals("SSL_RSA_WITH_RC4_128_MD5",
+                OpenSSLCipherConfigurationParser.openSSLToJsse("RC4-MD5"));
+        Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+                OpenSSLCipherConfigurationParser.openSSLToJsse("EXP-RC4-MD5"));
+        Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+                
OpenSSLCipherConfigurationParser.openSSLToJsse("EXP-RC2-CBC-MD5"));
+        // Unambiguous name
+        Assert.assertEquals("TLS_RSA_WITH_AES_128_CBC_SHA",
+                OpenSSLCipherConfigurationParser.openSSLToJsse("AES128-SHA"));
+        // Unknown name
+        
Assert.assertNull(OpenSSLCipherConfigurationParser.openSSLToJsse("Nonsense"));
+        // Alias shared by more than one modern cipher
+        
Assert.assertNull(OpenSSLCipherConfigurationParser.openSSLToJsse("SHA1"));
+        // Aliases that only match an unimplemented SSLv2 cipher
+        
Assert.assertNull(OpenSSLCipherConfigurationParser.openSSLToJsse("RC2-CBC-MD5"));
+        
Assert.assertNull(OpenSSLCipherConfigurationParser.openSSLToJsse("SSL_CK_RC4_128_WITH_MD5"));
+    }
+
+
     /**
      * Check that the elements of the Cipher enumeration are all using standard
      * names from the TLS registry or are known exceptions.
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 08fcac256f..6c6f279586 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -547,6 +547,17 @@
         using only the known terms. This matches OpenSSL behavior, where such
         an expression results in no cipher match. (remm)
       </fix>
+      <fix>
+        In the OpenSSL cipher name conversion, ignore the unimplemented SSLv2
+        ciphers so that names shared with a modern cipher, for example
+        <code>RC4-MD5</code>, resolve to the JSSE name of the modern cipher
+        rather than returning <code>null</code>, and so that names matching
+        only an SSLv2 cipher no longer resolve to a non-standard name.
+        Ambiguous and unknown names still resolve to <code>null</code>; the
+        OpenSSL engine implementations now filter such unmapped names rather
+        than adding <code>null</code> to the lists of cipher suites they
+        expose. (remm)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">


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

Reply via email to