You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by fo...@apache.org on 2017/07/25 08:20:05 UTC

[3/4] camel git commit: CAMEL-11438 new component crypto-cms

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptor.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptor.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptor.java
new file mode 100644
index 0000000..147d819
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptor.java
@@ -0,0 +1,122 @@
+/**
+ * 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.crypto.cms.crypt;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.X509Certificate;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.crypto.cms.common.AttributesGeneratorProvider;
+import org.apache.camel.component.crypto.cms.common.CryptoCmsMarshallerAbstract;
+import org.apache.camel.component.crypto.cms.common.OriginatorInformationProvider;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.util.IOHelper;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.cms.CMSEnvelopedDataStreamGenerator;
+import org.bouncycastle.cms.OriginatorInformation;
+import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.OutputEncryptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Processor for creating an enveloped data object.
+ */
+public class EnvelopedDataEncryptor extends CryptoCmsMarshallerAbstract {
+    private static final Logger LOG = LoggerFactory.getLogger(EnvelopedDataEncryptor.class);
+
+    private final EnvelopedDataEncryptorConfiguration conf;
+
+    public EnvelopedDataEncryptor(EnvelopedDataEncryptorConfiguration conf) {
+        super(conf);
+        this.conf = conf;
+    }
+
+    @Override
+    protected void marshalInternal(InputStream is, OutputStream os, Exchange exchange) throws Exception {
+
+        LOG.debug("Content encryption algorithm: {}", conf.getAlgorithmID());
+        LOG.debug("Parameter secretKeyLength: {}", conf.getSecretKeyLength());
+
+        OutputStream encryptingStream = null;
+        try {
+            CMSEnvelopedDataStreamGenerator gen = new CMSEnvelopedDataStreamGenerator();
+            OriginatorInformationProvider originatorInformationProvider = conf.getOriginatorInformationProvider();
+            if (originatorInformationProvider != null) {
+                LOG.debug("originatorInformationProvider found");
+                OriginatorInformation originatorInformation = originatorInformationProvider.getOriginatorInformation(exchange);
+                if (originatorInformation != null) {
+                    LOG.debug("originatorInformation found");
+                    gen.setOriginatorInfo(originatorInformation);
+                }
+            }
+            AttributesGeneratorProvider attributeGeneratorProvider = conf.getUnprotectedAttributesGeneratorProvider();
+            if (attributeGeneratorProvider != null) {
+                LOG.debug("attributeGeneratorProvider found");
+                gen.setUnprotectedAttributeGenerator(attributeGeneratorProvider.getAttributesGenerator(exchange));
+            }
+
+            if (conf.getRecipient().isEmpty()) {
+                throw new CryptoCmsException("No recipient configured.");
+            }
+
+            for (RecipientInfo recipientInfo : conf.getRecipient()) {
+                // currently we only support key transport alternative, in
+                // future there maybe others
+                TransRecipientInfo keyTransrecipientInfo = (TransRecipientInfo)recipientInfo;
+                LOG.debug("Recipient info: {}", keyTransrecipientInfo);
+                X509Certificate encryptCert = keyTransrecipientInfo.getCertificate(exchange);
+                LOG.debug("Encryption certificate for recipient with '{}' : {}", keyTransrecipientInfo, encryptCert);
+
+                AlgorithmIdentifier keyEncryptionAlgorithm = determineKeyEncryptionAlgorithmIdentifier(keyTransrecipientInfo.getKeyEncryptionAlgorithm(exchange),
+                                                                                                       keyTransrecipientInfo);
+                JceKeyTransRecipientInfoGenerator keyTransRecipeintInfoGen = new JceKeyTransRecipientInfoGenerator(encryptCert, keyEncryptionAlgorithm);
+
+                keyTransRecipeintInfoGen.setProvider(BouncyCastleProvider.PROVIDER_NAME);
+                gen.addRecipientInfoGenerator(keyTransRecipeintInfoGen);
+            }
+
+            OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(conf.getAlgorithmID()).setProvider(BouncyCastleProvider.PROVIDER_NAME).build();
+
+            encryptingStream = gen.open(os, encryptor);
+
+            IOHelper.copy(is, encryptingStream);
+
+            LOG.debug("CMS Enveloped Data creation successful");
+
+        } finally {
+            IOHelper.close(is);
+            IOHelper.close(encryptingStream);
+        }
+
+    }
+
+    private AlgorithmIdentifier determineKeyEncryptionAlgorithmIdentifier(String keyEncryptionAlgorithm, TransRecipientInfo keyTransRecipient) throws CryptoCmsException {
+
+        if (keyEncryptionAlgorithm == null) {
+            throw new CryptoCmsException("Key encryption algorithm  of recipient info '" + keyTransRecipient + "' is missing");
+        }
+        if ("RSA".equals(keyEncryptionAlgorithm)) {
+            return new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption);
+        }
+        throw new CryptoCmsException("Key encryption algorithm '" + keyEncryptionAlgorithm + "' of recipient info '" + keyTransRecipient + "' is not supported");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptorConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptorConfiguration.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptorConfiguration.java
new file mode 100644
index 0000000..50f3fc8
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/EnvelopedDataEncryptorConfiguration.java
@@ -0,0 +1,283 @@
+/**
+ * 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.crypto.cms.crypt;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.crypto.cms.common.AttributesGeneratorProvider;
+import org.apache.camel.component.crypto.cms.common.CryptoCmsMarshallerConfiguration;
+import org.apache.camel.component.crypto.cms.common.OriginatorInformationProvider;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.cms.CMSAlgorithm;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@UriParams
+public class EnvelopedDataEncryptorConfiguration extends CryptoCmsMarshallerConfiguration {
+
+    private static final String CAST5_CBC_PKCS5_PADDING = "CAST5/CBC/PKCS5Padding";
+
+    private static final String RC2_CBC_PKCS5_PADDING = "RC2/CBC/PKCS5Padding";
+
+    private static final String CAMELLIA_CBC_PKCS5_PADDING = "Camellia/CBC/PKCS5Padding";
+
+    private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
+
+    private static final String DES_CBC_PKCS5_PADDING = "DES/CBC/PKCS5Padding";
+
+    private static final String DESEDE_CBC_PKCS5_PADDING = "DESede/CBC/PKCS5Padding";
+
+    private static final Logger LOG = LoggerFactory.getLogger(EnvelopedDataEncryptorConfiguration.class);
+
+    private static final Map<String, List<Integer>> SUPPORTED_ENCRYPTION_ALGORITHMS = new HashMap<String, List<Integer>>(7);
+
+    static {
+
+        List<Integer> allowedKeyLengthForAESandCamellia;
+        if (isLimitedEncryptionStrength()) {
+            allowedKeyLengthForAESandCamellia = Arrays.asList(new Integer[] {128});
+        } else {
+            allowedKeyLengthForAESandCamellia = Arrays.asList(new Integer[] {256, 192, 128});
+        }
+
+        SUPPORTED_ENCRYPTION_ALGORITHMS.put(DESEDE_CBC_PKCS5_PADDING, Arrays.asList(new Integer[] {192, 128}));
+        SUPPORTED_ENCRYPTION_ALGORITHMS.put(DES_CBC_PKCS5_PADDING, Arrays.asList(new Integer[] {64, 56}));
+        SUPPORTED_ENCRYPTION_ALGORITHMS.put(AES_CBC_PKCS5_PADDING, allowedKeyLengthForAESandCamellia);
+        SUPPORTED_ENCRYPTION_ALGORITHMS.put(CAMELLIA_CBC_PKCS5_PADDING, allowedKeyLengthForAESandCamellia);
+        SUPPORTED_ENCRYPTION_ALGORITHMS.put(RC2_CBC_PKCS5_PADDING, Arrays.asList(new Integer[] {128, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40}));
+        SUPPORTED_ENCRYPTION_ALGORITHMS.put(CAST5_CBC_PKCS5_PADDING, Arrays.asList(new Integer[] {128, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40}));
+    }
+
+    @UriParam(label = "encrypt", multiValue = true, description = "Recipient Info: reference to a bean which implements the interface org.apache.camel.component.crypto.cms.api.TransRecipientInfo")
+    private final List<RecipientInfo> recipient = new ArrayList<RecipientInfo>(3);
+
+    @UriParam(label = "encrypt", enums = "AES/CBC/PKCS5Padding,DESede/CBC/PKCS5Padding,Camellia/CBC/PKCS5Padding,CAST5/CBC/PKCS5Padding")
+    private String contentEncryptionAlgorithm;
+
+    @UriParam(label = "encrypt")
+    private int secretKeyLength;
+
+    @UriParam(label = "encrypt", defaultValue = "null")
+    private AttributesGeneratorProvider unprotectedAttributesGeneratorProvider;
+
+    @UriParam(label = "encrypt", defaultValue = "null")
+    private OriginatorInformationProvider originatorInformationProvider;
+
+    // calculated parameters
+    private ASN1ObjectIdentifier algorithmId;
+
+    public EnvelopedDataEncryptorConfiguration(CamelContext context) {
+        super(context);
+    }
+
+    private static boolean isLimitedEncryptionStrength() {
+        // limited encryption strength
+        boolean limitedEncryptionStrength;
+        try {
+            limitedEncryptionStrength = Cipher.getMaxAllowedKeyLength("AES") < 256;
+        } catch (NoSuchAlgorithmException e) {
+            // should never occur
+            throw new IllegalStateException(e);
+        }
+        return limitedEncryptionStrength;
+    }
+
+    public List<RecipientInfo> getRecipient() {
+        return recipient;
+    }
+
+    public void setRecipient(RecipientInfo recipient) {
+        this.recipient.add(recipient);
+    }
+
+    // for multi values
+    public void setRecipient(List<?> recipients) {
+        if (recipients == null) {
+            return;
+        }
+        for (Object recipientOb : recipients) {
+            if (recipientOb instanceof String) {
+                String recipientName = (String)recipientOb;
+                String valueNoHash = recipientName.replaceAll("#", "");
+                if (getContext() != null && recipientName != null) {
+                    RecipientInfo recipient = getContext().getRegistry().lookupByNameAndType(valueNoHash, RecipientInfo.class);
+                    if (recipient != null) {
+                        setRecipient(recipient);
+                    }
+                }
+            }
+        }
+
+    }
+
+    public String getContentEncryptionAlgorithm() {
+        return contentEncryptionAlgorithm;
+    }
+
+    /**
+     * Encryption algorithm, for example "DESede/CBC/PKCS5Padding". Further
+     * possible values: DESede/CBC/PKCS5Padding, AES/CBC/PKCS5Padding,
+     * Camellia/CBC/PKCS5Padding, CAST5/CBC/PKCS5Padding.
+     */
+    public void setContentEncryptionAlgorithm(String contentEncryptionAlgorithm) {
+        this.contentEncryptionAlgorithm = contentEncryptionAlgorithm;
+    }
+
+    public int getSecretKeyLength() {
+        return secretKeyLength;
+    }
+
+    /**
+     * Key length for the secret symmetric key used for the content encryption.
+     * Only used if the specified content-encryption algorithm allows keys of
+     * different sizes. If contentEncryptionAlgorithm=AES/CBC/PKCS5Padding or
+     * Camellia/CBC/PKCS5Padding then 128; if
+     * contentEncryptionAlgorithm=DESede/CBC/PKCS5Padding then 192, 128; if
+     * strong encryption is enabled then for AES/CBC/PKCS5Padding and
+     * Camellia/CBC/PKCS5Padding also the key lengths 192 and 256 are possible.
+     */
+    public void setSecretKeyLength(int secretKeyLength) {
+        this.secretKeyLength = secretKeyLength;
+    }
+
+    public AttributesGeneratorProvider getUnprotectedAttributesGeneratorProvider() {
+        return unprotectedAttributesGeneratorProvider;
+    }
+
+    /**
+     * Provider of the generator for the unprotected attributes. The default
+     * value is <code>null</code> which means no unprotected attribute is added
+     * to the Enveloped Data object. See
+     * https://tools.ietf.org/html/rfc5652#section-6.1.
+     */
+    public void setUnprotectedAttributesGeneratorProvider(AttributesGeneratorProvider unprotectedAttributeTableGeneratorProvider) {
+        this.unprotectedAttributesGeneratorProvider = unprotectedAttributeTableGeneratorProvider;
+    }
+
+    public OriginatorInformationProvider getOriginatorInformationProvider() {
+        return originatorInformationProvider;
+    }
+
+    /**
+     * Provider for the originator info. See
+     * https://tools.ietf.org/html/rfc5652#section-6.1. The default value is
+     * <code>null</code>.
+     */
+    public void setOriginatorInformationProvider(OriginatorInformationProvider originatorInformationProvider) {
+        this.originatorInformationProvider = originatorInformationProvider;
+    }
+
+    public void init() throws CryptoCmsException {
+        if (recipient.size() == 0) {
+            logErrorAndThrow(LOG, "No recipient configured.");
+        }
+        checkEncryptionAlgorithmAndSecretKeyLength();
+
+        calcualteAlgorithmIdWithKeyLength();
+    }
+
+    private void checkEncryptionAlgorithmAndSecretKeyLength() throws CryptoCmsException {
+        if (contentEncryptionAlgorithm == null) {
+            logErrorAndThrow(LOG, "Content encryption algorithm is null");
+        } else if (!SUPPORTED_ENCRYPTION_ALGORITHMS.keySet().contains(contentEncryptionAlgorithm)) {
+            logErrorAndThrow(LOG, "Content encryption algorithm " + contentEncryptionAlgorithm + " not supported");
+        } else if (!SUPPORTED_ENCRYPTION_ALGORITHMS.get(contentEncryptionAlgorithm).contains(secretKeyLength)) {
+            logErrorAndThrow(LOG, "Content encryption algorithm " + contentEncryptionAlgorithm + " does not supported secretKeyLength of " + secretKeyLength);
+        }
+    }
+
+    private void calcualteAlgorithmIdWithKeyLength() {
+
+        if (DESEDE_CBC_PKCS5_PADDING.equals(getContentEncryptionAlgorithm())) {
+
+            algorithmId = CMSAlgorithm.DES_EDE3_CBC;
+
+        } else if (DES_CBC_PKCS5_PADDING.equals(getContentEncryptionAlgorithm())) {
+
+            algorithmId = CMSAlgorithm.DES_CBC;
+
+        } else if (AES_CBC_PKCS5_PADDING.equals(getContentEncryptionAlgorithm())) {
+
+            switch (getSecretKeyLength()) {
+            case 256:
+                algorithmId = CMSAlgorithm.AES256_CBC;
+                break;
+            case 192:
+                algorithmId = CMSAlgorithm.AES192_CBC;
+                break;
+            case 128:
+                algorithmId = CMSAlgorithm.AES128_CBC;
+                break;
+
+            default:
+                // should not happen, has already been checked
+                throw new IllegalStateException("Unsupported secret key length " + getSecretKeyLength() + " for algorithm AES");
+            }
+
+        } else if (CAMELLIA_CBC_PKCS5_PADDING.equals(getContentEncryptionAlgorithm())) {
+
+            switch (getSecretKeyLength()) {
+            case 256:
+                algorithmId = CMSAlgorithm.CAMELLIA256_CBC;
+                break;
+            case 192:
+                algorithmId = CMSAlgorithm.CAMELLIA192_CBC;
+                break;
+            case 128:
+                algorithmId = CMSAlgorithm.CAMELLIA128_CBC;
+                break;
+            default:
+                // should not happen, has already been checked
+                throw new IllegalStateException("Unsupported secret key length " + getSecretKeyLength() + " for algorithm Camellia");
+            }
+
+        } else if (RC2_CBC_PKCS5_PADDING.equals(getContentEncryptionAlgorithm())) {
+
+            algorithmId = CMSAlgorithm.RC2_CBC;
+
+        } else if (CAST5_CBC_PKCS5_PADDING.equals(getContentEncryptionAlgorithm())) {
+
+            algorithmId = CMSAlgorithm.CAST5_CBC;
+
+        } else {
+            // should not occur, has already been checked
+            throw new IllegalStateException("Content encryption algorithm " + getContentEncryptionAlgorithm() + " not supported");
+        }
+
+    }
+
+    /**
+     * Content encryption algorithm.
+     * 
+     * @return algorithm Id
+     */
+    public ASN1ObjectIdentifier getAlgorithmID() {
+        return algorithmId;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/PrivateKeyWithCertificate.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/PrivateKeyWithCertificate.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/PrivateKeyWithCertificate.java
new file mode 100644
index 0000000..bc1e726
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/PrivateKeyWithCertificate.java
@@ -0,0 +1,44 @@
+/**
+ * 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.crypto.cms.crypt;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import org.apache.camel.util.ObjectHelper;
+
+public class PrivateKeyWithCertificate {
+
+    private final PrivateKey privateKey;
+
+    private final X509Certificate certificate;
+
+    public PrivateKeyWithCertificate(PrivateKey privateKey, X509Certificate certificate) {
+
+        this.privateKey = ObjectHelper.notNull(privateKey, "privateKey");
+        this.certificate = ObjectHelper.notNull(certificate, "certificate");
+    }
+
+    public PrivateKey getPrivateKey() {
+        return privateKey;
+    }
+
+    public X509Certificate getCertificate() {
+        return certificate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/RecipientInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/RecipientInfo.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/RecipientInfo.java
new file mode 100644
index 0000000..06110a4
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/RecipientInfo.java
@@ -0,0 +1,54 @@
+/**
+ * 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.crypto.cms.crypt;
+
+/**
+ * Information about the receiver of an encrypted message used in
+ * {@link EnvelopedDataEncryptor}. The RecipientInfo type depends on the key
+ * management algorithm used for the recipient of an <code>EnvelopedData</code>
+ * or <code>AuthenticatedData</code>. CMS provides three alternatives (see rfc5652):
+ * <ul>
+ * <li>key transport: the content-encryption key is encrypted with the public
+ * key of the recipient. This technique id compatible to PKCS#7 when creating a
+ * RecipientInfo for the public key of the recipient's certificate, identified
+ * by issuer and serial number. CMS recommends to use RSA for encrypting the
+ * content encryption key.
+ * <li>key agreement: the recipient's public key and the sender's private key
+ * are used to generate a symmetric key, then the content encryption key is
+ * encrypted with the symmetric key. Each RecipientInfo of type may transfer the
+ * encrypted content encryption key to one or more recipient using the same key
+ * agreement algorithm and domain parameters for that algorithm. CMS recommends
+ * to use ESDH with an ephemeral sender key.
+ * <li>symmetric key-encryption keys: the content-encryption key is encrypted
+ * with a previously distributed symmetric key-encryption key. The RecipientInfo
+ * is using a CMS key wrap algorithm like Triple-DES key wrap or RC2 key wrap.
+ * <li>password based encryption: the content-encryption key is encrypted with
+ * key-encryption key derived from a password. The RecipientInfo is using a key
+ * derivation algorithm like PBKDF2 as specified by <a href =
+ * http://www.ietf.org/rfc/rfc2898.txt" target="_blank">RFC 2898</a> (PKCS#5)
+ * and a key encryption algorithm like PWRI-KEK as specified by <a href =
+ * http://www.ietf.org/rfc/rfc3211.txt" target="_blank">RFC 3211</a>.
+ * <li>any other technique: based on private, user defined key management
+ * techniques
+ * </ul>
+ * Currently we only support the "key transport" alternative. However in
+ * preparation to support in future further types, we have introduced this
+ * class.
+ */
+public interface RecipientInfo {
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/TransRecipientInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/TransRecipientInfo.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/TransRecipientInfo.java
new file mode 100644
index 0000000..d4cfa42
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/crypt/TransRecipientInfo.java
@@ -0,0 +1,45 @@
+/**
+ * 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.crypto.cms.crypt;
+
+import java.security.cert.X509Certificate;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+
+/**
+ * Information about the receiver of an encrypted message used in
+ * CmsEnvelopedDataEncryptor.
+ * <p>
+ * Represents the "key transport" recipient info alternative: The
+ * content-encryption key is encrypted with the public key of the recipient.
+ * This technique is compatible to PKCS#7 when creating a RecipientInfo for the
+ * public key of the recipient's certificate, identified by issuer and serial
+ * number. CMS recommends to use RSA for encrypting the content encryption key.
+ */
+public interface TransRecipientInfo extends RecipientInfo {
+
+    /** Currently, the key encryption algorithm is fixed to "RSA". */
+    String getKeyEncryptionAlgorithm(Exchange exchange) throws CryptoCmsException;
+
+    /**
+     * Returns the certificate containign the public key which is used for the
+     * encryption and the issuer and serial number which is added to the
+     * recipient information.
+     */
+    X509Certificate getCertificate(Exchange exchange) throws CryptoCmsException;
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsException.java
new file mode 100644
index 0000000..073c166
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsException.java
@@ -0,0 +1,40 @@
+/**
+ * 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.crypto.cms.exception;
+
+public class CryptoCmsException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsException() {
+    }
+
+    public CryptoCmsException(String message) {
+        super(message);
+
+    }
+
+    public CryptoCmsException(Throwable cause) {
+        super(cause);
+
+    }
+
+    public CryptoCmsException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsFormatException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsFormatException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsFormatException.java
new file mode 100644
index 0000000..02aea9a
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsFormatException.java
@@ -0,0 +1,37 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * Exception thrown when the decoding of an input stream to a cms object, like
+ * singed data or enveloped data, fails.
+ * 
+ * 
+ */
+public class CryptoCmsFormatException extends CryptoCmsException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsFormatException(String message) {
+        super(message);
+    }
+
+    public CryptoCmsFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsInvalidKeyException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsInvalidKeyException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsInvalidKeyException.java
new file mode 100644
index 0000000..5609f50
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsInvalidKeyException.java
@@ -0,0 +1,33 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * Exception thrown during singing if the key type does not fit to the signature
+ * algorithm.
+ * 
+ * 
+ */
+public class CryptoCmsInvalidKeyException extends CryptoCmsException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsInvalidKeyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForRecipientsException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForRecipientsException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForRecipientsException.java
new file mode 100644
index 0000000..ebf78ac
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForRecipientsException.java
@@ -0,0 +1,31 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * Exception thrown when no certificate in the keystore fits to the recipients
+ * in the CMS enveloped data during the decryption process.
+ */
+public class CryptoCmsNoCertificateForRecipientsException extends CryptoCmsException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsNoCertificateForRecipientsException(String message) {
+        super(message);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfoException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfoException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfoException.java
new file mode 100644
index 0000000..d1ed3a6
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfoException.java
@@ -0,0 +1,34 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * Is thrown when the signature validation fails because no certificate is found
+ * the keystore which corresponds to the a specific signer information.
+ * <p>
+ * Can only be thrown when the configuration "verifySignatureOfAllSigners" is
+ * true.
+ */
+public class CryptoCmsNoCertificateForSignerInfoException extends CryptoCmsSignatureException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsNoCertificateForSignerInfoException(String message) {
+        super(message);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfosException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfosException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfosException.java
new file mode 100644
index 0000000..ac05c77
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoCertificateForSignerInfosException.java
@@ -0,0 +1,35 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * Is thrown when the signature validation fails because no certificate is found
+ * in the keystore which corresponds to the sent signer infos.
+ */
+public class CryptoCmsNoCertificateForSignerInfosException extends CryptoCmsSignatureException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsNoCertificateForSignerInfosException(String message) {
+        super(message);
+    }
+
+    public CryptoCmsNoCertificateForSignerInfosException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoKeyOrCertificateForAliasException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoKeyOrCertificateForAliasException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoKeyOrCertificateForAliasException.java
new file mode 100644
index 0000000..00fa790
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsNoKeyOrCertificateForAliasException.java
@@ -0,0 +1,45 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * Exception which is thrown when for a specified alias a key or certificate is
+ * not found in the keystore.
+ * 
+ * 
+ */
+public class CryptoCmsNoKeyOrCertificateForAliasException extends CryptoCmsException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsNoKeyOrCertificateForAliasException() {
+
+    }
+
+    public CryptoCmsNoKeyOrCertificateForAliasException(String message) {
+        super(message);
+    }
+
+    public CryptoCmsNoKeyOrCertificateForAliasException(Throwable cause) {
+        super(cause);
+    }
+
+    public CryptoCmsNoKeyOrCertificateForAliasException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureException.java
new file mode 100644
index 0000000..66ba4b0
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureException.java
@@ -0,0 +1,33 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * This exception is thrown if SignedData signature verification fails.
+ */
+public class CryptoCmsSignatureException extends CryptoCmsException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsSignatureException(String message) {
+        super(message);
+    }
+
+    public CryptoCmsSignatureException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureInvalidContentHashException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureInvalidContentHashException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureInvalidContentHashException.java
new file mode 100644
index 0000000..cec8b9c
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsSignatureInvalidContentHashException.java
@@ -0,0 +1,33 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * This exception is thrown if the verification of a SignedData signature fails
+ * because the hash calculated over the content does not match to the value of
+ * signed MessageDigest attribute value.
+ * 
+ */
+public class CryptoCmsSignatureInvalidContentHashException extends CryptoCmsSignatureException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsSignatureInvalidContentHashException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsVerifierCertificateNotValidException.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsVerifierCertificateNotValidException.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsVerifierCertificateNotValidException.java
new file mode 100644
index 0000000..836e790
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/CryptoCmsVerifierCertificateNotValidException.java
@@ -0,0 +1,31 @@
+/**
+ * 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.crypto.cms.exception;
+
+/**
+ * If the verifier tries to verify a signature with a certificate which is not
+ * valid at the time given as the SignerInfo's signing time.
+ */
+public class CryptoCmsVerifierCertificateNotValidException extends CryptoCmsSignatureException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CryptoCmsVerifierCertificateNotValidException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/packageinfo
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/packageinfo b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/packageinfo
new file mode 100644
index 0000000..e252556
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/exception/packageinfo
@@ -0,0 +1 @@
+version 1.0.0
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignedDataVerifierConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignedDataVerifierConfiguration.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignedDataVerifierConfiguration.java
new file mode 100644
index 0000000..59c5c2e
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignedDataVerifierConfiguration.java
@@ -0,0 +1,105 @@
+/**
+ * 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.crypto.cms.sig;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.crypto.cms.common.DefaultCryptoCmsUnMarshallerConfiguration;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+
+/**
+ * Fetches the X.509 certificates which can be used for the verification from a
+ * Java keystore.
+ */
+@UriParams
+public class DefaultSignedDataVerifierConfiguration extends DefaultCryptoCmsUnMarshallerConfiguration implements SignedDataVerifierConfiguration, Cloneable {
+
+    @UriParam(label = "verify", defaultValue = "false")
+    private Boolean signedDataHeaderBase64 = Boolean.FALSE;
+
+    @UriParam(label = "verify", defaultValue = "true")
+    private Boolean verifySignaturesOfAllSigners = Boolean.TRUE;
+
+    /**
+     * Indicates whether the value in the header CamelCryptoCmsSignedData is
+     * base64 encoded. Default value is <code>false</code>.
+     * <p>
+     * Only relevant for detached signatures. In the detached signature case,
+     * the header contains the Signed Data object.
+     */
+    public void setSignedDataHeaderBase64(Boolean signedDataHeaderBase64) {
+        this.signedDataHeaderBase64 = signedDataHeaderBase64;
+    }
+
+    @Override
+    public Boolean isSignedDataHeaderBase64(Exchange exchange) throws CryptoCmsException {
+        return signedDataHeaderBase64;
+    }
+
+    /**
+     * If <code>true</code> then the signatures of all signers contained in the
+     * Signed Data object are verified. If <code>false</code> then only one
+     * signature whose signer info matches with one of the specified
+     * certificates is verified. Default value is <code>true</code>.
+     */
+    public void setVerifySignaturesOfAllSigners(Boolean verifySignaturesOfAllSigners) {
+        this.verifySignaturesOfAllSigners = verifySignaturesOfAllSigners;
+    }
+
+    @Override
+    public Boolean isVerifySignaturesOfAllSigners(Exchange exchange) throws CryptoCmsException {
+        return verifySignaturesOfAllSigners;
+    }
+
+    @Override
+    public Collection<X509Certificate> getCertificates(Exchange exchange) throws CryptoCmsException {
+        KeyStore keystore = getKeyStore();
+        try {
+            List<X509Certificate> certs = new ArrayList<>(keystore.size());
+            for (Enumeration<String> aliases = keystore.aliases(); aliases.hasMoreElements();) {
+                String alias = aliases.nextElement();
+                Certificate cert = keystore.getCertificate(alias);
+                if (cert instanceof X509Certificate) {
+                    certs.add((X509Certificate)cert);
+                }
+            }
+            return certs;
+        } catch (KeyStoreException e) {
+            throw new CryptoCmsException("Problem during reading the certificates of the verifier keystore");
+        }
+    }
+
+    public DefaultSignedDataVerifierConfiguration copy() {
+        try {
+            return (DefaultSignedDataVerifierConfiguration)clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeCamelException(e); // should never happen
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignerInfo.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignerInfo.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignerInfo.java
new file mode 100644
index 0000000..0a02a03
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/DefaultSignerInfo.java
@@ -0,0 +1,198 @@
+/**
+ * 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.crypto.cms.sig;
+
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.crypto.cms.common.DefaultCryptoCmsConfiguration;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsNoKeyOrCertificateForAliasException;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.bouncycastle.cms.CMSAttributeTableGenerator;
+import org.bouncycastle.cms.DefaultSignedAttributeTableGenerator;
+
+/**
+ * Reads the signer information from a Java keystore. You have to specify an
+ * alias for the private key entry, the signature algorithm, and the keystore.
+ */
+@UriParams
+public class DefaultSignerInfo extends DefaultCryptoCmsConfiguration implements SignerInfo {
+
+    @UriParam(label = "sign")
+    private String privateKeyAlias;
+
+    @UriParam(label = "sign")
+    private char[] password;
+    @UriParam(label = "sign", defaultValue = "SHA256withRSA")
+    private String signatureAlgorithm = "SHA256withRSA";
+    @UriParam(label = "sign", defaultValue = "true")
+    private boolean includeCertificates = true;
+
+    @UriParam(label = "sign,advanced")
+    private CMSAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator();
+
+    @UriParam(label = "sign,advanced", defaultValue = "null")
+    private CMSAttributeTableGenerator unsignedAttributeGenerator;
+
+    /**
+     * Password of the private key. If not set then the password set in the
+     * parameter 'keystoreParameters' is used.
+     */
+    public void setPassword(char[] password) {
+        this.password = password;
+    }
+
+    protected char[] getPassword(Exchange exchange) throws CryptoCmsException {
+        if (password != null) {
+            return password;
+        }
+
+        String pw = null;
+        if (getKeyStoreParameters() != null) {
+            pw = getKeyStoreParameters().getPassword();
+        }
+        if (pw == null) {
+            throw new CryptoCmsException("No password for accessing the private key from the keystore found for the singer infor " + this);
+        }
+        return pw.toCharArray();
+    }
+
+    protected String getPrivateKeyAlias(Exchange exchange) throws CryptoCmsException {
+        if (privateKeyAlias == null) {
+            throw new CryptoCmsException("No alias defined for signer info " + this);
+        }
+        return privateKeyAlias;
+    }
+
+    /**
+     * Alias of the private key entry in the keystore which is used for signing.
+     */
+    public void setPrivateKeyAlias(String privateKeyAlias) {
+        this.privateKeyAlias = privateKeyAlias;
+    }
+
+    /**
+     * Signature algorithm. The default algorithm is "SHA256withRSA".
+     * <p>
+     * Attention, the signature algorithm must fit to the signer private key.
+     */
+    public void setSignatureAlgorithm(String signatureAlgorithm) {
+        this.signatureAlgorithm = signatureAlgorithm;
+    }
+
+    /**
+     * If <tt>true</tt> then the certificate chain corresponding to the alias of
+     * the private key is added to the certificate list of the Signed Data
+     * instance.
+     */
+    public void setIncludeCertificates(boolean includeCertificates) {
+        this.includeCertificates = includeCertificates;
+    }
+
+    @Override
+    public String getSignatureAlgorithm(Exchange exchange) throws CryptoCmsException {
+        return signatureAlgorithm;
+    }
+
+    @Override
+    public PrivateKey getPrivateKey(Exchange exchange) throws CryptoCmsException {
+        String alias = getPrivateKeyAlias(exchange);
+        try {
+            Key key = getKeyStore().getKey(alias, getPassword(exchange));
+            if (key instanceof PrivateKey) {
+                return (PrivateKey)key;
+            }
+        } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
+            throw new CryptoCmsException("Problem occured during accessing the private key for the alias '" + alias + "' in the keystore of signer " + this);
+        }
+        throw new CryptoCmsNoKeyOrCertificateForAliasException("No private key found  for the alias '" + alias + "' in the keystore of signer " + this);
+    }
+
+    @Override
+    public X509Certificate getCertificate(Exchange exchange) throws CryptoCmsException {
+
+        String alias = getPrivateKeyAlias(exchange);
+        Certificate cert;
+        try {
+            cert = getKeyStore().getCertificate(alias);
+        } catch (KeyStoreException e) {
+            throw new CryptoCmsException("Problem during accessing the certificate for the alias '" + alias + "' in the signer " + this, e);
+        }
+        if (cert instanceof X509Certificate) {
+            return (X509Certificate)cert;
+        }
+        throw new CryptoCmsNoKeyOrCertificateForAliasException("No X.509 certificate found for alias '" + alias + "' in the keystore of signer " + this);
+    }
+
+    @Override
+    public Certificate[] getCertificateChain(Exchange exchange) throws CryptoCmsException {
+        if (includeCertificates) {
+            String alias = getPrivateKeyAlias(exchange);
+            Certificate[] certs;
+            try {
+                certs = getKeyStore().getCertificateChain(alias);
+            } catch (KeyStoreException e) {
+                throw new CryptoCmsException("Problem during accessing the certificate chain for the alias '" + alias + "' in the keystore of signer " + this, e);
+            }
+            if (certs == null) {
+                return new Certificate[0];
+            } else {
+                return certs;
+            }
+        } else {
+            return new Certificate[0];
+        }
+    }
+
+    /**
+     * Signed attributes of the Signed Data instance. By default contentType,
+     * signingTime, messageDigest, and id-aa-CMSAlgorithmProtection are set.
+     */
+    public void setSignedAttributeGenerator(CMSAttributeTableGenerator signedAttributeGenerator) {
+        this.signedAttributeGenerator = signedAttributeGenerator;
+    }
+
+    /**
+     * Unsigned attributes of the Signed Data instance. By default no unsigned
+     * attribute is set.
+     */
+    public void setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedAttributeGenerator) {
+        this.unsignedAttributeGenerator = unsignedAttributeGenerator;
+    }
+
+    @Override
+    public CMSAttributeTableGenerator getSignedAttributeGenerator(Exchange exchange) throws CryptoCmsException {
+        return signedAttributeGenerator;
+    }
+
+    @Override
+    public CMSAttributeTableGenerator getUnsignedAttributeGenerator(Exchange exchange) throws CryptoCmsException {
+        return unsignedAttributeGenerator;
+    }
+
+    public String toString() {
+        return "private key alias=" + privateKeyAlias + ", signature algorithm=" + signatureAlgorithm + ", isIncludeCertificates=" + includeCertificates;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreator.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreator.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreator.java
new file mode 100644
index 0000000..1369551
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreator.java
@@ -0,0 +1,129 @@
+/**
+ * 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.crypto.cms.sig;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.crypto.cms.common.CryptoCmsConstants;
+import org.apache.camel.component.crypto.cms.common.CryptoCmsMarshallerAbstract;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsInvalidKeyException;
+import org.apache.camel.util.IOHelper;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cms.CMSSignedDataStreamGenerator;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SignedDataCreator extends CryptoCmsMarshallerAbstract {
+    private static final Logger LOG = LoggerFactory.getLogger(SignedDataCreator.class);
+
+    private SignedDataCreatorConfiguration config;
+
+    public SignedDataCreator(SignedDataCreatorConfiguration conf) {
+        super(conf);
+        config = conf;
+    }
+
+    @Override
+    protected void setBodyAndHeader(Message out, Object encodedSignedData) {
+        if (config.getIncludeContent()) {
+            /*
+             * The encodedSignedData object contains the signer infos including
+             * the message content.
+             */
+            out.setBody(encodedSignedData);
+        } else {
+            /*
+             * The encodedSignedData object contains only the signer infos
+             * (without the message content). As the message body is not changed
+             * in this case and is passed through
+             */
+            out.setHeader(CryptoCmsConstants.CAMEL_CRYPTO_CMS_SIGNED_DATA, encodedSignedData);
+        }
+    }
+
+    @Override
+    protected void marshalInternal(InputStream is, OutputStream os, Exchange exchange) throws Exception {
+
+        CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+        if (config.getSigner().isEmpty()) {
+            throw new CryptoCmsException("No signer information configured");
+        }
+        for (SignerInfo signer : config.getSigner()) {
+            // these certificates are sent within the signature
+            LOG.debug("Signer info: {}", signer);
+            X509Certificate signerCert = signer.getCertificate(exchange);
+            if (signerCert == null) {
+                throw new CryptoCmsException("Certificate missing in the singer information " + signer);
+            }
+
+            PrivateKey key = signer.getPrivateKey(exchange);
+            if (key == null) {
+                throw new CryptoCmsException("Private key missing in the singer information " + signer);
+            }
+
+            ContentSigner contentSigner;
+            try {
+                contentSigner = new JcaContentSignerBuilder(signer.getSignatureAlgorithm(exchange)).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(key);
+            } catch (OperatorCreationException e) {
+                throw new CryptoCmsInvalidKeyException("The private key of the signer information  '" + signer + "' does not fit to the specified signature algorithm '"
+                                                       + signer.getSignatureAlgorithm(exchange) + "': " + e.getMessage(), e);
+            }
+
+            JcaSignerInfoGeneratorBuilder signerBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME)
+                .build());
+            signerBuilder.setSignedAttributeGenerator(signer.getSignedAttributeGenerator(exchange)).setUnsignedAttributeGenerator(signer.getUnsignedAttributeGenerator(exchange));
+
+            gen.addSignerInfoGenerator(signerBuilder.build(contentSigner, signerCert));
+
+            List<Certificate> certificateList = new ArrayList<Certificate>();
+            for (Certificate cert : signer.getCertificateChain(exchange)) {
+                if (!certificateList.contains(cert)) {
+                    certificateList.add(cert);
+                    gen.addCertificate(new X509CertificateHolder(cert.getEncoded()));
+                    LOG.debug("Certificate added to Signed Data certificate list: {}", cert);
+                }
+            }
+        }
+
+        OutputStream sigOut = gen.open(os, config.getIncludeContent());
+        try {
+            IOHelper.copyAndCloseInput(is, sigOut);
+        } finally {
+            IOHelper.close(sigOut);
+        }
+
+        LOG.debug("CMS Signed Data generation successful");
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreatorConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreatorConfiguration.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreatorConfiguration.java
new file mode 100644
index 0000000..354aede
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataCreatorConfiguration.java
@@ -0,0 +1,94 @@
+/**
+ * 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.crypto.cms.sig;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.crypto.cms.common.CryptoCmsMarshallerConfiguration;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@UriParams
+public class SignedDataCreatorConfiguration extends CryptoCmsMarshallerConfiguration {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SignedDataCreatorConfiguration.class);
+
+    @UriParam(label = "sign", defaultValue = "true")
+    private Boolean includeContent = Boolean.TRUE;
+
+    @UriParam(label = "sign", multiValue = true, description = "Signer information: reference to a bean which implements org.apache.camel.component.crypto.cms.api.SignerInfo")
+    private final List<SignerInfo> signer = new ArrayList<SignerInfo>(3);
+
+    public SignedDataCreatorConfiguration(CamelContext context) {
+        super(context);
+    }
+
+    public Boolean getIncludeContent() {
+        return includeContent;
+    }
+
+    /**
+     * Indicates whether the signed content should be included into the Signed
+     * Data instance. If false then a detached Signed Data instance is created
+     * in the header CamelCryptoCmsSignedData.
+     */
+    public void setIncludeContent(Boolean includeContent) {
+        this.includeContent = includeContent;
+    }
+
+    public List<SignerInfo> getSigner() {
+        return signer;
+    }
+
+    public void setSigner(SignerInfo signer) {
+        this.signer.add(signer);
+    }
+
+    // for multi values
+    public void setSigner(List<?> signers) {
+        if (signers == null) {
+            return;
+        }
+        for (Object signerOb : signers) {
+            if (signerOb instanceof String) {
+                String signerName = (String)signerOb;
+                String valueNoHash = signerName.replaceAll("#", "");
+                if (getContext() != null && signerName != null) {
+                    SignerInfo signer = getContext().getRegistry().lookupByNameAndType(valueNoHash, SignerInfo.class);
+                    if (signer != null) {
+                        setSigner(signer);
+                    }
+                }
+            }
+        }
+
+    }
+
+    public void init() throws CryptoCmsException {
+
+        if (signer.isEmpty()) {
+            logErrorAndThrow(LOG, "No signer set.");
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b831203b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataVerifier.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataVerifier.java b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataVerifier.java
new file mode 100644
index 0000000..f3c1e11
--- /dev/null
+++ b/components/camel-crypto-cms/src/main/java/org/apache/camel/component/crypto/cms/sig/SignedDataVerifier.java
@@ -0,0 +1,286 @@
+/**
+ * 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.crypto.cms.sig;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.crypto.cms.common.CryptoCmsUnmarshaller;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsFormatException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsNoCertificateForSignerInfoException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsNoCertificateForSignerInfosException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsSignatureException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsSignatureInvalidContentHashException;
+import org.apache.camel.component.crypto.cms.exception.CryptoCmsVerifierCertificateNotValidException;
+import org.apache.camel.converter.stream.OutputStreamBuilder;
+import org.apache.camel.util.IOHelper;
+import org.bouncycastle.asn1.cms.Attribute;
+import org.bouncycastle.asn1.cms.CMSAttributes;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSAttributeTableGenerator;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSSignedDataParser;
+import org.bouncycastle.cms.CMSSignerDigestMismatchException;
+import org.bouncycastle.cms.CMSVerifierCertificateNotValidException;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.SignerInformationStore;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SignedDataVerifier extends CryptoCmsUnmarshaller {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SignedDataVerifier.class);
+
+    private final SignedDataVerifierConfiguration conf;
+
+    public SignedDataVerifier(SignedDataVerifierConfiguration config) {
+        super(config);
+        this.conf = config;
+    }
+
+    @Override
+    protected Object unmarshalInternal(InputStream is, Exchange exchange) throws Exception {
+
+        CMSSignedDataParser sp;
+        try {
+            sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(), is);
+        } catch (CMSException e) {
+            throw new CryptoCmsFormatException(getFormatErrorMessage(), e);
+        }
+        OutputStreamBuilder output = getOutputStream(sp, exchange);
+
+        debugLog(sp);
+
+        verify(sp, exchange);
+
+        return output.build();
+    }
+
+    protected String getFormatErrorMessage() {
+        return "Message has invalid format. It was not possible to parse the message into a PKCS7/CMS content info object containing PKCS7/CMS Signed Data.";
+    }
+
+    protected OutputStreamBuilder getOutputStream(CMSSignedDataParser sp, Exchange exchange) throws Exception {
+        // get the InputStream with the plain data
+        InputStream data;
+        try {
+            data = sp.getSignedContent().getContentStream();
+        } catch (NullPointerException e) { // nullpointer exception is
+                                           // thrown when the signed content
+                                           // is missing
+            throw getContentMissingException(e);
+        }
+
+        // the input stream must be completely read, otherwise the signer
+        // info is not available!
+        OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange);
+
+        try {
+            // data can be null in the case of explicit Signed Data
+            if (data != null) {
+                try {
+                    IOHelper.copy(data, osb);
+                } finally {
+                    IOHelper.close(data);
+                }
+            }
+        } catch (IOException e) {
+            throw new CryptoCmsException("Error during reading the signed content of the signed data object", e);
+        }
+        return osb;
+    }
+
+    protected CryptoCmsException getContentMissingException(NullPointerException e) {
+        return new CryptoCmsException("PKCS7/CMS signature validation not possible: The content for which the hash-value must be calculated is missing in the PKCS7/CMS signed data instance. "
+                                      + "Please check the configuration of the sender of the PKCS7/CMS signature.", e);
+    }
+
+    protected void debugLog(CMSSignedDataParser sp) throws CMSException {
+        if (!LOG.isDebugEnabled()) {
+            return;
+        }
+        SignerInformationStore signers = sp.getSignerInfos();
+        Set<AlgorithmIdentifier> messageDigestAlgorithms = sp.getDigestAlgorithmIDs();
+        for (AlgorithmIdentifier algorithm : messageDigestAlgorithms) {
+            LOG.debug("Message digest algorithm: {}", algorithm.getAlgorithm().getId());
+        }
+
+        LOG.debug("Included Signer Infos:");
+        int i = 0;
+        for (SignerInformation signer : signers.getSigners()) {
+            i++;
+            LOG.debug("    Signer {}: {} ", new Object[] {i, signerInformationToString(signer)});
+            if (signer.getSignedAttributes() != null) {
+                @SuppressWarnings("unchecked")
+                Hashtable<String, Attribute> authAttTable = signer.getSignedAttributes().toHashtable();
+                if (authAttTable != null) {
+                    LOG.debug("    Signed attributes of signer {}: {}", i, attributesToString(authAttTable));
+                }
+            }
+            if (signer.getUnsignedAttributes() != null) {
+                @SuppressWarnings("unchecked")
+                Hashtable<String, Attribute> unAuthAtts = signer.getUnsignedAttributes().toHashtable();
+                if (unAuthAtts != null) {
+                    LOG.debug("    Unsigned attributes of signer {}: {}", i, attributesToString(unAuthAtts));
+                }
+            }
+        }
+    }
+
+    protected void verify(CMSSignedDataParser signed, Exchange exchange) throws Exception {
+
+        SignerInformationStore signers = getNonEmptySenderInfos(signed);
+
+        Collection<X509Certificate> allowedVerifyCerts = conf.getCertificates(exchange);
+        if (allowedVerifyCerts.isEmpty()) {
+            throw new CryptoCmsNoCertificateForSignerInfosException("Cannot verify the signatures of the the PKCS7/CMS Signed Data object: No verifier certificate is configured.");
+        }
+
+        JcaCertStore certStore = new JcaCertStore(allowedVerifyCerts);
+
+        boolean atLeastOneSignatureVerified = false;
+        for (SignerInformation signer : signers.getSigners()) {
+            @SuppressWarnings("unchecked")
+            Collection<X509CertificateHolder> certCollection = certStore.getMatches(signer.getSID());
+
+            if (certCollection.isEmpty()) {
+                if (conf.isVerifySignaturesOfAllSigners(exchange)) {
+                    throw new CryptoCmsNoCertificateForSignerInfoException("KCS7/CMS signature verification failed. The public key for the signer information with"
+                                                                           + signerInformationToString(signer) + " cannot be found in the configured certificates: "
+                                                                           + certsToString(allowedVerifyCerts));
+                } else {
+                    continue;
+                }
+            }
+            Iterator<X509CertificateHolder> certIt = certCollection.iterator();
+            X509CertificateHolder cert = certIt.next();
+
+            try {
+                if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(cert))) {
+                    LOG.debug("Verification successful");
+                    atLeastOneSignatureVerified = true;
+                    if (!conf.isVerifySignaturesOfAllSigners(exchange)) {
+                        return;
+                    }
+                } else {
+                    throw new CryptoCmsSignatureException("PKCS7/CMS signature verification failed for signer information with " + issuerSerialNumberSubject(cert));
+                }
+            } catch (CMSSignerDigestMismatchException e) {
+                throw new CryptoCmsSignatureInvalidContentHashException("PKCS7/CMS signature verification failed for signer information with " + issuerSerialNumberSubject(cert)
+                                                                        + ". Calculated hash differs from the signed hash value. Either the message content does not correspond "
+                                                                        + "to the signature or the message might be tampered.", e);
+            } catch (CMSVerifierCertificateNotValidException e) {
+                throw new CryptoCmsVerifierCertificateNotValidException("PKCS7/CMS signature verification failed for signer information with " + issuerSerialNumberSubject(cert)
+                                                                        + ". Certificate was not valid at the signing time.", e);
+            }
+        }
+
+        if (!atLeastOneSignatureVerified) {
+            throw new CryptoCmsNoCertificateForSignerInfosException("Cannot verify the signature of the PKCS7/CMS signed data object with the certificates "
+                                                                    + certsToString(allowedVerifyCerts)
+                                                                    + " specified in the configuration. The signers in the signed data object are: " + signersToString(signers));
+
+        }
+    }
+
+    SignerInformationStore getNonEmptySenderInfos(CMSSignedDataParser signed) throws CryptoCmsException, CMSException {
+        SignerInformationStore senders = signed.getSignerInfos();
+        if (senders.size() == 0) {
+            throw new CryptoCmsException("Sent CMS/PKCS7 signed data message is incorrect. No signer info found in signed data. Correct the sent message.");
+        }
+        return senders;
+    }
+
+    protected String signerInformationToString(SignerInformation sigInfo) {
+        if (sigInfo == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append("ContentTypeOID=");
+        sb.append(sigInfo.getContentType());
+        sb.append(", Issuer=");
+        sb.append(sigInfo.getSID().getIssuer());
+        sb.append(", SerialNumber=");
+        sb.append(sigInfo.getSID().getSerialNumber());
+        sb.append(", SignerInfoVersion=");
+        sb.append(sigInfo.getVersion());
+        sb.append(", SignatureAlgorithmOID=");
+        sb.append(sigInfo.getDigestAlgOID());
+        sb.append(", EncryptionAlgorithmOID=");
+        sb.append(sigInfo.getEncryptionAlgOID());
+        sb.append(", isCounterSignature=");
+        sb.append(sigInfo.isCounterSignature());
+
+        return sb.toString();
+
+    }
+
+    protected String signersToString(SignerInformationStore signers) {
+        if (signers == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        Collection<SignerInformation> sigInfos = signers.getSigners();
+        int size = sigInfos.size();
+        int counter = 0;
+        for (SignerInformation sigInfo : sigInfos) {
+            counter++;
+            sb.append('[');
+            sb.append("Issuer=");
+            sb.append(sigInfo.getSID().getIssuer());
+            sb.append(", SerialNumber=");
+            sb.append(sigInfo.getSID().getSerialNumber());
+            sb.append(']');
+            if (counter < size) {
+                sb.append("; ");
+            }
+        }
+        return sb.toString();
+    }
+
+    protected String attributesToString(Hashtable<String, Attribute> attributes) {
+        if (attributes == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (Attribute attr : attributes.values()) {
+            sb.append(attr.getAttrType());
+            if (CMSAttributes.signingTime.equals(attr.getAttrType()) || CMSAttributes.messageDigest.equals(attr.getAttrType())
+                || CMSAttributes.cmsAlgorithmProtect.equals(attr.getAttrType()) || CMSAttributeTableGenerator.CONTENT_TYPE.equals(attr.getAttrType())) {
+                // for these attributes we can print the value because we know
+                // they do not contain confidential or personal data
+                sb.append("=");
+                sb.append(attr.getAttrValues());
+            }
+            sb.append(",");
+        }
+        return sb.toString();
+    }
+
+}