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
The following commit(s) were added to refs/heads/11.0.x by this push:
new 74c04f204b Ease the migration from ciphers to ciphers plus cipherSuites
74c04f204b is described below
commit 74c04f204bacd4c8690a58e43d49ec63398b781b
Author: Mark Thomas <[email protected]>
AuthorDate: Mon Mar 9 17:46:59 2026 +0000
Ease the migration from ciphers to ciphers plus cipherSuites
---
.../apache/tomcat/util/net/LocalStrings.properties | 2 +-
java/org/apache/tomcat/util/net/SSLHostConfig.java | 62 +++++++++++++++-------
.../apache/tomcat/util/net/TestSSLHostConfig.java | 27 ++++++++--
webapps/docs/changelog.xml | 9 ++++
webapps/docs/config/http.xml | 12 +++--
5 files changed, 84 insertions(+), 28 deletions(-)
diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index e02ef67d7a..b023ad09a7 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -155,8 +155,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.handleTls13CiphersuiteInCiphers=The TLS 1.3 cipher suite [{0}]
included in the TLS 1.2 and below ciphers list will be removed from the TLS 1.2
ciphers list and added to the end of the TLS 1.3 cipher suite list
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 b0d11707fa..c8130b2230 100644
--- a/java/org/apache/tomcat/util/net/SSLHostConfig.java
+++ b/java/org/apache/tomcat/util/net/SSLHostConfig.java
@@ -113,6 +113,7 @@ public class SSLHostConfig implements Serializable {
private boolean certificateVerificationDepthConfigured = false;
private String ciphers = DEFAULT_TLS_CIPHERS_12;
private String cipherSuites = DEFAULT_TLS_CIPHERS_13;
+ private String cipherSuitesFromCiphers = null;
private LinkedHashSet<Cipher> cipherList = null;
private LinkedHashSet<Cipher> cipherSuiteList = null;
private List<String> jsseCipherNames = null;
@@ -400,51 +401,65 @@ public class SSLHostConfig implements Serializable {
if (ciphersList != null) {
if (ciphersList.contains(":")) {
// OpenSSL format
- StringBuilder sb = new StringBuilder();
+ StringBuilder sbCiphers = new StringBuilder();
+ StringBuilder sbCipherSuitesFromCiphers = 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));
+
log.warn(sm.getString("sslHostConfig.handleTls13CiphersuiteInCiphers",
trimmed));
+ if (!sbCipherSuitesFromCiphers.isEmpty()) {
+ sbCipherSuitesFromCiphers.append(':');
+ }
+ sbCipherSuitesFromCiphers.append(trimmed);
} else {
- if (!sb.isEmpty()) {
- sb.append(':');
+ if (!sbCiphers.isEmpty()) {
+ sbCiphers.append(':');
}
- sb.append(trimmed);
+ sbCiphers.append(trimmed);
}
}
- this.ciphers = sb.toString();
+ this.ciphers = sbCiphers.toString();
+ this.cipherSuitesFromCiphers =
sbCipherSuitesFromCiphers.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();
+ StringBuilder sbCiphers = new StringBuilder();
+ StringBuilder sbCipherSuitesFromCiphers = 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(':');
+
log.warn(sm.getString("sslHostConfig.handleTls13CiphersuiteInCiphers",
trimmed));
+ if (!sbCipherSuitesFromCiphers.isEmpty()) {
+ sbCipherSuitesFromCiphers.append(':');
+ }
+ sbCipherSuitesFromCiphers.append(trimmed);
+ } else {
+ String openSSLName =
OpenSSLCipherConfigurationParser.jsseToOpenSSL(trimmed);
+ if (openSSLName == null) {
+ // Not a JSSE name. Maybe an OpenSSL name or
alias
+ openSSLName = trimmed;
+ }
+ if (!sbCiphers.isEmpty()) {
+ sbCiphers.append(':');
+ }
+ sbCiphers.append(openSSLName);
}
- sb.append(openSSLName);
}
}
- this.ciphers = sb.toString();
+ this.ciphers = sbCiphers.toString();
+ this.cipherSuitesFromCiphers =
sbCipherSuitesFromCiphers.toString();
}
} else {
this.ciphers = null;
+ this.cipherSuitesFromCiphers = null;
}
this.cipherList = null;
this.jsseCipherNames = null;
+ this.cipherSuiteList = null;
}
@@ -530,7 +545,14 @@ public class SSLHostConfig implements Serializable {
* @return An OpenSSL cipher suite string for the current configuration.
*/
public String getCipherSuites() {
- return cipherSuites;
+ StringBuilder sb = new StringBuilder(cipherSuites);
+ if (cipherSuitesFromCiphers != null &&
!cipherSuitesFromCiphers.isEmpty()) {
+ if (!sb.isEmpty()) {
+ sb.append(':');
+ }
+ sb.append(cipherSuitesFromCiphers);
+ }
+ return sb.toString();
}
diff --git a/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
b/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
index 9bfdbfef94..82d4d38012 100644
--- a/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
+++ b/test/org/apache/tomcat/util/net/TestSSLHostConfig.java
@@ -40,6 +40,9 @@ public class TestSSLHostConfig {
// Single JSSE name
hc.setCiphers(c.getJsseNames().iterator().next());
Assert.assertEquals(c.getOpenSSLAlias(), hc.getCiphers());
+
+ // TLS 1.3 should be using defaults
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13,
hc.getCipherSuites());
}
@@ -53,6 +56,9 @@ public class TestSSLHostConfig {
hc.setCiphers(c1.getJsseNames().iterator().next() + "," +
c2.getJsseNames().iterator().next());
Assert.assertEquals(c1.getOpenSSLAlias() + ":" + c2.getOpenSSLAlias(),
hc.getCiphers());
+
+ // TLS 1.3 should be using defaults
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13,
hc.getCipherSuites());
}
@@ -62,6 +68,9 @@ public class TestSSLHostConfig {
// Single OpenSSL alias
hc.setCiphers("ALL");
Assert.assertEquals("ALL", hc.getCiphers());
+
+ // TLS 1.3 should be using defaults
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13,
hc.getCipherSuites());
}
@@ -73,6 +82,9 @@ public class TestSSLHostConfig {
// Single OpenSSLName name
hc.setCiphers(c.getOpenSSLAlias());
Assert.assertEquals(c.getOpenSSLAlias(), hc.getCiphers());
+
+ // TLS 1.3 should be using defaults
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13,
hc.getCipherSuites());
}
@@ -81,9 +93,12 @@ public class TestSSLHostConfig {
SSLHostConfig hc = new SSLHostConfig();
Cipher c = Cipher.TLS_AES_128_CCM_SHA256;
- // Single TLSv1.3 name - should be filtered out
+ // Single TLSv1.3 name - should be filtered out ...
hc.setCiphers(c.getOpenSSLAlias());
Assert.assertEquals("", hc.getCiphers());
+
+ // ... and added to cipher suite list
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13 + ":" +
c.getOpenSSLAlias(), hc.getCipherSuites());
}
@@ -93,9 +108,12 @@ public class TestSSLHostConfig {
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
+ // TLSv1.3 then TLSv1.2 - TLSv1.3 name should be filtered out ...
hc.setCiphers(c1.getOpenSSLAlias() + ":" + c2.getOpenSSLAlias());
Assert.assertEquals(c2.getOpenSSLAlias(), hc.getCiphers());
+
+ // ... and added to cipher suite list
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13 + ":" +
c1.getOpenSSLAlias(), hc.getCipherSuites());
}
@@ -105,9 +123,12 @@ public class TestSSLHostConfig {
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
+ // TLSv1.2 then TLSv1.3 - TLSv1.3 name should be filtered out ...
hc.setCiphers(c2.getOpenSSLAlias() + ":" + c1.getOpenSSLAlias());
Assert.assertEquals(c2.getOpenSSLAlias(), hc.getCiphers());
+
+ // ... and added to cipher suite list
+ Assert.assertEquals(SSLHostConfig.DEFAULT_TLS_CIPHERS_13 + ":" +
c1.getOpenSSLAlias(), hc.getCipherSuites());
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 2b497a45fa..5350ef26f3 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -177,6 +177,15 @@
<code>Integer</code> rather than a <code>Long</code> to be consistent
with how port is exposed in the Servlet API. (markt)
</fix>
+ <add>
+ To aid the migration from the single <code>ciphers</code> configuration
+ attribute to the use of <code>ciphers</code> and
+ <code>cipherSuites</code>, TLS 1.3 cipher suites listed in the
+ <code>ciphers</code> attribute will be removed from the
+ <code>ciphers</code> attribute and added to the end of the
+ <code>cipherSuites</code> attribute. This behaviour will be removed in
+ Tomcat 12.0.x onwards. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index 563a7ff88f..e256098be7 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -1359,10 +1359,14 @@
<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 TLSv1.2 and below ciphers that
- are supported by the configured SSL implementation.</p>
+ will be ignored and logged in a <code>WARNING</code> message when the
+ Connector starts. Any entires in the list that are TLSv1.3 cipher suites
+ will be removed from the cipher list, added to the end of the cipher
suite
+ list (they will not be added to the cipher suite list from Tomact 12.0.x
+ onwards) and logged in a <code>WARNING</code> message when the Connector
+ starts. The warnings can be 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>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]