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

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

commit a3301293ab851de75be15c2de66df4995ca7d24c
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Jan 6 08:12:52 2026 +0000

    Add support for setting TLS 1.3 cipher suites
    
    For consistency between OpenSSL and JSSE TLS implementations, TLSv.13 cipher
    suites included in the ciphers attribute of an SSLHostConfig are now always
    ignored (previously they would be ignored with OpenSSL implementations and
    used with JSSE implementations) and a warning is logged that the cipher 
suite
    has been ignored.
---
 .../apache/tomcat/util/net/LocalStrings.properties |   2 +
 java/org/apache/tomcat/util/net/SSLHostConfig.java | 131 ++++++++++++++++---
 .../tomcat/util/net/openssl/OpenSSLContext.java    |   1 +
 .../util/net/openssl/panama/OpenSSLContext.java    |   6 +-
 .../apache/tomcat/util/net/TestSSLHostConfig.java  |  70 ++++++++++
 .../tomcat/util/net/TestSSLHostConfigCipher.java   | 144 +++++++++++++++++++++
 test/org/apache/tomcat/util/net/TesterSupport.java |  11 ++
 webapps/docs/changelog.xml                         |  13 ++
 webapps/docs/config/http.xml                       |  44 +++++--
 9 files changed, 388 insertions(+), 34 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties 
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index f9eb84189e..ad39a0a83e 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -154,6 +154,8 @@ socketWrapper.writeTimeout=Write timeout
 sslHostConfig.certificate.notype=Multiple certificates were specified and at 
least one is missing the required attribute type
 sslHostConfig.certificateVerificationInvalid=The certificate verification 
value [{0}] is not recognised
 sslHostConfig.fileNotFound=Configured file [{0}] does not exist
+sslHostConfig.ignoreNonTls13Ciphersuite=The non-TLS 1.3 cipher suite [{0}] 
included in the TLS 1.3 cipher suite list will be ignored
+sslHostConfig.ignoreTls13Ciphersuite=The TLS 1.3 cipher suite [{0}] included 
in the TLS 1.2 and below ciphers list will be ignored
 sslHostConfig.invalid_truststore_password=The provided trust store password 
could not be used to unlock and/or validate the trust store. Retrying to access 
the trust store with a null password which will skip validation.
 sslHostConfig.mismatch=The property [{0}] was set on the SSLHostConfig named 
[{1}] and is for the [{2}] configuration syntax but the SSLHostConfig is being 
used with the [{3}] configuration syntax
 sslHostConfig.mismatch.trust=The trust configuration property [{0}] was set on 
the SSLHostConfig named [{1}] and is for the [{2}] configuration syntax but the 
SSLHostConfig is being used with the [{3}] trust configuration syntax
diff --git a/java/org/apache/tomcat/util/net/SSLHostConfig.java 
b/java/org/apache/tomcat/util/net/SSLHostConfig.java
index e78a155230..82859e273f 100644
--- a/java/org/apache/tomcat/util/net/SSLHostConfig.java
+++ b/java/org/apache/tomcat/util/net/SSLHostConfig.java
@@ -111,8 +111,10 @@ public class SSLHostConfig implements Serializable {
     private int certificateVerificationDepth = 10;
     // Used to track if certificateVerificationDepth has been explicitly set
     private boolean certificateVerificationDepthConfigured = false;
-    private String ciphers = DEFAULT_TLS_CIPHERS;
+    private String ciphers = DEFAULT_TLS_CIPHERS_12;
+    private String cipherSuites = DEFAULT_TLS_CIPHERS_13;
     private LinkedHashSet<Cipher> cipherList = null;
+    private LinkedHashSet<Cipher> cipherSuiteList = null;
     private List<String> jsseCipherNames = null;
     private boolean honorCipherOrder = false;
     private final Set<String> protocols = new HashSet<>();
@@ -383,36 +385,59 @@ public class SSLHostConfig implements Serializable {
 
 
     /**
-     * Set the new cipher configuration. Note: Regardless of the format used 
to set the configuration, it is always
-     * stored in OpenSSL format.
+     * Set the new cipher (TLSv1.2 and below) configuration. Note: Regardless 
of the format used to set the
+     * configuration, it is always stored in OpenSSL format.
      *
      * @param ciphersList The new cipher configuration in OpenSSL or JSSE 
format
      */
     public void setCiphers(String ciphersList) {
         // Ciphers is stored in OpenSSL format. Convert the provided value if
         // necessary.
-        if (ciphersList != null && !ciphersList.contains(":")) {
-            StringBuilder sb = new StringBuilder();
-            // Not obviously in OpenSSL format. Might be a single OpenSSL or 
JSSE
-            // cipher name. Might be a comma separated list of cipher names
-            String[] ciphers = ciphersList.split(",");
-            for (String cipher : ciphers) {
-                String trimmed = cipher.trim();
-                if (!trimmed.isEmpty()) {
-                    String openSSLName = 
OpenSSLCipherConfigurationParser.jsseToOpenSSL(trimmed);
-                    if (openSSLName == null) {
-                        // Not a JSSE name. Maybe an OpenSSL name or alias
-                        openSSLName = trimmed;
+        if (ciphersList != null) {
+            if (ciphersList.contains(":")) {
+                // OpenSSL format
+                StringBuilder sb = new StringBuilder();
+                String[] components = ciphersList.split(":");
+                // Remove any TLS 1.3 cipher suites
+                for (String component : components) {
+                    String trimmed = component.trim();
+                    if 
(OpenSSLCipherConfigurationParser.isTls13Cipher(trimmed)) {
+                        
log.warn(sm.getString("sslHostConfig.ignoreTls13Ciphersuite", trimmed));
+                    } else {
+                        if (!sb.isEmpty()) {
+                            sb.append(':');
+                        }
+                        sb.append(trimmed);
                     }
-                    if (!sb.isEmpty()) {
-                        sb.append(':');
+                }
+                this.ciphers = sb.toString();
+            } else {
+                // Not obviously in OpenSSL format. Might be a single OpenSSL 
or JSSE
+                // cipher name. Might be a comma separated list of cipher names
+                StringBuilder sb = new StringBuilder();
+                String[] ciphers = ciphersList.split(",");
+                for (String cipher : ciphers) {
+                    String trimmed = cipher.trim();
+                    if (!trimmed.isEmpty()) {
+                        if 
(OpenSSLCipherConfigurationParser.isTls13Cipher(trimmed)) {
+                            
log.warn(sm.getString("sslHostConfig.ignoreTls13Ciphersuite", trimmed));
+                            continue;
+                        }
+                        String openSSLName = 
OpenSSLCipherConfigurationParser.jsseToOpenSSL(trimmed);
+                        if (openSSLName == null) {
+                            // Not a JSSE name. Maybe an OpenSSL name or alias
+                            openSSLName = trimmed;
+                        }
+                        if (!sb.isEmpty()) {
+                            sb.append(':');
+                        }
+                        sb.append(openSSLName);
                     }
-                    sb.append(openSSLName);
                 }
+                this.ciphers = sb.toString();
             }
-            this.ciphers = sb.toString();
         } else {
-            this.ciphers = ciphersList;
+            this.ciphers = null;
         }
         this.cipherList = null;
         this.jsseCipherNames = null;
@@ -443,12 +468,76 @@ public class SSLHostConfig implements Serializable {
      */
     public List<String> getJsseCipherNames() {
         if (jsseCipherNames == null) {
-            jsseCipherNames = 
OpenSSLCipherConfigurationParser.convertForJSSE(getCipherList());
+            Set<Cipher> jsseCiphers = new HashSet<>();
+            jsseCiphers.addAll(getCipherSuiteList());
+            jsseCiphers.addAll(getCipherList());
+            jsseCipherNames = 
OpenSSLCipherConfigurationParser.convertForJSSE(jsseCiphers);
         }
         return jsseCipherNames;
     }
 
 
+    /**
+     * Set the cipher suite (TLSv1.3) configuration.
+     *
+     * @param cipherSuites The cipher suites to use in a colon-separated, 
preference order list
+     */
+    public void setCipherSuites(String cipherSuites) {
+        StringBuilder sb = new StringBuilder();
+        String[] values;
+        if (cipherSuites.contains(":")) {
+            // OpenSSL format
+            values = cipherSuites.split(":");
+        } else {
+            // JSSE format or possible a single cipher suite name
+            values = cipherSuites.split(",");
+        }
+        for (String value : values) {
+            String trimmed = value.trim();
+            if (!trimmed.isEmpty()) {
+                if (!OpenSSLCipherConfigurationParser.isTls13Cipher(trimmed)) {
+                    
log.warn(sm.getString("sslHostConfig.ignoreNonTls13Ciphersuite", trimmed));
+                    continue;
+                }
+                /*
+                 * OpenSSL and JSSE names for TLSv1.3 cipher suites are 
currently (January 2026) the same but handle the
+                 * possible future case where they are not.
+                 */
+                String openSSLName = 
OpenSSLCipherConfigurationParser.jsseToOpenSSL(trimmed);
+                if (openSSLName == null) {
+                    // Not a JSSE name. Maybe an OpenSSL name or alias
+                    openSSLName = trimmed;
+                }
+                if (!sb.isEmpty()) {
+                    sb.append(':');
+                }
+                sb.append(trimmed);
+            }
+        }
+        this.cipherSuites = sb.toString();
+        this.cipherSuiteList = null;
+        this.jsseCipherNames = null;
+    }
+
+
+    /**
+     * Obtain the current cipher suite (TLSv1.3) configuration.
+     *
+     * @return An OpenSSL cipher suite string for the current configuration.
+     */
+    public String getCipherSuites() {
+        return cipherSuites;
+    }
+
+
+    private LinkedHashSet<Cipher> getCipherSuiteList() {
+        if (cipherSuiteList == null) {
+            cipherSuiteList = 
OpenSSLCipherConfigurationParser.parse(getCipherSuites());
+        }
+        return cipherSuiteList;
+    }
+
+
     public void setHonorCipherOrder(boolean honorCipherOrder) {
         this.honorCipherOrder = honorCipherOrder;
     }
diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java 
b/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
index 15fba2cb4f..f29c08d39c 100644
--- a/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
+++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
@@ -318,6 +318,7 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
 
             // Configure the ciphers that the client is permitted to negotiate
             SSLContext.setCipherSuite(state.ctx, sslHostConfig.getCiphers());
+            SSLContext.setCipherSuitesEx(state.ctx, 
sslHostConfig.getCipherSuites());
 
             // If there is no certificate file must be using a KeyStore so a 
KeyManager is required.
             // If there is a certificate file a KeyManager is helpful but not 
strictly necessary.
diff --git a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java 
b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
index 25e2d5acc7..77e4de2c87 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
@@ -515,14 +515,14 @@ public class OpenSSLContext implements 
org.apache.tomcat.util.net.SSLContext {
             }
             if (maxTlsVersion >= TLS1_3_VERSION()) {
                 try {
-                    if (SSL_CTX_set_ciphersuites(state.sslCtx, 
localArena.allocateFrom(sslHostConfig.getCiphers())) <= 0) {
-                        tls13Warning = 
sm.getString("engine.failedCipherSuite", sslHostConfig.getCiphers());
+                    if (SSL_CTX_set_ciphersuites(state.sslCtx, 
localArena.allocateFrom(sslHostConfig.getCipherSuites())) <= 0) {
+                        tls13Warning = 
sm.getString("engine.failedCipherSuite", sslHostConfig.getCipherSuites());
                     } else {
                         ciphersSet = true;
                     }
                 } catch (NoClassDefFoundError | UnsatisfiedLinkError e) {
                     // Ignore unavailable TLS 1.3 call, which might be 
compiled out sometimes on LibreSSL
-                    tls13Warning = sm.getString("engine.failedCipherSuite", 
sslHostConfig.getCiphers());
+                    tls13Warning = sm.getString("engine.failedCipherSuite", 
sslHostConfig.getCipherSuites());
                 }
             }
             if (!ciphersSet) {
diff --git a/test/org/apache/tomcat/util/net/TestSSLHostConfig.java 
b/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
index 1ee4f80518..9bfdbfef94 100644
--- a/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
+++ b/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
@@ -76,6 +76,76 @@ public class TestSSLHostConfig {
     }
 
 
+    @Test
+    public void testCipher05() {
+        SSLHostConfig hc = new SSLHostConfig();
+        Cipher c = Cipher.TLS_AES_128_CCM_SHA256;
+
+        // Single TLSv1.3 name - should be filtered out
+        hc.setCiphers(c.getOpenSSLAlias());
+        Assert.assertEquals("", hc.getCiphers());
+    }
+
+
+    @Test
+    public void testCipher06() {
+        SSLHostConfig hc = new SSLHostConfig();
+        Cipher c1 = Cipher.TLS_AES_128_CCM_SHA256;
+        Cipher c2 = Cipher.TLS_RSA_WITH_NULL_MD5;
+
+        // TLSv1.3 then TLSv1.2 - TLSv1.3 name should be filtered out
+        hc.setCiphers(c1.getOpenSSLAlias() + ":" + c2.getOpenSSLAlias());
+        Assert.assertEquals(c2.getOpenSSLAlias(), hc.getCiphers());
+    }
+
+
+    @Test
+    public void testCipher07() {
+        SSLHostConfig hc = new SSLHostConfig();
+        Cipher c1 = Cipher.TLS_AES_128_CCM_SHA256;
+        Cipher c2 = Cipher.TLS_RSA_WITH_NULL_MD5;
+
+        // TLSv1.2 then TLSv1.3 - TLSv1.3 name should be filtered out
+        hc.setCiphers(c2.getOpenSSLAlias() + ":" + c1.getOpenSSLAlias());
+        Assert.assertEquals(c2.getOpenSSLAlias(), hc.getCiphers());
+    }
+
+
+    @Test
+    public void testCiphersuite01() {
+        SSLHostConfig hc = new SSLHostConfig();
+        Cipher c = Cipher.TLS_AES_128_CCM_SHA256;
+
+        // Single TLSv1.3 cipher suite name
+        hc.setCipherSuites(c.getOpenSSLAlias());
+        Assert.assertEquals(c.getOpenSSLAlias(), hc.getCipherSuites());
+    }
+
+
+    @Test
+    public void testCiphersuite02() {
+        SSLHostConfig hc = new SSLHostConfig();
+        Cipher c1 = Cipher.TLS_AES_128_CCM_SHA256;
+        Cipher c2 = Cipher.TLS_RSA_WITH_NULL_MD5;
+
+        // TLSv1.3 then TLSv1.2 - TLSv1.2 name should be filtered out
+        hc.setCipherSuites(c1.getOpenSSLAlias() + ":" + c2.getOpenSSLAlias());
+        Assert.assertEquals(c1.getOpenSSLAlias(), hc.getCipherSuites());
+    }
+
+
+    @Test
+    public void testCiphersuite03() {
+        SSLHostConfig hc = new SSLHostConfig();
+        Cipher c1 = Cipher.TLS_AES_128_CCM_SHA256;
+        Cipher c2 = Cipher.TLS_RSA_WITH_NULL_MD5;
+
+        // TLSv1.2 then TLSv1.3 - TLSv1.2 name should be filtered out
+        hc.setCipherSuites(c2.getOpenSSLAlias() + ":" + c1.getOpenSSLAlias());
+        Assert.assertEquals(c1.getOpenSSLAlias(), hc.getCipherSuites());
+    }
+
+
     @Test
     public void testSerialization() throws IOException, ClassNotFoundException 
{
         // Dummy OpenSSL command name/value pair
diff --git a/test/org/apache/tomcat/util/net/TestSSLHostConfigCipher.java 
b/test/org/apache/tomcat/util/net/TestSSLHostConfigCipher.java
new file mode 100644
index 0000000000..19e5fb0970
--- /dev/null
+++ b/test/org/apache/tomcat/util/net/TestSSLHostConfigCipher.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.net;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.startup.TesterServlet;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+@RunWith(Parameterized.class)
+public class TestSSLHostConfigCipher extends TomcatBaseTest {
+
+    private static final String CIPHER_12_AVAILABLE = 
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+    private static final String CIPHER_12_NOT_AVAILABLE = 
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
+    private static final String CIPHER_13_AVAILABLE = "TLS_AES_128_GCM_SHA256";
+    private static final String CIPHER_13_NOT_AVAILABLE = 
"TLS_AES_256_GCM_SHA384";
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+        parameterSets.add(new Object[] {
+                "JSSE", Boolean.FALSE, 
"org.apache.tomcat.util.net.jsse.JSSEImplementation"});
+        parameterSets.add(new Object[] {
+                "OpenSSL", Boolean.TRUE, 
"org.apache.tomcat.util.net.openssl.OpenSSLImplementation"});
+        parameterSets.add(new Object[] {
+                "OpenSSL-FFM", Boolean.TRUE, 
"org.apache.tomcat.util.net.openssl.panama.OpenSSLImplementation"});
+
+        return parameterSets;
+    }
+
+    @Parameter(0)
+    public String connectorName;
+
+    @Parameter(1)
+    public boolean useOpenSSL;
+
+    @Parameter(2)
+    public String sslImplementationName;
+
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        Tomcat tomcat = getTomcatInstance();
+
+        // Server-side TLS configuration
+        TesterSupport.initSsl(tomcat);
+        TesterSupport.configureSSLImplementation(tomcat, 
sslImplementationName, useOpenSSL);
+
+        // Test specific, server-side cipher & protocol configuration
+        SSLHostConfig sslHostConfig = getSSLHostConfig();
+        sslHostConfig.setProtocols("+TLSv1.2+TLSv1.3");
+        sslHostConfig.setCiphers(CIPHER_12_AVAILABLE);
+        sslHostConfig.setCipherSuites(CIPHER_13_AVAILABLE);
+
+        // Simple webapp
+        Context ctxt = getProgrammaticRootContext();
+        Tomcat.addServlet(ctxt, "TesterServlet", new TesterServlet());
+        ctxt.addServletMappingDecoded("/*", "TesterServlet");
+    }
+
+
+    @Test
+    public void testTls12CipherAvailable() throws Exception {
+        // Client-side TLS configuration
+        TesterSupport.configureClientSsl(true, new String[] { 
CIPHER_12_AVAILABLE } );
+
+        doTest();
+    }
+
+
+    @Test(expected=SSLHandshakeException.class)
+    public void testTls12CipherNotAvailable() throws Exception {
+        // Client-side TLS configuration
+        TesterSupport.configureClientSsl(true, new String[] { 
CIPHER_12_NOT_AVAILABLE } );
+
+        doTest();
+    }
+
+
+    @Test
+    public void testTls13CipherAvailable() throws Exception {
+        // Client-side TLS configuration
+        TesterSupport.configureClientSsl(new String[] { CIPHER_13_AVAILABLE } 
);
+
+        doTest();
+    }
+
+
+    @Test(expected=SSLHandshakeException.class)
+    public void testTls13CipherNotAvailable() throws Exception {
+        // Client-side TLS configuration
+        TesterSupport.configureClientSsl(new String[] { 
CIPHER_13_NOT_AVAILABLE } );
+
+        doTest();
+    }
+
+
+    private void doTest() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.start();
+
+        // Check a request can be made
+        ByteChunk res = getUrl("https://localhost:"; + getPort() + "/");
+        Assert.assertEquals("OK", res.toString());
+    }
+
+
+    private SSLHostConfig getSSLHostConfig() {
+        Tomcat tomcat = getTomcatInstance();
+        Connector connector = tomcat.getConnector();
+        return connector.findSslHostConfigs()[0];
+    }
+}
diff --git a/test/org/apache/tomcat/util/net/TesterSupport.java 
b/test/org/apache/tomcat/util/net/TesterSupport.java
index f67b2dc5d5..2aa332fe6b 100644
--- a/test/org/apache/tomcat/util/net/TesterSupport.java
+++ b/test/org/apache/tomcat/util/net/TesterSupport.java
@@ -181,7 +181,15 @@ public final class TesterSupport {
         return configureClientSsl(false);
     }
 
+    public static ClientSSLSocketFactory configureClientSsl(String[] ciphers) {
+        return configureClientSsl(false, ciphers);
+    }
+
     public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12) {
+        return configureClientSsl(forceTls12, null);
+    }
+
+    public static ClientSSLSocketFactory configureClientSsl(boolean 
forceTls12, String[] ciphers) {
         ClientSSLSocketFactory clientSSLSocketFactory = null;
         try {
             SSLContext sc;
@@ -192,6 +200,9 @@ public final class TesterSupport {
             }
             sc.init(getUser1KeyManagers(), getTrustManagers(), null);
             clientSSLSocketFactory = new 
ClientSSLSocketFactory(sc.getSocketFactory());
+            if (ciphers != null) {
+                clientSSLSocketFactory.setCipher(ciphers);
+            }
             
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(clientSSLSocketFactory);
         } catch (Exception e) {
             e.printStackTrace();
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index ec401e7b7f..743479029d 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -154,6 +154,19 @@
         certificates unless CA certificates were configured and the
         configuration failed. (markt)
       </fix>
+      <add>
+        For configuration consistency between OpenSSL and JSSE TLS
+        implementations, TLSv1.3 cipher suites included in the
+        <code>ciphers</code> attribute of an <code>SSLHostConfig</code> are now
+        always ignored (previously they would be ignored with OpenSSL
+        implementations and used with JSSE implementations) and a warning is
+        logged that the cipher suite has been ignored. (markt)
+      </add>
+      <add>
+        Add the <code>ciphersuite</code> attribute to
+        <code>SSLHostConfig</code> to configure the TLSv1.3 cipher suites.
+        (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Cluster">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index d9e24defac..6ea98b9e67 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -1332,10 +1332,11 @@
     </attribute>
 
     <attribute name="ciphers" required="false">
-      <p>The ciphers to enable using the OpenSSL syntax. (See the OpenSSL
-      documentation for the list of ciphers supported and the syntax).
-      Alternatively, a comma separated list of ciphers using the standard
-      OpenSSL cipher names or the standard JSSE cipher names may be used.</p>
+      <p>The TLSv1.2 and below ciphers to enable using the OpenSSL syntax. (See
+      the OpenSSL documentation for the list of ciphers supported and the
+      syntax). Alternatively, a comma separated list of TLS v1.2 and below
+      ciphers using the standard OpenSSL cipher names or the standard JSSE
+      cipher names may be used.</p>
       <p>Different versions of OpenSSL may interpret the same cipher string
       differently. For example, the <code>CCM8</code> ciphers were moved from
       <code>HIGH</code> to <code>MEDIUM</code> in OpenSSL 3.2. Regardless of
@@ -1343,17 +1344,40 @@
       value to a list of ciphers in a manner consistent with the latest OpenSSL
       development branch. This list of ciphers is then passed to the SSL
       implementation.</p>
-      <p>Only the ciphers that are supported by the SSL implementation will be
-      used. Any ciphers in the list derived from a non-default cipher string
-      that are not supported by the SSL implementation will be logged in a
+      <p>Only the TLSv1.2 and below ciphers that are supported by the SSL
+      implementation will be used. Any ciphers in the list derived from a
+      non-default cipher string that are not supported by the SSL 
implementation
+      or are TLSv1.3 cipher suites will be ignored and logged in a
       <code>WARNING</code> message when the Connector starts. The warning can 
be
-      avoided by providing an explicit list of ciphers that are supported by 
the
-      configured SSL implementation.</p>
+      avoided by providing an explicit list of TLSv1.2 and below ciphers that
+      are supported by the configured SSL implementation.</p>
       <p>If not specified, a default (using the OpenSSL notation) of
       
<code>HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256</code>
       will be used.</p>
       <p>Note that, by default, the order in which ciphers are defined is
-      treated as an order of preference. See <code>honorCipherOrder</code>.</p>
+      not treated as an order of preference. See
+      <code>honorCipherOrder</code>.</p>
+      <p>For JSSE (which - unlike OpenSSL - uses a single configuration setting
+      for both ciphers and cipher suites) the cipher suites attribute will be
+      prepended to the ciphers attribute before the combined value is used to
+      configure the JSSE implementation.</p>
+    </attribute>
+
+    <attribute name="cipherSuites" required="false">
+      <p>The TLSv1.3 cipher suites to enable using either the OpenSSL syntax
+      (colon separated list) or the JSSE syntax (comma separated list) using 
the
+      standard TLSv1.3 cipher suite names.</p>
+      <p>Only TLSv1.3 cipher suites will be used. Any other entries in the list
+      will be ignored and logged in a <code>WARNING</code> message when the
+      Connector starts. The warning can be avoided by providing an explicit 
list
+      of TLSv1.3 cipher suites.</p>
+      <p>If not specified, a default (using the OpenSSL notation) of
+      
<code>TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256</code>
+      will be used.</p>
+      <p>For JSSE (which - unlike OpenSSL - uses a single configuration setting
+      for both ciphers and cipher suites) the cipher suites attribute will be
+      prepended to the ciphers attribute before the combined value is used to
+      configure the JSSE implementation.</p>
     </attribute>
 
     <attribute name="disableCompression" required="false">


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

Reply via email to