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

oscerd 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 099124b79207 CAMEL-23764: camel-as2 - add 
signatureVerificationRequired to reject unverifiable inbound signed messages
099124b79207 is described below

commit 099124b7920739453ed481664aef8f8bd8583da9
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Jun 19 13:55:37 2026 +0200

    CAMEL-23764: camel-as2 - add signatureVerificationRequired to reject 
unverifiable inbound signed messages
    
    The AS2 server consumer delivered the payload of an inbound 
multipart/signed message
    without verifying its signature when no validateSigningCertificateChain was 
configured.
    This adds an opt-in signatureVerificationRequired option (server only, 
default false):
    a signed message that cannot be verified (no validation chain) is rejected 
with an
    insufficient-message-security error instead of being delivered unverified. 
With the
    default the behaviour is unchanged, but a warning is now logged so the 
unverified
    delivery is visible. No effect when a chain is set or for unsigned 
messages. Isolated
    to the consumer payload-extraction path; MDN/MIC generation is unaffected. 
Includes
    AS2ServerSecSignatureRequiredIT and a 4.21 upgrade-guide note.
    
    Closes #24115
---
 .../org/apache/camel/catalog/components/as2.json   |  15 +--
 .../component/as2/api/util/HttpMessageUtils.java   |  57 +++++++--
 ...rverManagerEndpointConfigurationConfigurer.java |   7 ++
 ...ientManagerEndpointConfigurationConfigurer.java |   7 ++
 .../component/as2/AS2ConfigurationConfigurer.java  |   7 ++
 .../camel/component/as2/AS2EndpointConfigurer.java |   7 ++
 .../camel/component/as2/AS2EndpointUriFactory.java |   3 +-
 ...rverManagerEndpointConfigurationConfigurer.java |   7 ++
 .../org/apache/camel/component/as2/as2.json        |  15 +--
 .../camel/component/as2/AS2Configuration.java      |  17 +++
 .../apache/camel/component/as2/AS2Consumer.java    |   3 +-
 .../apache/camel/component/as2/AS2Endpoint.java    |   8 ++
 .../as2/AS2ServerSecSignatureRequiredIT.java       |  61 ++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc    |   8 ++
 .../endpoint/dsl/AS2EndpointBuilderFactory.java    | 132 +++++++++++++++++++++
 15 files changed, 326 insertions(+), 28 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
index dace035b80dc..cd80b7017f62 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
@@ -76,13 +76,14 @@
     "mdnPassword": { "index": 40, "kind": "parameter", "displayName": "Mdn 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the server for 
basic authentication when it sends an async  [...]
     "mdnUserName": { "index": 41, "kind": "parameter", "displayName": "Mdn 
User Name", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the server for 
basic authentication when it sends an asyn [...]
     "password": { "index": 42, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the client for 
basic authentication." },
-    "signedReceiptMicAlgorithms": { "index": 43, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
-    "signingAlgorithm": { "index": 44, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
-    "signingCertificateChain": { "index": 45, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
-    "signingPrivateKey": { "index": 46, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
-    "sslContext": { "index": 47, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
-    "userName": { "index": 48, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authen [...]
-    "validateSigningCertificateChain": { "index": 49, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
+    "signatureVerificationRequired": { "index": 43, "kind": "parameter", 
"displayName": "Signature Verification Required", "group": "security", "label": 
"security", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "Whether to reject an 
inbound signed AS2 message that cann [...]
+    "signedReceiptMicAlgorithms": { "index": 44, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
+    "signingAlgorithm": { "index": 45, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
+    "signingCertificateChain": { "index": 46, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
+    "signingPrivateKey": { "index": 47, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
+    "sslContext": { "index": 48, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
+    "userName": { "index": 49, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authen [...]
+    "validateSigningCertificateChain": { "index": 50, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
   },
   "apis": {
     "client": { "consumerOnly": false, "producerOnly": true, "description": 
"Sends EDI Messages over HTTP", "methods": { "send": { "description": "Send 
ediMessage to trading partner", "signatures": [ 
"org.apache.hc.core5.http.protocol.HttpCoreContext send(Object ediMessage, 
String requestUri, String subject, String from, String as2From, String as2To, 
org.apache.camel.component.as2.api.AS2MessageStructure as2MessageStructure, 
String ediMessageContentType, String ediMessageCharset, String  [...]
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
index 7acc58adee41..1cfc126efa2d 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
@@ -43,9 +43,13 @@ import 
org.apache.hc.core5.http.message.BasicClassicHttpRequest;
 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
 import org.apache.hc.core5.http.message.MessageSupport;
 import org.bouncycastle.cms.jcajce.ZlibExpanderProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public final class HttpMessageUtils {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(HttpMessageUtils.class);
+
     private HttpMessageUtils() {
     }
 
@@ -206,6 +210,33 @@ public final class HttpMessageUtils {
         return ediEntity;
     }
 
+    /**
+     * Verifies the signature of an inbound signed entity, or decides how to 
handle a signed message that cannot be
+     * verified. When a validation chain is configured, the signature is 
validated and an invalid one is rejected. When
+     * no validation chain is configured, the message cannot be verified: it 
is rejected when
+     * {@code signatureVerificationRequired} is set, otherwise the unverified 
payload is delivered after logging a
+     * warning (preserving the previous behaviour).
+     */
+    private static void verifySignedEntity(
+            MultipartSignedEntity multipartSignedEntity, 
DecrpytingAndSigningInfo decrpytingAndSigningInfo)
+            throws HttpException {
+        Certificate[] validateSigningCertificateChain = 
decrpytingAndSigningInfo.getValidateSigningCertificateChain();
+        if (validateSigningCertificateChain != null) {
+            if (!SigningUtils.isValid(multipartSignedEntity, 
validateSigningCertificateChain)) {
+                throw new AS2AuthenticationException("Failed to validate the 
signature");
+            }
+        } else if (decrpytingAndSigningInfo.isSignatureVerificationRequired()) 
{
+            throw new AS2InsufficientSecurityException(
+                    "Signature verification is required but no 
validateSigningCertificateChain is configured"
+                                                       + " to verify the 
inbound signed AS2 message");
+        } else {
+            LOG.warn("Received a signed AS2 message but no 
validateSigningCertificateChain is configured;"
+                     + " delivering the payload without verifying its 
signature."
+                     + " Configure validateSigningCertificateChain to verify 
the signature,"
+                     + " or set signatureVerificationRequired=true to reject 
such messages.");
+        }
+    }
+
     private static ApplicationEntity extractMultipartSigned(
             HttpMessage message, DecrpytingAndSigningInfo 
decrpytingAndSigningInfo)
             throws HttpException {
@@ -216,10 +247,7 @@ public final class HttpMessageUtils {
         Objects.requireNonNull(multipartSignedEntity,
                 "Failed to extract EDI payload: the multipart signed entity is 
null");
 
-        if (decrpytingAndSigningInfo.getValidateSigningCertificateChain() != 
null && !SigningUtils
-                .isValid(multipartSignedEntity, 
decrpytingAndSigningInfo.getValidateSigningCertificateChain())) {
-            throw new AS2AuthenticationException("Failed to validate the 
signature");
-        }
+        verifySignedEntity(multipartSignedEntity, decrpytingAndSigningInfo);
 
         MimeEntity mimeEntity = multipartSignedEntity.getSignedDataEntity();
         if (mimeEntity instanceof ApplicationEntity) {
@@ -258,10 +286,7 @@ public final class HttpMessageUtils {
             }
             case AS2MimeType.MULTIPART_SIGNED: {
                 MultipartSignedEntity multipartSignedEntity = 
(MultipartSignedEntity) entity;
-                if 
(decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null && 
!SigningUtils
-                        .isValid(multipartSignedEntity, 
decrpytingAndSigningInfo.getValidateSigningCertificateChain())) {
-                    throw new AS2AuthenticationException("Failed to validate 
the signature");
-                }
+                verifySignedEntity(multipartSignedEntity, 
decrpytingAndSigningInfo);
 
                 MimeEntity mimeEntity = 
multipartSignedEntity.getSignedDataEntity();
                 if (mimeEntity instanceof ApplicationEntity) {
@@ -332,10 +357,7 @@ public final class HttpMessageUtils {
             }
             case AS2MimeType.MULTIPART_SIGNED: {
                 MultipartSignedEntity multipartSignedEntity = 
(MultipartSignedEntity) entity;
-                if 
(decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null && 
!SigningUtils
-                        .isValid(multipartSignedEntity, 
decrpytingAndSigningInfo.getValidateSigningCertificateChain())) {
-                    throw new AS2AuthenticationException("Failed to validate 
the signature");
-                }
+                verifySignedEntity(multipartSignedEntity, 
decrpytingAndSigningInfo);
 
                 MimeEntity mimeEntity = 
multipartSignedEntity.getSignedDataEntity();
                 if (mimeEntity instanceof ApplicationEntity applicationEntity) 
{
@@ -370,10 +392,17 @@ public final class HttpMessageUtils {
     public static class DecrpytingAndSigningInfo {
         private final Certificate[] validateSigningCertificateChain;
         private final PrivateKey decryptingPrivateKey;
+        private final boolean signatureVerificationRequired;
 
         public DecrpytingAndSigningInfo(Certificate[] 
validateSigningCertificateChain, PrivateKey decryptingPrivateKey) {
+            this(validateSigningCertificateChain, decryptingPrivateKey, false);
+        }
+
+        public DecrpytingAndSigningInfo(Certificate[] 
validateSigningCertificateChain, PrivateKey decryptingPrivateKey,
+                                        boolean signatureVerificationRequired) 
{
             this.validateSigningCertificateChain = 
validateSigningCertificateChain;
             this.decryptingPrivateKey = decryptingPrivateKey;
+            this.signatureVerificationRequired = signatureVerificationRequired;
         }
 
         public Certificate[] getValidateSigningCertificateChain() {
@@ -384,5 +413,9 @@ public final class HttpMessageUtils {
             return decryptingPrivateKey;
         }
 
+        public boolean isSignatureVerificationRequired() {
+            return signatureVerificationRequired;
+        }
+
     }
 }
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
index 9db61f44f424..1d9d953996b3 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
@@ -58,6 +58,7 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         map.put("Server", java.lang.String.class);
         map.put("ServerFqdn", java.lang.String.class);
         map.put("ServerPortNumber", java.lang.Integer.class);
+        map.put("SignatureVerificationRequired", boolean.class);
         map.put("SignedReceiptMicAlgorithms", java.lang.String.class);
         map.put("SigningAlgorithm", 
org.apache.camel.component.as2.api.AS2SignatureAlgorithm.class);
         map.put("SigningCertificateChain", 
java.security.cert.Certificate[].class);
@@ -145,6 +146,8 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         case "serverFqdn": target.setServerFqdn(property(camelContext, 
java.lang.String.class, value)); return true;
         case "serverportnumber":
         case "serverPortNumber": 
target.setServerPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": 
target.setSignatureVerificationRequired(property(camelContext, boolean.class, 
value)); return true;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": 
target.setSignedReceiptMicAlgorithms(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signingalgorithm":
@@ -247,6 +250,8 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         case "serverFqdn": return java.lang.String.class;
         case "serverportnumber":
         case "serverPortNumber": return java.lang.Integer.class;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return boolean.class;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return java.lang.String.class;
         case "signingalgorithm":
@@ -345,6 +350,8 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         case "serverFqdn": return target.getServerFqdn();
         case "serverportnumber":
         case "serverPortNumber": return target.getServerPortNumber();
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return 
target.isSignatureVerificationRequired();
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return 
target.getSignedReceiptMicAlgorithms();
         case "signingalgorithm":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
index ac5f29f261fd..cc25efd702dd 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
@@ -59,6 +59,7 @@ public class AS2ClientManagerEndpointConfigurationConfigurer 
extends org.apache.
         map.put("Server", java.lang.String.class);
         map.put("ServerFqdn", java.lang.String.class);
         map.put("ServerPortNumber", java.lang.Integer.class);
+        map.put("SignatureVerificationRequired", boolean.class);
         map.put("SignedReceiptMicAlgorithms", java.lang.String.class);
         map.put("SigningAlgorithm", 
org.apache.camel.component.as2.api.AS2SignatureAlgorithm.class);
         map.put("SigningCertificateChain", 
java.security.cert.Certificate[].class);
@@ -148,6 +149,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "serverFqdn": target.setServerFqdn(property(camelContext, 
java.lang.String.class, value)); return true;
         case "serverportnumber":
         case "serverPortNumber": 
target.setServerPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": 
target.setSignatureVerificationRequired(property(camelContext, boolean.class, 
value)); return true;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": 
target.setSignedReceiptMicAlgorithms(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signingalgorithm":
@@ -252,6 +255,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "serverFqdn": return java.lang.String.class;
         case "serverportnumber":
         case "serverPortNumber": return java.lang.Integer.class;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return boolean.class;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return java.lang.String.class;
         case "signingalgorithm":
@@ -352,6 +357,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "serverFqdn": return target.getServerFqdn();
         case "serverportnumber":
         case "serverPortNumber": return target.getServerPortNumber();
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return 
target.isSignatureVerificationRequired();
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return 
target.getSignedReceiptMicAlgorithms();
         case "signingalgorithm":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
index 8e4b26428c01..aded86eb73de 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
@@ -57,6 +57,7 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         map.put("Server", java.lang.String.class);
         map.put("ServerFqdn", java.lang.String.class);
         map.put("ServerPortNumber", java.lang.Integer.class);
+        map.put("SignatureVerificationRequired", boolean.class);
         map.put("SignedReceiptMicAlgorithms", java.lang.String.class);
         map.put("SigningAlgorithm", 
org.apache.camel.component.as2.api.AS2SignatureAlgorithm.class);
         map.put("SigningCertificateChain", 
java.security.cert.Certificate[].class);
@@ -142,6 +143,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "serverFqdn": target.setServerFqdn(property(camelContext, 
java.lang.String.class, value)); return true;
         case "serverportnumber":
         case "serverPortNumber": 
target.setServerPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": 
target.setSignatureVerificationRequired(property(camelContext, boolean.class, 
value)); return true;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": 
target.setSignedReceiptMicAlgorithms(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signingalgorithm":
@@ -242,6 +245,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "serverFqdn": return java.lang.String.class;
         case "serverportnumber":
         case "serverPortNumber": return java.lang.Integer.class;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return boolean.class;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return java.lang.String.class;
         case "signingalgorithm":
@@ -338,6 +343,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "serverFqdn": return target.getServerFqdn();
         case "serverportnumber":
         case "serverPortNumber": return target.getServerPortNumber();
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return 
target.isSignatureVerificationRequired();
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return 
target.getSignedReceiptMicAlgorithms();
         case "signingalgorithm":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
index 78c34d6a74fa..91eb0bb01448 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
@@ -65,6 +65,7 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         map.put("MdnPassword", java.lang.String.class);
         map.put("MdnUserName", java.lang.String.class);
         map.put("Password", java.lang.String.class);
+        map.put("SignatureVerificationRequired", boolean.class);
         map.put("SignedReceiptMicAlgorithms", java.lang.String.class);
         map.put("SigningAlgorithm", 
org.apache.camel.component.as2.api.AS2SignatureAlgorithm.class);
         map.put("SigningCertificateChain", 
java.security.cert.Certificate[].class);
@@ -150,6 +151,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "serverFqdn": 
target.getConfiguration().setServerFqdn(property(camelContext, 
java.lang.String.class, value)); return true;
         case "serverportnumber":
         case "serverPortNumber": 
target.getConfiguration().setServerPortNumber(property(camelContext, 
java.lang.Integer.class, value)); return true;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": 
target.getConfiguration().setSignatureVerificationRequired(property(camelContext,
 boolean.class, value)); return true;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": 
target.getConfiguration().setSignedReceiptMicAlgorithms(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signingalgorithm":
@@ -254,6 +257,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "serverFqdn": return java.lang.String.class;
         case "serverportnumber":
         case "serverPortNumber": return java.lang.Integer.class;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return boolean.class;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return java.lang.String.class;
         case "signingalgorithm":
@@ -354,6 +359,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "serverFqdn": return target.getConfiguration().getServerFqdn();
         case "serverportnumber":
         case "serverPortNumber": return 
target.getConfiguration().getServerPortNumber();
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return 
target.getConfiguration().isSignatureVerificationRequired();
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return 
target.getConfiguration().getSignedReceiptMicAlgorithms();
         case "signingalgorithm":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
index f3a2db46f251..ae00901c0b9e 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
@@ -24,7 +24,7 @@ public class AS2EndpointUriFactory extends 
org.apache.camel.support.component.En
     private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(53);
+        Set<String> props = new HashSet<>(54);
         props.add("accessToken");
         props.add("apiName");
         props.add("as2From");
@@ -67,6 +67,7 @@ public class AS2EndpointUriFactory extends 
org.apache.camel.support.component.En
         props.add("server");
         props.add("serverFqdn");
         props.add("serverPortNumber");
+        props.add("signatureVerificationRequired");
         props.add("signedReceiptMicAlgorithms");
         props.add("signingAlgorithm");
         props.add("signingCertificateChain");
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
index dc5f7682a064..c51a80c7f24f 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
@@ -58,6 +58,7 @@ public class AS2ServerManagerEndpointConfigurationConfigurer 
extends org.apache.
         map.put("Server", java.lang.String.class);
         map.put("ServerFqdn", java.lang.String.class);
         map.put("ServerPortNumber", java.lang.Integer.class);
+        map.put("SignatureVerificationRequired", boolean.class);
         map.put("SignedReceiptMicAlgorithms", java.lang.String.class);
         map.put("SigningAlgorithm", 
org.apache.camel.component.as2.api.AS2SignatureAlgorithm.class);
         map.put("SigningCertificateChain", 
java.security.cert.Certificate[].class);
@@ -145,6 +146,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "serverFqdn": target.setServerFqdn(property(camelContext, 
java.lang.String.class, value)); return true;
         case "serverportnumber":
         case "serverPortNumber": 
target.setServerPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": 
target.setSignatureVerificationRequired(property(camelContext, boolean.class, 
value)); return true;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": 
target.setSignedReceiptMicAlgorithms(property(camelContext, 
java.lang.String.class, value)); return true;
         case "signingalgorithm":
@@ -247,6 +250,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "serverFqdn": return java.lang.String.class;
         case "serverportnumber":
         case "serverPortNumber": return java.lang.Integer.class;
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return boolean.class;
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return java.lang.String.class;
         case "signingalgorithm":
@@ -345,6 +350,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "serverFqdn": return target.getServerFqdn();
         case "serverportnumber":
         case "serverPortNumber": return target.getServerPortNumber();
+        case "signatureverificationrequired":
+        case "signatureVerificationRequired": return 
target.isSignatureVerificationRequired();
         case "signedreceiptmicalgorithms":
         case "signedReceiptMicAlgorithms": return 
target.getSignedReceiptMicAlgorithms();
         case "signingalgorithm":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
 
b/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
index dace035b80dc..cd80b7017f62 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
+++ 
b/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
@@ -76,13 +76,14 @@
     "mdnPassword": { "index": 40, "kind": "parameter", "displayName": "Mdn 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the server for 
basic authentication when it sends an async  [...]
     "mdnUserName": { "index": 41, "kind": "parameter", "displayName": "Mdn 
User Name", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the server for 
basic authentication when it sends an asyn [...]
     "password": { "index": 42, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the client for 
basic authentication." },
-    "signedReceiptMicAlgorithms": { "index": 43, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
-    "signingAlgorithm": { "index": 44, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
-    "signingCertificateChain": { "index": 45, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
-    "signingPrivateKey": { "index": 46, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
-    "sslContext": { "index": 47, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
-    "userName": { "index": 48, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authen [...]
-    "validateSigningCertificateChain": { "index": 49, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
+    "signatureVerificationRequired": { "index": 43, "kind": "parameter", 
"displayName": "Signature Verification Required", "group": "security", "label": 
"security", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "Whether to reject an 
inbound signed AS2 message that cann [...]
+    "signedReceiptMicAlgorithms": { "index": 44, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
+    "signingAlgorithm": { "index": 45, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
+    "signingCertificateChain": { "index": 46, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
+    "signingPrivateKey": { "index": 47, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
+    "sslContext": { "index": 48, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
+    "userName": { "index": 49, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authen [...]
+    "validateSigningCertificateChain": { "index": 50, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
   },
   "apis": {
     "client": { "consumerOnly": false, "producerOnly": true, "description": 
"Sends EDI Messages over HTTP", "methods": { "send": { "description": "Send 
ediMessage to trading partner", "signatures": [ 
"org.apache.hc.core5.http.protocol.HttpCoreContext send(Object ediMessage, 
String requestUri, String subject, String from, String as2From, String as2To, 
org.apache.camel.component.as2.api.AS2MessageStructure as2MessageStructure, 
String ediMessageContentType, String ediMessageCharset, String  [...]
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
index e67bb1801623..e3cceb395f7b 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
@@ -115,6 +115,8 @@ public class AS2Configuration {
     @UriParam(label = "security")
     private Certificate[] validateSigningCertificateChain;
     @UriParam(label = "security")
+    private boolean signatureVerificationRequired;
+    @UriParam(label = "security")
     private SSLContext sslContext;
     // If you use localhost-based AS2 server, you don't need to specify a 
hostnameVerifier
     @UriParam(label = "security")
@@ -543,6 +545,21 @@ public class AS2Configuration {
         this.validateSigningCertificateChain = validateSigningCertificateChain;
     }
 
+    public boolean isSignatureVerificationRequired() {
+        return signatureVerificationRequired;
+    }
+
+    /**
+     * Whether to reject an inbound signed AS2 message that cannot be verified 
because no
+     * validateSigningCertificateChain is configured (server only). When false 
(default), such a message is delivered
+     * after logging a warning, preserving the previous behaviour. When true, 
the message is rejected instead of being
+     * delivered without verifying its signature. Has no effect when 
validateSigningCertificateChain is set (signatures
+     * are always validated then) or for unsigned messages.
+     */
+    public void setSignatureVerificationRequired(boolean 
signatureVerificationRequired) {
+        this.signatureVerificationRequired = signatureVerificationRequired;
+    }
+
     public SSLContext getSslContext() {
         return sslContext;
     }
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
index 675eb0df372e..9446fc6135e1 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
@@ -137,7 +137,8 @@ public class AS2Consumer extends 
AbstractApiConsumer<AS2ApiName, AS2Configuratio
                     = HttpMessageUtils.extractEdiPayload(request,
                             new HttpMessageUtils.DecrpytingAndSigningInfo(
                                     
getEndpoint().getValidateSigningCertificateChain(),
-                                    getEndpoint().getDecryptingPrivateKey()));
+                                    getEndpoint().getDecryptingPrivateKey(),
+                                    
getEndpoint().isSignatureVerificationRequired()));
 
             // Set AS2 Interchange property and EDI message into body of input 
message.
             Exchange exchange = createExchange(false);
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
index b8c1ccfa6321..14b4b8dbba47 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
@@ -206,6 +206,14 @@ public class AS2Endpoint extends 
AbstractApiEndpoint<AS2ApiName, AS2Configuratio
         
configuration.setValidateSigningCertificateChain(validateSigningCertificateChain);
     }
 
+    public boolean isSignatureVerificationRequired() {
+        return configuration.isSignatureVerificationRequired();
+    }
+
+    public void setSignatureVerificationRequired(boolean 
signatureVerificationRequired) {
+        
configuration.setSignatureVerificationRequired(signatureVerificationRequired);
+    }
+
     public PrivateKey getDecryptingPrivateKey() {
         return configuration.getDecryptingPrivateKey();
     }
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerSecSignatureRequiredIT.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerSecSignatureRequiredIT.java
new file mode 100644
index 000000000000..da5516ab5f07
--- /dev/null
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerSecSignatureRequiredIT.java
@@ -0,0 +1,61 @@
+/*
+ * 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.component.as2;
+
+import org.apache.camel.component.as2.api.AS2MessageStructure;
+import org.apache.camel.component.as2.api.entity.AS2DispositionModifier;
+import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+/**
+ * Tests an AS2 server configured to require signature verification ({@code 
signatureVerificationRequired=true}) but
+ * without a {@code validateSigningCertificateChain} to verify against. <br>
+ * A signed message cannot be verified in this configuration, so rather than 
silently delivering the unverified payload
+ * the server rejects it with an 'insufficient-message-security' error. <br>
+ * Unsigned messages have no signature to verify and are unaffected.
+ */
+public class AS2ServerSecSignatureRequiredIT extends AS2ServerSecTestBase {
+
+    @Override
+    protected void customizeConfiguration(AS2Configuration configuration) {
+        super.customizeConfiguration(configuration);
+        // Require signature verification, but deliberately leave 
validateSigningCertificateChain unset so that a
+        // signed message cannot be verified.
+        configuration.setSignatureVerificationRequired(true);
+    }
+
+    // A signed message that cannot be verified (no validation chain 
configured) must be rejected, not delivered.
+    @ParameterizedTest
+    @EnumSource(value = AS2MessageStructure.class,
+                names = { "SIGNED", "COMPRESSED_SIGNED", "SIGNED_COMPRESSED" })
+    public void unverifiableSignedMessageRejectedTest(AS2MessageStructure 
messageStructure) throws Exception {
+        HttpCoreContext context = send(messageStructure);
+        verifyOkResponse(context);
+        verifyMdnErrorDisposition(context, 
AS2DispositionModifier.ERROR_INSUFFICIENT_MESSAGE_SECURITY);
+    }
+
+    // An unsigned message has no signature to verify, so 
signatureVerificationRequired has no effect on it.
+    @ParameterizedTest
+    @EnumSource(value = AS2MessageStructure.class,
+                names = { "PLAIN", "PLAIN_COMPRESSED" })
+    public void unsignedMessageStillDeliveredTest(AS2MessageStructure 
messageStructure) throws Exception {
+        HttpCoreContext context = send(messageStructure);
+        verifyOkResponse(context);
+        verifyMdnSuccessDisposition(context);
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
index 84f264d0ab6c..5c98bca70fa9 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
@@ -1021,6 +1021,14 @@ aligning the component with the rest of the Camel 
component catalog (`camel-kafk
 names from NATS messages can supply a custom `headerFilterStrategy` to restore 
the previous
 behaviour.
 
+=== camel-as2
+
+The AS2 server consumer now logs a warning when it delivers an inbound signed 
message without verifying
+its signature because no `validateSigningCertificateChain` is configured. A 
new opt-in
+`signatureVerificationRequired` option (server only, default `false`) can be 
set to reject such
+unverifiable signed messages with an `insufficient-message-security` error 
instead of delivering them
+unverified. The default behaviour is otherwise unchanged.
+
 === camel-oauth
 
 `OAuthTokenRequest.refreshTokenGrant(...)` now sends the RFC 6749 
`refresh_token` form parameter for
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
index e9d04b7f1e7b..e34bfad092f6 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
@@ -800,6 +800,50 @@ public interface AS2EndpointBuilderFactory {
             doSetProperty("password", password);
             return this;
         }
+        /**
+         * Whether to reject an inbound signed AS2 message that cannot be
+         * verified because no validateSigningCertificateChain is configured
+         * (server only). When false (default), such a message is delivered
+         * after logging a warning, preserving the previous behaviour. When
+         * true, the message is rejected instead of being delivered without
+         * verifying its signature. Has no effect when
+         * validateSigningCertificateChain is set (signatures are always
+         * validated then) or for unsigned messages.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param signatureVerificationRequired the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointConsumerBuilder 
signatureVerificationRequired(boolean signatureVerificationRequired) {
+            doSetProperty("signatureVerificationRequired", 
signatureVerificationRequired);
+            return this;
+        }
+        /**
+         * Whether to reject an inbound signed AS2 message that cannot be
+         * verified because no validateSigningCertificateChain is configured
+         * (server only). When false (default), such a message is delivered
+         * after logging a warning, preserving the previous behaviour. When
+         * true, the message is rejected instead of being delivered without
+         * verifying its signature. Has no effect when
+         * validateSigningCertificateChain is set (signatures are always
+         * validated then) or for unsigned messages.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param signatureVerificationRequired the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointConsumerBuilder 
signatureVerificationRequired(String signatureVerificationRequired) {
+            doSetProperty("signatureVerificationRequired", 
signatureVerificationRequired);
+            return this;
+        }
         /**
          * The list of algorithms, in order of preference, requested to 
generate
          * a message integrity check (MIC) returned in message disposition
@@ -1871,6 +1915,50 @@ public interface AS2EndpointBuilderFactory {
             doSetProperty("password", password);
             return this;
         }
+        /**
+         * Whether to reject an inbound signed AS2 message that cannot be
+         * verified because no validateSigningCertificateChain is configured
+         * (server only). When false (default), such a message is delivered
+         * after logging a warning, preserving the previous behaviour. When
+         * true, the message is rejected instead of being delivered without
+         * verifying its signature. Has no effect when
+         * validateSigningCertificateChain is set (signatures are always
+         * validated then) or for unsigned messages.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param signatureVerificationRequired the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointProducerBuilder 
signatureVerificationRequired(boolean signatureVerificationRequired) {
+            doSetProperty("signatureVerificationRequired", 
signatureVerificationRequired);
+            return this;
+        }
+        /**
+         * Whether to reject an inbound signed AS2 message that cannot be
+         * verified because no validateSigningCertificateChain is configured
+         * (server only). When false (default), such a message is delivered
+         * after logging a warning, preserving the previous behaviour. When
+         * true, the message is rejected instead of being delivered without
+         * verifying its signature. Has no effect when
+         * validateSigningCertificateChain is set (signatures are always
+         * validated then) or for unsigned messages.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param signatureVerificationRequired the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointProducerBuilder 
signatureVerificationRequired(String signatureVerificationRequired) {
+            doSetProperty("signatureVerificationRequired", 
signatureVerificationRequired);
+            return this;
+        }
         /**
          * The list of algorithms, in order of preference, requested to 
generate
          * a message integrity check (MIC) returned in message disposition
@@ -2883,6 +2971,50 @@ public interface AS2EndpointBuilderFactory {
             doSetProperty("password", password);
             return this;
         }
+        /**
+         * Whether to reject an inbound signed AS2 message that cannot be
+         * verified because no validateSigningCertificateChain is configured
+         * (server only). When false (default), such a message is delivered
+         * after logging a warning, preserving the previous behaviour. When
+         * true, the message is rejected instead of being delivered without
+         * verifying its signature. Has no effect when
+         * validateSigningCertificateChain is set (signatures are always
+         * validated then) or for unsigned messages.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param signatureVerificationRequired the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointBuilder signatureVerificationRequired(boolean 
signatureVerificationRequired) {
+            doSetProperty("signatureVerificationRequired", 
signatureVerificationRequired);
+            return this;
+        }
+        /**
+         * Whether to reject an inbound signed AS2 message that cannot be
+         * verified because no validateSigningCertificateChain is configured
+         * (server only). When false (default), such a message is delivered
+         * after logging a warning, preserving the previous behaviour. When
+         * true, the message is rejected instead of being delivered without
+         * verifying its signature. Has no effect when
+         * validateSigningCertificateChain is set (signatures are always
+         * validated then) or for unsigned messages.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param signatureVerificationRequired the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointBuilder signatureVerificationRequired(String 
signatureVerificationRequired) {
+            doSetProperty("signatureVerificationRequired", 
signatureVerificationRequired);
+            return this;
+        }
         /**
          * The list of algorithms, in order of preference, requested to 
generate
          * a message integrity check (MIC) returned in message disposition

Reply via email to