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

davsclaus 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 bd989118a61 CAMEL-18917 camel-as2: add validating signature support to 
server (#9219)
bd989118a61 is described below

commit bd989118a61a565a636e187f630825fdd54f19b1
Author: Dennis Schwarz <[email protected]>
AuthorDate: Fri Jan 27 15:40:14 2023 +0100

    CAMEL-18917 camel-as2: add validating signature support to server (#9219)
    
    * CAMEL-18917 - Implement Signature verfication 1st step
    
    * CAMEL-18917 - Implement Signature verfication 2nd step
---
 .../component/as2/api/AS2ServerConnection.java     |  26 ++--
 .../AS2MessageDispositionNotificationEntity.java   |   7 +-
 ...spositionNotificationMultipartReportEntity.java |   8 +-
 .../as2/api/entity/MultipartSignedEntity.java      |  53 --------
 .../component/as2/api/protocol/ResponseMDN.java    |   8 +-
 .../component/as2/api/util/HttpMessageUtils.java   |  73 ++++++++---
 .../camel/component/as2/api/util/MicUtils.java     |   6 +-
 .../camel/component/as2/api/util/SigningUtils.java |  63 ++++++++++
 .../camel/component/as2/api/AS2MessageTest.java    |  16 ++-
 .../camel/component/as2/api/util/MicUtilsTest.java |   2 +-
 .../component/as2/api/util/SigningUtilsTest.java   | 110 ++++++++++++++++
 ...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        |   1 +
 .../camel/component/as2/AS2Configuration.java      |  14 +++
 .../apache/camel/component/as2/AS2Consumer.java    |   6 +-
 .../as2/internal/AS2ConnectionHelper.java          |   3 +-
 .../camel/component/as2/AS2ClientManagerIT.java    | 140 ++++++---------------
 .../camel/component/as2/AS2ServerManagerIT.java    |  95 +++++++++++++-
 22 files changed, 459 insertions(+), 203 deletions(-)

diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
index 1dd94f28483..1e82ac09142 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
@@ -68,14 +68,16 @@ public class AS2ServerConnection {
                                      Certificate[] signingCertificateChain,
                                      PrivateKey signingPrivateKey,
                                      PrivateKey decryptingPrivateKey,
-                                     String mdnMessageTemplate)
-                                                                throws 
IOException {
+                                     String mdnMessageTemplate,
+                                     Certificate[] 
validateSigningCertificateChain)
+                                                                               
     throws IOException {
             setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);
             serversocket = new ServerSocket(port);
 
             // Set up HTTP protocol processor for incoming connections
             final HttpProcessor inhttpproc = initProtocolProcessor(as2Version, 
originServer, serverFqdn,
-                    signatureAlgorithm, signingCertificateChain, 
signingPrivateKey, decryptingPrivateKey, mdnMessageTemplate);
+                    signatureAlgorithm, signingCertificateChain, 
signingPrivateKey, decryptingPrivateKey, mdnMessageTemplate,
+                    validateSigningCertificateChain);
 
             reqistry = new UriHttpRequestHandlerMapper();
 
@@ -194,6 +196,7 @@ public class AS2ServerConnection {
     private PrivateKey signingPrivateKey;
     private PrivateKey decryptingPrivateKey;
     private String mdnMessageTemplate;
+    private Certificate[] validateSigningCertificateChain;
 
     public AS2ServerConnection(String as2Version,
                                String originServer,
@@ -203,8 +206,9 @@ public class AS2ServerConnection {
                                Certificate[] signingCertificateChain,
                                PrivateKey signingPrivateKey,
                                PrivateKey decryptingPrivateKey,
-                               String mdnMessageTemplate)
-                                                          throws IOException {
+                               String mdnMessageTemplate,
+                               Certificate[] validateSigningCertificateChain)
+                                                                              
throws IOException {
         this.as2Version = ObjectHelper.notNull(as2Version, "as2Version");
         this.originServer = ObjectHelper.notNull(originServer, "userAgent");
         this.serverFqdn = ObjectHelper.notNull(serverFqdn, "serverFqdn");
@@ -214,15 +218,20 @@ public class AS2ServerConnection {
         this.signingPrivateKey = signingPrivateKey;
         this.decryptingPrivateKey = decryptingPrivateKey;
         this.mdnMessageTemplate = mdnMessageTemplate;
+        this.validateSigningCertificateChain = validateSigningCertificateChain;
 
         listenerThread = new RequestListenerThread(
                 this.as2Version, this.originServer, this.serverFqdn,
                 this.serverPortNumber, this.signingAlgorithm, 
this.signingCertificateChain, this.signingPrivateKey,
-                this.decryptingPrivateKey, this.mdnMessageTemplate);
+                this.decryptingPrivateKey, this.mdnMessageTemplate, 
validateSigningCertificateChain);
         listenerThread.setDaemon(true);
         listenerThread.start();
     }
 
+    public Certificate[] getValidateSigningCertificateChain() {
+        return validateSigningCertificateChain;
+    }
+
     public PrivateKey getSigningPrivateKey() {
         return signingPrivateKey;
     }
@@ -267,12 +276,13 @@ public class AS2ServerConnection {
             Certificate[] signingCertificateChain,
             PrivateKey signingPrivateKey,
             PrivateKey decryptingPrivateKey,
-            String mdnMessageTemplate) {
+            String mdnMessageTemplate,
+            Certificate[] validateSigningCertificateChain) {
         return HttpProcessorBuilder.create().add(new 
ResponseContent(true)).add(new ResponseServer(originServer))
                 .add(new ResponseDate()).add(new 
ResponseConnControl()).add(new ResponseMDN(
                         as2Version, serverFqdn,
                         signatureAlgorithm, signingCertificateChain, 
signingPrivateKey, decryptingPrivateKey,
-                        mdnMessageTemplate))
+                        mdnMessageTemplate, validateSigningCertificateChain))
                 .build();
     }
 
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
index 31789498555..24591a849f6 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
+import java.security.cert.Certificate;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -78,7 +79,8 @@ public class AS2MessageDispositionNotificationEntity extends 
MimeEntity {
                                                    Map<String, String> 
extensionFields,
                                                    String charset,
                                                    boolean isMainBody,
-                                                   PrivateKey 
decryptingPrivateKey) throws HttpException {
+                                                   PrivateKey 
decryptingPrivateKey,
+                                                   Certificate[] 
validateSigningCertificateChain) throws HttpException {
         setMainBody(isMainBody);
         
setContentType(ContentType.create(AS2MimeType.MESSAGE_DISPOSITION_NOTIFICATION, 
charset));
 
@@ -89,7 +91,8 @@ public class AS2MessageDispositionNotificationEntity extends 
MimeEntity {
 
         this.originalMessageId = HttpMessageUtils.getHeaderValue(request, 
AS2Header.MESSAGE_ID);
 
-        this.receivedContentMic = MicUtils.createReceivedContentMic(request, 
decryptingPrivateKey);
+        this.receivedContentMic
+                = MicUtils.createReceivedContentMic(request, 
validateSigningCertificateChain, decryptingPrivateKey);
 
         this.reportingUA = HttpMessageUtils.getHeaderValue(response, 
AS2Header.SERVER);
 
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/DispositionNotificationMultipartReportEntity.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/DispositionNotificationMultipartReportEntity.java
index b94b8ab60e4..9da207edf94 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/DispositionNotificationMultipartReportEntity.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/DispositionNotificationMultipartReportEntity.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.as2.api.entity;
 
 import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
+import java.security.cert.Certificate;
 import java.util.Map;
 
 import org.apache.camel.component.as2.api.AS2Header;
@@ -51,8 +52,9 @@ public class DispositionNotificationMultipartReportEntity 
extends MultipartRepor
                                                         String boundary,
                                                         boolean isMainBody,
                                                         PrivateKey 
decryptingPrivateKey,
-                                                        String mdnMessage)
-                                                                           
throws HttpException {
+                                                        String mdnMessage,
+                                                        Certificate[] 
validateSigningCertificateChain)
+                                                                               
                        throws HttpException {
         super(charset, isMainBody, boundary);
         removeHeaders(AS2Header.CONTENT_TYPE);
         setContentType(getContentTypeValue(boundary));
@@ -64,7 +66,7 @@ public class DispositionNotificationMultipartReportEntity 
extends MultipartRepor
         addPart(new AS2MessageDispositionNotificationEntity(
                 request, response, dispositionMode, dispositionType,
                 dispositionModifier, failureFields, errorFields, 
warningFields, extensionFields, charset, false,
-                decryptingPrivateKey));
+                decryptingPrivateKey, validateSigningCertificateChain));
     }
 
     public String getMainMessageContentType() {
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java
index bf5f7d5685e..0b38996dd7f 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java
@@ -16,23 +16,8 @@
  */
 package org.apache.camel.component.as2.api.entity;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.security.cert.X509Certificate;
-import java.util.Collection;
-
 import org.apache.camel.component.as2.api.AS2SignedDataGenerator;
 import org.apache.http.HttpException;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cms.CMSProcessable;
-import org.bouncycastle.cms.CMSProcessableByteArray;
-import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.SignerInformation;
-import org.bouncycastle.cms.SignerInformationStore;
-import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
-import org.bouncycastle.util.Store;
 
 public class MultipartSignedEntity extends MultipartMimeEntity {
 
@@ -51,44 +36,6 @@ public class MultipartSignedEntity extends 
MultipartMimeEntity {
         this.isMainBody = isMainBody;
     }
 
-    public boolean isValid() {
-        MimeEntity signedEntity = getSignedDataEntity();
-        ApplicationPkcs7SignatureEntity applicationPkcs7SignatureEntity = 
getSignatureEntity();
-
-        if (signedEntity == null || applicationPkcs7SignatureEntity == null) {
-            return false;
-        }
-
-        try {
-            ByteArrayOutputStream outstream = new ByteArrayOutputStream();
-            signedEntity.writeTo(outstream);
-            CMSProcessable signedContent = new 
CMSProcessableByteArray(outstream.toByteArray());
-
-            byte[] signature = applicationPkcs7SignatureEntity.getSignature();
-            InputStream is = new ByteArrayInputStream(signature);
-
-            CMSSignedData signedData = new CMSSignedData(signedContent, is);
-
-            Store<X509CertificateHolder> store = signedData.getCertificates();
-            SignerInformationStore signers = signedData.getSignerInfos();
-
-            for (SignerInformation signer : signers.getSigners()) {
-                @SuppressWarnings("unchecked")
-                Collection<X509CertificateHolder> certCollection = 
store.getMatches(signer.getSID());
-
-                X509CertificateHolder certHolder = 
certCollection.iterator().next();
-                X509Certificate cert = new 
JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
-                if (!signer.verify(new 
JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
-                    return false;
-                }
-            }
-        } catch (Exception e) {
-            return false;
-        }
-
-        return true;
-    }
-
     public MimeEntity getSignedDataEntity() {
         if (getPartCount() > 0) {
             return getPart(0);
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
index 1cb577e25a0..5cfb275ece0 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
@@ -83,12 +83,13 @@ public class ResponseMDN implements HttpResponseInterceptor 
{
     private PrivateKey signingPrivateKey;
     private PrivateKey decryptingPrivateKey;
     private String mdnMessageTemplate;
+    private Certificate[] validateSigningCertificateChain;
 
     private VelocityEngine velocityEngine;
 
     public ResponseMDN(String as2Version, String serverFQDN, 
AS2SignatureAlgorithm signingAlgorithm,
                        Certificate[] signingCertificateChain, PrivateKey 
signingPrivateKey, PrivateKey decryptingPrivateKey,
-                       String mdnMessageTemplate) {
+                       String mdnMessageTemplate, Certificate[] 
validateSigningCertificateChain) {
         this.as2Version = as2Version;
         this.serverFQDN = serverFQDN;
         this.signingAlgorithm = signingAlgorithm;
@@ -102,6 +103,7 @@ public class ResponseMDN implements HttpResponseInterceptor 
{
         } else {
             this.mdnMessageTemplate = DEFAULT_MDN_MESSAGE_TEMPLATE;
         }
+        this.validateSigningCertificateChain = validateSigningCertificateChain;
     }
 
     @Override
@@ -145,7 +147,7 @@ public class ResponseMDN implements HttpResponseInterceptor 
{
             multipartReportEntity = new 
DispositionNotificationMultipartReportEntity(
                     httpEntityEnclosingRequest, response, 
DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY,
                     AS2DispositionType.FAILED, null, null, null, null, null, 
StandardCharsets.US_ASCII.name(), boundary, true,
-                    decryptingPrivateKey, mdnMessage);
+                    decryptingPrivateKey, mdnMessage, 
validateSigningCertificateChain);
         } else {
             String mdnMessage = 
createMdnDescription(httpEntityEnclosingRequest, response,
                     DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY,
@@ -155,7 +157,7 @@ public class ResponseMDN implements HttpResponseInterceptor 
{
                     httpEntityEnclosingRequest, response, 
DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY,
                     AS2DispositionType.PROCESSED, null, null, null, null, 
null, StandardCharsets.US_ASCII.name(), boundary,
                     true,
-                    decryptingPrivateKey, mdnMessage);
+                    decryptingPrivateKey, mdnMessage, 
validateSigningCertificateChain);
         }
 
         DispositionNotificationOptions dispositionNotificationOptions = 
DispositionNotificationOptionsParser
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 e8068e9f7ec..b2027569d4f 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
@@ -17,6 +17,7 @@
 package org.apache.camel.component.as2.api.util;
 
 import java.security.PrivateKey;
+import java.security.cert.Certificate;
 import java.util.Objects;
 
 import org.apache.camel.component.as2.api.AS2Header;
@@ -126,7 +127,8 @@ public final class HttpMessageUtils {
         return null;
     }
 
-    public static ApplicationEDIEntity extractEdiPayload(HttpMessage message, 
PrivateKey privateKey) throws HttpException {
+    public static ApplicationEDIEntity extractEdiPayload(HttpMessage message, 
DecrpytingAndSigningInfo decrpytingAndSigningInfo)
+            throws HttpException {
 
         String contentTypeString = getHeaderValue(message, 
AS2Header.CONTENT_TYPE);
         if (contentTypeString == null) {
@@ -144,17 +146,17 @@ public final class HttpMessageUtils {
                 break;
             }
             case AS2MimeType.MULTIPART_SIGNED: {
-                ediEntity = extractMultipartSigned(message);
+                ediEntity = extractMultipartSigned(message, 
decrpytingAndSigningInfo);
                 break;
             }
             case AS2MimeType.APPLICATION_PKCS7_MIME: {
                 switch (contentType.getParameter("smime-type")) {
                     case "compressed-data": {
-                        ediEntity = extractCompressedData(message);
+                        ediEntity = extractCompressedData(message, 
decrpytingAndSigningInfo);
                         break;
                     }
                     case "enveloped-data": {
-                        ediEntity = extractEnvelopedData(message, privateKey);
+                        ediEntity = extractEnvelopedData(message, 
decrpytingAndSigningInfo);
                         break;
                     }
                     default:
@@ -174,9 +176,11 @@ public final class HttpMessageUtils {
 
     }
 
-    private static ApplicationEDIEntity extractEnvelopedData(HttpMessage 
message, PrivateKey privateKey) throws HttpException {
+    private static ApplicationEDIEntity extractEnvelopedData(
+            HttpMessage message, DecrpytingAndSigningInfo 
decrpytingAndSigningInfo)
+            throws HttpException {
         ApplicationEDIEntity ediEntity;
-        if (privateKey == null) {
+        if (decrpytingAndSigningInfo.getDecryptingPrivateKey() == null) {
             throw new HttpException(
                     "Failed to extract EDI payload: private key can not be 
null for AS2 enveloped message");
         }
@@ -185,11 +189,13 @@ public final class HttpMessageUtils {
 
         Objects.requireNonNull(envelopedDataEntity,
                 "Failed to extract EDI payload: the enveloped data entity is 
null");
-        ediEntity = extractEdiPayloadFromEnvelopedEntity(envelopedDataEntity, 
privateKey);
+        ediEntity = extractEdiPayloadFromEnvelopedEntity(envelopedDataEntity, 
decrpytingAndSigningInfo);
         return ediEntity;
     }
 
-    private static ApplicationEDIEntity extractCompressedData(HttpMessage 
message) throws HttpException {
+    private static ApplicationEDIEntity extractCompressedData(
+            HttpMessage message, DecrpytingAndSigningInfo 
decrpytingAndSigningInfo)
+            throws HttpException {
         ApplicationEDIEntity ediEntity;
         ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity
                 = getEntity(message, 
ApplicationPkcs7MimeCompressedDataEntity.class);
@@ -197,11 +203,13 @@ public final class HttpMessageUtils {
         Objects.requireNonNull(compressedDataEntity,
                 "Failed to extract the EDI payload: the compressed data entity 
is null");
 
-        ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity);
+        ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity, 
decrpytingAndSigningInfo);
         return ediEntity;
     }
 
-    private static ApplicationEDIEntity extractMultipartSigned(HttpMessage 
message) throws HttpException {
+    private static ApplicationEDIEntity extractMultipartSigned(
+            HttpMessage message, DecrpytingAndSigningInfo 
decrpytingAndSigningInfo)
+            throws HttpException {
         ApplicationEDIEntity ediEntity;
         MultipartSignedEntity multipartSignedEntity = getEntity(message,
                 MultipartSignedEntity.class);
@@ -209,13 +217,18 @@ 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 HttpException("Failed to validate the signature");
+        }
+
         MimeEntity mimeEntity = multipartSignedEntity.getSignedDataEntity();
         if (mimeEntity instanceof ApplicationEDIEntity) {
             ediEntity = (ApplicationEDIEntity) mimeEntity;
         } else if (mimeEntity instanceof 
ApplicationPkcs7MimeCompressedDataEntity) {
             ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity
                     = (ApplicationPkcs7MimeCompressedDataEntity) mimeEntity;
-            ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity);
+            ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity, 
decrpytingAndSigningInfo);
         } else {
             throw new HttpException(
                     "Failed to extract EDI payload: invalid content type '" + 
mimeEntity.getContentTypeValue()
@@ -225,11 +238,11 @@ public final class HttpMessageUtils {
     }
 
     private static ApplicationEDIEntity extractEdiPayloadFromEnvelopedEntity(
-            ApplicationPkcs7MimeEnvelopedDataEntity envelopedDataEntity, 
PrivateKey privateKey)
+            ApplicationPkcs7MimeEnvelopedDataEntity envelopedDataEntity, 
DecrpytingAndSigningInfo decrpytingAndSigningInfo)
             throws HttpException {
         ApplicationEDIEntity ediEntity = null;
 
-        MimeEntity entity = envelopedDataEntity.getEncryptedEntity(privateKey);
+        MimeEntity entity = 
envelopedDataEntity.getEncryptedEntity(decrpytingAndSigningInfo.getDecryptingPrivateKey());
         String contentTypeString = entity.getContentTypeValue();
         if (contentTypeString == null) {
             throw new HttpException("Failed to extract EDI message: content 
type missing from encrypted entity");
@@ -245,13 +258,18 @@ public final class HttpMessageUtils {
             }
             case AS2MimeType.MULTIPART_SIGNED: {
                 MultipartSignedEntity multipartSignedEntity = 
(MultipartSignedEntity) entity;
+                if 
(decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null && 
!SigningUtils
+                        .isValid(multipartSignedEntity, 
decrpytingAndSigningInfo.getValidateSigningCertificateChain())) {
+                    throw new HttpException("Failed to validate the 
signature");
+                }
+
                 MimeEntity mimeEntity = 
multipartSignedEntity.getSignedDataEntity();
                 if (mimeEntity instanceof ApplicationEDIEntity) {
                     ediEntity = (ApplicationEDIEntity) mimeEntity;
                 } else if (mimeEntity instanceof 
ApplicationPkcs7MimeCompressedDataEntity) {
                     ApplicationPkcs7MimeCompressedDataEntity 
compressedDataEntity
                             = (ApplicationPkcs7MimeCompressedDataEntity) 
mimeEntity;
-                    ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity);
+                    ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity, 
decrpytingAndSigningInfo);
                 } else {
 
                     throw new HttpException(
@@ -268,7 +286,7 @@ public final class HttpMessageUtils {
                 }
                 ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity
                         = (ApplicationPkcs7MimeCompressedDataEntity) entity;
-                ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity);
+                ediEntity = 
extractEdiPayloadFromCompressedEntity(compressedDataEntity, 
decrpytingAndSigningInfo);
                 break;
             }
             default:
@@ -281,7 +299,7 @@ public final class HttpMessageUtils {
     }
 
     public static ApplicationEDIEntity extractEdiPayloadFromCompressedEntity(
-            ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity)
+            ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity, 
DecrpytingAndSigningInfo decrpytingAndSigningInfo)
             throws HttpException {
         ApplicationEDIEntity ediEntity = null;
 
@@ -301,6 +319,11 @@ public final class HttpMessageUtils {
             }
             case AS2MimeType.MULTIPART_SIGNED: {
                 MultipartSignedEntity multipartSignedEntity = 
(MultipartSignedEntity) entity;
+                if 
(decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null && 
!SigningUtils
+                        .isValid(multipartSignedEntity, 
decrpytingAndSigningInfo.getValidateSigningCertificateChain())) {
+                    throw new HttpException("Failed to validate the 
signature");
+                }
+
                 MimeEntity mimeEntity = 
multipartSignedEntity.getSignedDataEntity();
                 if (mimeEntity instanceof ApplicationEDIEntity) {
                     ediEntity = (ApplicationEDIEntity) mimeEntity;
@@ -321,4 +344,22 @@ public final class HttpMessageUtils {
         return ediEntity;
     }
 
+    public static class DecrpytingAndSigningInfo {
+        private Certificate[] validateSigningCertificateChain;
+        private PrivateKey decryptingPrivateKey;
+
+        public DecrpytingAndSigningInfo(Certificate[] 
validateSigningCertificateChain, PrivateKey decryptingPrivateKey) {
+            this.validateSigningCertificateChain = 
validateSigningCertificateChain;
+            this.decryptingPrivateKey = decryptingPrivateKey;
+        }
+
+        public Certificate[] getValidateSigningCertificateChain() {
+            return validateSigningCertificateChain;
+        }
+
+        public PrivateKey getDecryptingPrivateKey() {
+            return decryptingPrivateKey;
+        }
+
+    }
 }
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
index af84d5da6ad..87f42229fa1 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
@@ -21,6 +21,7 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.PrivateKey;
+import java.security.cert.Certificate;
 
 import org.apache.camel.component.as2.api.AS2Header;
 import org.apache.camel.component.as2.api.AS2MicAlgorithm;
@@ -79,7 +80,7 @@ public final class MicUtils {
     }
 
     public static ReceivedContentMic createReceivedContentMic(
-            HttpEntityEnclosingRequest request, PrivateKey 
decryptingPrivateKey)
+            HttpEntityEnclosingRequest request, Certificate[] 
validateSigningCertificateChain, PrivateKey decryptingPrivateKey)
             throws HttpException {
 
         String dispositionNotificationOptionsString
@@ -97,7 +98,8 @@ public final class MicUtils {
             return null;
         }
 
-        HttpEntity entity = HttpMessageUtils.extractEdiPayload(request, 
decryptingPrivateKey);
+        HttpEntity entity = HttpMessageUtils.extractEdiPayload(request,
+                new 
HttpMessageUtils.DecrpytingAndSigningInfo(validateSigningCertificateChain, 
decryptingPrivateKey));
 
         byte[] content = EntityUtils.getContent(entity);
 
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java
index 7a17387a1ef..f2cdf8f44c0 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.component.as2.api.util;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
@@ -24,6 +27,9 @@ import java.util.Arrays;
 
 import org.apache.camel.component.as2.api.AS2SignatureAlgorithm;
 import org.apache.camel.component.as2.api.AS2SignedDataGenerator;
+import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7SignatureEntity;
+import org.apache.camel.component.as2.api.entity.MimeEntity;
+import org.apache.camel.component.as2.api.entity.MultipartSignedEntity;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.http.HttpException;
 import org.bouncycastle.asn1.ASN1EncodableVector;
@@ -36,11 +42,21 @@ import 
org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
 import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.cert.jcajce.JcaCertStore;
 import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.SignerId;
 import org.bouncycastle.cms.SignerInfoGenerator;
+import org.bouncycastle.cms.SignerInformationVerifier;
+import org.bouncycastle.cms.SignerInformationVerifierProvider;
 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public final class SigningUtils {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(SigningUtils.class);
+
     private SigningUtils() {
     }
 
@@ -93,4 +109,51 @@ public final class SigningUtils {
         return gen;
 
     }
+
+    public static boolean isValidSigned(byte[] signedContent, byte[] 
signature, Certificate[] signingCertificateChain) {
+        if (signedContent == null || signature == null || 
signingCertificateChain == null) {
+            return false;
+        }
+
+        try {
+            CMSSignedData signedData
+                    = new CMSSignedData(new 
CMSProcessableByteArray(signedContent), new ByteArrayInputStream(signature));
+
+            SignerInformationVerifierProvider sivp = (SignerId sid) -> {
+                for (Certificate knownCert : signingCertificateChain) {
+                    SignerInformationVerifier siv
+                            = new 
JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build((X509Certificate) 
knownCert);
+                    if 
(siv.getAssociatedCertificate().getIssuer().equals(sid.getIssuer())
+                            && 
siv.getAssociatedCertificate().getSerialNumber().equals(sid.getSerialNumber())) 
{
+                        return siv;
+                    }
+                }
+                throw new RuntimeException("Signature was created with an 
unknown certificate");
+            };
+
+            return signedData.verifySignatures(sivp);
+        } catch (CMSException e) {
+            //Probably the signature was created with an unknown certificate 
or something else is wrong with the signature
+            LOG.debug(e.getMessage(), e);
+        } catch (Exception e) {
+            LOG.debug(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    public static boolean isValid(MultipartSignedEntity multipartSignedEntity, 
Certificate[] signingCertificateChain) {
+        MimeEntity signedEntity = multipartSignedEntity.getSignedDataEntity();
+        ApplicationPkcs7SignatureEntity applicationPkcs7SignatureEntity = 
multipartSignedEntity.getSignatureEntity();
+        if (signedEntity == null || applicationPkcs7SignatureEntity == null) {
+            return false;
+        }
+
+        try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
+            signedEntity.writeTo(o);
+            return isValidSigned(o.toByteArray(), 
applicationPkcs7SignatureEntity.getSignature(), signingCertificateChain);
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
 }
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
index d4c68c9dadc..5643af6957e 100644
--- 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
@@ -58,6 +58,7 @@ import org.apache.camel.component.as2.api.util.EntityUtils;
 import org.apache.camel.component.as2.api.util.HttpMessageUtils;
 import org.apache.camel.component.as2.api.util.MicUtils;
 import org.apache.camel.component.as2.api.util.MicUtils.ReceivedContentMic;
+import org.apache.camel.component.as2.api.util.SigningUtils;
 import org.apache.camel.test.AvailablePortFinder;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
@@ -140,6 +141,7 @@ public class AS2MessageTest {
     private static final Duration HTTP_CONNECTION_TIMEOUT = 
Duration.ofSeconds(5);
     private static final Integer HTTP_CONNECTION_POOL_SIZE = 5;
     private static final Duration HTTP_CONNECTION_POOL_TTL = 
Duration.ofMinutes(15);
+    private static final Certificate[] VALIDATE_SIGNING_CERTIFICATE_CHAIN = 
null;
     private static final String RECIPIENT_DELIVERY_ADDRESS = 
"http://localhost:"; + TARGET_PORT + "/handle-receipts";
     private static final String AS2_VERSION = "1.1";
     private static final String USER_AGENT = "Camel AS2 Endpoint";
@@ -214,7 +216,8 @@ public class AS2MessageTest {
 
         testServer = new AS2ServerConnection(
                 AS2_VERSION, "MyServer-HTTP/1.1", SERVER_FQDN, TARGET_PORT, 
AS2SignatureAlgorithm.SHA256WITHRSA,
-                certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
decryptingKP.getPrivate(), MDN_MESSAGE_TEMPLATE);
+                certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
decryptingKP.getPrivate(), MDN_MESSAGE_TEMPLATE,
+                VALIDATE_SIGNING_CERTIFICATE_CHAIN);
         testServer.listen("*", new HttpRequestHandler() {
             @Override
             public void handle(HttpRequest request, HttpResponse response, 
HttpContext context)
@@ -224,7 +227,8 @@ public class AS2MessageTest {
                     context.setAttribute(AS2ServerManager.SUBJECT, SUBJECT);
                     context.setAttribute(AS2ServerManager.FROM, AS2_NAME);
                     LOG.debug("{}", AS2Utils.printMessage(request));
-                    ediEntity = HttpMessageUtils.extractEdiPayload(request, 
testServer.getDecryptingPrivateKey());
+                    ediEntity = HttpMessageUtils.extractEdiPayload(request, 
new HttpMessageUtils.DecrpytingAndSigningInfo(
+                            testServer.getValidateSigningCertificateChain(), 
testServer.getDecryptingPrivateKey()));
                 } catch (Exception e) {
                     throw new HttpException("Failed to parse AS2 Message 
Entity", e);
                 }
@@ -658,7 +662,7 @@ public class AS2MessageTest {
         assertNotNull(signatureEntity, "Multipart signed entity does not 
contain signature entity");
 
         // Validate Signature
-        assertTrue(multipartSignedEntity.isValid(), "Signature is invalid");
+        assertTrue(SigningUtils.isValid(multipartSignedEntity, new 
Certificate[] { signingCert }), "Signature is invalid");
 
     }
 
@@ -699,7 +703,7 @@ public class AS2MessageTest {
         assertNotNull(signatureEntity, "Signature Entity");
 
         // Validate Signature
-        assertTrue(responseSignedEntity.isValid(), "Signature is invalid");
+        assertTrue(SigningUtils.isValid(responseSignedEntity, new 
Certificate[] { signingCert }), "Signature is invalid");
     }
 
     @Test
@@ -741,7 +745,7 @@ public class AS2MessageTest {
                 request,
                 response, 
DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY, 
AS2DispositionType.PROCESSED,
                 dispositionModifier, failureFields, errorFields, 
warningFields, extensionFields, null, "boundary", true,
-                null, "Got ya message!");
+                null, "Got ya message!", null);
 
         // Send MDN
         HttpCoreContext httpContext = mdnManager.send(mdn, 
RECIPIENT_DELIVERY_ADDRESS);
@@ -766,7 +770,7 @@ public class AS2MessageTest {
         assertArrayEquals(errorFields, mdnEntity.getErrorFields(), "Unexpected 
value for Error Fields");
         assertArrayEquals(warningFields, mdnEntity.getWarningFields(), 
"Unexpected value for Warning Fields");
         assertEquals(extensionFields, mdnEntity.getExtensionFields(), 
"Unexpected value for Extension Fields");
-        ReceivedContentMic expectedMic = 
MicUtils.createReceivedContentMic(request, null);
+        ReceivedContentMic expectedMic = 
MicUtils.createReceivedContentMic(request, null, null);
         ReceivedContentMic mdnMic = mdnEntity.getReceivedContentMic();
         assertEquals(expectedMic.getEncodedMessageDigest(), 
mdnMic.getEncodedMessageDigest(),
                 "Unexpected value for Received Content Mic");
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/MicUtilsTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/MicUtilsTest.java
index 84629b94893..ad85477c12d 100644
--- 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/MicUtilsTest.java
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/MicUtilsTest.java
@@ -101,7 +101,7 @@ public class MicUtilsTest {
         basicEntity.setContentType(CONTENT_TYPE_VALUE);
         request.setEntity(basicEntity);
 
-        ReceivedContentMic receivedContentMic = 
MicUtils.createReceivedContentMic(request, null);
+        ReceivedContentMic receivedContentMic = 
MicUtils.createReceivedContentMic(request, null, null);
         assertNotNull(receivedContentMic, "Failed to create Received Content 
MIC");
         LOG.debug("Digest Algorithm: " + 
receivedContentMic.getDigestAlgorithmId());
         assertEquals(EXPECTED_MESSAGE_DIGEST_ALGORITHM, 
receivedContentMic.getDigestAlgorithmId(),
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/SigningUtilsTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/SigningUtilsTest.java
new file mode 100644
index 00000000000..8533efe3b9a
--- /dev/null
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/SigningUtilsTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.api.util;
+
+import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import org.apache.camel.component.as2.api.AS2SignatureAlgorithm;
+import org.apache.camel.component.as2.api.AS2SignedDataGenerator;
+import org.apache.camel.component.as2.api.Utils;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.SignerId;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class SigningUtilsTest {
+
+    private static KeyPair signingKP;
+    private static X509Certificate signingCert;
+    private static X509Certificate evilSigningCert;
+    private static final String MESSAGE = "Test message to be signed";
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        Security.addProvider(new BouncyCastleProvider());
+        setupKeysAndCertificates();
+    }
+
+    @AfterEach
+    public void tearDown() throws Exception {
+    }
+
+    @Test
+    public void createSigningGeneratorTest() throws Exception {
+        AS2SignedDataGenerator gen = 
SigningUtils.createSigningGenerator(AS2SignatureAlgorithm.SHA1WITHRSA,
+                new Certificate[] { signingCert }, signingKP.getPrivate());
+        CMSProcessableByteArray sData = new 
CMSProcessableByteArray(MESSAGE.getBytes(StandardCharsets.UTF_8));
+        CMSSignedData signedData = gen.generate(sData, true);
+
+        assertTrue(signedData.verifySignatures((SignerId sid) -> {
+            return new 
JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(signingCert);
+        }), "Message was wrongly signed");
+    }
+
+    @Test
+    public void isValidSignedTest() throws Exception {
+        AS2SignedDataGenerator gen = 
SigningUtils.createSigningGenerator(AS2SignatureAlgorithm.SHA1WITHRSA,
+                new Certificate[] { signingCert }, signingKP.getPrivate());
+        CMSProcessableByteArray sData = new 
CMSProcessableByteArray(MESSAGE.getBytes(StandardCharsets.UTF_8));
+        CMSSignedData signedData = gen.generate(sData, true);
+        
assertTrue(SigningUtils.isValidSigned(MESSAGE.getBytes(StandardCharsets.UTF_8), 
signedData.getEncoded(),
+                new Certificate[] { signingCert }), "Message must be valid");
+        
assertFalse(SigningUtils.isValidSigned(MESSAGE.getBytes(StandardCharsets.UTF_8),
 signedData.getEncoded(),
+                new Certificate[] { evilSigningCert }), "Message must be 
invalid");
+    }
+
+    private static void setupKeysAndCertificates() throws Exception {
+        //
+        // set up our certificates
+        //
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
+        kpg.initialize(1024, new SecureRandom());
+        //
+        // certificate we sign against
+        //
+        {
+            String signingDN = "O=AS2 Test Orgaisation, C=US";
+            signingKP = kpg.generateKeyPair();
+            signingCert = Utils.makeCertificate(
+                    signingKP, signingDN, signingKP, signingDN);
+        }
+
+        //
+        // certificate some else signed against
+        //
+        {
+            String evilSigningDN = "O=Evil Haxor Coorp, C=RU";
+            KeyPair evilSigningKP = kpg.generateKeyPair();
+            evilSigningCert = Utils.makeCertificate(
+                    evilSigningKP, evilSigningDN, evilSigningKP, 
evilSigningDN);
+        }
+    }
+
+}
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 374bbfa4bef..25bfcad9f8e 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
@@ -55,6 +55,7 @@ public class AS2ClientManagerEndpointConfigurationConfigurer 
extends org.apache.
         map.put("TargetHostname", java.lang.String.class);
         map.put("TargetPortNumber", java.lang.Integer.class);
         map.put("UserAgent", java.lang.String.class);
+        map.put("ValidateSigningCertificateChain", 
java.security.cert.Certificate[].class);
         ALL_OPTIONS = map;
     }
 
@@ -132,6 +133,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "TargetPortNumber": 
target.setTargetPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "useragent":
         case "UserAgent": target.setUserAgent(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": 
target.setValidateSigningCertificateChain(property(camelContext, 
java.security.cert.Certificate[].class, value)); return true;
         default: return false;
         }
     }
@@ -214,6 +217,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "TargetPortNumber": return java.lang.Integer.class;
         case "useragent":
         case "UserAgent": return java.lang.String.class;
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": return 
java.security.cert.Certificate[].class;
         default: return null;
         }
     }
@@ -292,6 +297,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "TargetPortNumber": return target.getTargetPortNumber();
         case "useragent":
         case "UserAgent": return target.getUserAgent();
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": return 
target.getValidateSigningCertificateChain();
         default: return null;
         }
     }
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 46225f9739a..2924d31cacd 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
@@ -53,6 +53,7 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         map.put("TargetHostname", java.lang.String.class);
         map.put("TargetPortNumber", java.lang.Integer.class);
         map.put("UserAgent", java.lang.String.class);
+        map.put("ValidateSigningCertificateChain", 
java.security.cert.Certificate[].class);
         ALL_OPTIONS = map;
     }
 
@@ -126,6 +127,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "TargetPortNumber": 
target.setTargetPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "useragent":
         case "UserAgent": target.setUserAgent(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": 
target.setValidateSigningCertificateChain(property(camelContext, 
java.security.cert.Certificate[].class, value)); return true;
         default: return false;
         }
     }
@@ -204,6 +207,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "TargetPortNumber": return java.lang.Integer.class;
         case "useragent":
         case "UserAgent": return java.lang.String.class;
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": return 
java.security.cert.Certificate[].class;
         default: return null;
         }
     }
@@ -278,6 +283,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "TargetPortNumber": return target.getTargetPortNumber();
         case "useragent":
         case "UserAgent": return target.getUserAgent();
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": return 
target.getValidateSigningCertificateChain();
         default: return null;
         }
     }
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 a6252b60c7c..0222151dcde 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
@@ -54,6 +54,7 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         map.put("targetHostname", java.lang.String.class);
         map.put("targetPortNumber", java.lang.Integer.class);
         map.put("userAgent", java.lang.String.class);
+        map.put("validateSigningCertificateChain", 
java.security.cert.Certificate[].class);
         map.put("exceptionHandler", 
org.apache.camel.spi.ExceptionHandler.class);
         map.put("exchangePattern", org.apache.camel.ExchangePattern.class);
         map.put("lazyStartProducer", boolean.class);
@@ -131,6 +132,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "targetPortNumber": 
target.getConfiguration().setTargetPortNumber(property(camelContext, 
java.lang.Integer.class, value)); return true;
         case "useragent":
         case "userAgent": 
target.getConfiguration().setUserAgent(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "validatesigningcertificatechain":
+        case "validateSigningCertificateChain": 
target.getConfiguration().setValidateSigningCertificateChain(property(camelContext,
 java.security.cert.Certificate[].class, value)); return true;
         default: return false;
         }
     }
@@ -210,6 +213,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "targetPortNumber": return java.lang.Integer.class;
         case "useragent":
         case "userAgent": return java.lang.String.class;
+        case "validatesigningcertificatechain":
+        case "validateSigningCertificateChain": return 
java.security.cert.Certificate[].class;
         default: return null;
         }
     }
@@ -285,6 +290,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "targetPortNumber": return 
target.getConfiguration().getTargetPortNumber();
         case "useragent":
         case "userAgent": return target.getConfiguration().getUserAgent();
+        case "validatesigningcertificatechain":
+        case "validateSigningCertificateChain": return 
target.getConfiguration().getValidateSigningCertificateChain();
         default: return null;
         }
     }
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 3d138d2b9d8..2528eb6bf04 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
@@ -21,7 +21,7 @@ public class AS2EndpointUriFactory extends 
org.apache.camel.support.component.En
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Set<String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(40);
+        Set<String> props = new HashSet<>(41);
         props.add("apiName");
         props.add("as2From");
         props.add("as2MessageStructure");
@@ -62,6 +62,7 @@ public class AS2EndpointUriFactory extends 
org.apache.camel.support.component.En
         props.add("targetHostname");
         props.add("targetPortNumber");
         props.add("userAgent");
+        props.add("validateSigningCertificateChain");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
         SECRET_PROPERTY_NAMES = Collections.emptySet();
         MULTI_VALUE_PREFIXES = Collections.emptySet();
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 7952b980868..e4ca3775905 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
@@ -54,6 +54,7 @@ public class AS2ServerManagerEndpointConfigurationConfigurer 
extends org.apache.
         map.put("TargetHostname", java.lang.String.class);
         map.put("TargetPortNumber", java.lang.Integer.class);
         map.put("UserAgent", java.lang.String.class);
+        map.put("ValidateSigningCertificateChain", 
java.security.cert.Certificate[].class);
         ALL_OPTIONS = map;
     }
 
@@ -129,6 +130,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "TargetPortNumber": 
target.setTargetPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "useragent":
         case "UserAgent": target.setUserAgent(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": 
target.setValidateSigningCertificateChain(property(camelContext, 
java.security.cert.Certificate[].class, value)); return true;
         default: return false;
         }
     }
@@ -209,6 +212,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "TargetPortNumber": return java.lang.Integer.class;
         case "useragent":
         case "UserAgent": return java.lang.String.class;
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": return 
java.security.cert.Certificate[].class;
         default: return null;
         }
     }
@@ -285,6 +290,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "TargetPortNumber": return target.getTargetPortNumber();
         case "useragent":
         case "UserAgent": return target.getUserAgent();
+        case "validatesigningcertificatechain":
+        case "ValidateSigningCertificateChain": return 
target.getValidateSigningCertificateChain();
         default: return null;
         }
     }
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/resources/org/apache/camel/component/as2/as2.json
 
b/components/camel-as2/camel-as2-component/src/generated/resources/org/apache/camel/component/as2/as2.json
index 9c9f6756db1..d1e8b4de975 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/resources/org/apache/camel/component/as2/as2.json
+++ 
b/components/camel-as2/camel-as2-component/src/generated/resources/org/apache/camel/component/as2/as2.json
@@ -64,6 +64,7 @@
     "targetHostname": { "kind": "parameter", "displayName": "Target Hostname", 
"group": "common", "label": "", "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 host name (IP or DNS name) of target 
host." },
     "targetPortNumber": { "kind": "parameter", "displayName": "Target Port 
Number", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The port number of target host. -1 indicates 
the scheme default port." },
     "userAgent": { "kind": "parameter", "displayName": "User Agent", "group": 
"common", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": "Camel AS2 Client Endpoint", "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The value included in the User-Agent message 
header identifying the AS2 user agent." },
+    "validateSigningCertificateChain": { "kind": "parameter", "displayName": 
"Validate Signing Certificate Chain", "group": "common", "label": "", 
"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": "Certifiates to validate the messages signature 
against. If not supplied, v [...]
     "exceptionHandler": { "kind": "parameter", "displayName": "Exception 
Handler", "group": "consumer (advanced)", "label": "consumer,advanced", 
"required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By default the 
con [...]
     "exchangePattern": { "kind": "parameter", "displayName": "Exchange 
Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", 
"required": false, "type": "object", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut", 
"InOptionalOut" ], "deprecated": false, "autowired": false, "secret": false, 
"description": "Sets the exchange pattern when the consumer creates an 
exchange." },
     "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start 
Producer", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether the producer should be started lazy (on the first 
message). By starting lazy you can use this to allow CamelContext and routes to 
startup in situations where a producer may other [...]
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 1ce9ddfb9cd..aa01c91687c 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
@@ -108,6 +108,8 @@ public class AS2Configuration {
     private Integer httpConnectionPoolSize = 5;
     @UriParam(defaultValue = "15m")
     private Duration httpConnectionPoolTtl = Duration.ofMinutes(15);
+    @UriParam
+    private Certificate[] validateSigningCertificateChain;
 
     public AS2ApiName getApiName() {
         return apiName;
@@ -490,4 +492,16 @@ public class AS2Configuration {
         this.httpConnectionPoolTtl = httpConnectionPoolTtl;
     }
 
+    public Certificate[] getValidateSigningCertificateChain() {
+        return validateSigningCertificateChain;
+    }
+
+    /**
+     * Certifiates to validate the messages signature against. If not 
supplied, validation will not take place. Server:
+     * validates the received message. Client: not yet implemented, should 
validate the MDN
+     */
+    public void setValidateSigningCertificateChain(Certificate[] 
validateSigningCertificateChain) {
+        this.validateSigningCertificateChain = validateSigningCertificateChain;
+    }
+
 }
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 2c6142b1eda..540fe9c0242 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
@@ -120,9 +120,11 @@ public class AS2Consumer extends 
AbstractApiConsumer<AS2ApiName, AS2Configuratio
                 apiProxy.handleMDNResponse(context, getEndpoint().getSubject(),
                         
ofNullable(getEndpoint().getFrom()).orElse(getEndpoint().getConfiguration().getServer()));
             }
-
             ApplicationEDIEntity ediEntity
-                    = HttpMessageUtils.extractEdiPayload(request, 
as2ServerConnection.getDecryptingPrivateKey());
+                    = HttpMessageUtils.extractEdiPayload(request,
+                            new HttpMessageUtils.DecrpytingAndSigningInfo(
+                                    
as2ServerConnection.getValidateSigningCertificateChain(),
+                                    
as2ServerConnection.getDecryptingPrivateKey()));
 
             // 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/internal/AS2ConnectionHelper.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
index 13f5146ef18..da1b01e2eb4 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
@@ -73,7 +73,8 @@ public final class AS2ConnectionHelper {
                         configuration.getAs2Version(), 
configuration.getServer(),
                         configuration.getServerFqdn(), 
configuration.getServerPortNumber(), configuration.getSigningAlgorithm(),
                         configuration.getSigningCertificateChain(), 
configuration.getSigningPrivateKey(),
-                        configuration.getDecryptingPrivateKey(), 
configuration.getMdnMessageTemplate());
+                        configuration.getDecryptingPrivateKey(), 
configuration.getMdnMessageTemplate(),
+                        configuration.getValidateSigningCertificateChain());
                 serverConnections.put(configuration.getServerPortNumber(), 
serverConnection);
             }
             return serverConnection;
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
index f055938ca76..bb3eec87c38 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIT.java
@@ -24,9 +24,7 @@ import java.security.SecureRandom;
 import java.security.Security;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.CamelException;
@@ -43,7 +41,6 @@ import org.apache.camel.component.as2.api.AS2MimeType;
 import org.apache.camel.component.as2.api.AS2ServerConnection;
 import org.apache.camel.component.as2.api.AS2ServerManager;
 import org.apache.camel.component.as2.api.AS2SignatureAlgorithm;
-import org.apache.camel.component.as2.api.AS2SignedDataGenerator;
 import org.apache.camel.component.as2.api.entity.AS2DispositionModifier;
 import org.apache.camel.component.as2.api.entity.AS2DispositionType;
 import 
org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity;
@@ -60,6 +57,7 @@ import org.apache.camel.component.as2.api.util.EntityUtils;
 import org.apache.camel.component.as2.api.util.HttpMessageUtils;
 import org.apache.camel.component.as2.api.util.MicUtils;
 import org.apache.camel.component.as2.api.util.MicUtils.ReceivedContentMic;
+import org.apache.camel.component.as2.api.util.SigningUtils;
 import org.apache.camel.component.as2.internal.AS2ApiCollection;
 import org.apache.camel.component.as2.internal.AS2ClientManagerApiMethod;
 import org.apache.camel.http.common.HttpMessage;
@@ -79,21 +77,10 @@ import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.protocol.HttpDateGenerator;
 import org.apache.http.protocol.HttpRequestHandler;
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.cms.AttributeTable;
-import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
-import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
-import org.bouncycastle.asn1.smime.SMIMECapability;
-import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
-import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
 import org.bouncycastle.cms.jcajce.ZlibExpanderProvider;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -164,63 +151,14 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
     private static final String REPORTING_UA = "Server Responding with MDN";
 
     private static AS2ServerConnection serverConnection;
-    private static KeyPair serverSigningKP;
-    private static List<X509Certificate> serverCertList;
+    private static KeyPair serverKP;
+    private static X509Certificate serverCert;
     private static RequestHandler requestHandler;
 
     private static final HttpDateGenerator DATE_GENERATOR = new 
HttpDateGenerator();
 
-    private KeyPair issueKP;
-    private X509Certificate issueCert;
-
-    private KeyPair signingKP;
-    private KeyPair decryptingKP;
-    private X509Certificate signingCert;
-    private List<X509Certificate> certList;
-    private AS2SignedDataGenerator gen;
-
-    @Override
-    @BeforeEach
-    public void setUp() throws Exception {
-        super.setUp();
-        Security.addProvider(new BouncyCastleProvider());
-
-        setupKeysAndCertificates();
-
-        // Create and populate certificate store.
-        JcaCertStore certs = new JcaCertStore(certList);
-
-        // Create capabilities vector
-        SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
-        capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
-        capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
-        capabilities.addCapability(SMIMECapability.dES_CBC);
-
-        // Create signing attributes
-        ASN1EncodableVector attributes = new ASN1EncodableVector();
-        attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(
-                new IssuerAndSerialNumber(new 
X500Name(signingCert.getIssuerDN().getName()), signingCert.getSerialNumber())));
-        attributes.add(new SMIMECapabilitiesAttribute(capabilities));
-
-        for (String signingAlgorithmName : AS2SignedDataGenerator
-                
.getSupportedSignatureAlgorithmNamesForKey(signingKP.getPrivate())) {
-            try {
-                this.gen = new AS2SignedDataGenerator();
-                this.gen.addSignerInfoGenerator(new 
JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC")
-                        .setSignedAttributeGenerator(new 
AttributeTable(attributes))
-                        .build(signingAlgorithmName, signingKP.getPrivate(), 
signingCert));
-                this.gen.addCertificates(certs);
-                break;
-            } catch (Exception e) {
-                this.gen = null;
-                continue;
-            }
-        }
-
-        if (this.gen == null) {
-            throw new Exception("failed to create signing generator");
-        }
-    }
+    private static KeyPair clientKeyPair;
+    private static X509Certificate clientCert;
 
     @Test
     public void plainMessageSendTest() throws Exception {
@@ -409,7 +347,7 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         // parameter type is 
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm
         headers.put("CamelAS2.encryptingAlgorithm", 
AS2EncryptionAlgorithm.AES128_CBC);
         // parameter type is java.security.cert.Certificate[]
-        headers.put("CamelAS2.encryptingCertificateChain", certList);
+        headers.put("CamelAS2.encryptingCertificateChain", new Certificate[] { 
clientCert });
         // parameter type is String
         headers.put("CamelAS2.attachedFileName", "");
 
@@ -428,7 +366,7 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         assertTrue(entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity,
                 "Request body does not contain ApplicationPkcs7Mime entity");
         MimeEntity envelopeEntity
-                = ((ApplicationPkcs7MimeEnvelopedDataEntity) 
entity).getEncryptedEntity(decryptingKP.getPrivate());
+                = ((ApplicationPkcs7MimeEnvelopedDataEntity) 
entity).getEncryptedEntity(clientKeyPair.getPrivate());
         assertTrue(envelopeEntity instanceof ApplicationEDIEntity, "Enveloped 
entity is not an EDI entity");
         String ediMessage = ((ApplicationEDIEntity) 
envelopeEntity).getEdiMessage();
         assertEquals(EDI_MESSAGE.replaceAll("[\n\r]", ""), 
ediMessage.replaceAll("[\n\r]", ""), "EDI message is different");
@@ -499,9 +437,9 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         // parameter type is 
org.apache.camel.component.as2.api.AS2SignatureAlgorithm
         headers.put("CamelAS2.signingAlgorithm", 
AS2SignatureAlgorithm.SHA512WITHRSA);
         // parameter type is java.security.cert.Certificate[]
-        headers.put("CamelAS2.signingCertificateChain", certList.toArray(new 
Certificate[0]));
+        headers.put("CamelAS2.signingCertificateChain", new Certificate[] { 
clientCert });
         // parameter type is java.security.PrivateKey
-        headers.put("CamelAS2.signingPrivateKey", signingKP.getPrivate());
+        headers.put("CamelAS2.signingPrivateKey", clientKeyPair.getPrivate());
         // parameter type is String
         headers.put("CamelAS2.dispositionNotificationTo", "[email protected]");
         // parameter type is String[]
@@ -546,7 +484,8 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         assertNotNull(responseEntity, "Response entity");
         assertTrue(responseEntity instanceof MultipartSignedEntity, 
"Unexpected response entity type");
         MultipartSignedEntity responseSignedEntity = (MultipartSignedEntity) 
responseEntity;
-        assertTrue(responseSignedEntity.isValid(), "Signature for response 
entity is invalid");
+        assertTrue(SigningUtils.isValid(responseSignedEntity, new 
Certificate[] { serverCert }),
+                "Signature for response entity is invalid");
         MimeEntity responseSignedDataEntity = 
responseSignedEntity.getSignedDataEntity();
         assertTrue(responseSignedDataEntity instanceof 
DispositionNotificationMultipartReportEntity,
                 "Signed entity wrong type");
@@ -579,7 +518,8 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
 
         ReceivedContentMic receivedContentMic = 
messageDispositionNotificationEntity.getReceivedContentMic();
         ReceivedContentMic computedContentMic
-                = 
MicUtils.createReceivedContentMic((HttpEntityEnclosingRequest) request, 
decryptingKP.getPrivate());
+                = 
MicUtils.createReceivedContentMic((HttpEntityEnclosingRequest) request, new 
Certificate[] { clientCert },
+                        clientKeyPair.getPrivate());
         assertEquals(computedContentMic.getEncodedMessageDigest(), 
receivedContentMic.getEncodedMessageDigest(),
                 "Received content MIC does not match computed");
     }
@@ -651,7 +591,8 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         assertNotNull(responseEntity, "Response entity");
         assertTrue(responseEntity instanceof MultipartSignedEntity, 
"Unexpected response entity type");
         MultipartSignedEntity responseSignedEntity = (MultipartSignedEntity) 
responseEntity;
-        assertTrue(responseSignedEntity.isValid(), "Signature for response 
entity is invalid");
+        assertTrue(SigningUtils.isValid(responseSignedEntity, new 
Certificate[] { serverCert }),
+                "Signature for response entity is invalid");
         MimeEntity responseSignedDataEntity = 
responseSignedEntity.getSignedDataEntity();
         assertTrue(responseSignedDataEntity instanceof 
DispositionNotificationMultipartReportEntity,
                 "Signed entity wrong type");
@@ -684,7 +625,8 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
 
         ReceivedContentMic receivedContentMic = 
messageDispositionNotificationEntity.getReceivedContentMic();
         ReceivedContentMic computedContentMic
-                = 
MicUtils.createReceivedContentMic((HttpEntityEnclosingRequest) request, 
decryptingKP.getPrivate());
+                = 
MicUtils.createReceivedContentMic((HttpEntityEnclosingRequest) request, new 
Certificate[] { clientCert },
+                        clientKeyPair.getPrivate());
         assertEquals(computedContentMic.getEncodedMessageDigest(), 
receivedContentMic.getEncodedMessageDigest(),
                 "Received content MIC does not match computed");
     }
@@ -698,7 +640,7 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
     private void runAsyncMDNTest() throws CamelException, HttpException {
         AS2AsynchronousMDNManager mdnManager = new AS2AsynchronousMDNManager(
                 AS2_VERSION, ORIGIN_SERVER_NAME, SERVER_FQDN,
-                certList.toArray(new X509Certificate[0]), 
signingKP.getPrivate());
+                new Certificate[] { clientCert }, clientKeyPair.getPrivate());
 
         // Create plain edi request message to acknowledge
         ApplicationEDIEntity ediEntity = 
EntityUtils.createEDIEntity(EDI_MESSAGE,
@@ -733,7 +675,7 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
                 request,
                 response, 
DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY, 
AS2DispositionType.PROCESSED,
                 dispositionModifier, failureFields, errorFields, 
warningFields, extensionFields, null, "boundary",
-                true, serverSigningKP.getPrivate(), "Got your message!");
+                true, serverKP.getPrivate(), "Got your message!", new 
Certificate[] { clientCert });
 
         // Send MDN
         @SuppressWarnings("unused")
@@ -743,6 +685,7 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
     @BeforeAll
     public static void setupTest() throws Exception {
         setupServerKeysAndCertificates();
+        setupClientKeysAndCertificates();
         receiveTestMessages();
     }
 
@@ -803,11 +746,15 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
                     }
                 };
                 // test route for send
-                from("direct://SEND").to("as2://" + PATH_PREFIX + 
"/send?inBody=ediMessage");
+                from("direct://SEND")
+                        .to("as2://" + PATH_PREFIX + 
"/send?inBody=ediMessage&httpSocketTimeout=5m&httpConnectionTimeout=5m");
 
                 // test route for send2
-                from("direct://SEND2").toF("as2://" + PATH_PREFIX + 
"/send?inBody=ediMessage&as2From=%s&as2To=%s", AS2_NAME,
-                        AS2_NAME);
+                from("direct://SEND2")
+                        .toF("as2://" + PATH_PREFIX
+                             + 
"/send?inBody=ediMessage&as2From=%s&as2To=%s&httpSocketTimeout=5m&httpConnectionTimeout=5m",
+                                AS2_NAME,
+                                AS2_NAME);
 
                 from("jetty:http://localhost:"; + MDN_TARGET_PORT + 
"/handle-receipts").process(proc);
 
@@ -834,27 +781,21 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         // certificate we sign against
         //
         String signingDN = "CN=William J. Collins, [email protected], 
O=Punkhorn Software, C=US";
-        serverSigningKP = kpg.generateKeyPair();
-        X509Certificate signingCert = Utils.makeCertificate(
-                serverSigningKP, signingDN, issueKP, issueDN);
-
-        serverCertList = new ArrayList<>();
-
-        serverCertList.add(signingCert);
-        serverCertList.add(issueCert);
+        serverKP = kpg.generateKeyPair();
+        serverCert = Utils.makeCertificate(serverKP, signingDN, issueKP, 
issueDN);
     }
 
     private static void receiveTestMessages() throws IOException {
         serverConnection = new AS2ServerConnection(
                 AS2_VERSION, ORIGIN_SERVER_NAME,
                 SERVER_FQDN, PARTNER_TARGET_PORT, 
AS2SignatureAlgorithm.SHA256WITHRSA,
-                serverCertList.toArray(new Certificate[0]), 
serverSigningKP.getPrivate(), serverSigningKP.getPrivate(),
-                MDN_MESSAGE_TEMPLATE);
+                new Certificate[] { serverCert }, serverKP.getPrivate(), 
serverKP.getPrivate(),
+                MDN_MESSAGE_TEMPLATE, new Certificate[] { clientCert });
         requestHandler = new RequestHandler();
         serverConnection.listen("/", requestHandler);
     }
 
-    private void setupKeysAndCertificates() throws Exception {
+    private static void setupClientKeysAndCertificates() throws Exception {
         //
         // set up our certificates
         //
@@ -863,24 +804,15 @@ public class AS2ClientManagerIT extends 
AbstractAS2ITSupport {
         kpg.initialize(1024, new SecureRandom());
 
         String issueDN = "O=Punkhorn Software, C=US";
-        issueKP = kpg.generateKeyPair();
-        issueCert = Utils.makeCertificate(
+        KeyPair issueKP = kpg.generateKeyPair();
+        X509Certificate issueCert = Utils.makeCertificate(
                 issueKP, issueDN, issueKP, issueDN);
 
         //
         // certificate we sign against
         //
         String signingDN = "CN=William J. Collins, [email protected], 
O=Punkhorn Software, C=US";
-        signingKP = kpg.generateKeyPair();
-        signingCert = Utils.makeCertificate(
-                signingKP, signingDN, issueKP, issueDN);
-
-        certList = new ArrayList<>();
-
-        certList.add(signingCert);
-        certList.add(issueCert);
-
-        // keys used to encrypt/decrypt
-        decryptingKP = signingKP;
+        clientKeyPair = kpg.generateKeyPair();
+        clientCert = Utils.makeCertificate(clientKeyPair, signingDN, issueKP, 
issueDN);
     }
 }
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIT.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIT.java
index 3aab83ffeef..6d33a2b4a2d 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIT.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIT.java
@@ -289,7 +289,100 @@ public class AS2ServerManagerIT extends 
AbstractAS2ITSupport {
         assertFalse(signatureEntity.isMainBody(), "First mime type set as main 
body of request");
 
         // Validate Signature
-        assertTrue(signedEntity.isValid(), "Signature is invalid");
+        assertTrue(SigningUtils.isValid(signedEntity, new Certificate[] { 
signingCert }), "Signature is invalid");
+
+        String rcvdMessage = message.getBody(String.class);
+        assertEquals(EDI_MESSAGE.replaceAll("[\n\r]", ""), 
rcvdMessage.replaceAll("[\n\r]", ""),
+                "Unexpected content for enveloped mime part");
+    }
+
+    @Test
+    public void receiveMultipartInvalidSignedMessageTest() throws Exception {
+
+        AS2ClientConnection clientConnection
+                = new AS2ClientConnection(
+                        AS2_VERSION, USER_AGENT, CLIENT_FQDN, TARGET_HOST, 
TARGET_PORT, HTTP_SOCKET_TIMEOUT,
+                        HTTP_CONNECTION_TIMEOUT, HTTP_CONNECTION_POOL_SIZE, 
HTTP_CONNECTION_POOL_TTL);
+        AS2ClientManager clientManager = new 
AS2ClientManager(clientConnection);
+
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
+
+        kpg.initialize(1024, new SecureRandom());
+        String hackerIssueDN = "O=Hackers Unlimited Ltd., C=US";
+        var hackerIssueKP = kpg.generateKeyPair();
+        var hackerissueCert = Utils.makeCertificate(
+                hackerIssueKP, hackerIssueDN, hackerIssueKP, hackerIssueDN);
+        String hackerSigningDN = "CN=John Doe, [email protected], O=Self 
Signed, C=US";
+        var hackerSigningKP = kpg.generateKeyPair();
+        var hackerSigningCert = Utils.makeCertificate(
+                hackerSigningKP, hackerSigningDN, hackerIssueKP, 
hackerIssueDN);
+
+        clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, 
AS2_NAME, AS2MessageStructure.SIGNED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, 
StandardCharsets.US_ASCII), null,
+                AS2SignatureAlgorithm.SHA256WITHRSA,
+                new Certificate[] { hackerSigningCert }, 
hackerSigningKP.getPrivate(), null, DISPOSITION_NOTIFICATION_TO,
+                SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs");
+        mockEndpoint.expectedMinimumMessageCount(1);
+        mockEndpoint.setResultWaitTime(TimeUnit.MILLISECONDS.convert(30, 
TimeUnit.SECONDS));
+        mockEndpoint.assertIsSatisfied();
+
+        final List<Exchange> exchanges = mockEndpoint.getExchanges();
+        assertNotNull(exchanges, "listen result");
+        assertFalse(exchanges.isEmpty(), "listen result");
+        LOG.debug("poll result: " + exchanges);
+
+        Exchange exchange = exchanges.get(0);
+        Message message = exchange.getIn();
+        assertNotNull(message, "exchange message");
+        HttpCoreContext coreContext = 
exchange.getProperty(AS2Constants.AS2_INTERCHANGE, HttpCoreContext.class);
+        assertNotNull(coreContext, "context");
+        HttpRequest request = coreContext.getRequest();
+        assertNotNull(request, "request");
+        assertEquals(METHOD, request.getRequestLine().getMethod(), "Unexpected 
method value");
+        assertEquals(REQUEST_URI, request.getRequestLine().getUri(), 
"Unexpected request URI value");
+        assertEquals(HttpVersion.HTTP_1_1, 
request.getRequestLine().getProtocolVersion(), "Unexpected HTTP version value");
+
+        assertEquals(SUBJECT, 
request.getFirstHeader(AS2Header.SUBJECT).getValue(), "Unexpected subject 
value");
+        assertEquals(FROM, request.getFirstHeader(AS2Header.FROM).getValue(), 
"Unexpected from value");
+        assertEquals(AS2_VERSION, 
request.getFirstHeader(AS2Header.AS2_VERSION).getValue(), "Unexpected AS2 
version value");
+        assertEquals(AS2_NAME, 
request.getFirstHeader(AS2Header.AS2_FROM).getValue(), "Unexpected AS2 from 
value");
+        assertEquals(AS2_NAME, 
request.getFirstHeader(AS2Header.AS2_TO).getValue(), "Unexpected AS2 to value");
+        
assertTrue(request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN
 + ">"),
+                "Unexpected message id value");
+        assertEquals(TARGET_HOST + ":" + TARGET_PORT, 
request.getFirstHeader(AS2Header.TARGET_HOST).getValue(),
+                "Unexpected target host value");
+        assertEquals(USER_AGENT, 
request.getFirstHeader(AS2Header.USER_AGENT).getValue(), "Unexpected user agent 
value");
+        assertNotNull(request.getFirstHeader(AS2Header.DATE), "Date value 
missing");
+        assertNotNull(request.getFirstHeader(AS2Header.CONTENT_LENGTH), 
"Content length value missing");
+        
assertTrue(request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MediaType.MULTIPART_SIGNED),
+                "Unexpected content type for message");
+
+        assertTrue(request instanceof BasicHttpEntityEnclosingRequest, 
"Request does not contain entity");
+        HttpEntity entity = ((BasicHttpEntityEnclosingRequest) 
request).getEntity();
+        assertNotNull(entity, "Request does not contain entity");
+        assertTrue(entity instanceof MultipartSignedEntity, "Unexpected 
request entity type");
+        MultipartSignedEntity signedEntity = (MultipartSignedEntity) entity;
+        assertTrue(signedEntity.isMainBody(), "Entity not set as main body of 
request");
+        assertEquals(2, signedEntity.getPartCount(), "Request contains invalid 
number of mime parts");
+
+        // Validated first mime part.
+        assertTrue(signedEntity.getPart(0) instanceof 
ApplicationEDIFACTEntity, "First mime part incorrect type ");
+        ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) 
signedEntity.getPart(0);
+        
assertTrue(ediEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_EDIFACT),
+                "Unexpected content type for first mime part");
+        assertFalse(ediEntity.isMainBody(), "First mime type set as main body 
of request");
+
+        // Validate second mime part.
+        assertTrue(signedEntity.getPart(1) instanceof 
ApplicationPkcs7SignatureEntity, "Second mime part incorrect type ");
+        ApplicationPkcs7SignatureEntity signatureEntity = 
(ApplicationPkcs7SignatureEntity) signedEntity.getPart(1);
+        
assertTrue(signatureEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_PKCS7_SIGNATURE),
+                "Unexpected content type for second mime part");
+        assertFalse(signatureEntity.isMainBody(), "First mime type set as main 
body of request");
+
+        // Validate Signature
+        assertFalse(SigningUtils.isValid(signedEntity, new Certificate[] { 
signingCert }), "Signature must be invalid");
 
         String rcvdMessage = message.getBody(String.class);
         assertEquals(EDI_MESSAGE.replaceAll("[\n\r]", ""), 
rcvdMessage.replaceAll("[\n\r]", ""),


Reply via email to