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

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

commit e2681a7649bfc98993c2acc4f289eeacb7bf41a7
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 13340afc09..2ec5c8a894 100644
--- a/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
+++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
@@ -87,7 +87,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 157d716a47..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.get(0);
+        // 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 b8691992d2..cac10c2a89 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLLibrary.java
@@ -456,7 +456,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 7a2d8143f3..10463defe3 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -340,6 +340,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="Web applications">


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

Reply via email to