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 fa87236 [CAMEL-12605] Integrated encryption logic into component. fa87236 is described below commit fa87236f78ea0682e64618b80f87e81acc3105f7 Author: William Collins <punkhor...@gmail.com> AuthorDate: Tue Aug 28 11:59:25 2018 -0400 [CAMEL-12605] Integrated encryption logic into component. --- .../camel/component/as2/api/AS2Algorithm.java | 346 +++++++++++++++++++++ .../camel/component/as2/api/AS2ClientManager.java | 59 +++- .../as2/api/entity/ApplicationPkcs7MimeEntity.java | 10 - .../component/as2/api/util/EncryptingUtils.java | 67 ++++ .../camel/component/as2/api/util/SigningUtils.java | 8 +- .../camel/component/as2/api/AS2MessageTest.java | 67 +++- .../component/as2/api/entity/EntityParserTest.java | 120 +++++++ .../src/main/docs/as2-component.adoc | 8 +- .../camel/component/as2/AS2Configuration.java | 41 +++ .../as2/AS2ServerManagerIntegrationTest.java | 4 +- .../as2/springboot/AS2ComponentConfiguration.java | 37 +++ 11 files changed, 739 insertions(+), 28 deletions(-) diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2Algorithm.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2Algorithm.java new file mode 100644 index 0000000..8e71f47 --- /dev/null +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2Algorithm.java @@ -0,0 +1,346 @@ +/** + * 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; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.cms.CMSAlgorithm; + +interface AS2AlgorithmConstants { + static final String DES_CBC = "DES_CBC"; + static final String DES_EDE3_CBC = "DES_EDE3_CBC"; + static final String RC2_CBC = "RC2_CBC"; + static final String IDEA_CBC = "IDEA_CBC"; + static final String CAST5_CBC = "CAST5_CBC"; + static final String AES128_CBC = "AES128_CBC"; + static final String AES192_CBC = "AES192_CBC"; + static final String AES256_CBC = "AES256_CBC"; + static final String AES128_CCM = "AES128_CCM"; + static final String AES192_CCM = "AES192_CCM"; + static final String AES256_CCM = "AES256_CCM"; + static final String AES128_GCM = "AES128_GCM"; + static final String AES192_GCM = "AES192_GCM"; + static final String AES256_GCM = "AES256_GCM"; + static final String CAMELLIA128_CBC = "CAMELLIA128_CBC"; + static final String CAMELLIA192_CBC = "CAMELLIA192_CBC"; + static final String CAMELLIA256_CBC = "CAMELLIA256_CBC"; + static final String GOST28147_GCFB = "GOST28147_GCFB"; + static final String SEED_CBC = "SEED_CBC"; + static final String DES_EDE3_WRAP = "DES_EDE3_WRAP"; + static final String AES128_WRAP = "AES128_WRAP"; + static final String AES192_WRAP = "AES192_WRAP"; + static final String AES256_WRAP = "AES256_WRAP"; + static final String CAMELLIA128_WRAP = "CAMELLIA128_WRAP"; + static final String CAMELLIA192_WRAP = "CAMELLIA192_WRAP"; + static final String CAMELLIA256_WRAP = "CAMELLIA256_WRAP"; + static final String SEED_WRAP = "SEED_WRAP"; + static final String GOST28147_WRAP = "GOST28147_WRAP"; + static final String GOST28147_CRYPTOPRO_WRAP = "GOST28147_CRYPTOPRO_WRAP"; + static final String ECDH_SHA1KDF = "ECDH_SHA1KDF"; + static final String ECCDH_SHA1KDF = "ECCDH_SHA1KDF"; + static final String ECMQV_SHA1KDF = "ECMQV_SHA1KDF"; + static final String ECDH_SHA224KDF = "ECDH_SHA224KDF"; + static final String ECCDH_SHA224KDF = "ECCDH_SHA224KDF"; + static final String ECMQV_SHA224KDF = "ECMQV_SHA224KDF"; + static final String ECDH_SHA256KDF = "ECDH_SHA256KDF"; + static final String ECCDH_SHA256KDF = "ECCDH_SHA256KDF"; + static final String ECMQV_SHA256KDF = "ECMQV_SHA256KDF"; + static final String ECDH_SHA384KDF = "ECDH_SHA384KDF"; + static final String ECCDH_SHA384KDF = "ECCDH_SHA384KDF"; + static final String ECMQV_SHA384KDF = "ECMQV_SHA384KDF"; + static final String ECDH_SHA512KDF = "ECDH_SHA512KDF"; + static final String ECCDH_SHA512KDF = "ECCDH_SHA512KDF"; + static final String ECMQV_SHA512KDF = "ECMQV_SHA512KDF"; + static final String ECDHGOST3410_2001 = "ECDHGOST3410_2001"; + static final String ECDHGOST3410_2012_256 = "ECDHGOST3410_2012_256"; + static final String ECDHGOST3410_2012_512 = "ECDHGOST3410_2012_512"; + static final String SHA1 = "SHA1"; + static final String SHA224 = "SHA224"; + static final String SHA256 = "SHA256"; + static final String SHA384 = "SHA384"; + static final String SHA512 = "SHA512"; + static final String MD5 = "MD5"; + static final String GOST3411 = "GOST3411"; + static final String GOST3411_2012_256 = "GOST3411_2012_256"; + static final String GOST3411_2012_512 = "GOST3411_2012_512"; + static final String RIPEMD128 = "RIPEMD128"; + static final String RIPEMD160 = "RIPEMD160"; + static final String RIPEMD256 = "RIPEMD256"; +} + +public enum AS2Algorithm { + DES_CBC(AS2AlgorithmConstants.DES_CBC, CMSAlgorithm.DES_CBC), + DES_EDE3_CBC(AS2AlgorithmConstants.DES_EDE3_CBC, CMSAlgorithm.DES_EDE3_CBC), + RC2_CBC(AS2AlgorithmConstants.RC2_CBC, CMSAlgorithm.RC2_CBC), + IDEA_CBC(AS2AlgorithmConstants.IDEA_CBC, CMSAlgorithm.IDEA_CBC), + CAST5_CBC(AS2AlgorithmConstants.CAST5_CBC, CMSAlgorithm.CAST5_CBC), + AES128_CBC(AS2AlgorithmConstants.AES128_CBC, CMSAlgorithm.AES128_CBC), + AES192_CBC(AS2AlgorithmConstants.AES192_CBC, CMSAlgorithm.AES192_CBC), + AES256_CBC(AS2AlgorithmConstants.AES256_CBC, CMSAlgorithm.AES256_CBC), + AES128_CCM(AS2AlgorithmConstants.AES128_CCM, CMSAlgorithm.AES128_CCM), + AES192_CCM(AS2AlgorithmConstants.AES192_CCM, CMSAlgorithm.AES192_CCM), + AES256_CCM(AS2AlgorithmConstants.AES256_CCM, CMSAlgorithm.AES256_CCM), + AES128_GCM(AS2AlgorithmConstants.AES128_GCM, CMSAlgorithm.AES128_GCM), + AES192_GCM(AS2AlgorithmConstants.AES192_GCM, CMSAlgorithm.AES192_GCM), + AES256_GCM(AS2AlgorithmConstants.AES256_GCM, CMSAlgorithm.AES256_GCM), + CAMELLIA128_CBC(AS2AlgorithmConstants.CAMELLIA128_CBC, CMSAlgorithm.CAMELLIA128_CBC), + CAMELLIA192_CBC(AS2AlgorithmConstants.CAMELLIA192_CBC, CMSAlgorithm.CAMELLIA192_CBC), + CAMELLIA256_CBC(AS2AlgorithmConstants.CAMELLIA256_CBC, CMSAlgorithm.CAMELLIA256_CBC), + GOST28147_GCFB(AS2AlgorithmConstants.GOST28147_GCFB, CMSAlgorithm.GOST28147_GCFB), + SEED_CBC(AS2AlgorithmConstants.SEED_CBC, CMSAlgorithm.SEED_CBC), + DES_EDE3_WRAP(AS2AlgorithmConstants.DES_EDE3_WRAP, CMSAlgorithm.DES_EDE3_WRAP), + AES128_WRAP(AS2AlgorithmConstants.AES128_WRAP, CMSAlgorithm.AES128_WRAP), + AES192_WRAP(AS2AlgorithmConstants.AES192_WRAP, CMSAlgorithm.AES192_WRAP), + AES256_WRAP(AS2AlgorithmConstants.AES256_WRAP, CMSAlgorithm.AES256_WRAP), + CAMELLIA128_WRAP(AS2AlgorithmConstants.CAMELLIA128_WRAP, CMSAlgorithm.CAMELLIA128_WRAP), + CAMELLIA192_WRAP(AS2AlgorithmConstants.CAMELLIA192_WRAP, CMSAlgorithm.CAMELLIA192_WRAP), + CAMELLIA256_WRAP(AS2AlgorithmConstants.CAMELLIA256_WRAP, CMSAlgorithm.CAMELLIA256_WRAP), + SEED_WRAP(AS2AlgorithmConstants.SEED_WRAP, CMSAlgorithm.SEED_WRAP), + GOST28147_WRAP(AS2AlgorithmConstants.GOST28147_WRAP, CMSAlgorithm.GOST28147_WRAP), + GOST28147_CRYPTOPRO_WRAP(AS2AlgorithmConstants.GOST28147_CRYPTOPRO_WRAP, CMSAlgorithm.GOST28147_CRYPTOPRO_WRAP), + ECDH_SHA1KDF(AS2AlgorithmConstants.ECDH_SHA1KDF, CMSAlgorithm.ECDH_SHA1KDF), + ECCDH_SHA1KDF(AS2AlgorithmConstants.ECCDH_SHA1KDF, CMSAlgorithm.ECCDH_SHA1KDF), + ECMQV_SHA1KDF(AS2AlgorithmConstants.ECMQV_SHA1KDF, CMSAlgorithm.ECMQV_SHA1KDF), + ECDH_SHA224KDF(AS2AlgorithmConstants.ECDH_SHA224KDF, CMSAlgorithm.ECDH_SHA224KDF), + ECCDH_SHA224KDF(AS2AlgorithmConstants.ECCDH_SHA224KDF, CMSAlgorithm.ECCDH_SHA224KDF), + ECMQV_SHA224KDF(AS2AlgorithmConstants.ECMQV_SHA224KDF, CMSAlgorithm.ECMQV_SHA224KDF), + ECDH_SHA256KDF(AS2AlgorithmConstants.ECDH_SHA256KDF, CMSAlgorithm.ECDH_SHA256KDF), + ECCDH_SHA256KDF(AS2AlgorithmConstants.ECCDH_SHA256KDF, CMSAlgorithm.ECCDH_SHA256KDF), + ECMQV_SHA256KDF(AS2AlgorithmConstants.ECMQV_SHA256KDF, CMSAlgorithm.ECMQV_SHA256KDF), + ECDH_SHA384KDF(AS2AlgorithmConstants.ECDH_SHA384KDF, CMSAlgorithm.ECDH_SHA384KDF), + ECCDH_SHA384KDF(AS2AlgorithmConstants.ECCDH_SHA384KDF, CMSAlgorithm.ECCDH_SHA384KDF), + ECMQV_SHA384KDF(AS2AlgorithmConstants.ECMQV_SHA384KDF, CMSAlgorithm.ECMQV_SHA384KDF), + ECDH_SHA512KDF(AS2AlgorithmConstants.ECDH_SHA512KDF, CMSAlgorithm.ECDH_SHA512KDF), + ECCDH_SHA512KDF(AS2AlgorithmConstants.ECCDH_SHA512KDF, CMSAlgorithm.ECCDH_SHA512KDF), + ECMQV_SHA512KDF(AS2AlgorithmConstants.ECMQV_SHA512KDF, CMSAlgorithm.ECMQV_SHA512KDF), + ECDHGOST3410_2001(AS2AlgorithmConstants.ECDHGOST3410_2001, CMSAlgorithm.ECDHGOST3410_2001), + ECDHGOST3410_2012_256(AS2AlgorithmConstants.ECDHGOST3410_2012_256, CMSAlgorithm.ECDHGOST3410_2012_256), + ECDHGOST3410_2012_512(AS2AlgorithmConstants.ECDHGOST3410_2012_512, CMSAlgorithm.ECDHGOST3410_2012_512), + SHA1(AS2AlgorithmConstants.SHA1, CMSAlgorithm.SHA1), + SHA224(AS2AlgorithmConstants.SHA224, CMSAlgorithm.SHA224), + SHA256(AS2AlgorithmConstants.SHA256, CMSAlgorithm.SHA256), + SHA384(AS2AlgorithmConstants.SHA384, CMSAlgorithm.SHA384), + SHA512(AS2AlgorithmConstants.SHA512, CMSAlgorithm.SHA512), + MD5(AS2AlgorithmConstants.MD5, CMSAlgorithm.MD5), + GOST3411(AS2AlgorithmConstants.GOST3411, CMSAlgorithm.GOST3411), + GOST3411_2012_256(AS2AlgorithmConstants.GOST3411_2012_256, CMSAlgorithm.GOST3411_2012_256), + GOST3411_2012_512(AS2AlgorithmConstants.GOST3411_2012_512, CMSAlgorithm.GOST3411_2012_512), + RIPEMD128(AS2AlgorithmConstants.RIPEMD128, CMSAlgorithm.RIPEMD128), + RIPEMD160(AS2AlgorithmConstants.RIPEMD160, CMSAlgorithm.RIPEMD160), + RIPEMD256(AS2AlgorithmConstants.RIPEMD256, CMSAlgorithm.RIPEMD256); + + private String algorithmName; + private ASN1ObjectIdentifier algorithmOID; + + private AS2Algorithm(String algorithmName, ASN1ObjectIdentifier algorithmOID) { + this.algorithmName = algorithmName; + this.algorithmOID = algorithmOID; + } + public String getAlgorithmName() { + return algorithmName; + } + public ASN1ObjectIdentifier getAlgorithmOID() { + return algorithmOID; + } + + public static AS2Algorithm getAS2Algorithm(String algorithmName) { + AS2Algorithm as2Algorithm; + switch (algorithmName) { + case "DES_CBC": + as2Algorithm = DES_CBC; + break; + case "DES_EDE3_CBC": + as2Algorithm = DES_EDE3_CBC; + break; + case "RC2_CBC": + as2Algorithm = RC2_CBC; + break; + case "IDEA_CBC": + as2Algorithm = IDEA_CBC; + break; + case "CAST5_CBC": + as2Algorithm = CAST5_CBC; + break; + case "AES128_CBC": + as2Algorithm = AES128_CBC; + break; + case "AES192_CBC": + as2Algorithm = AES192_CBC; + break; + case "AES256_CBC": + as2Algorithm = AES256_CBC; + break; + case "AES128_CCM": + as2Algorithm = AES128_CCM; + break; + case "AES192_CCM": + as2Algorithm = AES192_CCM; + break; + case "AES256_CCM": + as2Algorithm = AES256_CCM; + break; + case "AES128_GCM": + as2Algorithm = AES128_GCM; + break; + case "AES192_GCM": + as2Algorithm = AES192_GCM; + break; + case "AES256_GCM": + as2Algorithm = AES256_GCM; + break; + case "CAMELLIA128_CBC": + as2Algorithm = CAMELLIA128_CBC; + break; + case "CAMELLIA192_CBC": + as2Algorithm = CAMELLIA192_CBC; + break; + case "CAMELLIA256_CBC": + as2Algorithm = CAMELLIA256_CBC; + break; + case "GOST28147_GCFB": + as2Algorithm = GOST28147_GCFB; + break; + case "SEED_CBC": + as2Algorithm = SEED_CBC; + break; + case "DES_EDE3_WRAP": + as2Algorithm = DES_EDE3_WRAP; + break; + case "AES128_WRAP": + as2Algorithm = AES128_WRAP; + break; + case "AES192_WRAP": + as2Algorithm = AES192_WRAP; + break; + case "AES256_WRAP": + as2Algorithm = AES256_WRAP; + break; + case "CAMELLIA128_WRAP": + as2Algorithm = CAMELLIA128_WRAP; + break; + case "CAMELLIA192_WRAP": + as2Algorithm = CAMELLIA192_WRAP; + break; + case "CAMELLIA256_WRAP": + as2Algorithm = CAMELLIA256_WRAP; + break; + case "SEED_WRAP": + as2Algorithm = SEED_WRAP; + break; + case "GOST28147_WRAP": + as2Algorithm = GOST28147_WRAP; + break; + case "GOST28147_CRYPTOPRO_WRAP": + as2Algorithm = GOST28147_CRYPTOPRO_WRAP; + break; + case "ECDH_SHA1KDF": + as2Algorithm = ECDH_SHA1KDF; + break; + case "ECCDH_SHA1KDF": + as2Algorithm = ECCDH_SHA1KDF; + break; + case "ECMQV_SHA1KDF": + as2Algorithm = ECMQV_SHA1KDF; + break; + case "ECDH_SHA224KDF": + as2Algorithm = ECDH_SHA224KDF; + break; + case "ECCDH_SHA224KDF": + as2Algorithm = ECCDH_SHA224KDF; + break; + case "ECMQV_SHA224KDF": + as2Algorithm = ECMQV_SHA224KDF; + break; + case "ECDH_SHA256KDF": + as2Algorithm = ECDH_SHA256KDF; + break; + case "ECCDH_SHA256KDF": + as2Algorithm = ECCDH_SHA256KDF; + break; + case "ECMQV_SHA256KDF": + as2Algorithm = ECMQV_SHA256KDF; + break; + case "ECDH_SHA384KDF": + as2Algorithm = ECDH_SHA384KDF; + break; + case "ECCDH_SHA384KDF": + as2Algorithm = ECCDH_SHA384KDF; + break; + case "ECMQV_SHA384KDF": + as2Algorithm = ECMQV_SHA384KDF; + break; + case "ECDH_SHA512KDF": + as2Algorithm = ECDH_SHA512KDF; + break; + case "ECCDH_SHA512KDF": + as2Algorithm = ECCDH_SHA512KDF; + break; + case "ECMQV_SHA512KDF": + as2Algorithm = ECMQV_SHA512KDF; + break; + case "ECDHGOST3410_2001": + as2Algorithm = ECDHGOST3410_2001; + break; + case "ECDHGOST3410_2012_256": + as2Algorithm = ECDHGOST3410_2012_256; + break; + case "ECDHGOST3410_2012_512": + as2Algorithm = ECDHGOST3410_2012_512; + break; + case "SHA1": + as2Algorithm = SHA1; + break; + case "SHA224": + as2Algorithm = SHA224; + break; + case "SHA256": + as2Algorithm = SHA256; + break; + case "SHA384": + as2Algorithm = SHA384; + break; + case "SHA512": + as2Algorithm = SHA512; + break; + case "MD5": + as2Algorithm = MD5; + break; + case "GOST3411": + as2Algorithm = GOST3411; + break; + case "GOST3411_2012_256": + as2Algorithm = GOST3411_2012_256; + break; + case "GOST3411_2012_512": + as2Algorithm = GOST3411_2012_512; + break; + case "RIPEMD128": + as2Algorithm = RIPEMD128; + break; + case "RIPEMD160": + as2Algorithm = RIPEMD160; + break; + case "RIPEMD256": + as2Algorithm = RIPEMD256; + break; + + default: + throw new IllegalArgumentException("Unsupported algorithm '" + algorithmName + "'"); + } + return as2Algorithm; + } + +} 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 4e22e7b..9c33d9a 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 @@ -21,8 +21,10 @@ import java.security.PrivateKey; import java.security.cert.Certificate; import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity; +import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity; import org.apache.camel.component.as2.api.entity.EntityParser; import org.apache.camel.component.as2.api.entity.MultipartSignedEntity; +import org.apache.camel.component.as2.api.util.EncryptingUtils; import org.apache.camel.component.as2.api.util.EntityUtils; import org.apache.camel.component.as2.api.util.SigningUtils; import org.apache.http.HttpException; @@ -31,6 +33,8 @@ import org.apache.http.entity.ContentType; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.protocol.HttpCoreContext; import org.apache.http.util.Args; +import org.bouncycastle.cms.CMSEnvelopedDataGenerator; +import org.bouncycastle.operator.OutputEncryptor; /** * AS2 Client Manager @@ -135,6 +139,24 @@ public class AS2ClientManager { public static final String SIGNING_PRIVATE_KEY = CAMEL_AS2_CLIENT_PREFIX + "signing-private-key"; /** + * The HTTP Context Attribute containing the algorithm name used to encrypt EDI + * message + */ + public static final String ENCRYPTING_ALGORITHM_NAME = CAMEL_AS2_CLIENT_PREFIX + "encrypting-algorithm-name"; + + /** + * The HTTP Context Attribute containing the certificate used to encrypt + * EDI message + */ + public static final String ENCRYPTING_CERTIFICATE_CHAIN = CAMEL_AS2_CLIENT_PREFIX + "encrypting-certificate-chain"; + + /** + * The HTTP Context Attribute containing the private key used to encrypt EDI + * message + */ + public static final String ENCRYPTING_PRIVATE_KEY = CAMEL_AS2_CLIENT_PREFIX + "encrypting-private-key"; + + /** * The HTTP Context Attribute containing the internet e-mail address of * sending system requesting a message disposition notification. */ @@ -172,6 +194,9 @@ public class AS2ClientManager { * @param signingPrivateKey - the private key used to sign EDI message * @param dispositionNotificationTo - an RFC2822 address to request a receipt or <code>null</code> if no receipt requested * @param signedReceiptMicAlgorithms - the senders list of signing algorithms for signing receipt, in preferred order, or <code>null</code> if requesting an unsigned receipt. + * @param encryptionAlgorithmName - the name of the algorithm used to encrypt the message or <code>null</code> if sending EDI message unencrypted + * @param encryptionCertificateChain - the chain of certificates used to encrypt the message or <code>null</code> if sending EDI message unencrypted + * @param encryptionPrivateKey - the private key used to encrypt EDI message * @return {@link HttpCoreContext} containing request and response used to send EDI message * @throws HttpException when things go wrong. */ @@ -187,7 +212,10 @@ public class AS2ClientManager { Certificate[] signingCertificateChain, PrivateKey signingPrivateKey, String dispositionNotificationTo, - String[] signedReceiptMicAlgorithms) + String[] signedReceiptMicAlgorithms, + String encryptionAlgorithmName, + Certificate[] encryptionCertificateChain, + PrivateKey encryptionPrivateKey) throws HttpException { Args.notNull(ediMessage, "EDI Message"); @@ -209,6 +237,9 @@ public class AS2ClientManager { httpContext.setAttribute(AS2ClientManager.SIGNING_PRIVATE_KEY, signingPrivateKey); httpContext.setAttribute(AS2ClientManager.DISPOSITION_NOTIFICATION_TO, dispositionNotificationTo); httpContext.setAttribute(AS2ClientManager.SIGNED_RECEIPT_MIC_ALGORITHMS, signedReceiptMicAlgorithms); + httpContext.setAttribute(AS2ClientManager.ENCRYPTING_ALGORITHM_NAME, encryptionAlgorithmName); + httpContext.setAttribute(AS2ClientManager.ENCRYPTING_CERTIFICATE_CHAIN, encryptionCertificateChain); + httpContext.setAttribute(AS2ClientManager.ENCRYPTING_PRIVATE_KEY, encryptionPrivateKey); BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", requestUri); httpContext.setAttribute(HTTP_REQUEST, request); @@ -238,7 +269,10 @@ public class AS2ClientManager { } break; case ENCRYPTED: - // TODO : Add code here to add application/pkcs7-mime entity when encryption facility available. + 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. @@ -275,20 +309,25 @@ public class AS2ClientManager { } - public AS2SignedDataGenerator createEncryptingGenerator(HttpCoreContext httpContext) throws HttpException { + public CMSEnvelopedDataGenerator createEncryptingGenerator(HttpCoreContext httpContext) throws HttpException { - Certificate[] certificateChain = httpContext.getAttribute(SIGNING_CERTIFICATE_CHAIN, Certificate[].class); + Certificate[] certificateChain = httpContext.getAttribute(ENCRYPTING_CERTIFICATE_CHAIN, Certificate[].class); if (certificateChain == null) { - throw new HttpException("Signing certificate chain missing"); + throw new HttpException("Encrypting certificate chain missing"); } - PrivateKey privateKey = httpContext.getAttribute(SIGNING_PRIVATE_KEY, PrivateKey.class); - if (privateKey == null) { - throw new HttpException("Signing private key missing"); - } + return EncryptingUtils.createEnvelopDataGenerator(certificateChain); - return SigningUtils.createSigningGenerator(certificateChain, privateKey); + } + + public OutputEncryptor createEncryptor(HttpCoreContext httpContext) throws HttpException { + + String algorithmName = httpContext.getAttribute(ENCRYPTING_ALGORITHM_NAME, String.class); + if (algorithmName == null) { + throw new HttpException("Encrypting algorithm name missing"); + } + return EncryptingUtils.createEncryptor(algorithmName); } } diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java index b61b440..c1d6952 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java @@ -16,35 +16,25 @@ */ package org.apache.camel.component.as2.api.entity; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.security.PrivateKey; -import java.util.Collection; -import java.util.Iterator; import org.apache.camel.component.as2.api.AS2Charset; import org.apache.camel.component.as2.api.AS2Header; import org.apache.camel.component.as2.api.CanonicalOutputStream; -import org.apache.camel.component.as2.api.io.AS2SessionInputBuffer; import org.apache.camel.component.as2.api.util.EntityUtils; import org.apache.http.Header; import org.apache.http.HeaderIterator; import org.apache.http.HttpException; import org.apache.http.entity.ContentType; -import org.apache.http.impl.io.HttpTransportMetricsImpl; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.Args; import org.bouncycastle.cms.CMSEnvelopedData; import org.bouncycastle.cms.CMSEnvelopedDataGenerator; import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSTypedData; -import org.bouncycastle.cms.Recipient; -import org.bouncycastle.cms.RecipientInformation; -import org.bouncycastle.cms.RecipientInformationStore; -import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; import org.bouncycastle.operator.OutputEncryptor; public class ApplicationPkcs7MimeEntity extends MimeEntity { diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EncryptingUtils.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EncryptingUtils.java new file mode 100644 index 0000000..8e0c9b3 --- /dev/null +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EncryptingUtils.java @@ -0,0 +1,67 @@ +/** + * 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.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.apache.camel.component.as2.api.AS2Algorithm; +import org.apache.http.HttpException; +import org.apache.http.util.Args; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.cms.CMSEnvelopedDataGenerator; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; +import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; +import org.bouncycastle.operator.OutputEncryptor; + +public final class EncryptingUtils { + + private EncryptingUtils() { + } + + public static CMSEnvelopedDataGenerator createEnvelopDataGenerator(Certificate[] encryptionCertificateChain) throws HttpException { + Args.notNull(encryptionCertificateChain, "encryptionCertificateChain"); + if (encryptionCertificateChain.length == 0 || !(encryptionCertificateChain[0] instanceof X509Certificate)) { + throw new IllegalArgumentException("Invalid certificate chain"); + } + + try { + X509Certificate encryptionCertificate = (X509Certificate) encryptionCertificateChain[0]; + + CMSEnvelopedDataGenerator cmsEnvelopeDataGenerator = new CMSEnvelopedDataGenerator(); + + JceKeyTransRecipientInfoGenerator recipientInfoGenerator = new JceKeyTransRecipientInfoGenerator(encryptionCertificate); + cmsEnvelopeDataGenerator.addRecipientInfoGenerator(recipientInfoGenerator); + + return cmsEnvelopeDataGenerator; + } catch (CertificateEncodingException e) { + throw new HttpException("Failed to create envelope data generator", e); + } + } + + public static OutputEncryptor createEncryptor(String encryptionAlgorithmName) throws HttpException { + Args.notNull(encryptionAlgorithmName, "encryptionAlgorithmName"); + try { + ASN1ObjectIdentifier algorithmOID = AS2Algorithm.getAS2Algorithm(encryptionAlgorithmName).getAlgorithmOID(); + return new JceCMSContentEncryptorBuilder(algorithmOID).build(); + } catch (CMSException e) { + throw new HttpException("Failed to create encryptor ", e); + } + } +} 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 ab608bb..66aabda 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 @@ -24,6 +24,7 @@ import java.util.Arrays; import org.apache.camel.component.as2.api.AS2SignedDataGenerator; import org.apache.http.HttpException; +import org.apache.http.util.Args; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; @@ -43,7 +44,12 @@ public final class SigningUtils { } public static AS2SignedDataGenerator createSigningGenerator(Certificate[] certificateChain, PrivateKey privateKey) throws HttpException { - + Args.notNull(certificateChain, "certificateChain"); + if (certificateChain.length == 0 || !(certificateChain[0] instanceof X509Certificate)) { + throw new IllegalArgumentException("Invalid certificate chain"); + } + Args.notNull(privateKey, "privateKey"); + AS2SignedDataGenerator gen = new AS2SignedDataGenerator(); // Get first certificate in chain for signing 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 f17e7c4..65684b7 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 @@ -270,7 +270,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), - null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS); + null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -314,7 +314,66 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO, - SIGNED_RECEIPT_MIC_ALGORITHMS); + SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); + + 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(AS2MediaType.MULTIPART_SIGNED)); + + 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 MultipartSignedEntity); + MultipartSignedEntity signedEntity = (MultipartSignedEntity) entity; + assertTrue("Entity not set as main body of request", signedEntity.isMainBody()); + assertTrue("Request contains invalid number of mime parts", signedEntity.getPartCount() == 2); + + // Validated first mime part. + assertTrue("First mime part incorrect type ", signedEntity.getPart(0) instanceof ApplicationEDIFACTEntity); + ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) signedEntity.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 ", + signedEntity.getPart(1) instanceof ApplicationPkcs7SignatureEntity); + ApplicationPkcs7SignatureEntity signatureEntity = (ApplicationPkcs7SignatureEntity) signedEntity.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 envelopeddMessageTest() throws Exception { + AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN, + TARGET_HOST, TARGET_PORT); + AS2ClientManager clientManager = new AS2ClientManager(clientConnection); + + HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, + AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), + null, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO, + SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -373,7 +432,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO, - SIGNED_RECEIPT_MIC_ALGORITHMS); + SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); HttpRequest request = httpContext.getRequest(); assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest); @@ -401,7 +460,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), - null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS); + null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); HttpResponse response = httpContext.getResponse(); assertEquals("Unexpected method value", HttpVersion.HTTP_1_1, response.getStatusLine().getProtocolVersion()); diff --git a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java index 306d9cd..cd47c82 100644 --- a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java +++ b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java @@ -17,7 +17,20 @@ package org.apache.camel.component.as2.api.entity; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; import org.apache.camel.component.as2.api.AS2Header; import org.apache.camel.component.as2.api.io.AS2SessionInputBuffer; @@ -31,6 +44,23 @@ import org.apache.http.entity.BasicHttpEntity; import org.apache.http.impl.EnglishReasonPhraseCatalog; import org.apache.http.impl.io.HttpTransportMetricsImpl; import org.apache.http.message.BasicHttpResponse; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.bc.BcX509ExtensionUtils; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.cms.CMSAlgorithm; +import org.bouncycastle.cms.CMSEnvelopedDataGenerator; +import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; +import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.OutputEncryptor; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -150,6 +180,11 @@ public class EntityParserTest { private static final int DEFAULT_BUFFER_SIZE = 8 * 1024; + // + // certificate serial number seed. + // + int serialNo = 1; + @Before public void setUp() throws Exception { } @@ -237,4 +272,89 @@ public class EntityParserTest { assertEquals("Unexpected Digest Algorithm ID", EXPECTED_DIGEST_ALGORITHM_ID, messageDispositionNotificationEntity.getReceivedContentMic().getDigestAlgorithmId()); } + @Test + public void parseEnvelopedBodyTest() throws Exception { + + Security.addProvider(new BouncyCastleProvider()); + + // + // set up our certificates + // + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC"); + + kpg.initialize(1024, new SecureRandom()); + + String issueDN = "O=Punkhorn Software, C=US"; + KeyPair issueKP = kpg.generateKeyPair(); + X509Certificate issuerCertificate = makeCertificate(issueKP, issueDN, issueKP, issueDN); + + // + // certificate we encrypt against + // + String encryptDN = "CN=William J. Collins, E=punkhor...@gmail.com, O=Punkhorn Software, C=US"; + KeyPair encryptKP = kpg.generateKeyPair(); + X509Certificate encryptionCertificate = makeCertificate(encryptKP, encryptDN, issueKP, issueDN); + + List<X509Certificate> certList = new ArrayList<>(); + + certList.add(encryptionCertificate); + certList.add(issuerCertificate); + + // + // Create generator + // + CMSEnvelopedDataGenerator cmsEnvelopeDataGenerator = new CMSEnvelopedDataGenerator(); + + JceKeyTransRecipientInfoGenerator recipientInfoGenerator = new JceKeyTransRecipientInfoGenerator(encryptionCertificate); + cmsEnvelopeDataGenerator.addRecipientInfoGenerator(recipientInfoGenerator); + + // + // Create encryptor + // + OutputEncryptor contentEncryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CCM).build(); + + // + // Build Enveloped Entity + // + TextPlainEntity textEntity = new TextPlainEntity("This is a super secret messatge!", "US-ASCII", "7bit", false); + ApplicationPkcs7MimeEntity applicationPkcs7MimeEntity = new ApplicationPkcs7MimeEntity(textEntity, cmsEnvelopeDataGenerator, contentEncryptor, "binary", true); + + MimeEntity decryptedMimeEntity = applicationPkcs7MimeEntity.getEncryptedEntity(encryptKP.getPrivate()); + assertEquals("Decrypted entity has unexpected content type", "text/plain; charset=US-ASCII", decryptedMimeEntity.getContentTypeValue()); + assertEquals("Decrypted entity has unexpected content", "This is a super secret messatge!", ((TextPlainEntity)decryptedMimeEntity).getText()); + } + + /** + * create a basic X509 certificate from the given keys + */ + private X509Certificate makeCertificate(KeyPair subKP, String subDN, KeyPair issKP, String issDN) + throws GeneralSecurityException, IOException, OperatorCreationException { + PublicKey subPub = subKP.getPublic(); + PrivateKey issPriv = issKP.getPrivate(); + PublicKey issPub = issKP.getPublic(); + + X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(new X500Name(issDN), + BigInteger.valueOf(serialNo++), new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)), new X500Name(subDN), subPub); + + v3CertGen.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyId(subPub)); + + v3CertGen.addExtension(Extension.authorityKeyIdentifier, false, createAuthorityKeyId(issPub)); + + return new JcaX509CertificateConverter().setProvider("BC").getCertificate( + v3CertGen.build(new JcaContentSignerBuilder("MD5withRSA").setProvider("BC").build(issPriv))); + } + + private AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pub) throws IOException { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pub.getEncoded()); + + BcX509ExtensionUtils utils = new BcX509ExtensionUtils(); + return utils.createAuthorityKeyIdentifier(info); + } + + static SubjectKeyIdentifier createSubjectKeyId(PublicKey pub) throws IOException { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pub.getEncoded()); + + return new BcX509ExtensionUtils().createSubjectKeyIdentifier(info); + } } diff --git a/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc b/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc index 4260d40..565e8fa 100644 --- a/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc +++ b/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc @@ -70,7 +70,7 @@ with the following path and query parameters: |=== -==== Query Parameters (27 parameters): +==== Query Parameters (30 parameters): [width="100%",cols="2,5,^1,2",options="header"] @@ -84,6 +84,9 @@ with the following path and query parameters: | *dispositionNotificationTo* (common) | The value of the Disposition-Notification-To header. Assigning a value to this parameter requests a message disposition notification (MDN) for the AS2 message. | | String | *ediMessageTransferEncoding* (common) | The transfer encoding of EDI message. | | String | *ediMessageType* (common) | The content type of EDI message. One of application/edifact, application/edi-x12, application/edi-consent | | ContentType +| *encryptingAlgorithmName* (common) | The name of algorithm used to encrypt EDI message. | | String +| *encryptingCertificateChain* (common) | The chain of certificates used to encrypt EDI message. | | Certificate[] +| *encryptingPrivateKey* (common) | The key used to encrypt the EDI message. | | PrivateKey | *from* (common) | The value of the From header of AS2 message. | | String | *inBody* (common) | Sets the name of a parameter to be passed in the exchange In Body | | String | *methodName* (common) | *Required* What sub operation to use for the selected operation | | String @@ -135,6 +138,9 @@ The component supports 25 options, which are listed below. | *camel.component.as2.configuration.signing-algorithm-name* | The name of algorithm used to sign EDI message. | | String | *camel.component.as2.configuration.signing-certificate-chain* | The chain of certificates used to sign EDI message. | | Certificate[] | *camel.component.as2.configuration.signing-private-key* | The key used to sign the EDI message. | | PrivateKey +| *camel.component.as2.configuration.encrypting-algorithm-name* | The name of algorithm used to encrypt EDI message. | | String +| *camel.component.as2.configuration.encrypting-certificate-chain* | The chain of certificates used to encrypt EDI message. | | Certificate[] +| *camel.component.as2.configuration.encrypting-private-key* | The key used to encrypt the EDI message. | | PrivateKey | *camel.component.as2.configuration.subject* | The value of Subject header of AS2 message. | | String | *camel.component.as2.configuration.target-hostname* | The host name (IP or DNS name) of target host. | | String | *camel.component.as2.configuration.target-port-number* | The port number of target host. -1 indicates the scheme default port. | | Integer 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 bcc6adc..b819c5a 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 @@ -105,6 +105,15 @@ public class AS2Configuration { @UriParam private String[] signedReceiptMicAlgorithms; + @UriParam + private String encryptingAlgorithmName; + + @UriParam + private Certificate[] encryptingCertificateChain; + + @UriParam + private PrivateKey encryptingPrivateKey; + public AS2ApiName getApiName() { return apiName; } @@ -404,4 +413,36 @@ public class AS2Configuration { this.signedReceiptMicAlgorithms = signedReceiptMicAlgorithms; } + public String getEncryptingingAlgorithmName() { + return signingAlgorithmName; + } + + /** + * The name of algorithm used to encrypt EDI message. + */ + public void setEncryptingAlgorithmName(String signingAlgorithmName) { + this.encryptingAlgorithmName = signingAlgorithmName; + } + + public Certificate[] getEncryptingCertificateChain() { + return encryptingCertificateChain; + } + + /** + * The chain of certificates used to encrypt EDI message. + */ + public void setEncryptingCertificateChain(Certificate[] signingCertificateChain) { + this.encryptingCertificateChain = signingCertificateChain; + } + + public PrivateKey getEncryptingPrivateKey() { + return encryptingPrivateKey; + } + + /** + * The key used to encrypt the EDI message. + */ + public void setEncryptingPrivateKey(PrivateKey signingPrivateKey) { + this.encryptingPrivateKey = signingPrivateKey; + } } diff --git a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java index e199217..129310b 100644 --- a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java +++ b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java @@ -127,7 +127,7 @@ public class AS2ServerManagerIntegrationTest extends AbstractAS2TestSupport { clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, null, null, - DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS); + DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs"); mockEndpoint.expectedMinimumMessageCount(1); @@ -185,7 +185,7 @@ public class AS2ServerManagerIntegrationTest extends AbstractAS2TestSupport { clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO, - SIGNED_RECEIPT_MIC_ALGORITHMS); + SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs"); mockEndpoint.expectedMinimumMessageCount(1); diff --git a/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java index 13c751a..27ddc9b 100644 --- a/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java +++ b/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java @@ -176,6 +176,18 @@ public class AS2ComponentConfiguration * notification (MDN) */ private String[] signedReceiptMicAlgorithms; + /** + * The name of algorithm used to encrypt EDI message. + */ + private String encryptingAlgorithmName; + /** + * The chain of certificates used to encrypt EDI message. + */ + private Certificate[] encryptingCertificateChain; + /** + * The key used to encrypt the EDI message. + */ + private PrivateKey encryptingPrivateKey; public AS2ApiName getApiName() { return apiName; @@ -365,5 +377,30 @@ public class AS2ComponentConfiguration String[] signedReceiptMicAlgorithms) { this.signedReceiptMicAlgorithms = signedReceiptMicAlgorithms; } + + public String getEncryptingAlgorithmName() { + return encryptingAlgorithmName; + } + + public void setEncryptingAlgorithmName(String encryptingAlgorithmName) { + this.encryptingAlgorithmName = encryptingAlgorithmName; + } + + public Certificate[] getEncryptingCertificateChain() { + return encryptingCertificateChain; + } + + public void setEncryptingCertificateChain( + Certificate[] encryptingCertificateChain) { + this.encryptingCertificateChain = encryptingCertificateChain; + } + + public PrivateKey getEncryptingPrivateKey() { + return encryptingPrivateKey; + } + + public void setEncryptingPrivateKey(PrivateKey encryptingPrivateKey) { + this.encryptingPrivateKey = encryptingPrivateKey; + } } } \ No newline at end of file