You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2018/09/27 06:47:41 UTC

[camel] branch master updated: [CAMEL-12605] Added support for encrypted and signed AS2 message

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

acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new 2233a6a  [CAMEL-12605] Added support for encrypted and signed AS2 message
2233a6a is described below

commit 2233a6a98a7fc23de6e451390c11f40c5d9d59f5
Author: William Collins <pu...@gmail.com>
AuthorDate: Wed Sep 26 14:27:25 2018 -0400

    [CAMEL-12605] Added support for encrypted and signed AS2 message
---
 .../camel/component/as2/api/AS2ClientManager.java  |  37 ++++---
 .../component/as2/api/entity/EntityParser.java     |   2 +-
 .../as2/api/entity/MultipartMimeEntity.java        |   4 +
 .../as2/api/entity/MultipartSignedEntity.java      |   9 +-
 .../camel/component/as2/api/AS2MessageTest.java    | 116 +++++++++++++++++----
 5 files changed, 126 insertions(+), 42 deletions(-)

diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
index c99f341..5865efa 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
@@ -29,8 +29,10 @@ import org.apache.camel.component.as2.api.util.EntityUtils;
 import org.apache.camel.component.as2.api.util.SigningUtils;
 import org.apache.http.HttpException;
 import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
 import org.apache.http.entity.ContentType;
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.util.Args;
 import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
@@ -252,31 +254,38 @@ public class AS2ClientManager {
             throw new HttpException("Failed to create EDI message entity", e);
         }
         switch (as2MessageStructure) {
-        case PLAIN:
+        case PLAIN: {
             applicationEDIEntity.setMainBody(true);
             EntityUtils.setMessageEntity(request, applicationEDIEntity);
             break;
-        case SIGNED:
+        }
+        case SIGNED: {
             AS2SignedDataGenerator gen = createSigningGenerator(httpContext);
             // Create Multipart Signed Entity
-            try {
-                MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, gen,
-                        AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, null);
-                multipartSignedEntity.setMainBody(true);
-                EntityUtils.setMessageEntity(request, multipartSignedEntity);
-            } catch (Exception e) {
-                throw new HttpException("Failed to sign message", e);
-            }
+            MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, gen,
+                    AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, null);
+            multipartSignedEntity.setMainBody(true);
+            EntityUtils.setMessageEntity(request, multipartSignedEntity);
             break;
-        case ENCRYPTED:
+        }
+        case ENCRYPTED: {
             CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
             OutputEncryptor encryptor = createEncryptor(httpContext);
             ApplicationPkcs7MimeEntity pkcs7MimeEntity = new ApplicationPkcs7MimeEntity(applicationEDIEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
             EntityUtils.setMessageEntity(request, pkcs7MimeEntity);
             break;
-        case ENCRYPTED_SIGNED:
-            // TODO : Add code here to add application/pkcs7-mime entity when encryption facility available.
+        }
+        case ENCRYPTED_SIGNED: {
+            AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity,
+                    signingGenrator, AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, false, null);
+             
+            CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext);
+            OutputEncryptor encryptor = createEncryptor(httpContext);
+            ApplicationPkcs7MimeEntity pkcs7MimeEntity = new ApplicationPkcs7MimeEntity(multipartSignedEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true);
+            EntityUtils.setMessageEntity(request, pkcs7MimeEntity);
             break;
+        }
         default:
             throw new HttpException("Unknown AS2 Message Structure");
         }
@@ -292,7 +301,7 @@ public class AS2ClientManager {
         httpContext.setAttribute(HTTP_RESPONSE, response);
         return httpContext;
     }
-
+    
     public AS2SignedDataGenerator createSigningGenerator(HttpCoreContext httpContext) throws HttpException {
 
         Certificate[] certificateChain = httpContext.getAttribute(SIGNING_CERTIFICATE_CHAIN, Certificate[].class);
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
index fcb2431..aaf12e8 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
@@ -171,7 +171,7 @@ public final class EntityParser {
             throw new HttpException("Failed to read start boundary for body part", e);
         }
 
-        if (!foundEndBoundary) {
+        if (!foundEndBoundary && boundary != null) {
             throw new HttpException("Failed to find start boundary for body part");
         }
 
diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java
index 2b206f3..03f5835 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java
@@ -55,6 +55,10 @@ public abstract class MultipartMimeEntity extends MimeEntity {
 
     protected MultipartMimeEntity() {
     }
+    
+    public String getBoundary() {
+        return boundary;
+    }
 
     public void addPart(MimeEntity part) {
         parts.add(part);
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 6869b5f..3b0a6d2 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
@@ -22,10 +22,8 @@ import java.io.InputStream;
 import java.security.cert.X509Certificate;
 import java.util.Collection;
 
-import org.apache.camel.component.as2.api.AS2Header;
 import org.apache.camel.component.as2.api.AS2SignedDataGenerator;
-import org.apache.http.entity.ContentType;
-import org.apache.http.message.BasicHeader;
+import org.apache.http.HttpException;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
 import org.bouncycastle.cms.CMSProcessable;
@@ -38,10 +36,9 @@ import org.bouncycastle.util.Store;
 
 public class MultipartSignedEntity extends MultipartMimeEntity {
 
-    public MultipartSignedEntity(MimeEntity data, AS2SignedDataGenerator signer, String signatureCharSet, String signatureTransferEncoding, boolean isMainBody, String boundary) throws Exception {
+    public MultipartSignedEntity(MimeEntity data, AS2SignedDataGenerator signer, String signatureCharSet, String signatureTransferEncoding, boolean isMainBody, String boundary) throws HttpException {
         super(null, isMainBody, boundary);
-        ContentType contentType = signer.createMultipartSignedContentType(this.boundary);
-        this.contentType = new BasicHeader(AS2Header.CONTENT_TYPE, contentType.toString());
+        setContentType(signer.createMultipartSignedContentType(this.boundary));
         addPart(data);
         ApplicationPkcs7SignatureEntity signature = new ApplicationPkcs7SignatureEntity(data, signer, signatureCharSet, signatureTransferEncoding, false);
         addPart(signature);
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 d9d3338..7d181aa 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
@@ -366,105 +366,105 @@ public class AS2MessageTest {
 
     @Test
     public void aes128CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES128_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES128_CBC);
     }
     
     @Test
     public void aes192CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES192_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES192_CBC);
     }
     
     @Test
     public void aes256CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES256_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES256_CBC);
     }
     
     @Test
     public void aes128CcmEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES128_CCM);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES128_CCM);
     }
     
     @Test
     public void aes192CcmEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES192_CCM);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES192_CCM);
     }
     
     @Test
     public void aes256CcmEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES256_CCM);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES256_CCM);
     }
     
     @Test
     public void aes128GcmEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES128_GCM);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES128_GCM);
     }
     
     @Test
     public void aes192GcmEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES192_GCM);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES192_GCM);
     }
     
     @Test
     public void aes256GcmEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.AES256_GCM);
+        envelopedMessageTest(AS2EncryptionAlgorithm.AES256_GCM);
     }
     
     @Test
     public void camellia128CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.CAMELLIA128_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.CAMELLIA128_CBC);
     }
     
     @Test
     public void camellia192CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.CAMELLIA192_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.CAMELLIA192_CBC);
     }
     
     @Test
     public void camellia256CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.CAMELLIA256_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.CAMELLIA256_CBC);
     }
     
     @Test
     public void cast5CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.CAST5_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.CAST5_CBC);
     }
     
     @Test
     public void desCbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.DES_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.DES_CBC);
     }
     
     @Test
     public void desEde3CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.DES_EDE3_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.DES_EDE3_CBC);
     }
     
     @Test
     public void cost28147GcfbEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.GOST28147_GCFB);
+        envelopedMessageTest(AS2EncryptionAlgorithm.GOST28147_GCFB);
     }
     
     @Test
     public void ideaCbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.IDEA_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.IDEA_CBC);
     }
     
     @Test
     public void rc2CbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.RC2_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.RC2_CBC);
     }
     
     @Test
     public void rc4EnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.RC4);
+        envelopedMessageTest(AS2EncryptionAlgorithm.RC4);
     }
     
     @Test
     public void seedCbcEnvelopedMessageTest() throws Exception {
-        envelopeddMessageTest(AS2EncryptionAlgorithm.SEED_CBC);
+        envelopedMessageTest(AS2EncryptionAlgorithm.SEED_CBC);
     }
 
-    public void envelopeddMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) throws Exception {
+    public void envelopedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) throws Exception {
         AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN,
                 TARGET_HOST, TARGET_PORT);
         AS2ClientManager clientManager = new AS2ClientManager(clientConnection);
@@ -520,6 +520,80 @@ public class AS2MessageTest {
     }
 
     @Test
+    public void aes128CbcEnvelopedAndSignedMessageTest() throws Exception {
+        envelopedAndSignedMessageTest(AS2EncryptionAlgorithm.AES128_CBC);
+    }
+    
+    public void envelopedAndSignedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) throws Exception {
+        AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN,
+                TARGET_HOST, TARGET_PORT);
+        AS2ClientManager clientManager = new AS2ClientManager(clientConnection);
+        
+        LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
+
+        HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
+                AS2MessageStructure.ENCRYPTED_SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
+                null, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO,
+                SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, certList.toArray(new Certificate[0]),
+                signingKP.getPrivate());
+
+        HttpRequest request = httpContext.getRequest();
+        assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod());
+        assertEquals("Unexpected request URI value", REQUEST_URI, request.getRequestLine().getUri());
+        assertEquals("Unexpected HTTP version value", HttpVersion.HTTP_1_1,
+                request.getRequestLine().getProtocolVersion());
+
+        assertEquals("Unexpected subject value", SUBJECT, request.getFirstHeader(AS2Header.SUBJECT).getValue());
+        assertEquals("Unexpected from value", FROM, request.getFirstHeader(AS2Header.FROM).getValue());
+        assertEquals("Unexpected AS2 version value", AS2_VERSION,
+                request.getFirstHeader(AS2Header.AS2_VERSION).getValue());
+        assertEquals("Unexpected AS2 from value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_FROM).getValue());
+        assertEquals("Unexpected AS2 to value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_TO).getValue());
+        assertTrue("Unexpected message id value",
+                request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN + ">"));
+        assertEquals("Unexpected target host value", TARGET_HOST + ":" + TARGET_PORT,
+                request.getFirstHeader(AS2Header.TARGET_HOST).getValue());
+        assertEquals("Unexpected user agent value", USER_AGENT,
+                request.getFirstHeader(AS2Header.USER_AGENT).getValue());
+        assertNotNull("Date value missing", request.getFirstHeader(AS2Header.DATE));
+        assertNotNull("Content length value missing", request.getFirstHeader(AS2Header.CONTENT_LENGTH));
+        assertTrue("Unexpected content type for message",
+                request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME));
+
+        assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest);
+        HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity();
+        assertNotNull("Request does not contain entity", entity);
+        assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEntity);
+        ApplicationPkcs7MimeEntity envelopedEntity = (ApplicationPkcs7MimeEntity) entity;
+        assertTrue("Entity not set as main body of request", envelopedEntity.isMainBody());
+
+        // Validated enveloped part.
+        MimeEntity encryptedEntity = envelopedEntity.getEncryptedEntity(signingKP.getPrivate());
+        assertTrue("Enveloped mime part incorrect type ", encryptedEntity instanceof MultipartSignedEntity);
+        MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) encryptedEntity;
+        assertTrue("Unexpected content type for enveloped mime part",
+                multipartSignedEntity.getContentType().getValue().startsWith(AS2MediaType.MULTIPART_SIGNED));
+        assertFalse("Enveloped mime type set as main body of request", multipartSignedEntity.isMainBody());
+        assertTrue("Request contains invalid number of mime parts", multipartSignedEntity.getPartCount() == 2);
+
+        // Validated first mime part.
+        assertTrue("First mime part incorrect type ", multipartSignedEntity.getPart(0) instanceof ApplicationEDIFACTEntity);
+        ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) multipartSignedEntity.getPart(0);
+        assertTrue("Unexpected content type for first mime part",
+                ediEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_EDIFACT));
+        assertFalse("First mime type set as main body of request", ediEntity.isMainBody());
+
+        // Validate second mime part.
+        assertTrue("Second mime part incorrect type ",
+                multipartSignedEntity.getPart(1) instanceof ApplicationPkcs7SignatureEntity);
+        ApplicationPkcs7SignatureEntity signatureEntity = (ApplicationPkcs7SignatureEntity) multipartSignedEntity.getPart(1);
+        assertTrue("Unexpected content type for second mime part",
+                signatureEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_PKCS7_SIGNATURE));
+        assertFalse("First mime type set as main body of request", signatureEntity.isMainBody());
+
+    }
+
+    @Test
     public void signatureVerificationTest() throws Exception {
         AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN,
                 TARGET_HOST, TARGET_PORT);