This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 5e8baf46787e CAMEL-23159 - Post-Quantum Cryptography (PQC) readiness:
Add signatureSchemes support to BaseSSLContextParameters and
SSLConfigurationProperties for PQC readiness (#21875)
5e8baf46787e is described below
commit 5e8baf46787e66c97268b78eb470620e1322c42e
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Mar 9 16:22:54 2026 +0100
CAMEL-23159 - Post-Quantum Cryptography (PQC) readiness: Add
signatureSchemes support to BaseSSLContextParameters and
SSLConfigurationProperties for PQC readiness (#21875)
Add full TLS signature schemes configuration support mirroring the existing
named groups pattern, enabling PQC signature algorithms like ML-DSA to be
configured for TLS handshakes across all Camel components.
Core API (BaseSSLContextParameters):
- Add SignatureSchemesParameters POJO with List<String> signatureScheme
- Add signatureSchemes and signatureSchemesFilter fields
- Add resolveSignatureSchemes() helper for filter-based resolution
- Wire into all 3 SSL configurers (SSLEngine, SSLSocket, SSLServerSocket)
calling SSLParameters.setSignatureSchemes()
- Add SignatureSchemesParametersDefinition JAXB XML binding
- Wire into AbstractBaseSSLContextParametersFactoryBean
Camel Main (SSLConfigurationProperties):
- Add camel.ssl.signatureSchemes property (comma-separated list)
- Add camel.ssl.signatureSchemesInclude/Exclude filter properties
- Add mapping logic in BaseMainSupport.createSSLContextParameters()
- Update generated configurer, metadata, and documentation
Tests:
- 3 new JSSE-level tests in SSLContextParametersTest (explicit config,
filter, isolation)
- 4 new Main config tests in MainSSLTest (property-based, fluent,
filter property-based, fluent filter)
Signed-off-by: Andrea Cosentino <[email protected]>
---
.../main/camel-main-configuration-metadata.json | 3 +
.../apache/camel/catalog/schemas/camel-spring.xsd | 11 ++
.../support/jsse/BaseSSLContextParameters.java | 202 +++++++++++++++++++++
.../support/jsse/SignatureSchemesParameters.java | 65 +++++++
.../org/apache/camel/core/xml/util/jsse/jaxb.index | 1 +
...bstractBaseSSLContextParametersFactoryBean.java | 31 ++++
.../jsse/SignatureSchemesParametersDefinition.java | 46 +++++
.../support/jsse/SSLContextParametersTest.java | 145 +++++++++++++++
.../main/SSLConfigurationPropertiesConfigurer.java | 21 +++
.../camel-main-configuration-metadata.json | 3 +
core/camel-main/src/main/docs/main.adoc | 5 +-
.../org/apache/camel/main/BaseMainSupport.java | 22 +++
.../camel/main/SSLConfigurationProperties.java | 89 +++++++++
.../java/org/apache/camel/main/MainSSLTest.java | 128 +++++++++++++
14 files changed, 771 insertions(+), 1 deletion(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 5e5d6ba74821..1b156fda5539 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -351,6 +351,9 @@
{ "name": "camel.ssl.secureRandomProvider", "required": false,
"description": "To use a specific provider for creating SecureRandom. The list
of available providers returned by java.security.Security.getProviders() or
null to use the highest priority provider implementing the secure socket
protocol.", "sourceType": "org.apache.camel.main.SSLConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.ssl.secureSocketProtocol", "required": false,
"description": "The protocol for the secure sockets created by the SSLContext.
See
https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/specs\/security\/standard-names.html",
"sourceType": "org.apache.camel.main.SSLConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "defaultValue": "TLSv1.3", "secret":
false },
{ "name": "camel.ssl.sessionTimeout", "required": false, "description":
"Timeout in seconds to use for SSLContext. The default is 24 hours.",
"sourceType": "org.apache.camel.main.SSLConfigurationProperties", "type":
"integer", "javaType": "int", "defaultValue": 86400, "secret": false },
+ { "name": "camel.ssl.signatureSchemes", "required": false, "description":
"List of TLS\/SSL signature schemes. Multiple names can be separated by comma.
Signature schemes control which signature algorithms are available during the
TLS handshake, including post-quantum signature algorithms such as ML-DSA.",
"sourceType": "org.apache.camel.main.SSLConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
+ { "name": "camel.ssl.signatureSchemesExclude", "required": false,
"description": "Filters TLS\/SSL signature schemes. This filter is used for
excluding signature schemes that match the naming pattern. Multiple names can
be separated by comma. Notice that if the signatureSchemes option has been
configured then the include\/exclude filters are not in use.", "sourceType":
"org.apache.camel.main.SSLConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
+ { "name": "camel.ssl.signatureSchemesInclude", "required": false,
"description": "Filters TLS\/SSL signature schemes. This filter is used for
including signature schemes that match the naming pattern. Multiple names can
be separated by comma. Notice that if the signatureSchemes option has been
configured then the include\/exclude filters are not in use.", "sourceType":
"org.apache.camel.main.SSLConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
{ "name": "camel.ssl.trustAllCertificates", "required": false,
"description": "Allows to trust all SSL certificates without performing
certificate validation. This can be used in development environment but may
expose the system to security risks. Notice that if the trustAllCertificates
option is set to true then the trustStore\/trustStorePassword options are not
in use.", "sourceType": "org.apache.camel.main.SSLConfigurationProperties",
"type": "boolean", "javaType": "boolean", "def [...]
{ "name": "camel.ssl.trustStore", "required": false, "description": "The
trust store to load. The trust store is by default loaded from classpath. If
you must load from file system, then use file: as prefix. file:nameOfFile (to
refer to the file system) classpath:nameOfFile (to refer to the classpath;
default) http:uri (to load the resource using HTTP) ref:nameOfBean (to lookup
an existing KeyStore instance from the registry, for example for testing and
development).", "sourceType": [...]
{ "name": "camel.ssl.trustStorePassword", "required": false,
"description": "Sets the SSL Truststore password.", "sourceType":
"org.apache.camel.main.SSLConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 235f087ea21e..5b7f7fd8ba57 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -3492,6 +3492,11 @@ configuration.
<xs:element maxOccurs="unbounded" minOccurs="0"
name="secureSocketProtocol" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="signatureSchemesParameters">
+ <xs:sequence>
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="signatureScheme"
nillable="true" type="xs:string"/>
+ </xs:sequence>
+ </xs:complexType>
<xs:complexType name="output">
<xs:complexContent>
<xs:extension base="tns:processorDefinition">
@@ -18053,6 +18058,8 @@ converter. The default logging level is DEBUG. Default
value: DEBUG
<xs:element minOccurs="0" name="secureSocketProtocolsFilter"
type="tns:filterParameters"/>
<xs:element minOccurs="0" name="namedGroups"
type="tns:namedGroupsParameters"/>
<xs:element minOccurs="0" name="namedGroupsFilter"
type="tns:filterParameters"/>
+ <xs:element minOccurs="0" name="signatureSchemes"
type="tns:signatureSchemesParameters"/>
+ <xs:element minOccurs="0" name="signatureSchemesFilter"
type="tns:filterParameters"/>
<xs:element minOccurs="0" name="sniHostNames"
type="tns:sniHostNames"/>
</xs:all>
<xs:attribute name="sessionTimeout" type="xs:string"/>
@@ -18069,6 +18076,8 @@ converter. The default logging level is DEBUG. Default
value: DEBUG
<xs:element minOccurs="0" name="secureSocketProtocolsFilter"
type="tns:filterParameters"/>
<xs:element minOccurs="0" name="namedGroups"
type="tns:namedGroupsParameters"/>
<xs:element minOccurs="0" name="namedGroupsFilter"
type="tns:filterParameters"/>
+ <xs:element minOccurs="0" name="signatureSchemes"
type="tns:signatureSchemesParameters"/>
+ <xs:element minOccurs="0" name="signatureSchemesFilter"
type="tns:filterParameters"/>
<xs:element minOccurs="0" name="keyManagers"
type="tns:keyManagersParametersFactoryBean"/>
<xs:element minOccurs="0" name="trustManagers"
type="tns:trustManagersParametersFactoryBean"/>
<xs:element minOccurs="0" name="secureRandom"
type="tns:secureRandomParametersFactoryBean"/>
@@ -18141,6 +18150,8 @@ An optional certificate alias to use. This is useful
when the keystore has multi
<xs:element minOccurs="0" name="secureSocketProtocolsFilter"
type="tns:filterParameters"/>
<xs:element minOccurs="0" name="namedGroups"
type="tns:namedGroupsParameters"/>
<xs:element minOccurs="0" name="namedGroupsFilter"
type="tns:filterParameters"/>
+ <xs:element minOccurs="0" name="signatureSchemes"
type="tns:signatureSchemesParameters"/>
+ <xs:element minOccurs="0" name="signatureSchemesFilter"
type="tns:filterParameters"/>
</xs:all>
<xs:attribute name="sessionTimeout" type="xs:string"/>
<xs:attribute name="clientAuthentication" type="xs:string"/>
diff --git
a/core/camel-api/src/main/java/org/apache/camel/support/jsse/BaseSSLContextParameters.java
b/core/camel-api/src/main/java/org/apache/camel/support/jsse/BaseSSLContextParameters.java
index 3c1a464f7d04..0356459cd8f2 100644
---
a/core/camel-api/src/main/java/org/apache/camel/support/jsse/BaseSSLContextParameters.java
+++
b/core/camel-api/src/main/java/org/apache/camel/support/jsse/BaseSSLContextParameters.java
@@ -89,6 +89,13 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
private static final String SSL_SERVER_SOCKET_NAMED_GROUP_LOG_MSG =
createNamedGroupLogMessage("SSLServerSocket");
+ private static final String SSL_ENGINE_SIGNATURE_SCHEME_LOG_MSG =
createSignatureSchemeLogMessage("SSLEngine");
+
+ private static final String SSL_SOCKET_SIGNATURE_SCHEME_LOG_MSG =
createSignatureSchemeLogMessage("SSLSocket");
+
+ private static final String SSL_SERVER_SOCKET_SIGNATURE_SCHEME_LOG_MSG
+ = createSignatureSchemeLogMessage("SSLServerSocket");
+
/**
* The optional explicitly configured cipher suites for this configuration.
*/
@@ -121,6 +128,18 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
*/
private FilterParameters namedGroupsFilter;
+ /**
+ * The optional explicitly configured signature schemes for this
configuration. Signature schemes control which
+ * signature algorithms are available during the TLS handshake, including
post-quantum signature algorithms such as
+ * ML-DSA.
+ */
+ private SignatureSchemesParameters signatureSchemes;
+
+ /**
+ * The optional signature schemes filter configuration for this
configuration.
+ */
+ private FilterParameters signatureSchemesFilter;
+
/**
* The optional {@link SSLSessionContext} timeout time for {@link
javax.net.ssl.SSLSession}s in seconds.
*/
@@ -284,6 +303,62 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
this.namedGroupsFilter = namedGroupsFilter;
}
+ /**
+ * Returns the optional explicitly configured signature schemes for this
configuration. These options are used in
+ * the configuration of {@link SSLEngine}, {@link SSLSocketFactory} and
{@link SSLServerSocketFactory} depending on
+ * the context in which they are applied.
+ * <p/>
+ * Signature schemes control which signature algorithms are available
during the TLS handshake, including
+ * post-quantum signature algorithms such as ML-DSA.
+ * <p/>
+ * These values override any filters supplied in {@link
#setSignatureSchemesFilter(FilterParameters)}
+ */
+ public SignatureSchemesParameters getSignatureSchemes() {
+ return signatureSchemes;
+ }
+
+ /**
+ * Sets the optional explicitly configured signature schemes for this
configuration. These options are used in the
+ * configuration of {@link SSLEngine}, {@link SSLSocketFactory} and {@link
SSLServerSocketFactory} depending on the
+ * context in which they are applied.
+ * <p/>
+ * Signature schemes control which signature algorithms are available
during the TLS handshake, including
+ * post-quantum signature algorithms such as ML-DSA.
+ * <p/>
+ * These values override any filters supplied in {@link
#setSignatureSchemesFilter(FilterParameters)}
+ *
+ * @param signatureSchemes the signature schemes configuration
+ */
+ public void setSignatureSchemes(SignatureSchemesParameters
signatureSchemes) {
+ this.signatureSchemes = signatureSchemes;
+ }
+
+ /**
+ * Returns the optional signature schemes filter for this configuration.
These options are used in the configuration
+ * of {@link SSLEngine}, {@link SSLSocketFactory} and {@link
SSLServerSocketFactory} depending on the context in
+ * which they are applied.
+ * <p/>
+ * These values are ignored if {@link
#setSignatureSchemes(SignatureSchemesParameters)} is called with a non
+ * {@code null} argument.
+ */
+ public FilterParameters getSignatureSchemesFilter() {
+ return signatureSchemesFilter;
+ }
+
+ /**
+ * Sets the optional signature schemes filter for this JSSE configuration.
These options are used in the
+ * configuration of {@link SSLEngine}, {@link SSLSocketFactory} and {@link
SSLServerSocketFactory} depending on the
+ * context in which they are applied.
+ * <p/>
+ * These values are ignored if {@link
#setSignatureSchemes(SignatureSchemesParameters)} is called with a non
+ * {@code null} argument.
+ *
+ * @param signatureSchemesFilter the filter configuration
+ */
+ public void setSignatureSchemesFilter(FilterParameters
signatureSchemesFilter) {
+ this.signatureSchemesFilter = signatureSchemesFilter;
+ }
+
/**
* Returns the optional {@link SSLSessionContext} timeout time for {@link
javax.net.ssl.SSLSession}s in seconds.
*/
@@ -399,6 +474,17 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
enabledNamedGroupsPatterns = null;
}
+ final List<String> enabledSignatureSchemes =
this.getSignatureSchemes() == null
+ ? null :
this.parsePropertyValues(this.getSignatureSchemes().getSignatureScheme());
+
+ final Patterns enabledSignatureSchemesPatterns;
+
+ if (this.getSignatureSchemesFilter() != null) {
+ enabledSignatureSchemesPatterns =
this.getSignatureSchemesFilter().getPatterns();
+ } else {
+ enabledSignatureSchemesPatterns = null;
+ }
+
//
final boolean allowPassthrough = getAllowPassthrough();
@@ -466,6 +552,23 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
engine.setSSLParameters(params);
}
+ String[] signatureSchemes = resolveSignatureSchemes(
+ engine.getSSLParameters().getSignatureSchemes(),
+ enabledSignatureSchemes,
enabledSignatureSchemesPatterns);
+ if (signatureSchemes != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(SSL_ENGINE_SIGNATURE_SCHEME_LOG_MSG,
+ engine,
+ enabledSignatureSchemes,
+ enabledSignatureSchemesPatterns,
+
engine.getSSLParameters().getSignatureSchemes(),
+ signatureSchemes);
+ }
+ SSLParameters params = engine.getSSLParameters();
+ params.setSignatureSchemes(signatureSchemes);
+ engine.setSSLParameters(params);
+ }
+
return engine;
}
};
@@ -592,6 +695,17 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
enabledNamedGroupsPatterns = null;
}
+ final List<String> enabledSignatureSchemes =
this.getSignatureSchemes() == null
+ ? null :
this.parsePropertyValues(this.getSignatureSchemes().getSignatureScheme());
+
+ final Patterns enabledSignatureSchemesPatterns;
+
+ if (this.getSignatureSchemesFilter() != null) {
+ enabledSignatureSchemesPatterns =
this.getSignatureSchemesFilter().getPatterns();
+ } else {
+ enabledSignatureSchemesPatterns = null;
+ }
+
//
final boolean allowPassthrough = getAllowPassthrough();
@@ -664,6 +778,23 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
socket.setSSLParameters(params);
}
+ String[] signatureSchemes = resolveSignatureSchemes(
+ socket.getSSLParameters().getSignatureSchemes(),
+ enabledSignatureSchemes,
enabledSignatureSchemesPatterns);
+ if (signatureSchemes != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(SSL_SOCKET_SIGNATURE_SCHEME_LOG_MSG,
+ socket,
+ enabledSignatureSchemes,
+ enabledSignatureSchemesPatterns,
+
socket.getSSLParameters().getSignatureSchemes(),
+ signatureSchemes);
+ }
+ SSLParameters params = socket.getSSLParameters();
+ params.setSignatureSchemes(signatureSchemes);
+ socket.setSSLParameters(params);
+ }
+
return socket;
}
};
@@ -720,6 +851,17 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
enabledNamedGroupsPatterns = null;
}
+ final List<String> enabledSignatureSchemes =
this.getSignatureSchemes() == null
+ ? null :
this.parsePropertyValues(this.getSignatureSchemes().getSignatureScheme());
+
+ final Patterns enabledSignatureSchemesPatterns;
+
+ if (this.getSignatureSchemesFilter() != null) {
+ enabledSignatureSchemesPatterns =
this.getSignatureSchemesFilter().getPatterns();
+ } else {
+ enabledSignatureSchemesPatterns = null;
+ }
+
//
final boolean allowPassthrough = getAllowPassthrough();
@@ -787,6 +929,23 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
socket.setSSLParameters(params);
}
+ String[] signatureSchemes = resolveSignatureSchemes(
+ socket.getSSLParameters().getSignatureSchemes(),
+ enabledSignatureSchemes,
enabledSignatureSchemesPatterns);
+ if (signatureSchemes != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(SSL_SERVER_SOCKET_SIGNATURE_SCHEME_LOG_MSG,
+ socket,
+ enabledSignatureSchemes,
+ enabledSignatureSchemesPatterns,
+
socket.getSSLParameters().getSignatureSchemes(),
+ signatureSchemes);
+ }
+ SSLParameters params = socket.getSSLParameters();
+ params.setSignatureSchemes(signatureSchemes);
+ socket.setSSLParameters(params);
+ }
+
return socket;
}
};
@@ -962,6 +1121,41 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
return filteredNamedGroups.toArray(new String[0]);
}
+ /**
+ * Resolves the signature schemes to configure based on explicit values or
filter patterns. Returns {@code null} if
+ * no signature schemes configuration is needed (both parameters are
{@code null}).
+ *
+ * @param currentSignatureSchemes the currently available
signature schemes from the SSL object
+ * @param enabledSignatureSchemes the optional explicit signature
schemes list
+ * @param enabledSignatureSchemesPatterns the optional filter patterns
+ *
+ * @return the filtered signature schemes
array, or {@code null} if no configuration
+ * is needed
+ */
+ private String[] resolveSignatureSchemes(
+ String[] currentSignatureSchemes, List<String>
enabledSignatureSchemes,
+ Patterns enabledSignatureSchemesPatterns) {
+
+ if (enabledSignatureSchemes == null && enabledSignatureSchemesPatterns
== null) {
+ return null;
+ }
+
+ if (currentSignatureSchemes == null) {
+ currentSignatureSchemes = new String[0];
+ }
+
+ Collection<String> filteredSignatureSchemes;
+ if (enabledSignatureSchemes != null) {
+ filteredSignatureSchemes = new
ArrayList<>(enabledSignatureSchemes);
+ } else {
+ filteredSignatureSchemes = this.filter(
+ null, Arrays.asList(currentSignatureSchemes),
+ enabledSignatureSchemesPatterns.getIncludes(),
enabledSignatureSchemesPatterns.getExcludes());
+ }
+
+ return filteredSignatureSchemes.toArray(new String[0]);
+ }
+
/**
* Configures a {@code T} based on the related configuration options.
*/
@@ -1308,4 +1502,12 @@ public abstract class BaseSSLContextParameters extends
JsseParameters {
+ "\t available named groups [{}]," + LS
+ "\t Resulting enabled named groups are [{}].";
}
+
+ private static String createSignatureSchemeLogMessage(String entityName) {
+ return "Configuring " + entityName + " [{}] with " + LS
+ + "\t explicitly set signature schemes [{}]," + LS
+ + "\t signature scheme patterns [{}]," + LS
+ + "\t available signature schemes [{}]," + LS
+ + "\t Resulting enabled signature schemes are [{}].";
+ }
}
diff --git
a/core/camel-api/src/main/java/org/apache/camel/support/jsse/SignatureSchemesParameters.java
b/core/camel-api/src/main/java/org/apache/camel/support/jsse/SignatureSchemesParameters.java
new file mode 100644
index 000000000000..bb13c65825b3
--- /dev/null
+++
b/core/camel-api/src/main/java/org/apache/camel/support/jsse/SignatureSchemesParameters.java
@@ -0,0 +1,65 @@
+/*
+ * 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.camel.support.jsse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a list of TLS/SSL signature schemes for use in TLS handshakes.
Signature schemes control which signature
+ * algorithms are available during the TLS handshake, including post-quantum
signature algorithms such as ML-DSA.
+ */
+public class SignatureSchemesParameters {
+ private List<String> signatureScheme;
+
+ /**
+ * Returns a live reference to the list of signature scheme names.
+ *
+ * @return a reference to the list, never {@code null}
+ */
+ public List<String> getSignatureScheme() {
+ if (this.signatureScheme == null) {
+ this.signatureScheme = new ArrayList<>();
+ }
+ return this.signatureScheme;
+ }
+
+ public void addSignatureScheme(String scheme) {
+ if (this.signatureScheme == null) {
+ this.signatureScheme = new ArrayList<>();
+ }
+ this.signatureScheme.add(scheme.trim());
+ }
+
+ /**
+ * Sets the signature schemes. It creates a copy of the given list.
+ *
+ * @param signatureScheme signature schemes
+ */
+ public void setSignatureScheme(List<String> signatureScheme) {
+ this.signatureScheme = signatureScheme == null ? null : new
ArrayList<>(signatureScheme);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SignatureSchemesParameters[signatureScheme=");
+ builder.append(getSignatureScheme());
+ builder.append("]");
+ return builder.toString();
+ }
+}
diff --git
a/core/camel-core-xml/src/generated/resources/org/apache/camel/core/xml/util/jsse/jaxb.index
b/core/camel-core-xml/src/generated/resources/org/apache/camel/core/xml/util/jsse/jaxb.index
index ecefb19403b1..3fd51d5143a2 100644
---
a/core/camel-core-xml/src/generated/resources/org/apache/camel/core/xml/util/jsse/jaxb.index
+++
b/core/camel-core-xml/src/generated/resources/org/apache/camel/core/xml/util/jsse/jaxb.index
@@ -4,3 +4,4 @@ FilterParametersDefinition
NamedGroupsParametersDefinition
SNIHostNamesDefinition
SecureSocketProtocolsParametersDefinition
+SignatureSchemesParametersDefinition
diff --git
a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/AbstractBaseSSLContextParametersFactoryBean.java
b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/AbstractBaseSSLContextParametersFactoryBean.java
index ff0d4d944dc9..25cea709bf5b 100644
---
a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/AbstractBaseSSLContextParametersFactoryBean.java
+++
b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/AbstractBaseSSLContextParametersFactoryBean.java
@@ -25,6 +25,7 @@ import org.apache.camel.support.jsse.CipherSuitesParameters;
import org.apache.camel.support.jsse.FilterParameters;
import org.apache.camel.support.jsse.NamedGroupsParameters;
import org.apache.camel.support.jsse.SecureSocketProtocolsParameters;
+import org.apache.camel.support.jsse.SignatureSchemesParameters;
@XmlTransient
public abstract class AbstractBaseSSLContextParametersFactoryBean<T extends
BaseSSLContextParameters>
@@ -42,6 +43,10 @@ public abstract class
AbstractBaseSSLContextParametersFactoryBean<T extends Base
private FilterParametersDefinition namedGroupsFilter;
+ private SignatureSchemesParametersDefinition signatureSchemes;
+
+ private FilterParametersDefinition signatureSchemesFilter;
+
@XmlAttribute
@Metadata(description = "The optional SSLSessionContext timeout time for
javax.net.ssl.SSLSession in seconds.")
private String sessionTimeout;
@@ -98,6 +103,16 @@ public abstract class
AbstractBaseSSLContextParametersFactoryBean<T extends Base
newInstance.setNamedGroupsFilter(createFilterParameters(namedGroupsFilter));
}
+ if (signatureSchemes != null) {
+ SignatureSchemesParameters signatureSchemesInstance = new
SignatureSchemesParameters();
+
signatureSchemesInstance.setSignatureScheme(signatureSchemes.getSignatureScheme());
+ newInstance.setSignatureSchemes(signatureSchemesInstance);
+ }
+
+ if (signatureSchemesFilter != null) {
+
newInstance.setSignatureSchemesFilter(createFilterParameters(signatureSchemesFilter));
+ }
+
if (sessionTimeout != null) {
newInstance.setSessionTimeout(sessionTimeout);
}
@@ -162,6 +177,22 @@ public abstract class
AbstractBaseSSLContextParametersFactoryBean<T extends Base
this.namedGroupsFilter = namedGroupsFilter;
}
+ public SignatureSchemesParametersDefinition getSignatureSchemes() {
+ return signatureSchemes;
+ }
+
+ public void setSignatureSchemes(SignatureSchemesParametersDefinition
signatureSchemes) {
+ this.signatureSchemes = signatureSchemes;
+ }
+
+ public FilterParametersDefinition getSignatureSchemesFilter() {
+ return signatureSchemesFilter;
+ }
+
+ public void setSignatureSchemesFilter(FilterParametersDefinition
signatureSchemesFilter) {
+ this.signatureSchemesFilter = signatureSchemesFilter;
+ }
+
public String getSessionTimeout() {
return sessionTimeout;
}
diff --git
a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/SignatureSchemesParametersDefinition.java
b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/SignatureSchemesParametersDefinition.java
new file mode 100644
index 000000000000..9ccb7a46321c
--- /dev/null
+++
b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/util/jsse/SignatureSchemesParametersDefinition.java
@@ -0,0 +1,46 @@
+/*
+ * 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.camel.core.xml.util.jsse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlType;
+
+import org.apache.camel.spi.Metadata;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "signatureSchemesParameters", propOrder = { "signatureScheme"
})
+public class SignatureSchemesParametersDefinition {
+
+ @Metadata(description = "List of TLS/SSL signature schemes")
+ private List<String> signatureScheme;
+
+ /**
+ * Returns a live reference to the list of signature scheme names.
+ *
+ * @return a reference to the list, never {@code null}
+ */
+ public List<String> getSignatureScheme() {
+ if (this.signatureScheme == null) {
+ this.signatureScheme = new ArrayList<>();
+ }
+ return this.signatureScheme;
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/support/jsse/SSLContextParametersTest.java
b/core/camel-core/src/test/java/org/apache/camel/support/jsse/SSLContextParametersTest.java
index 0ad671cf15a3..903e69c5d6a5 100644
---
a/core/camel-core/src/test/java/org/apache/camel/support/jsse/SSLContextParametersTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/support/jsse/SSLContextParametersTest.java
@@ -900,6 +900,151 @@ public class SSLContextParametersTest extends
AbstractJsseParametersTest {
assertEquals("x25519", engine.getSSLParameters().getNamedGroups()[0]);
}
+ @Test
+ public void testSignatureSchemes() throws Exception {
+ SSLContext controlContext = SSLContext.getInstance("TLSv1.3");
+ controlContext.init(null, null, null);
+ SSLEngine controlEngine = controlContext.createSSLEngine();
+ String[] controlSignatureSchemes =
controlEngine.getSSLParameters().getSignatureSchemes();
+
+ // default - no signature schemes configured, should keep defaults
+ SSLContextParameters scp = new SSLContextParameters();
+ SSLContext context = scp.createSSLContext(null);
+
+ SSLEngine engine = context.createSSLEngine();
+ SSLSocket socket = (SSLSocket)
context.getSocketFactory().createSocket();
+ SSLServerSocket serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ assertArrayEquals(controlSignatureSchemes,
engine.getSSLParameters().getSignatureSchemes());
+ assertArrayEquals(controlSignatureSchemes,
socket.getSSLParameters().getSignatureSchemes());
+ assertArrayEquals(controlSignatureSchemes,
serverSocket.getSSLParameters().getSignatureSchemes());
+
+ // empty ssp - sets empty list
+ SignatureSchemesParameters ssp = new SignatureSchemesParameters();
+ scp.setSignatureSchemes(ssp);
+ context = scp.createSSLContext(null);
+ engine = context.createSSLEngine();
+ socket = (SSLSocket) context.getSocketFactory().createSocket();
+ serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ assertEquals(0,
engine.getSSLParameters().getSignatureSchemes().length);
+ assertEquals(0,
socket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals(0,
serverSocket.getSSLParameters().getSignatureSchemes().length);
+
+ // explicit signature scheme
+
ssp.setSignatureScheme(Collections.singletonList("rsa_pss_rsae_sha256"));
+ context = scp.createSSLContext(null);
+ engine = context.createSSLEngine();
+ socket = (SSLSocket) context.getSocketFactory().createSocket();
+ serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ assertEquals(1,
engine.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
engine.getSSLParameters().getSignatureSchemes()[0]);
+ assertEquals(1,
socket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
socket.getSSLParameters().getSignatureSchemes()[0]);
+ assertEquals(1,
serverSocket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
serverSocket.getSSLParameters().getSignatureSchemes()[0]);
+
+ // explicit signature schemes override filter
+ FilterParameters filter = new FilterParameters();
+ filter.getInclude().add(".*");
+ scp.setSignatureSchemesFilter(filter);
+ context = scp.createSSLContext(null);
+ engine = context.createSSLEngine();
+ socket = (SSLSocket) context.getSocketFactory().createSocket();
+ serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ assertEquals(1,
engine.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
engine.getSSLParameters().getSignatureSchemes()[0]);
+ assertEquals(1,
socket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
socket.getSSLParameters().getSignatureSchemes()[0]);
+ assertEquals(1,
serverSocket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
serverSocket.getSSLParameters().getSignatureSchemes()[0]);
+ }
+
+ @Test
+ public void testSignatureSchemesFilter() throws Exception {
+ // Note: SSLParameters.getSignatureSchemes() returns null by default
(unlike getNamedGroups()),
+ // so filters operate on explicitly provided schemes rather than JDK
defaults.
+
+ // default - no filter, keeps defaults (null)
+ SSLContextParameters scp = new SSLContextParameters();
+ SSLContext context = scp.createSSLContext(null);
+
+ SSLEngine engine = context.createSSLEngine();
+ SSLSocket socket = (SSLSocket)
context.getSocketFactory().createSocket();
+ SSLServerSocket serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ assertNull(engine.getSSLParameters().getSignatureSchemes());
+ assertNull(socket.getSSLParameters().getSignatureSchemes());
+ assertNull(serverSocket.getSSLParameters().getSignatureSchemes());
+
+ // empty filter - no includes means no schemes match (empty array)
+ FilterParameters filter = new FilterParameters();
+ scp.setSignatureSchemesFilter(filter);
+ context = scp.createSSLContext(null);
+ engine = context.createSSLEngine();
+ socket = (SSLSocket) context.getSocketFactory().createSocket();
+ serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ assertEquals(0,
engine.getSSLParameters().getSignatureSchemes().length);
+ assertEquals(0,
socket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals(0,
serverSocket.getSSLParameters().getSignatureSchemes().length);
+
+ // explicit schemes override filter - filter ignored when schemes are
set
+ SignatureSchemesParameters ssp = new SignatureSchemesParameters();
+ List<String> allSchemes = new LinkedList<>();
+ allSchemes.add("ecdsa_secp256r1_sha256");
+ allSchemes.add("ecdsa_secp384r1_sha384");
+ allSchemes.add("rsa_pss_rsae_sha256");
+ allSchemes.add("ed25519");
+ ssp.setSignatureScheme(allSchemes);
+ scp.setSignatureSchemes(ssp);
+
+ filter.getInclude().add("ecdsa_.*");
+ context = scp.createSSLContext(null);
+ engine = context.createSSLEngine();
+
+ // explicit schemes take precedence over filter
+ assertEquals(4,
engine.getSSLParameters().getSignatureSchemes().length);
+
+ // clear explicit schemes, keep filter - now filter applies to empty
JDK defaults
+ scp.setSignatureSchemes(null);
+ filter.getInclude().clear();
+ filter.getInclude().add(".*");
+ context = scp.createSSLContext(null);
+ engine = context.createSSLEngine();
+ socket = (SSLSocket) context.getSocketFactory().createSocket();
+ serverSocket = (SSLServerSocket)
context.getServerSocketFactory().createServerSocket();
+
+ // JDK defaults are null → filtering null gives empty array
+ assertEquals(0,
engine.getSSLParameters().getSignatureSchemes().length);
+ assertEquals(0,
socket.getSSLParameters().getSignatureSchemes().length);
+ assertEquals(0,
serverSocket.getSSLParameters().getSignatureSchemes().length);
+ }
+
+ @Test
+ public void testSignatureSchemesDoNotAffectOtherSettings() throws
Exception {
+ SSLContext controlContext = SSLContext.getInstance("TLSv1.3");
+ controlContext.init(null, null, null);
+ SSLEngine controlEngine = controlContext.createSSLEngine();
+
+ // setting signature schemes should not change cipher suites,
protocols, or named groups
+ SSLContextParameters scp = new SSLContextParameters();
+ SignatureSchemesParameters ssp = new SignatureSchemesParameters();
+
ssp.setSignatureScheme(Collections.singletonList("rsa_pss_rsae_sha256"));
+ scp.setSignatureSchemes(ssp);
+
+ SSLContext context = scp.createSSLContext(null);
+ SSLEngine engine = context.createSSLEngine();
+
+ assertArrayEquals(controlEngine.getEnabledCipherSuites(),
engine.getEnabledCipherSuites());
+ assertArrayEquals(controlEngine.getEnabledProtocols(),
engine.getEnabledProtocols());
+ assertArrayEquals(controlEngine.getSSLParameters().getNamedGroups(),
engine.getSSLParameters().getNamedGroups());
+ assertEquals(1,
engine.getSSLParameters().getSignatureSchemes().length);
+ assertEquals("rsa_pss_rsae_sha256",
engine.getSSLParameters().getSignatureSchemes()[0]);
+ }
+
@Test
public void testSessionTimeout() throws Exception {
SSLContextParameters scp = new SSLContextParameters();
diff --git
a/core/camel-main/src/generated/java/org/apache/camel/main/SSLConfigurationPropertiesConfigurer.java
b/core/camel-main/src/generated/java/org/apache/camel/main/SSLConfigurationPropertiesConfigurer.java
index bd5547568b98..375dd286459a 100644
---
a/core/camel-main/src/generated/java/org/apache/camel/main/SSLConfigurationPropertiesConfigurer.java
+++
b/core/camel-main/src/generated/java/org/apache/camel/main/SSLConfigurationPropertiesConfigurer.java
@@ -42,6 +42,9 @@ public class SSLConfigurationPropertiesConfigurer extends
org.apache.camel.suppo
map.put("SecureRandomProvider", java.lang.String.class);
map.put("SecureSocketProtocol", java.lang.String.class);
map.put("SessionTimeout", int.class);
+ map.put("SignatureSchemes", java.lang.String.class);
+ map.put("SignatureSchemesExclude", java.lang.String.class);
+ map.put("SignatureSchemesInclude", java.lang.String.class);
map.put("TrustAllCertificates", boolean.class);
map.put("TrustStore", java.lang.String.class);
map.put("TrustStorePassword", java.lang.String.class);
@@ -90,6 +93,12 @@ public class SSLConfigurationPropertiesConfigurer extends
org.apache.camel.suppo
case "secureSocketProtocol":
target.setSecureSocketProtocol(property(camelContext, java.lang.String.class,
value)); return true;
case "sessiontimeout":
case "sessionTimeout": target.setSessionTimeout(property(camelContext,
int.class, value)); return true;
+ case "signatureschemes":
+ case "signatureSchemes":
target.setSignatureSchemes(property(camelContext, java.lang.String.class,
value)); return true;
+ case "signatureschemesexclude":
+ case "signatureSchemesExclude":
target.setSignatureSchemesExclude(property(camelContext,
java.lang.String.class, value)); return true;
+ case "signatureschemesinclude":
+ case "signatureSchemesInclude":
target.setSignatureSchemesInclude(property(camelContext,
java.lang.String.class, value)); return true;
case "trustallcertificates":
case "trustAllCertificates":
target.setTrustAllCertificates(property(camelContext, boolean.class, value));
return true;
case "truststore":
@@ -146,6 +155,12 @@ public class SSLConfigurationPropertiesConfigurer extends
org.apache.camel.suppo
case "secureSocketProtocol": return java.lang.String.class;
case "sessiontimeout":
case "sessionTimeout": return int.class;
+ case "signatureschemes":
+ case "signatureSchemes": return java.lang.String.class;
+ case "signatureschemesexclude":
+ case "signatureSchemesExclude": return java.lang.String.class;
+ case "signatureschemesinclude":
+ case "signatureSchemesInclude": return java.lang.String.class;
case "trustallcertificates":
case "trustAllCertificates": return boolean.class;
case "truststore":
@@ -198,6 +213,12 @@ public class SSLConfigurationPropertiesConfigurer extends
org.apache.camel.suppo
case "secureSocketProtocol": return target.getSecureSocketProtocol();
case "sessiontimeout":
case "sessionTimeout": return target.getSessionTimeout();
+ case "signatureschemes":
+ case "signatureSchemes": return target.getSignatureSchemes();
+ case "signatureschemesexclude":
+ case "signatureSchemesExclude": return
target.getSignatureSchemesExclude();
+ case "signatureschemesinclude":
+ case "signatureSchemesInclude": return
target.getSignatureSchemesInclude();
case "trustallcertificates":
case "trustAllCertificates": return target.isTrustAllCertificates();
case "truststore":
diff --git
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 5e5d6ba74821..1b156fda5539 100644
---
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -351,6 +351,9 @@
{ "name": "camel.ssl.secureRandomProvider", "required": false,
"description": "To use a specific provider for creating SecureRandom. The list
of available providers returned by java.security.Security.getProviders() or
null to use the highest priority provider implementing the secure socket
protocol.", "sourceType": "org.apache.camel.main.SSLConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.ssl.secureSocketProtocol", "required": false,
"description": "The protocol for the secure sockets created by the SSLContext.
See
https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/specs\/security\/standard-names.html",
"sourceType": "org.apache.camel.main.SSLConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "defaultValue": "TLSv1.3", "secret":
false },
{ "name": "camel.ssl.sessionTimeout", "required": false, "description":
"Timeout in seconds to use for SSLContext. The default is 24 hours.",
"sourceType": "org.apache.camel.main.SSLConfigurationProperties", "type":
"integer", "javaType": "int", "defaultValue": 86400, "secret": false },
+ { "name": "camel.ssl.signatureSchemes", "required": false, "description":
"List of TLS\/SSL signature schemes. Multiple names can be separated by comma.
Signature schemes control which signature algorithms are available during the
TLS handshake, including post-quantum signature algorithms such as ML-DSA.",
"sourceType": "org.apache.camel.main.SSLConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
+ { "name": "camel.ssl.signatureSchemesExclude", "required": false,
"description": "Filters TLS\/SSL signature schemes. This filter is used for
excluding signature schemes that match the naming pattern. Multiple names can
be separated by comma. Notice that if the signatureSchemes option has been
configured then the include\/exclude filters are not in use.", "sourceType":
"org.apache.camel.main.SSLConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
+ { "name": "camel.ssl.signatureSchemesInclude", "required": false,
"description": "Filters TLS\/SSL signature schemes. This filter is used for
including signature schemes that match the naming pattern. Multiple names can
be separated by comma. Notice that if the signatureSchemes option has been
configured then the include\/exclude filters are not in use.", "sourceType":
"org.apache.camel.main.SSLConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
{ "name": "camel.ssl.trustAllCertificates", "required": false,
"description": "Allows to trust all SSL certificates without performing
certificate validation. This can be used in development environment but may
expose the system to security risks. Notice that if the trustAllCertificates
option is set to true then the trustStore\/trustStorePassword options are not
in use.", "sourceType": "org.apache.camel.main.SSLConfigurationProperties",
"type": "boolean", "javaType": "boolean", "def [...]
{ "name": "camel.ssl.trustStore", "required": false, "description": "The
trust store to load. The trust store is by default loaded from classpath. If
you must load from file system, then use file: as prefix. file:nameOfFile (to
refer to the file system) classpath:nameOfFile (to refer to the classpath;
default) http:uri (to load the resource using HTTP) ref:nameOfBean (to lookup
an existing KeyStore instance from the registry, for example for testing and
development).", "sourceType": [...]
{ "name": "camel.ssl.trustStorePassword", "required": false,
"description": "Sets the SSL Truststore password.", "sourceType":
"org.apache.camel.main.SSLConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
diff --git a/core/camel-main/src/main/docs/main.adoc
b/core/camel-main/src/main/docs/main.adoc
index 9d52d82ad48b..eb81817ede0f 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -299,7 +299,7 @@ The camel.trace supports 14 options, which are listed below.
=== Camel SSL configurations
-The camel.ssl supports 23 options, which are listed below.
+The camel.ssl supports 26 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
@@ -324,6 +324,9 @@ The camel.ssl supports 23 options, which are listed below.
| *camel.ssl.secureRandomProvider* | To use a specific provider for creating
SecureRandom. The list of available providers returned by
java.security.Security.getProviders() or null to use the highest priority
provider implementing the secure socket protocol. | | String
| *camel.ssl.secureSocketProtocol* | The protocol for the secure sockets
created by the SSLContext. See
\https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html
| TLSv1.3 | String
| *camel.ssl.sessionTimeout* | Timeout in seconds to use for SSLContext. The
default is 24 hours. | 86400 | int
+| *camel.ssl.signatureSchemes* | List of TLS/SSL signature schemes. Multiple
names can be separated by comma. Signature schemes control which signature
algorithms are available during the TLS handshake, including post-quantum
signature algorithms such as ML-DSA. | | String
+| *camel.ssl.signatureSchemes{zwsp}Exclude* | Filters TLS/SSL signature
schemes. This filter is used for excluding signature schemes that match the
naming pattern. Multiple names can be separated by comma. Notice that if the
signatureSchemes option has been configured then the include/exclude filters
are not in use. | | String
+| *camel.ssl.signatureSchemes{zwsp}Include* | Filters TLS/SSL signature
schemes. This filter is used for including signature schemes that match the
naming pattern. Multiple names can be separated by comma. Notice that if the
signatureSchemes option has been configured then the include/exclude filters
are not in use. | | String
| *camel.ssl.trustAllCertificates* | Allows to trust all SSL certificates
without performing certificate validation. This can be used in development
environment but may expose the system to security risks. Notice that if the
trustAllCertificates option is set to true then the
trustStore/trustStorePassword options are not in use. | false | boolean
| *camel.ssl.trustStore* | The trust store to load. The trust store is by
default loaded from classpath. If you must load from file system, then use
file: as prefix. file:nameOfFile (to refer to the file system)
classpath:nameOfFile (to refer to the classpath; default) http:uri (to load the
resource using HTTP) ref:nameOfBean (to lookup an existing KeyStore instance
from the registry, for example for testing and development). | | String
| *camel.ssl.trustStorePassword* | Sets the SSL Truststore password. | |
String
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 05b3ec116032..e73e1565752c 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -101,6 +101,7 @@ import org.apache.camel.support.jsse.NamedGroupsParameters;
import org.apache.camel.support.jsse.SSLContextParameters;
import org.apache.camel.support.jsse.SSLContextServerParameters;
import org.apache.camel.support.jsse.SecureRandomParameters;
+import org.apache.camel.support.jsse.SignatureSchemesParameters;
import org.apache.camel.support.jsse.TrustAllTrustManager;
import org.apache.camel.support.jsse.TrustManagersParameters;
import org.apache.camel.support.scan.PackageScanHelper;
@@ -2220,6 +2221,27 @@ public abstract class BaseMainSupport extends
BaseService {
}
sslContextParameters.setNamedGroupsFilter(fp);
}
+ if (sslConfig.getSignatureSchemes() != null) {
+ SignatureSchemesParameters ssp = new SignatureSchemesParameters();
+ for (String s : sslConfig.getSignatureSchemes().split(",")) {
+ ssp.addSignatureScheme(s);
+ }
+ sslContextParameters.setSignatureSchemes(ssp);
+ }
+ if (sslConfig.getSignatureSchemesInclude() != null ||
sslConfig.getSignatureSchemesExclude() != null) {
+ FilterParameters fp = new FilterParameters();
+ if (sslConfig.getSignatureSchemesInclude() != null) {
+ for (String s :
sslConfig.getSignatureSchemesInclude().split(",")) {
+ fp.addInclude(s);
+ }
+ }
+ if (sslConfig.getSignatureSchemesExclude() != null) {
+ for (String s :
sslConfig.getSignatureSchemesExclude().split(",")) {
+ fp.addExclude(s);
+ }
+ }
+ sslContextParameters.setSignatureSchemesFilter(fp);
+ }
sslContextParameters.setKeyManagers(kmp);
sslContextParameters.setTrustManagers(tmp);
sslContextParameters.setServerParameters(scsp);
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/SSLConfigurationProperties.java
b/core/camel-main/src/main/java/org/apache/camel/main/SSLConfigurationProperties.java
index 4d6395d14120..77b84bd3b5a7 100644
---
a/core/camel-main/src/main/java/org/apache/camel/main/SSLConfigurationProperties.java
+++
b/core/camel-main/src/main/java/org/apache/camel/main/SSLConfigurationProperties.java
@@ -50,6 +50,12 @@ public class SSLConfigurationProperties implements
BootstrapCloseable {
private String namedGroupsInclude;
@Metadata(label = "advanced")
private String namedGroupsExclude;
+ @Metadata(label = "advanced")
+ private String signatureSchemes;
+ @Metadata(label = "advanced")
+ private String signatureSchemesInclude;
+ @Metadata(label = "advanced")
+ private String signatureSchemesExclude;
@Metadata
private String keyStore;
@Metadata(label = "advanced")
@@ -237,6 +243,52 @@ public class SSLConfigurationProperties implements
BootstrapCloseable {
this.namedGroupsExclude = namedGroupsExclude;
}
+ public String getSignatureSchemes() {
+ return signatureSchemes;
+ }
+
+ /**
+ * List of TLS/SSL signature schemes. Multiple names can be separated by
comma.
+ * <p>
+ * Signature schemes control which signature algorithms are available
during the TLS handshake, including
+ * post-quantum signature algorithms such as ML-DSA.
+ */
+ public void setSignatureSchemes(String signatureSchemes) {
+ this.signatureSchemes = signatureSchemes;
+ }
+
+ public String getSignatureSchemesInclude() {
+ return signatureSchemesInclude;
+ }
+
+ /**
+ * Filters TLS/SSL signature schemes.
+ * <p>
+ * This filter is used for including signature schemes that match the
naming pattern. Multiple names can be
+ * separated by comma.
+ * <p>
+ * Notice that if the signatureSchemes option has been configured then the
include/exclude filters are not in use.
+ */
+ public void setSignatureSchemesInclude(String signatureSchemesInclude) {
+ this.signatureSchemesInclude = signatureSchemesInclude;
+ }
+
+ public String getSignatureSchemesExclude() {
+ return signatureSchemesExclude;
+ }
+
+ /**
+ * Filters TLS/SSL signature schemes.
+ * <p>
+ * This filter is used for excluding signature schemes that match the
naming pattern. Multiple names can be
+ * separated by comma.
+ * <p>
+ * Notice that if the signatureSchemes option has been configured then the
include/exclude filters are not in use.
+ */
+ public void setSignatureSchemesExclude(String signatureSchemesExclude) {
+ this.signatureSchemesExclude = signatureSchemesExclude;
+ }
+
public String getKeyStore() {
return keyStore;
}
@@ -514,6 +566,43 @@ public class SSLConfigurationProperties implements
BootstrapCloseable {
return this;
}
+ /**
+ * List of TLS/SSL signature schemes. Multiple names can be separated by
comma.
+ * <p>
+ * Signature schemes control which signature algorithms are available
during the TLS handshake, including
+ * post-quantum signature algorithms such as ML-DSA.
+ */
+ public SSLConfigurationProperties withSignatureSchemes(String
signatureSchemes) {
+ this.signatureSchemes = signatureSchemes;
+ return this;
+ }
+
+ /**
+ * Filters TLS/SSL signature schemes.
+ * <p>
+ * This filter is used for including signature schemes that match the
naming pattern. Multiple names can be
+ * separated by comma.
+ * <p>
+ * Notice that if the signatureSchemes option has been configured then the
include/exclude filters are not in use.
+ */
+ public SSLConfigurationProperties withSignatureSchemesInclude(String
signatureSchemesInclude) {
+ this.signatureSchemesInclude = signatureSchemesInclude;
+ return this;
+ }
+
+ /**
+ * Filters TLS/SSL signature schemes.
+ * <p>
+ * This filter is used for excluding signature schemes that match the
naming pattern. Multiple names can be
+ * separated by comma.
+ * <p>
+ * Notice that if the signatureSchemes option has been configured then the
include/exclude filters are not in use.
+ */
+ public SSLConfigurationProperties withSignatureSchemesExclude(String
signatureSchemesExclude) {
+ this.signatureSchemesExclude = signatureSchemesExclude;
+ return this;
+ }
+
/**
* The keystore to load.
*
diff --git
a/core/camel-main/src/test/java/org/apache/camel/main/MainSSLTest.java
b/core/camel-main/src/test/java/org/apache/camel/main/MainSSLTest.java
index 50353a31899a..21f22e7f1cb6 100644
--- a/core/camel-main/src/test/java/org/apache/camel/main/MainSSLTest.java
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MainSSLTest.java
@@ -26,6 +26,7 @@ import org.apache.camel.support.jsse.KeyStoreParameters;
import org.apache.camel.support.jsse.NamedGroupsParameters;
import org.apache.camel.support.jsse.SSLContextParameters;
import org.apache.camel.support.jsse.SSLContextServerParameters;
+import org.apache.camel.support.jsse.SignatureSchemesParameters;
import org.apache.camel.support.jsse.TrustAllTrustManager;
import org.apache.camel.support.jsse.TrustManagersParameters;
import org.junit.jupiter.api.Assertions;
@@ -290,4 +291,131 @@ public class MainSSLTest {
main.stop();
}
+
+ @Test
+ public void testMainSSLSignatureSchemes() {
+ Main main = new Main();
+
+ main.addInitialProperty("camel.ssl.enabled", "true");
+ main.addInitialProperty("camel.ssl.keyStore", "server.jks");
+ main.addInitialProperty("camel.ssl.keystorePassword", "security");
+ main.addInitialProperty("camel.ssl.signatureSchemes",
"ed25519,rsa_pss_rsae_sha256,ecdsa_secp256r1_sha256");
+
+ main.start();
+
+ CamelContext context = main.getCamelContext();
+ assertNotNull(context);
+
+ SSLContextParameters sslParams = context.getSSLContextParameters();
+ assertNotNull(sslParams);
+
+ SignatureSchemesParameters ssp = sslParams.getSignatureSchemes();
+ assertNotNull(ssp);
+
+ List<String> schemes = ssp.getSignatureScheme();
+ Assertions.assertEquals(3, schemes.size());
+ Assertions.assertEquals("ed25519", schemes.get(0));
+ Assertions.assertEquals("rsa_pss_rsae_sha256", schemes.get(1));
+ Assertions.assertEquals("ecdsa_secp256r1_sha256", schemes.get(2));
+
+ assertNull(sslParams.getSignatureSchemesFilter());
+
+ main.stop();
+ }
+
+ @Test
+ public void testMainSSLSignatureSchemesFluent() {
+ Main main = new Main();
+
+ main.configure().sslConfig()
+ .withEnabled(true)
+ .withKeyStore("server.jks")
+ .withKeystorePassword("security")
+ .withSignatureSchemes("ed25519,rsa_pss_rsae_sha256");
+
+ main.start();
+
+ CamelContext context = main.getCamelContext();
+ assertNotNull(context);
+
+ SSLContextParameters sslParams = context.getSSLContextParameters();
+ assertNotNull(sslParams);
+
+ SignatureSchemesParameters ssp = sslParams.getSignatureSchemes();
+ assertNotNull(ssp);
+
+ List<String> schemes = ssp.getSignatureScheme();
+ Assertions.assertEquals(2, schemes.size());
+ Assertions.assertEquals("ed25519", schemes.get(0));
+ Assertions.assertEquals("rsa_pss_rsae_sha256", schemes.get(1));
+
+ main.stop();
+ }
+
+ @Test
+ public void testMainSSLSignatureSchemesFilter() {
+ Main main = new Main();
+
+ main.addInitialProperty("camel.ssl.enabled", "true");
+ main.addInitialProperty("camel.ssl.keyStore", "server.jks");
+ main.addInitialProperty("camel.ssl.keystorePassword", "security");
+ main.addInitialProperty("camel.ssl.signatureSchemesInclude",
"ecdsa_.*,ed.*");
+ main.addInitialProperty("camel.ssl.signatureSchemesExclude", "ed448");
+
+ main.start();
+
+ CamelContext context = main.getCamelContext();
+ assertNotNull(context);
+
+ SSLContextParameters sslParams = context.getSSLContextParameters();
+ assertNotNull(sslParams);
+
+ assertNull(sslParams.getSignatureSchemes());
+
+ FilterParameters fp = sslParams.getSignatureSchemesFilter();
+ assertNotNull(fp);
+
+ List<String> includes = fp.getInclude();
+ Assertions.assertEquals(2, includes.size());
+ Assertions.assertEquals("ecdsa_.*", includes.get(0));
+ Assertions.assertEquals("ed.*", includes.get(1));
+
+ List<String> excludes = fp.getExclude();
+ Assertions.assertEquals(1, excludes.size());
+ Assertions.assertEquals("ed448", excludes.get(0));
+
+ main.stop();
+ }
+
+ @Test
+ public void testMainSSLSignatureSchemesFilterFluent() {
+ Main main = new Main();
+
+ main.configure().sslConfig()
+ .withEnabled(true)
+ .withKeyStore("server.jks")
+ .withKeystorePassword("security")
+ .withSignatureSchemesInclude("ecdsa_.*")
+ .withSignatureSchemesExclude("ed448");
+
+ main.start();
+
+ CamelContext context = main.getCamelContext();
+ assertNotNull(context);
+
+ SSLContextParameters sslParams = context.getSSLContextParameters();
+ assertNotNull(sslParams);
+
+ assertNull(sslParams.getSignatureSchemes());
+
+ FilterParameters fp = sslParams.getSignatureSchemesFilter();
+ assertNotNull(fp);
+
+ Assertions.assertEquals(1, fp.getInclude().size());
+ Assertions.assertEquals("ecdsa_.*", fp.getInclude().get(0));
+ Assertions.assertEquals(1, fp.getExclude().size());
+ Assertions.assertEquals("ed448", fp.getExclude().get(0));
+
+ main.stop();
+ }
}