This is an automated email from the ASF dual-hosted git repository.
ffang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new 16ac0e403ca [CXF-9229] Add PQC TLS 1.3 support via X25519MLKEM768
hybrid KEM (#3299)
16ac0e403ca is described below
commit 16ac0e403ca3cc5f97d3c93d8ccfe98d993b4a66
Author: Freeman(Yue) Fang <[email protected]>
AuthorDate: Fri Jul 10 09:59:01 2026 -0400
[CXF-9229] Add PQC TLS 1.3 support via X25519MLKEM768 hybrid KEM (#3299)
* [CXF-9229] Add PQC TLS 1.3 support via X25519MLKEM768 hybrid KEM
- TLSParameterBase: new namedGroups API (getNamedGroups/setNamedGroups) to
configure the ordered list of TLS named groups offered during the
handshake
- security.xsd: new NamedGroups complex type and
<sec:namedGroups>/<sec:namedGroup>
elements on both TLSClientParametersType and TLSServerParametersType
- TLSClientParametersConfig / TLSServerParametersConfig: wire namedGroups
from
XML config into SSLParameters via SSLUtils.applyNamedGroups() (JDK 20+)
- SSLUtils.applyNamedGroupsBC(): reflection-based helper to set named groups
on BC JSSE's ProvSSLEngine without a compile-time bctls-jdk18on dependency
- JettyHTTPServerEngine: override customize(SSLEngine) to call
applyNamedGroupsBC()
so each accepted engine gets named groups from tlsServerParameters
configuration
- BCJsseServerALPNProcessor: ALPNProcessor.Server for BC JSSE's
ProvSSLEngine;
bridges it into Jetty's ALPN negotiation (JDK9ServerALPNProcessor only
accepts
java.base engines); registered via META-INF/services; enables HTTP/2 + BC
JSSE
- BCJssePQCTest + BCJsseJettyServer: system test using BC JSSE on JDK 17-26;
sets jdk.tls.namedGroups=X25519MLKEM768 before SSLContext creation so the
BC JSSE context-level named-group map includes the PQC group; verifies
X25519MLKEM768 was negotiated by restricting a raw BCSSLSocket to that
group only
- PQCTLSTest: system test for SunJSSE on JDK 27+ (JEP 527); skips
automatically
when X25519MLKEM768 is absent from the configured named groups
* [CXF-9229]update BC version to 1.84 for jdk25 compatibility
---
.../jsse/TLSClientParametersConfig.java | 3 +
.../cxf/configuration/jsse/TLSParameterBase.java | 21 +++
.../jsse/TLSServerParametersConfig.java | 3 +
.../resources/schemas/configuration/security.xsd | 32 ++++
parent/pom.xml | 2 +-
.../http_jetty/BCJsseServerALPNProcessor.java | 79 ++++++++++
.../http_jetty/JettyHTTPServerEngine.java | 31 +++-
.../org.eclipse.jetty.io.ssl.ALPNProcessor$Server | 1 +
.../cxf/transport/http/HttpClientHTTPConduit.java | 4 +
.../org/apache/cxf/transport/https/SSLUtils.java | 40 +++++
systests/transports/pom.xml | 29 ++++
.../cxf/systest/https/pqc/BCJssePQCTest.java | 166 +++++++++++++++++++++
.../apache/cxf/systest/https/pqc/PQCTLSTest.java | 148 ++++++++++++++++++
.../src/test/resources/logging.properties | 4 +-
.../apache/cxf/systest/https/pqc/bcjsse-client.xml | 52 +++++++
.../apache/cxf/systest/https/pqc/bcjsse-server.xml | 74 +++++++++
.../apache/cxf/systest/https/pqc/pqc-client.xml | 49 ++++++
.../apache/cxf/systest/https/pqc/pqc-server.xml | 69 +++++++++
18 files changed, 803 insertions(+), 4 deletions(-)
diff --git
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
index 7eb060074f9..d0fdcd9cde0 100644
---
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
+++
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
@@ -131,6 +131,9 @@ public final class TLSClientParametersConfig {
if (params.isSetCertAlias()) {
ret.setCertAlias(params.getCertAlias());
}
+ if (params.isSetNamedGroups()) {
+ ret.setNamedGroups(params.getNamedGroups().getNamedGroup());
+ }
if (iparams != null && iparams.isSetKeyManagersRef() &&
!usingDefaults) {
ret.setKeyManagers(iparams.getKeyManagersRef());
}
diff --git
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterBase.java
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterBase.java
index ac17533ad2d..920b85cc895 100644
--- a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterBase.java
+++ b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterBase.java
@@ -50,6 +50,7 @@ public class TLSParameterBase {
protected SecureRandom secureRandom;
protected String protocol;
protected String certAlias;
+ protected List<String> namedGroups = new ArrayList<>();
/**
* Set the JSSE provider. If not set,
* it uses system default.
@@ -187,4 +188,24 @@ public class TLSParameterBase {
public String getCertAlias() {
return certAlias;
}
+
+ /**
+ * Sets the ordered list of TLS named groups (key-exchange groups) to offer
+ * during the handshake, e.g. {@code "X25519MLKEM768"}, {@code "x25519"}.
+ * Applied via {@code SSLParameters.setNamedGroups()} which requires JDK
20+;
+ * silently ignored on older JDKs.
+ */
+ public final void setNamedGroups(List<String> groups) {
+ namedGroups = groups;
+ }
+
+ /**
+ * Returns the configured TLS named groups list.
+ */
+ public List<String> getNamedGroups() {
+ if (namedGroups == null) {
+ namedGroups = new ArrayList<>();
+ }
+ return namedGroups;
+ }
}
diff --git
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSServerParametersConfig.java
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSServerParametersConfig.java
index e63623b2caa..625fbbb42f2 100644
---
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSServerParametersConfig.java
+++
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSServerParametersConfig.java
@@ -95,6 +95,9 @@ public class TLSServerParametersConfig
if (params.isSetSniHostCheck()) {
this.setSniHostCheck(params.isSniHostCheck());
}
+ if (params.isSetNamedGroups()) {
+ this.setNamedGroups(params.getNamedGroups().getNamedGroup());
+ }
if (iparams != null && iparams.isSetKeyManagersRef()) {
this.setKeyManagers(iparams.getKeyManagersRef());
}
diff --git a/core/src/main/resources/schemas/configuration/security.xsd
b/core/src/main/resources/schemas/configuration/security.xsd
index fbc28a30e78..0055e78f5a2 100644
--- a/core/src/main/resources/schemas/configuration/security.xsd
+++ b/core/src/main/resources/schemas/configuration/security.xsd
@@ -383,6 +383,20 @@
<xs:element name="includeProtocol" type="xs:string" minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
+
+ <xs:complexType name="NamedGroups">
+ <xs:annotation>
+ <xs:documentation>
+ This structure holds an ordered list of TLS named groups (key-exchange
groups) to offer
+ during the handshake. Examples: "X25519MLKEM768" (PQC hybrid, JDK 27+
/ BC JSSE 1.81+),
+ "x25519", "secp256r1". When set, the list is applied via
SSLParameters.setNamedGroups()
+ (requires JDK 20+; silently ignored on older JDKs).
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="namedGroup" type="xs:string" minOccurs="0"
maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
<xs:complexType name="SecureRandomParameters">
<xs:annotation>
@@ -512,6 +526,15 @@
</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element name="namedGroups" type="tns:NamedGroups" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ This element contains the ordered list of TLS named groups to
offer during
+ the handshake (e.g. "X25519MLKEM768", "x25519", "secp256r1").
+ Requires JDK 20+; silently ignored on older JDKs.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
</xs:all>
<xs:attribute name="useHttpsURLConnectionDefaultSslSocketFactory"
type="pt:ParameterizedBoolean" default="false">
<xs:annotation>
@@ -651,6 +674,15 @@
</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element name="namedGroups" type="tns:NamedGroups" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ This element contains the ordered list of TLS named groups to
offer during
+ the handshake (e.g. "X25519MLKEM768", "x25519", "secp256r1").
+ Requires JDK 20+; silently ignored on older JDKs.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
</xs:all>
<xs:attribute name="jsseProvider" type="xs:string">
<xs:annotation>
diff --git a/parent/pom.xml b/parent/pom.xml
index 338708b66d9..3165b508f39 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -97,7 +97,7 @@
<cxf.assertj.version>4.0.0-M1</cxf.assertj.version>
<cxf.atmosphere.version.range>[3.0, 4.0)</cxf.atmosphere.version.range>
<cxf.atmosphere.version>3.1.0</cxf.atmosphere.version>
- <cxf.bcprov.version>1.81</cxf.bcprov.version>
+ <cxf.bcprov.version>1.84</cxf.bcprov.version>
<cxf.brave.version>6.3.1</cxf.brave.version>
<cxf.cdi.api.version>4.1.0</cxf.cdi.api.version>
<cxf.classgraph.version>4.8.25</cxf.classgraph.version>
diff --git
a/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/BCJsseServerALPNProcessor.java
b/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/BCJsseServerALPNProcessor.java
new file mode 100644
index 00000000000..3fcf1c072d4
--- /dev/null
+++
b/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/BCJsseServerALPNProcessor.java
@@ -0,0 +1,79 @@
+/**
+ * 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.cxf.transport.http_jetty;
+
+import javax.net.ssl.SSLEngine;
+
+import org.eclipse.jetty.alpn.server.ALPNServerConnection;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.ssl.ALPNProcessor;
+import org.eclipse.jetty.io.ssl.SslConnection;
+import org.eclipse.jetty.io.ssl.SslHandshakeListener;
+
+/**
+ * Jetty {@link ALPNProcessor.Server} for BouncyCastle JSSE ({@code
bctls-jdk18on}).
+ *
+ * <p>Jetty's built-in {@code JDK9ServerALPNProcessor} only matches engines
whose
+ * module is {@code java.base}, so it rejects BC JSSE's {@code ProvSSLEngine}
and
+ * throws {@code IllegalStateException: No suitable ALPNProcessor}. This
processor
+ * bridges the gap: it claims BC JSSE engines and wires up the same
+ * {@link SSLEngine#setHandshakeApplicationProtocolSelector} callback that the
+ * built-in processor uses, delegating to {@link ALPNServerConnection#select}.
+ *
+ * <p>A {@link SslHandshakeListener} is also registered so that if the client
does not
+ * advertise any ALPN protocols, {@link ALPNServerConnection#unsupported()} is
called
+ * on handshake success to fall back to the server's default protocol
(HTTP/1.1).
+ *
+ * <p>Registered via {@code
META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server}.
+ */
+public class BCJsseServerALPNProcessor implements ALPNProcessor.Server {
+
+ @Override
+ public boolean appliesTo(SSLEngine sslEngine) {
+ return sslEngine.getClass().getName().startsWith("org.bouncycastle.");
+ }
+
+ @Override
+ public void configure(SSLEngine sslEngine, Connection connection) {
+ ALPNServerConnection alpnConn = (ALPNServerConnection) connection;
+
+ // Called when the client includes an ALPN extension in its
ClientHello.
+ sslEngine.setHandshakeApplicationProtocolSelector((engine, protocols)
-> {
+ try {
+ alpnConn.select(protocols);
+ return alpnConn.getProtocol();
+ } catch (Throwable t) {
+ return null;
+ }
+ });
+
+ // When the client sends no ALPN extension the selector above is never
invoked,
+ // leaving getProtocol() null. The SslHandshakeListener fires on
handshake
+ // completion and calls unsupported() to fall back to the default
protocol.
+ SslConnection.SslEndPoint sslEndPoint = (SslConnection.SslEndPoint)
alpnConn.getEndPoint();
+ sslEndPoint.getSslConnection().addHandshakeListener(new
SslHandshakeListener() {
+ @Override
+ public void handshakeSucceeded(Event event) {
+ if (alpnConn.getProtocol() == null) {
+ alpnConn.unsupported();
+ }
+ }
+ });
+ }
+}
diff --git
a/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
b/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
index 9a32cd63bb6..f17a42dc9ef 100644
---
a/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
+++
b/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
@@ -40,6 +40,8 @@ import java.util.logging.Logger;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.RequestDispatcher;
@@ -731,6 +733,19 @@ public class JettyHTTPServerEngine implements
ServerEngine, HttpServerEngineSupp
public void checkKeyStore() {
//we'll handle this later
}
+ @Override
+ public SSLParameters customize(SSLParameters sslParams) {
+ sslParams = super.customize(sslParams);
+ org.apache.cxf.transport.https.SSLUtils.applyNamedGroups(
+ sslParams, tlsServerParameters.getNamedGroups());
+ return sslParams;
+ }
+ @Override
+ public void customize(SSLEngine sslEngine) {
+ super.customize(sslEngine);
+ org.apache.cxf.transport.https.SSLUtils.applyNamedGroupsBC(
+ sslEngine, tlsServerParameters.getNamedGroups());
+ }
};
decorateCXFJettySslSocketConnector(sslcf);
}
@@ -857,7 +872,21 @@ public class JettyHTTPServerEngine implements
ServerEngine, HttpServerEngineSupp
protected SSLContext createSSLContext(SslContextFactory scf) throws
Exception {
// The full SSL context is provided by SSLContextServerParameters
if (tlsServerParameters instanceof SSLContextServerParameters
sslContextServerParameters) {
- return sslContextServerParameters.getSslContext();
+ SSLContext context = sslContextServerParameters.getSslContext();
+ // Without setting included cipher suites here, Jetty's default
+ // SslContextFactory filter drops suite names it does not
+ // recognise (e.g. BouncyCastle JSSE names), causing
+ // handshake_failure even if the SSLContext supports them.
+ String[] supported =
+ SSLUtils.getServerSupportedCipherSuites(context);
+ String[] included = SSLUtils.getCiphersuitesToInclude(
+ tlsServerParameters.getCipherSuites(),
+ tlsServerParameters.getCipherSuitesFilter(),
+ context.getServerSocketFactory().getDefaultCipherSuites(),
+ supported,
+ LOG);
+ scf.setIncludeCipherSuites(included);
+ return context;
}
String proto = tlsServerParameters.getSecureSocketProtocol() == null
diff --git
a/rt/transports/http-jetty/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server
b/rt/transports/http-jetty/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server
new file mode 100644
index 00000000000..4bef6cb1d47
--- /dev/null
+++
b/rt/transports/http-jetty/src/main/resources/META-INF/services/org.eclipse.jetty.io.ssl.ALPNProcessor$Server
@@ -0,0 +1 @@
+org.apache.cxf.transport.http_jetty.BCJsseServerALPNProcessor
diff --git
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
index 5efbef4c1e6..a4840ec06ef 100644
---
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
+++
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
@@ -433,10 +433,14 @@ public class HttpClientHTTPConduit extends
URLConnectionHTTPConduit {
if (clientParameters.getSecureSocketProtocol() !=
null) {
String protocol =
clientParameters.getSecureSocketProtocol();
SSLParameters params = new
SSLParameters(cipherSuites, new String[] {protocol});
+
org.apache.cxf.transport.https.SSLUtils.applyNamedGroups(
+ params, clientParameters.getNamedGroups());
cb.sslParameters(params);
} else {
final SSLParameters params = new
SSLParameters(cipherSuites,
TLSClientParameters.getPreferredClientProtocols());
+
org.apache.cxf.transport.https.SSLUtils.applyNamedGroups(
+ params, clientParameters.getNamedGroups());
cb.sslParameters(params);
}
}
diff --git
a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
index 9ef974cc11d..970f9382710 100644
---
a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
+++
b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
@@ -18,6 +18,7 @@
*/
package org.apache.cxf.transport.https;
+import java.lang.reflect.Method;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
@@ -531,4 +532,43 @@ public final class SSLUtils {
}
};
+ /**
+ * Applies the given named groups to {@code SSLParameters} via reflection.
+ * {@code SSLParameters.setNamedGroups()} requires JDK 20+; this method
+ * silently skips the call on older JDKs.
+ */
+ public static void applyNamedGroups(SSLParameters params, List<String>
namedGroups) {
+ if (namedGroups == null || namedGroups.isEmpty()) {
+ return;
+ }
+ try {
+ Method m = SSLParameters.class.getMethod("setNamedGroups",
String[].class);
+ m.invoke(params, (Object) namedGroups.toArray(new String[0]));
+ } catch (NoSuchMethodException e) {
+ LOG.fine("SSLParameters.setNamedGroups() not available on this
JDK; namedGroups ignored");
+ } catch (ReflectiveOperationException e) {
+ LOG.warning("Failed to apply TLS namedGroups: " + e.getMessage());
+ }
+ }
+
+ // Reflection-based BC JSSE path: avoids a compile-time dependency on
bctls-jdk18on.
+ public static void applyNamedGroupsBC(SSLEngine sslEngine, List<String>
namedGroups) {
+ if (namedGroups == null || namedGroups.isEmpty()) {
+ return;
+ }
+ try {
+ Class<?> bcEngineClass =
Class.forName("org.bouncycastle.jsse.BCSSLEngine");
+ if (!bcEngineClass.isInstance(sslEngine)) {
+ return;
+ }
+ Class<?> bcParamsClass =
Class.forName("org.bouncycastle.jsse.BCSSLParameters");
+ Object bcParams =
bcEngineClass.getMethod("getParameters").invoke(sslEngine);
+ bcParamsClass.getMethod("setNamedGroups", String[].class)
+ .invoke(bcParams, (Object) namedGroups.toArray(new String[0]));
+ bcEngineClass.getMethod("setParameters",
bcParamsClass).invoke(sslEngine, bcParams);
+ } catch (ReflectiveOperationException e) {
+ LOG.fine("Could not apply named groups via BC JSSE engine: " +
e.getMessage());
+ }
+ }
+
}
diff --git a/systests/transports/pom.xml b/systests/transports/pom.xml
index 2326fb1db1f..cafe5d38abf 100644
--- a/systests/transports/pom.xml
+++ b/systests/transports/pom.xml
@@ -111,6 +111,23 @@
</systemPropertyVariables>
</configuration>
</execution>
+ <execution>
+ <!-- Runs PQCTLSTest with jdk.tls.namedGroups
including X25519MLKEM768,
+ overriding the parent pom's BouncyCastle
workaround that restricts
+ named groups to classical-only. Requires JDK 27+
(JEP 527). -->
+ <id>pqc-tls-test</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>**/pqc/PQCTLSTest.java</include>
+ </includes>
+ <systemPropertyVariables>
+
<jdk.tls.namedGroups>X25519MLKEM768,x25519,secp256r1,secp384r1,secp521r1</jdk.tls.namedGroups>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
</executions>
</plugin>
<plugin>
@@ -245,6 +262,18 @@
<scope>test</scope>
<classifier>keys</classifier>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk18on</artifactId>
+ <version>${cxf.bcprov.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bctls-jdk18on</artifactId>
+ <version>${cxf.bcprov.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
diff --git
a/systests/transports/src/test/java/org/apache/cxf/systest/https/pqc/BCJssePQCTest.java
b/systests/transports/src/test/java/org/apache/cxf/systest/https/pqc/BCJssePQCTest.java
new file mode 100644
index 00000000000..6be5fe5f83e
--- /dev/null
+++
b/systests/transports/src/test/java/org/apache/cxf/systest/https/pqc/BCJssePQCTest.java
@@ -0,0 +1,166 @@
+/**
+ * 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.cxf.systest.https.pqc;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.security.KeyStore;
+import java.security.Security;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManagerFactory;
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.hello_world.Greeter;
+import org.apache.hello_world.services.SOAPService;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jsse.BCSSLParameters;
+import org.bouncycastle.jsse.BCSSLSocket;
+import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Verifies BouncyCastle JSSE ({@code bctls-jdk18on} 1.84+) TLS support on JDK
17-26
+ * using standard CXF XML configuration.
+ *
+ * <p>The server is configured via {@code bcjsse-server.xml} using
+ * {@code jsseProvider="BCJSSE"} on {@code httpj:tlsServerParameters}.
+ * HTTP/2 is supported via {@link BCJsseServerALPNProcessor}, which bridges
+ * BC JSSE's {@code ProvSSLEngine} into Jetty's ALPN negotiation framework.
+ * The client is configured via {@code bcjsse-client.xml}.
+ *
+ * <p>On JDK 27+, {@code PQCTLSTest} provides coverage via SunJSSE (JEP 527).
+ */
+public class BCJssePQCTest extends AbstractBusClientServerTestBase {
+
+ static final String PORT = allocatePort(BCJsseJettyServer.class);
+
+ // ------------------------------------------------------------------ setup
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ // JDK 27+ is covered by PQCTLSTest via SunJSSE (JEP 527).
+ Assume.assumeTrue(
+ "BCJssePQCTest targets JDK 17-26; use PQCTLSTest on JDK 27+",
+ Runtime.version().feature() < 27);
+ // BC JSSE builds its context-level named-group map when SSLContext is
first
+ // created; X25519MLKEM768 must be present there before the server
starts.
+ System.setProperty("jdk.tls.namedGroups", "X25519MLKEM768");
+ // Append so Sun's JKS (which supports private-key entries) stays
first.
+ // BC's JKS is read-only and cannot load private-key entries.
+ Security.addProvider(new BouncyCastleProvider());
+ Security.addProvider(new BouncyCastleJsseProvider());
+ assertTrue("Server failed to launch",
launchServer(BCJsseJettyServer.class, true));
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ stopAllServers();
+ Security.removeProvider(BouncyCastleJsseProvider.PROVIDER_NAME);
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ System.clearProperty("jdk.tls.namedGroups");
+ }
+
+ // ------------------------------------------------------------------
server
+
+ /**
+ * CXF/Jetty server configured via {@code bcjsse-server.xml}: uses
+ * {@code jsseProvider="BCJSSE"} on {@code httpj:tlsServerParameters} so
that
+ * CXF builds the SSLContext from BC JSSE rather than SunJSSE. HTTP/2 is
+ * enabled via {@link BCJsseServerALPNProcessor}.
+ */
+ public static class BCJsseJettyServer extends AbstractBusTestServerBase {
+ @Override
+ protected void run() {
+ URL busFile =
BCJsseJettyServer.class.getResource("bcjsse-server.xml");
+ Bus busLocal = new SpringBusFactory().createBus(busFile);
+ BusFactory.setDefaultBus(busLocal);
+ setBus(busLocal);
+ }
+ }
+
+ // ------------------------------------------------------------------ tests
+
+ @Test
+ public void testJettyMlKemHandshake() throws Exception {
+ SpringBusFactory bf = new SpringBusFactory();
+ URL busFile = BCJssePQCTest.class.getResource("bcjsse-client.xml");
+ Bus bus = bf.createBus(busFile.toString());
+ BusFactory.setDefaultBus(bus);
+ BusFactory.setThreadDefaultBus(bus);
+
+ QName serviceName =
+ new QName("http://apache.org/hello_world/services", "SOAPService");
+ URL wsdl = SOAPService.WSDL_LOCATION;
+ SOAPService service = new SOAPService(wsdl, serviceName);
+ assertNotNull("Service is null", service);
+
+ Greeter greeter = service.getHttpsPort();
+ assertNotNull("Port is null", greeter);
+
+ updateAddressPort(greeter, PORT);
+
+ assertEquals("Hello Kitty", greeter.greetMe("Kitty"));
+
+ assertX25519MlKem768Negotiated();
+
+ ((java.io.Closeable) greeter).close();
+ bus.shutdown(true);
+ }
+
+ // Indirect proof: client restricted to X25519MLKEM768 only; server must
pick from offered groups.
+ private void assertX25519MlKem768Negotiated() throws Exception {
+ KeyStore ts = KeyStore.getInstance("JKS");
+ try (InputStream is = BCJssePQCTest.class.getClassLoader()
+ .getResourceAsStream("keys/Truststore.jks")) {
+ ts.load(is, "password".toCharArray());
+ }
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(ts);
+
+ SSLContext ctx = SSLContext.getInstance("TLS", "BCJSSE");
+ ctx.init(null, tmf.getTrustManagers(), null);
+
+ try (SSLSocket sock = (SSLSocket) ctx.getSocketFactory()
+ .createSocket("localhost", Integer.parseInt(PORT))) {
+ sock.setSoTimeout(5000);
+ BCSSLSocket bcSock = (BCSSLSocket) sock;
+ BCSSLParameters p = bcSock.getParameters();
+ p.setNamedGroups(new String[] {"X25519MLKEM768"});
+ bcSock.setParameters(p);
+ sock.startHandshake();
+ assertEquals("TLSv1.3", sock.getSession().getProtocol());
+ }
+ }
+}
diff --git
a/systests/transports/src/test/java/org/apache/cxf/systest/https/pqc/PQCTLSTest.java
b/systests/transports/src/test/java/org/apache/cxf/systest/https/pqc/PQCTLSTest.java
new file mode 100644
index 00000000000..3f6b3e94cef
--- /dev/null
+++
b/systests/transports/src/test/java/org/apache/cxf/systest/https/pqc/PQCTLSTest.java
@@ -0,0 +1,148 @@
+/**
+ * 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.cxf.systest.https.pqc;
+
+import java.lang.reflect.Method;
+import java.net.URL;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.hello_world.Greeter;
+import org.apache.hello_world.services.SOAPService;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Verifies that CXF can complete a TLS 1.3 handshake using the post-quantum
+ * hybrid key-encapsulation mechanism X25519MLKEM768 (JEP 527, JDK 27+).
+ *
+ * <p>The test requires SunJSSE to list {@value #MLKEM_GROUP} as a supported
TLS
+ * named group. This is the case only when running under the {@code
pqc-tls-test}
+ * surefire execution, which overrides the parent-pom's classical-only
+ * {@code jdk.tls.namedGroups} setting and requires JDK 27+. The test is
+ * automatically skipped on older JDKs or when the named-group override is
absent.
+ *
+ * <p>The server is configured via {@code pqc-server.xml} (standard
+ * {@code httpj:tlsServerParameters}) and the client via {@code
pqc-client.xml}.
+ * Because {@code jdk.tls.namedGroups} lists {@code X25519MLKEM768} first in
the
+ * {@code pqc-tls-test} surefire execution, SunJSSE negotiates it by preference
+ * without any per-connection named-group override.
+ */
+public class PQCTLSTest extends AbstractBusClientServerTestBase {
+
+ static final String MLKEM_GROUP = "X25519MLKEM768";
+
+ static final String PORT = allocatePort(PQCServer.class);
+
+ /**
+ * True when SunJSSE lists {@value #MLKEM_GROUP} as a supported TLS named
+ * group in the current JVM configuration — JDK 27+ (JEP 527) with the
right
+ * {@code jdk.tls.namedGroups} setting.
+ */
+ private static final boolean ML_KEM_AVAILABLE = isMlKemTlsSupported();
+
+ // ------------------------------------------------------------------
server
+
+ public static class PQCServer extends AbstractBusTestServerBase {
+ @Override
+ protected void run() {
+ URL busFile = PQCServer.class.getResource("pqc-server.xml");
+ Bus busLocal = new SpringBusFactory().createBus(busFile);
+ BusFactory.setDefaultBus(busLocal);
+ setBus(busLocal);
+ }
+ }
+
+ // ------------------------------------------------------------------ setup
+
+ @BeforeClass
+ public static void startServer() throws Exception {
+ Assume.assumeTrue(
+ "X25519MLKEM768 TLS not available — requires JDK 27+ with "
+ + "jdk.tls.namedGroups including " + MLKEM_GROUP,
+ ML_KEM_AVAILABLE);
+ assertTrue("Server failed to launch",
+ launchServer(PQCServer.class, true));
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ stopAllServers();
+ }
+
+ // ------------------------------------------------------------------ tests
+
+ @Test
+ public void testMlKemHandshakeSucceeds() throws Exception {
+ SpringBusFactory bf = new SpringBusFactory();
+ URL busFile = PQCTLSTest.class.getResource("pqc-client.xml");
+ Bus bus = bf.createBus(busFile.toString());
+ BusFactory.setDefaultBus(bus);
+ BusFactory.setThreadDefaultBus(bus);
+
+ QName serviceName =
+ new QName("http://apache.org/hello_world/services", "SOAPService");
+ URL wsdl = SOAPService.WSDL_LOCATION;
+ SOAPService service = new SOAPService(wsdl, serviceName);
+ assertNotNull("Service is null", service);
+
+ Greeter port = service.getHttpsPort();
+ assertNotNull("Port is null", port);
+
+ updateAddressPort(port, PORT);
+
+ assertEquals("Hello Kitty", port.greetMe("Kitty"));
+
+ ((java.io.Closeable) port).close();
+ bus.shutdown(true);
+ }
+
+ // ------------------------------------------------------------------
helpers
+
+ /**
+ * Returns true only when SunJSSE lists {@value #MLKEM_GROUP} in its
supported
+ * TLS named groups — JDK 27+ (JEP 527) with the right
+ * {@code jdk.tls.namedGroups} configuration.
+ */
+ private static boolean isMlKemTlsSupported() {
+ try {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(null, null, null);
+ Method gm = SSLParameters.class.getMethod("getNamedGroups");
+ String[] groups = (String[])
gm.invoke(ctx.getSupportedSSLParameters());
+ return groups != null &&
java.util.Arrays.asList(groups).contains(MLKEM_GROUP);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/systests/transports/src/test/resources/logging.properties
b/systests/transports/src/test/resources/logging.properties
index 4889366a3ab..d7cb5074122 100644
--- a/systests/transports/src/test/resources/logging.properties
+++ b/systests/transports/src/test/resources/logging.properties
@@ -22,7 +22,7 @@
# Default Logging Configuration File
#
# You can use a different file by specifying a filename
-# with the java.util.logging.config.file system property.
+# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################
@@ -30,7 +30,7 @@
# Global properties
############################################################
-# "handlers" specifies a comma separated list of log Handler
+# "handlers" specifies a comma separated list of log Handler
# classes. These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
diff --git
a/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/bcjsse-client.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/bcjsse-client.xml
new file mode 100644
index 00000000000..e452fe527bf
--- /dev/null
+++
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/bcjsse-client.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/transports/http/configuration
+ http://cxf.apache.org/schemas/configuration/http-conf.xsd
+ http://cxf.apache.org/configuration/security
+ http://cxf.apache.org/schemas/configuration/security.xsd
+ http://cxf.apache.org/core
+ http://cxf.apache.org/schemas/core.xsd">
+
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+
+ <http:conduit name="https://localhost:.*">
+ <http:tlsClientParameters jsseProvider="BCJSSE" disableCNCheck="true">
+ <sec:trustManagers>
+ <sec:keyStore type="JKS" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ <sec:namedGroups>
+ <sec:namedGroup>X25519MLKEM768</sec:namedGroup>
+ </sec:namedGroups>
+ </http:tlsClientParameters>
+ </http:conduit>
+
+</beans>
diff --git
a/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/bcjsse-server.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/bcjsse-server.xml
new file mode 100644
index 00000000000..9a7a877579f
--- /dev/null
+++
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/bcjsse-server.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/jaxws
+ http://cxf.apache.org/schemas/jaxws.xsd
+ http://cxf.apache.org/core
+ http://cxf.apache.org/schemas/core.xsd
+ http://cxf.apache.org/transports/http-jetty/configuration
+ http://cxf.apache.org/schemas/configuration/http-jetty.xsd
+ http://cxf.apache.org/configuration/security
+ http://cxf.apache.org/schemas/configuration/security.xsd">
+
+ <bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+
+ <httpj:engine-factory id="bcjsse-tls-settings">
+ <httpj:engine port="${testutil.ports.BCJsseJettyServer}">
+ <httpj:tlsServerParameters jsseProvider="BCJSSE">
+ <sec:keyManagers keyPassword="password">
+ <sec:keyStore type="JKS" password="password"
resource="keys/Bethal.jks"/>
+ </sec:keyManagers>
+ <sec:trustManagers>
+ <sec:keyStore type="JKS" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ <!-- Disable client authentication: BC JSSE rejects an empty
client
+ Certificate message even when only wantClientAuth is set.
-->
+ <sec:clientAuthentication want="false" required="false"/>
+ <sec:namedGroups>
+ <sec:namedGroup>X25519MLKEM768</sec:namedGroup>
+ </sec:namedGroups>
+ </httpj:tlsServerParameters>
+ </httpj:engine>
+ </httpj:engine-factory>
+
+ <jaxws:endpoint xmlns:e="http://apache.org/hello_world/services"
+ xmlns:s="http://apache.org/hello_world/services"
+ id="BCJsseServer"
+ implementor="org.apache.cxf.systest.http.GreeterImpl"
+
address="https://localhost:${testutil.ports.BCJsseJettyServer}/SoapContext/HttpsPort"
+ serviceName="s:SOAPService"
+ endpointName="e:HttpsPort"
+ depends-on="bcjsse-tls-settings"/>
+
+</beans>
diff --git
a/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/pqc-client.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/pqc-client.xml
new file mode 100644
index 00000000000..d18ba890af7
--- /dev/null
+++
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/pqc-client.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/transports/http/configuration
+ http://cxf.apache.org/schemas/configuration/http-conf.xsd
+ http://cxf.apache.org/configuration/security
+ http://cxf.apache.org/schemas/configuration/security.xsd
+ http://cxf.apache.org/core
+ http://cxf.apache.org/schemas/core.xsd">
+
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+
+ <http:conduit name="https://localhost:.*">
+ <http:tlsClientParameters disableCNCheck="true">
+ <sec:trustManagers>
+ <sec:keyStore type="JKS" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ </http:tlsClientParameters>
+ </http:conduit>
+
+</beans>
diff --git
a/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/pqc-server.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/pqc-server.xml
new file mode 100644
index 00000000000..b9c900b3f22
--- /dev/null
+++
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/pqc/pqc-server.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/jaxws
+ http://cxf.apache.org/schemas/jaxws.xsd
+ http://cxf.apache.org/core
+ http://cxf.apache.org/schemas/core.xsd
+ http://cxf.apache.org/transports/http-jetty/configuration
+ http://cxf.apache.org/schemas/configuration/http-jetty.xsd
+ http://cxf.apache.org/configuration/security
+ http://cxf.apache.org/schemas/configuration/security.xsd">
+
+ <bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+
+ <httpj:engine-factory id="pqc-tls-settings">
+ <httpj:engine port="${testutil.ports.PQCServer}">
+ <httpj:tlsServerParameters>
+ <sec:keyManagers keyPassword="password">
+ <sec:keyStore type="JKS" password="password"
resource="keys/Bethal.jks"/>
+ </sec:keyManagers>
+ <sec:trustManagers>
+ <sec:keyStore type="JKS" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ <sec:clientAuthentication want="false" required="false"/>
+ </httpj:tlsServerParameters>
+ </httpj:engine>
+ </httpj:engine-factory>
+
+ <jaxws:endpoint xmlns:e="http://apache.org/hello_world/services"
+ xmlns:s="http://apache.org/hello_world/services"
+ id="PQCTLSServer"
+ implementor="org.apache.cxf.systest.http.GreeterImpl"
+
address="https://localhost:${testutil.ports.PQCServer}/SoapContext/HttpsPort"
+ serviceName="s:SOAPService"
+ endpointName="e:HttpsPort"
+ depends-on="pqc-tls-settings"/>
+
+</beans>