This is an automated email from the ASF dual-hosted git repository.
remm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new 7d94ba2b4f Add hybrid PQC support for OpenSSL 3.5
7d94ba2b4f is described below
commit 7d94ba2b4fe98d1eb9ead1531a9bce0edd147cb5
Author: remm <[email protected]>
AuthorDate: Thu Sep 4 16:18:46 2025 +0200
Add hybrid PQC support for OpenSSL 3.5
This adds any of the PQC certificates to the other SSL contexts. Each
certificate still gets its own SSL context. The PQC certificate will
never be selected by itself for a handshake.
This technique is simple but will likely remain OpenSSL specific. The
code is clearly separate and could be refactored out if a more general
solution is implemented for JSSE.
Based on PR#888.
Based itself on the current mod_ssl code for doing hybrid PQC
handshakes.
---
.../apache/tomcat/util/net/AbstractEndpoint.java | 33 ++++++++++++++++++++++
.../tomcat/util/net/SSLHostConfigCertificate.java | 3 +-
java/org/apache/tomcat/util/net/SSLUtil.java | 10 +++++++
.../util/net/openssl/LocalStrings.properties | 1 +
.../tomcat/util/net/openssl/OpenSSLUtil.java | 10 +++++++
.../net/openssl/panama/LocalStrings.properties | 1 +
.../util/net/openssl/panama/OpenSSLContext.java | 2 +-
.../util/net/openssl/panama/OpenSSLUtil.java | 18 ++++++++++++
webapps/docs/changelog.xml | 6 ++++
9 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/java/org/apache/tomcat/util/net/AbstractEndpoint.java
b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
index 41484905bf..ffd26e9f1b 100644
--- a/java/org/apache/tomcat/util/net/AbstractEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
@@ -55,6 +55,7 @@ import org.apache.tomcat.util.collections.SynchronizedStack;
import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.Acceptor.AcceptorState;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.StoreType;
+import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
import org.apache.tomcat.util.res.StringManager;
import org.apache.tomcat.util.threads.LimitLatch;
@@ -396,6 +397,25 @@ public abstract class AbstractEndpoint<S, U> {
*/
protected void createSSLContext(SSLHostConfig sslHostConfig) throws
IllegalArgumentException {
+ boolean useHybridSslContext = false;
+ Set<SSLHostConfigCertificate> certificates =
sslHostConfig.getCertificates(true);
+ if (sslHostConfig.getProtocols().contains(Constants.SSL_PROTO_TLSv1_3)
&& OpenSSLStatus.isAvailable()) {
+ // If TLS 1.3 is enabled, check if a hybrid scheme using a single
SSL context
+ // should be attempted
+ boolean nonMldsaFound = false;
+ boolean mldsaFound = false;
+ for (SSLHostConfigCertificate certificate : certificates) {
+ if
(certificate.getType().equals(SSLHostConfigCertificate.Type.MLDSA)) {
+ mldsaFound = true;
+ } else {
+ nonMldsaFound = true;
+ }
+ }
+ if (mldsaFound && nonMldsaFound) {
+ useHybridSslContext = true;
+ }
+ }
+
boolean firstCertificate = true;
for (SSLHostConfigCertificate certificate :
sslHostConfig.getCertificates(true)) {
SSLUtil sslUtil = sslImplementation.getSSLUtil(certificate);
@@ -423,8 +443,21 @@ public abstract class AbstractEndpoint<S, U> {
certificate.setSslContextGenerated(sslContext);
}
+ // If using a hybrid scheme, add any MLDSA certificates to all
other SSL contexts
+ if (useHybridSslContext &&
!certificate.getType().equals(SSLHostConfigCertificate.Type.MLDSA)) {
+ for (SSLHostConfigCertificate certificateToAdd :
sslHostConfig.getCertificates(true)) {
+ // Add additional certificate to all non MLDSA contexts
+ if
(certificateToAdd.getType().equals(SSLHostConfigCertificate.Type.MLDSA)) {
+ if (!sslUtil.addSecondCertificate(sslContext,
certificateToAdd)) {
+ throw new
IllegalArgumentException(sm.getString("endpoint.errorCreatingSSLContext"));
+ }
+ }
+ }
+ }
+
logCertificate(certificate);
}
+
}
diff --git a/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
b/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
index f4111ed981..77bbd3e615 100644
--- a/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
+++ b/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
@@ -318,7 +318,8 @@ public class SSLHostConfigCertificate implements
Serializable {
UNDEFINED,
RSA(Authentication.RSA),
DSA(Authentication.DSS),
- EC(Authentication.ECDH, Authentication.ECDSA);
+ EC(Authentication.ECDH, Authentication.ECDSA),
+ MLDSA;
private final Set<Authentication> compatibleAuthentications;
diff --git a/java/org/apache/tomcat/util/net/SSLUtil.java
b/java/org/apache/tomcat/util/net/SSLUtil.java
index da89dddb20..7a9c32dc4a 100644
--- a/java/org/apache/tomcat/util/net/SSLUtil.java
+++ b/java/org/apache/tomcat/util/net/SSLUtil.java
@@ -90,4 +90,14 @@ public interface SSLUtil {
*/
String getNegotiatedProtocol();
}
+
+ /**
+ * Add a second certificate to an existing context, to enable hybrid TLS
1.3 handshakes.
+ * @param context the existing context
+ * @param certificate the second certificate to add
+ * @return true if supported by the context
+ */
+ default boolean addSecondCertificate(SSLContext context,
SSLHostConfigCertificate certificate) {
+ return false;
+ }
}
diff --git a/java/org/apache/tomcat/util/net/openssl/LocalStrings.properties
b/java/org/apache/tomcat/util/net/openssl/LocalStrings.properties
index 7823c29050..dffccd01dd 100644
--- a/java/org/apache/tomcat/util/net/openssl/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/openssl/LocalStrings.properties
@@ -53,6 +53,7 @@ openssl.keyManagerMissing.warn=No key manager found. TLS will
work but the certi
openssl.makeConf=Creating OpenSSLConf context
openssl.nonJsseCertificate=The certificate [{0}] or its private key [{1}]
could not be processed using a JSSE key manager and will be given directly to
OpenSSL
openssl.nonJsseChain=The certificate chain [{0}] was not specified or was not
valid and JSSE requires a valid certificate chain so attempting to use OpenSSL
directly
+openssl.secondCertificateError=Error adding second certificate to OpenSSL
context
openssl.trustManagerMissing=No trust manager found
opensslconf.applyCommand=OpenSSLConf applying command (name [{0}], value [{1}])
diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java
b/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java
index dc792281a2..5f3ec28eda 100644
--- a/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java
+++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java
@@ -131,4 +131,14 @@ public class OpenSSLUtil extends SSLUtilBase {
}
}
+ @Override
+ public boolean addSecondCertificate(SSLContext context,
SSLHostConfigCertificate certificate) {
+ try {
+ ((OpenSSLContext) context).addCertificate(certificate);
+ return true;
+ } catch (Exception e) {
+ throw new
IllegalArgumentException(sm.getString("openssl.secondCertificateError"), e);
+ }
+ }
+
}
diff --git
a/java/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
b/java/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
index 7cc6531ec7..328a36ac49 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/openssl/panama/LocalStrings.properties
@@ -67,6 +67,7 @@ openssl.noCACerts=No CA certificates were configured
openssl.nonJsseCertificate=The certificate [{0}] or its private key [{1}]
could not be processed using a JSSE key manager and will be given directly to
OpenSSL
openssl.nonJsseChain=The certificate chain [{0}] was not specified or was not
valid and JSSE requires a valid certificate chain so attempting to use OpenSSL
directly
openssl.passwordTooLong=The certificate password is too long
+openssl.secondCertificateError=Error adding second certificate to OpenSSL
context
openssl.setCustomDHParameters=Setting custom DH parameters ([{0}] bits) for
the key [{1}]
openssl.setECDHCurve=Setting ECDH curve ([{0}]) for the key [{1}]
openssl.trustManagerMissing=No trust manager found
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 bb2f916567..2d7d654357 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLContext.java
@@ -874,7 +874,7 @@ public class OpenSSLContext implements
org.apache.tomcat.util.net.SSLContext {
}
- private boolean addCertificate(SSLHostConfigCertificate certificate, Arena
localArena) throws Exception {
+ public boolean addCertificate(SSLHostConfigCertificate certificate, Arena
localArena) throws Exception {
int index = getCertificateIndex(certificate);
// Load Server key and certificate
if (certificate.getCertificateFile() != null) {
diff --git a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLUtil.java
b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLUtil.java
index 3475190e5a..955d0aba0d 100644
--- a/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLUtil.java
+++ b/java/org/apache/tomcat/util/net/openssl/panama/OpenSSLUtil.java
@@ -17,6 +17,7 @@
package org.apache.tomcat.util.net.openssl.panama;
import java.io.IOException;
+import java.lang.foreign.Arena;
import java.security.KeyException;
import java.security.KeyStoreException;
import java.util.List;
@@ -106,4 +107,21 @@ public class OpenSSLUtil extends SSLUtilBase {
}
}
+
+ @Override
+ public boolean addSecondCertificate(SSLContext context,
SSLHostConfigCertificate certificate) {
+ try (var localArena = Arena.ofConfined()) {
+ try {
+ if (((OpenSSLContext) context).addCertificate(certificate,
localArena)) {
+ return true;
+ } else {
+ log.warn(sm.getString("openssl.secondCertificateError"));
+ return false;
+ }
+ } catch (Exception e) {
+ throw new
IllegalArgumentException(sm.getString("openssl.secondCertificateError"), e);
+ }
+ }
+ }
+
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 1832d06049..418bd453ef 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -196,6 +196,12 @@
Remove NIO2 connector. (remm)
</update>
<!-- Entries for backport and removal before 12.0.0-M1 below this line
-->
+ <update>
+ Add hybrid PQC support to OpenSSL, based on code from
+ <code>mod_ssl</code>. Using this OpenSSL specific code path,
+ additional PQC certificates defined with type <code>MLDSA</code> are
+ added to contexts which use classic certificates. (jfclere/remm)
+ </update>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]