You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2014/03/13 10:41:42 UTC

git commit: CAMEL-7283: PGP Data Format: Signature Verification Options. Thanks to Franz Forsthofer for the patch.

Repository: camel
Updated Branches:
  refs/heads/master 4be7f3630 -> e8c9f630b


CAMEL-7283: PGP Data Format: Signature Verification Options. Thanks to Franz Forsthofer for the patch.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e8c9f630
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e8c9f630
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e8c9f630

Branch: refs/heads/master
Commit: e8c9f630b482f4687274cd2f184a0e16238ed94c
Parents: 4be7f36
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Mar 13 10:42:03 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Mar 13 10:42:03 2014 +0100

----------------------------------------------------------------------
 .../converter/crypto/PGPDataFormatUtil.java     | 148 ++++++-------
 .../crypto/PGPKeyAccessDataFormat.java          | 222 +++++++++++++------
 .../converter/crypto/PGPDataFormatTest.java     |  93 ++++++--
 3 files changed, 303 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e8c9f630/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
index b8849db..8713c3e 100644
--- a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
@@ -24,10 +24,8 @@ import java.security.NoSuchProviderException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.util.IOHelper;
@@ -112,7 +110,7 @@ public final class PGPDataFormatUtil {
         }
         return pubKey;
     }
-    
+
     public static PGPPublicKeyRingCollection getPublicKeyRingCollection(CamelContext context, String filename, byte[] keyRing, boolean forEncryption) throws IOException, PGPException {
         InputStream is = determineKeyRingInputStream(context, filename, keyRing, forEncryption);
         try {
@@ -204,35 +202,37 @@ public final class PGPDataFormatUtil {
         return findPublicKeys(userids, forEncryption, pgpSec);
     }
 
-    
     @SuppressWarnings("unchecked")
-    public static List<PGPPublicKey> findPublicKeys(List<String> userids, boolean forEncryption, PGPPublicKeyRingCollection pgpPublicKeyringCollection) {
-        List<PGPPublicKey> result = new ArrayList<PGPPublicKey>(userids.size());
+    public static List<PGPPublicKey> findPublicKeys(List<String> useridParts, boolean forEncryption, PGPPublicKeyRingCollection pgpPublicKeyringCollection) {
+        List<PGPPublicKey> result = new ArrayList<PGPPublicKey>(useridParts.size());
         for (Iterator<PGPPublicKeyRing> keyRingIter = pgpPublicKeyringCollection.getKeyRings(); keyRingIter.hasNext();) {
             PGPPublicKeyRing keyRing = keyRingIter.next();
-            Set<String> keyUserIds = getUserIds(keyRing);
+            PGPPublicKey primaryKey = keyRing.getPublicKey();
+            String[] foundKeyUserIdForUserIdPart = findFirstKeyUserIdContainingOneOfTheParts(useridParts, primaryKey);
+            if (foundKeyUserIdForUserIdPart == null) {
+                LOG.debug("No User ID found in primary key with key ID {} containing one of the parts {}", primaryKey.getKeyID(),
+                        useridParts);
+                continue;
+            }
+            LOG.debug("User ID {} found in primary key with key ID {} containing one of the parts {}", new Object[] {
+                foundKeyUserIdForUserIdPart[0], primaryKey.getKeyID(), useridParts });
+            // add adequate keys to the result
             for (Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys(); keyIter.hasNext();) {
                 PGPPublicKey key = keyIter.next();
-                for (String useridPart : userids) {
-                    for (String keyUserId : keyUserIds) {
-                        if (keyUserId != null && keyUserId.contains(useridPart)) {
-                            if (forEncryption) {
-                                if (isEncryptionKey(key)) {
-                                    LOG.debug(
-                                            "Public encryption key with key user ID {} and key ID {} found for specified user ID part {}",
-                                            new Object[] {keyUserId, Long.toString(key.getKeyID()), useridPart });
-                                    result.add(key);
-                                }
-                            } else if (!forEncryption && isSignatureKey(key)) {
-                                // not used!
-                                result.add(key);
-                                LOG.debug("Public key with key user ID {} and key ID {} found for specified user ID part {}", new Object[] {
-                                    keyUserId, Long.toString(key.getKeyID()), useridPart });
-                            }
-                        }
+                if (forEncryption) {
+                    if (isEncryptionKey(key)) {
+                        LOG.debug("Public encryption key with key user ID {} and key ID {} added to the encryption keys",
+                                foundKeyUserIdForUserIdPart[0], Long.toString(key.getKeyID()));
+                        result.add(key);
                     }
+                } else if (!forEncryption && isSignatureKey(key)) {
+                    // not used!
+                    result.add(key);
+                    LOG.debug("Public key with key user ID {} and key ID {} added to the signing keys", foundKeyUserIdForUserIdPart[0],
+                            Long.toString(key.getKeyID()));
                 }
             }
+
         }
 
         return result;
@@ -247,7 +247,7 @@ public final class PGPDataFormatUtil {
         if (hasEncryptionKeyFlags != null && !hasEncryptionKeyFlags) {
             LOG.debug(
                     "Public key with key key ID {} found for specified user ID. But this key will not be used for the encryption, because its key flags are not encryption key flags.",
-                    new Object[] {Long.toString(key.getKeyID()) });
+                    Long.toString(key.getKeyID()));
             return false;
         } else {
             // also without keyflags (hasEncryptionKeyFlags = null), true is returned!
@@ -261,31 +261,18 @@ public final class PGPDataFormatUtil {
     // the user IDs of the master / primary key. The master / primary key is the first key in
     // the keyring, and the rest of the keys are subkeys.
     // http://bouncy-castle.1462172.n4.nabble.com/How-to-find-PGP-subkeys-td1465289.html
-    @SuppressWarnings("unchecked")
-    private static Set<String> getUserIds(PGPPublicKeyRing keyRing) {
-        Set<String> userIds = new LinkedHashSet<String>(3);
-        for (Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys(); keyIter.hasNext();) {
-            PGPPublicKey key = keyIter.next();
-            for (Iterator<String> iterator = key.getUserIDs(); iterator.hasNext();) {
-                userIds.add(iterator.next());
+    private static String[] findFirstKeyUserIdContainingOneOfTheParts(List<String> useridParts, PGPPublicKey primaryKey) {
+        String[] foundKeyUserIdForUserIdPart = null;
+        for (@SuppressWarnings("unchecked")
+        Iterator<String> iterator = primaryKey.getUserIDs(); iterator.hasNext();) {
+            String keyUserId = iterator.next();
+            for (String userIdPart : useridParts) {
+                if (keyUserId.contains(userIdPart)) {
+                    foundKeyUserIdForUserIdPart = new String[] {keyUserId, userIdPart };
+                }
             }
         }
-        return userIds;
-    }
-
-    // Within a secret keyring, the master / primary key has the user ID(s); the subkeys don't
-    // have user IDs associated directly to them, but the subkeys are implicitly associated with
-    // the user IDs of the master / primary key. The master / primary key is the first key in
-    // the keyring, and the rest of the keys are subkeys.
-    // http://bouncy-castle.1462172.n4.nabble.com/How-to-find-PGP-subkeys-td1465289.html
-    @SuppressWarnings("unchecked")
-    private static Set<String> getUserIds(PGPSecretKeyRing keyRing) {
-        Set<String> userIds = new LinkedHashSet<String>(3);
-        PGPSecretKey key = keyRing.getSecretKey();
-        for (Iterator<String> iterator = key.getUserIDs(); iterator.hasNext();) {
-            userIds.add(iterator.next());
-        }
-        return userIds;
+        return foundKeyUserIdForUserIdPart;
     }
 
     private static boolean isSignatureKey(PGPPublicKey key) {
@@ -409,31 +396,33 @@ public final class PGPDataFormatUtil {
 
     public static List<PGPSecretKeyAndPrivateKeyAndUserId> findSecretKeysWithPrivateKeyAndUserId(Map<String, String> sigKeyUserId2Password,
             String provider, PGPSecretKeyRingCollection pgpSec) throws PGPException {
-        List<PGPSecretKeyAndPrivateKeyAndUserId> result = new ArrayList<PGPSecretKeyAndPrivateKeyAndUserId>(
-                sigKeyUserId2Password.size());
+        List<PGPSecretKeyAndPrivateKeyAndUserId> result = new ArrayList<PGPSecretKeyAndPrivateKeyAndUserId>(sigKeyUserId2Password.size());
         for (Iterator<?> i = pgpSec.getKeyRings(); i.hasNext();) {
             Object data = i.next();
             if (data instanceof PGPSecretKeyRing) {
                 PGPSecretKeyRing keyring = (PGPSecretKeyRing) data;
-                Set<String> keyUserIds = getUserIds(keyring);
-
-                for (String userIdPart : sigKeyUserId2Password.keySet()) {
-                    for (String keyUserId : keyUserIds) {
-                        if (keyUserId.contains(userIdPart)) {
-                            for (@SuppressWarnings("unchecked")
-                            Iterator<PGPSecretKey> iterKey = keyring.getSecretKeys(); iterKey.hasNext();) {
-                                PGPSecretKey secKey = iterKey.next();
-                                if (isSigningKey(secKey)) {
-                                    PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(
-                                            provider).build(sigKeyUserId2Password.get(userIdPart).toCharArray()));
-                                    if (privateKey != null) {
-                                        result.add(new PGPSecretKeyAndPrivateKeyAndUserId(secKey, privateKey, keyUserId));
-                                        LOG.debug("Private key with key user ID {} and key ID {} found for specified user ID part {}",
-                                                new Object[] {keyUserId, Long.toString(privateKey.getKeyID()), userIdPart });
-
-                                    }
-                                }
-                            }
+                PGPSecretKey primaryKey = keyring.getSecretKey();
+                List<String> useridParts = new ArrayList<String>(sigKeyUserId2Password.keySet());
+                String[] foundKeyUserIdForUserIdPart = findFirstKeyUserIdContainingOneOfTheParts(useridParts, primaryKey.getPublicKey());
+                if (foundKeyUserIdForUserIdPart == null) {
+                    LOG.debug("No User ID found in primary key with key ID {} containing one of the parts {}", primaryKey.getKeyID(),
+                            useridParts);
+                    continue;
+                }
+                LOG.debug("User ID {} found in primary key with key ID {} containing one of the parts {}", new Object[] {
+                    foundKeyUserIdForUserIdPart[0], primaryKey.getKeyID(), useridParts });
+                // add all signing keys
+                for (@SuppressWarnings("unchecked")
+                Iterator<PGPSecretKey> iterKey = keyring.getSecretKeys(); iterKey.hasNext();) {
+                    PGPSecretKey secKey = iterKey.next();
+                    if (isSigningKey(secKey)) {
+                        PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider)
+                                .build(sigKeyUserId2Password.get(foundKeyUserIdForUserIdPart[1]).toCharArray()));
+                        if (privateKey != null) {
+                            result.add(new PGPSecretKeyAndPrivateKeyAndUserId(secKey, privateKey, foundKeyUserIdForUserIdPart[0]));
+                            LOG.debug("Private key with user ID {} and key ID {} added to the signing keys",
+                                    foundKeyUserIdForUserIdPart[0], Long.toString(privateKey.getKeyID()));
+
                         }
                     }
                 }
@@ -493,14 +482,19 @@ public final class PGPDataFormatUtil {
         }
         return null; // no key flag
     }
-    
-    
+
     /**
-     * Determines a public key from the keyring collection which has a certain key ID and which has a User ID which contains at least one of the User ID parts.
+     * Determines a public key from the keyring collection which has a certain
+     * key ID and which has a User ID which contains at least one of the User ID
+     * parts.
      * 
-     * @param keyId key ID
-     * @param userIdParts user ID parts, can be empty, than no filter on the User ID is executed
-     * @param publicKeyringCollection keyring collection
+     * @param keyId
+     *            key ID
+     * @param userIdParts
+     *            user ID parts, can be empty, than no filter on the User ID is
+     *            executed
+     * @param publicKeyringCollection
+     *            keyring collection
      * @return public key or <code>null</code> if no fitting key is found
      * @throws PGPException
      */
@@ -519,7 +513,7 @@ public final class PGPDataFormatUtil {
             return null;
         }
     }
-    
+
     private static boolean isAllowedKey(List<String> allowedUserIds, Iterator<String> verifyingPublicKeyUserIds) {
 
         if (allowedUserIds == null || allowedUserIds.isEmpty()) {
@@ -543,5 +537,5 @@ public final class PGPDataFormatUtil {
                 keyUserId, allowedUserIds);
         return false;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e8c9f630/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
index 92663c4..179a4d1 100644
--- a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
@@ -18,12 +18,14 @@ package org.apache.camel.converter.crypto;
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.SecureRandom;
 import java.security.Security;
 import java.security.SignatureException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -76,6 +78,10 @@ import org.slf4j.LoggerFactory;
  * array or file, then you should use the class {@link PGPDataFormat}.
  * 
  */
+/**
+ * @author D023101
+ * 
+ */
 public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat {
 
     public static final String KEY_USERID = "CamelPGPDataFormatKeyUserid";
@@ -87,10 +93,40 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
     public static final String COMPRESSION_ALGORITHM = "CamelPGPDataFormatCompressionAlgorithm";
 
     /**
-     * During encryption the number of asymmectirc encryption keys is set to
-     * this header parameter. The Value is of type Integer.
+     * Signature verification option "optional": Used during unmarshaling. The
+     * PGP message can or cannot contain signatures. If it does contain
+     * signatures then one of them is verified. This is the default option.
+     */
+    public static final String SIGNATURE_VERIFICATION_OPTION_OPTIONAL = "optional";
+
+    /**
+     * Signature verification option "required": Used during unmarshaling. It is
+     * checked that the PGP message does contain at least one signature. If this
+     * is not the case a {@link PGPException} is thrown. One of the contained 
+     * signatures is verified.
+     */
+    public static final String SIGNATURE_VERIFICATION_OPTION_REQUIRED = "required";
+    
+    /**
+     * Signature verification option "required": Used during unmarshaling. If 
+     * the PGP message contains signatures then they are ignored. No 
+     * verification takes place.
+     */
+    public static final String SIGNATURE_VERIFICATION_OPTION_IGNORE = "ignore";
+
+    /**
+     * Signature verification option "no signature allowed": Used during
+     * unmarshaling. It is checked that the PGP message does contain not any
+     * signatures. If this is not the case a {@link PGPException} is thrown.
+     */
+    public static final String SIGNATURE_VERIFICATION_OPTION_NO_SIGNATURE_ALLOWED = "no_signature_allowed";
+
+    /**
+     * During encryption the number of asymmetric encryption keys is set to this
+     * header parameter. The Value is of type Integer.
      */
     public static final String NUMBER_OF_ENCRYPTION_KEYS = "CamelPGPDataFormatNumberOfEncryptionKeys";
+
     /**
      * During signing the number of signing keys is set to this header
      * parameter. This corresponds to the number of signatures. The Value is of
@@ -99,11 +135,13 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
     public static final String NUMBER_OF_SIGNING_KEYS = "CamelPGPDataFormatNumberOfSigningKeys";
 
     private static final Logger LOG = LoggerFactory.getLogger(PGPKeyAccessDataFormat.class);
-    
+
+    private static final List<String> SIGNATURE_VERIFICATION_OPTIONS = Arrays.asList(new String[] {SIGNATURE_VERIFICATION_OPTION_OPTIONAL,
+        SIGNATURE_VERIFICATION_OPTION_REQUIRED, SIGNATURE_VERIFICATION_OPTION_IGNORE, SIGNATURE_VERIFICATION_OPTION_NO_SIGNATURE_ALLOWED });
 
     private static final String BC = "BC";
     private static final int BUFFER_SIZE = 16 * 1024;
-    
+
     PGPPublicKeyAccessor publicKeyAccessor;
 
     PGPSecretKeyAccessor secretKeyAccessor;
@@ -130,6 +168,8 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
 
     private int compressionAlgorithm = CompressionAlgorithmTags.ZIP; // for encryption
 
+    private String signatureVerificationOption = "optional";
+
     public PGPKeyAccessDataFormat() {
     }
 
@@ -308,52 +348,9 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
             return null;
         }
         InputStream in = PGPUtil.getDecoderStream(encryptedStream);
-        PGPObjectFactory pgpFactory = new PGPObjectFactory(in);
-        Object firstObject = pgpFactory.nextObject();
-        // the first object might be a PGP marker packet 
-        PGPEncryptedDataList enc;
-        if (firstObject instanceof PGPEncryptedDataList) {
-            enc = (PGPEncryptedDataList) firstObject;
-        } else {
-            Object secondObject = pgpFactory.nextObject();
-            if (secondObject instanceof PGPEncryptedDataList) {
-                enc = (PGPEncryptedDataList)secondObject;
-            } else {
-                enc = null;
-            }
-        } 
-        
-        if (enc == null) {
-            throw getFormatException();
-        }
-
-        PGPPublicKeyEncryptedData pbe = null;
-        PGPPrivateKey key = null;
-        // find encrypted data for which a private key exists in the secret key ring
-        for (int i = 0; i < enc.size() && key == null; i++) {
-            Object encryptedData = enc.get(i);
-            if (!(encryptedData instanceof PGPPublicKeyEncryptedData)) {
-                throw getFormatException();
-            }
-            pbe = (PGPPublicKeyEncryptedData) encryptedData;
-            key = secretKeyAccessor.getPrivateKey(exchange, pbe.getKeyID());
-            if (key != null) {
-                // take the first key
-                break;
-            }
-        }
-        if (key == null) {
-            throw new PGPException("Message is encrypted with a key which could not be found in the Secret Key Ring.");
-        }
-
-        InputStream encData = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider(getProvider()).build(key));
-        pgpFactory = new PGPObjectFactory(encData);
-        Object compObj = pgpFactory.nextObject();
-        if (!(compObj instanceof PGPCompressedData)) {
-            throw getFormatException();
-        }
-        PGPCompressedData comData = (PGPCompressedData)compObj;
-        pgpFactory = new PGPObjectFactory(comData.getDataStream());
+        InputStream encData = getDecryptedData(exchange, in);
+        InputStream uncompressedData = getUncompressedData(encData);
+        PGPObjectFactory pgpFactory = new PGPObjectFactory(uncompressedData);
         Object object = pgpFactory.nextObject();
 
         PGPOnePassSignature signature;
@@ -361,7 +358,12 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
             signature = getSignature(exchange, (PGPOnePassSignatureList) object);
             object = pgpFactory.nextObject();
         } else {
+            // no signature contained in PGP message
             signature = null;
+            if (SIGNATURE_VERIFICATION_OPTION_REQUIRED.equals(getSignatureVerificationOption())) {
+                throw new PGPException(
+                        "PGP message does not contain any signatures although a signature is expected. Either send a PGP message with signature or change the configuration of the PGP decryptor.");
+            }
         }
 
         PGPLiteralData ld;
@@ -400,12 +402,7 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
             IOHelper.close(os, litData, encData, in);
         }
 
-        if (signature != null) {
-            PGPSignatureList sigList = (PGPSignatureList) pgpFactory.nextObject();
-            if (!signature.verify(getSignatureWithKeyId(signature.getKeyID(), sigList))) {
-                throw new SignatureException("Cannot verify PGP signature");
-            }
-        }
+        verifySignature(pgpFactory, signature);
 
         if (cos != null) {
             return cos.newStreamCache();
@@ -414,11 +411,79 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
         }
     }
 
+    private InputStream getUncompressedData(InputStream encData) throws IOException, PGPException {
+        PGPObjectFactory pgpFactory = new PGPObjectFactory(encData);
+        Object compObj = pgpFactory.nextObject();
+        if (!(compObj instanceof PGPCompressedData)) {
+            throw getFormatException();
+        }
+        PGPCompressedData comData = (PGPCompressedData) compObj;
+        InputStream uncompressedData = comData.getDataStream();
+        return uncompressedData;
+    }
+
+    private InputStream getDecryptedData(Exchange exchange, InputStream encryptedStream) throws Exception, PGPException {
+        PGPObjectFactory pgpFactory = new PGPObjectFactory(encryptedStream);
+        Object firstObject = pgpFactory.nextObject();
+        // the first object might be a PGP marker packet 
+        PGPEncryptedDataList enc = getEcryptedDataList(pgpFactory, firstObject);
+
+        if (enc == null) {
+            throw getFormatException();
+        }
+        PGPPublicKeyEncryptedData pbe = null;
+        PGPPrivateKey key = null;
+        // find encrypted data for which a private key exists in the secret key ring
+        for (int i = 0; i < enc.size() && key == null; i++) {
+            Object encryptedData = enc.get(i);
+            if (!(encryptedData instanceof PGPPublicKeyEncryptedData)) {
+                throw getFormatException();
+            }
+            pbe = (PGPPublicKeyEncryptedData) encryptedData;
+            key = secretKeyAccessor.getPrivateKey(exchange, pbe.getKeyID());
+            if (key != null) {
+                // take the first key
+                break;
+            }
+        }
+        if (key == null) {
+            throw new PGPException("PGP message is encrypted with a key which could not be found in the Secret Keyring.");
+        }
+
+        InputStream encData = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider(getProvider()).build(key));
+        return encData;
+    }
+
+    private PGPEncryptedDataList getEcryptedDataList(PGPObjectFactory pgpFactory, Object firstObject) throws IOException {
+        PGPEncryptedDataList enc;
+        if (firstObject instanceof PGPEncryptedDataList) {
+            enc = (PGPEncryptedDataList) firstObject;
+        } else {
+            Object secondObject = pgpFactory.nextObject();
+            if (secondObject instanceof PGPEncryptedDataList) {
+                enc = (PGPEncryptedDataList) secondObject;
+            } else {
+                enc = null;
+            }
+        }
+        return enc;
+    }
+
+    private void verifySignature(PGPObjectFactory pgpFactory, PGPOnePassSignature signature) throws IOException, PGPException, SignatureException {
+        if (signature != null) {
+            PGPSignatureList sigList = (PGPSignatureList) pgpFactory.nextObject();
+            if (!signature.verify(getSignatureWithKeyId(signature.getKeyID(), sigList))) {
+                throw new SignatureException("Verification of the PGP signature with the key ID " + signature.getKeyID() + " failed. The PGP message may have been tampered.");
+            }
+        }
+    }
+
     private IllegalArgumentException getFormatException() {
-        return new IllegalArgumentException("The input message body has an invalid format. The PGP decryption/verification processor expects a sequence of PGP packets of the form "
-            + "(entries in brackets are optional and ellipses indicate repetition, comma represents  sequential composition, and vertical bar separates alternatives): "
-            + "Public Key Encrypted Session Key ..., Symmetrically Encrypted Data | Sym. Encrypted and Integrity Protected Data, Compressed Data, (One Pass Signature ...,) "
-            + "Literal Data, (Signature ...,)");
+        return new IllegalArgumentException(
+                "The input message body has an invalid format. The PGP decryption/verification processor expects a sequence of PGP packets of the form "
+                        + "(entries in brackets are optional and ellipses indicate repetition, comma represents  sequential composition, and vertical bar separates alternatives): "
+                        + "Public Key Encrypted Session Key ..., Symmetrically Encrypted Data | Sym. Encrypted and Integrity Protected Data, Compressed Data, (One Pass Signature ...,) "
+                        + "Literal Data, (Signature ...,)");
     }
 
     protected PGPSignature getSignatureWithKeyId(long keyID, PGPSignatureList sigList) {
@@ -432,7 +497,13 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
     }
 
     protected PGPOnePassSignature getSignature(Exchange exchange, PGPOnePassSignatureList signatureList) throws Exception {
-
+        if (SIGNATURE_VERIFICATION_OPTION_IGNORE.equals(getSignatureVerificationOption())) {
+            return null;
+        }
+        if (SIGNATURE_VERIFICATION_OPTION_NO_SIGNATURE_ALLOWED.equals(getSignatureVerificationOption())) {
+            throw new PGPException(
+                    "PGP message contains a signature although a signature is not expected. Either change the configuration of the PGP decryptor or send a PGP message with no signature.");
+        }
         List<String> allowedUserIds = determineSignaturenUserIds(exchange);
         for (int i = 0; i < signatureList.size(); i++) {
             PGPOnePassSignature signature = signatureList.get(i);
@@ -448,7 +519,8 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
         if (signatureList.isEmpty()) {
             return null;
         } else {
-            throw new IllegalArgumentException("No public key found fitting to the signature key Id; cannot verify the signature.");
+            throw new IllegalArgumentException("Cannot verify the PGP signature: No public key found for the key ID(s) contained in the PGP signature(s). "
+                + "Either the received PGP message contains a signature from an unexpected sender or the Public Keyring does not contain the public key of the sender.");
         }
 
     }
@@ -626,6 +698,32 @@ public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat
         this.secretKeyAccessor = secretKeyAccessor;
     }
 
+    public String getSignatureVerificationOption() {
+        return signatureVerificationOption;
+    }
+
+    /**
+     * Signature verification option. Controls the behavior for the signature
+     * verification during unmarshaling. Possible values are
+     * {@link #SIGNATURE_VERIFICATION_OPTION_OPTIONAL},
+     * {@link #SIGNATURE_VERIFICATION_OPTION_REQUIRED},
+     * {@link #SIGNATURE_VERIFICATION_OPTION_NO_SIGNATURE_ALLOWED}, and
+     * {@link #SIGNATURE_VERIFICATION_OPTION_IGNORE}. The default
+     * value is {@link #SIGNATURE_VERIFICATION_OPTION_OPTIONAL}
+     * 
+     * @param signatureVerificationOption
+     *            signature verification option
+     * @throws IllegalArgument
+     *             exception if an invalid value is entered
+     */
+    public void setSignatureVerificationOption(String signatureVerificationOption) {
+        if (SIGNATURE_VERIFICATION_OPTIONS.contains(signatureVerificationOption)) {
+            this.signatureVerificationOption = signatureVerificationOption;
+        } else {
+            throw new IllegalArgumentException(signatureVerificationOption + " is not a valid signature verification option");
+        }
+    }
+
     @Override
     protected void doStart() throws Exception {
         if (Security.getProvider(BC) == null && BC.equals(getProvider())) {

http://git-wip-us.apache.org/repos/asf/camel/blob/e8c9f630/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
index 5237710..98f9121 100644
--- a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
+++ b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
@@ -64,6 +64,7 @@ import org.bouncycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerat
 import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
 import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
 import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
+import org.junit.Before;
 import org.junit.Test;
 
 public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
@@ -72,6 +73,26 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
     private static final String SEC_KEY_RING_FILE_NAME = "org/apache/camel/component/crypto/secring.gpg";
     private static final String PUB_KEY_RING_FILE_NAME = "org/apache/camel/component/crypto/pubring.gpg";
 
+    PGPDataFormat encryptor = new PGPDataFormat();
+    PGPDataFormat decryptor = new PGPDataFormat();
+
+    @Before
+    public void setUpEncryptorAndDecryptor() {
+
+        // the following keyring contains a primary key with KeyFlag "Certify" and a subkey for signing and a subkey for encryption
+        encryptor.setKeyFileName(PUB_KEY_RING_SUBKEYS_FILE_NAME);
+        encryptor.setSignatureKeyFileName("org/apache/camel/component/crypto/secringSubKeys.gpg");
+        encryptor.setSignaturePassword("Abcd1234");
+        encryptor.setKeyUserid("keyflag");
+        encryptor.setSignatureKeyUserid("keyflag");
+
+        // the following keyring contains a primary key with KeyFlag "Certify" and a subkey for signing and a subkey for encryption
+        decryptor.setKeyFileName("org/apache/camel/component/crypto/secringSubKeys.gpg");
+        decryptor.setSignatureKeyFileName(PUB_KEY_RING_SUBKEYS_FILE_NAME);
+        decryptor.setPassword("Abcd1234");
+        decryptor.setSignatureKeyUserid("keyflag");
+    }
+
     protected String getKeyFileName() {
         return PUB_KEY_RING_FILE_NAME;
     }
@@ -173,7 +194,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
         template.sendBodyAndHeaders("direct:verify_exception_sig_userids", payload, headers);
         assertMockEndpointsSatisfied();
 
-        checkThrownException(exception, IllegalArgumentException.class, null, "No public key found fitting to the signature key Id");
+        checkThrownException(exception, IllegalArgumentException.class, null, "No public key found for the key ID(s)");
 
     }
 
@@ -299,7 +320,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
         assertMockEndpointsSatisfied();
 
         checkThrownException(mock, PGPException.class, null,
-                "Message is encrypted with a key which could not be found in the Secret Key Ring");
+                "PGP message is encrypted with a key which could not be found in the Secret Keyring");
     }
 
     void createEncryptedNonCompressedData(ByteArrayOutputStream bos, String keyringPath) throws Exception, IOException, PGPException,
@@ -419,6 +440,49 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
         checkThrownException(mock, IllegalArgumentException.class, null, "The input message body has an invalid format.");
     }
 
+    @Test
+    public void testExceptionForSignatureVerificationOptionNoSignatureAllowed() throws Exception {
+
+        decryptor.setSignatureVerificationOption(PGPDataFormat.SIGNATURE_VERIFICATION_OPTION_NO_SIGNATURE_ALLOWED);
+
+        MockEndpoint mock = getMockEndpoint("mock:exception");
+        mock.expectedMessageCount(1);
+        template.sendBody("direct:subkey", "Test Message");
+        assertMockEndpointsSatisfied();
+
+        checkThrownException(mock, PGPException.class, null, "PGP message contains a signature although a signature is not expected");
+    }
+
+    @Test
+    public void testExceptionForSignatureVerificationOptionRequired() throws Exception {
+
+        encryptor.setSignatureKeyUserid(null); // no signature
+        decryptor.setSignatureVerificationOption(PGPDataFormat.SIGNATURE_VERIFICATION_OPTION_REQUIRED);
+
+        MockEndpoint mock = getMockEndpoint("mock:exception");
+        mock.expectedMessageCount(1);
+        template.sendBody("direct:subkey", "Test Message");
+        assertMockEndpointsSatisfied();
+
+        checkThrownException(mock, PGPException.class, null, "PGP message does not contain any signatures although a signature is expected");
+    }
+
+    @Test
+    public void testSignatureVerificationOptionIgnore() throws Exception {
+
+        // encryptor is sending a PGP message with signature! Decryptor is ignoreing the signature
+        decryptor.setSignatureVerificationOption(PGPDataFormat.SIGNATURE_VERIFICATION_OPTION_IGNORE);
+        decryptor.setSignatureKeyUserids(null);
+        decryptor.setSignatureKeyFileName(null); // no public keyring! --> no signature validation possible
+
+        String payload = "Test Message";
+        MockEndpoint mock = getMockEndpoint("mock:unencrypted");
+        mock.expectedBodiesReceived(payload);
+        template.sendBody("direct:subkey", payload);
+        assertMockEndpointsSatisfied();
+
+    }
+
     protected RouteBuilder[] createRouteBuilders() {
         return new RouteBuilder[] {new RouteBuilder() {
             public void configure() throws Exception {
@@ -451,6 +515,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                 pgpDecrypt.setKeyFileName(keyFileNameSec);
                 pgpDecrypt.setPassword(keyPassword);
                 pgpDecrypt.setProvider(getProvider());
+                pgpDecrypt.setSignatureVerificationOption(PGPDataFormat.SIGNATURE_VERIFICATION_OPTION_NO_SIGNATURE_ALLOWED);
 
                 from("direct:inline2").marshal(pgpEncrypt).to("mock:encrypted").unmarshal(pgpDecrypt).to("mock:unencrypted");
 
@@ -523,6 +588,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                 pgpVerifyAndDecryptByteArray.setProvider(getProvider());
                 // restrict verification to public keys with certain User ID
                 pgpVerifyAndDecryptByteArray.setSignatureKeyUserids(getSignatureKeyUserIds());
+                pgpVerifyAndDecryptByteArray.setSignatureVerificationOption(PGPDataFormat.SIGNATURE_VERIFICATION_OPTION_REQUIRED);
 
                 from("direct:sign-key-ring-byte-array").streamCaching()
                 // encryption key ring can also be set as header
@@ -609,28 +675,13 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
             public void configure() throws Exception {
 
                 onException(Exception.class).handled(true).to("mock:exception");
-                // keyflag test
-                PGPDataFormat pgpKeyFlag = new PGPDataFormat();
-                // the following keyring contains a primary key with KeyFlag "Certify" and a subkey for signing and a subkey for encryption
-                pgpKeyFlag.setKeyFileName(PUB_KEY_RING_SUBKEYS_FILE_NAME);
-                pgpKeyFlag.setSignatureKeyFileName("org/apache/camel/component/crypto/secringSubKeys.gpg");
-                pgpKeyFlag.setSignaturePassword("Abcd1234");
-                pgpKeyFlag.setKeyUserid("keyflag");
-                pgpKeyFlag.setSignatureKeyUserid("keyflag");
-
-                from("direct:keyflag").marshal(pgpKeyFlag).to("mock:encrypted_keyflag");
-
-                PGPDataFormat pgpDecryptVerifySubkey = new PGPDataFormat();
-                // the following keyring contains a primary key with KeyFlag "Certify" and a subkey for signing and a subkey for encryption
-                pgpDecryptVerifySubkey.setKeyFileName("org/apache/camel/component/crypto/secringSubKeys.gpg");
-                pgpDecryptVerifySubkey.setSignatureKeyFileName(PUB_KEY_RING_SUBKEYS_FILE_NAME);
-                pgpDecryptVerifySubkey.setPassword("Abcd1234");
-                pgpDecryptVerifySubkey.setSignatureKeyUserid("keyflag");
+
+                from("direct:keyflag").marshal(encryptor).to("mock:encrypted_keyflag");
 
                 // test that the correct subkey is selected during decrypt and verify
-                from("direct:subkey").marshal(pgpKeyFlag).to("mock:encrypted").unmarshal(pgpDecryptVerifySubkey).to("mock:unencrypted");
+                from("direct:subkey").marshal(encryptor).to("mock:encrypted").unmarshal(decryptor).to("mock:unencrypted");
 
-                from("direct:subkeyUnmarshal").unmarshal(pgpDecryptVerifySubkey).to("mock:unencrypted");
+                from("direct:subkeyUnmarshal").unmarshal(decryptor).to("mock:unencrypted");
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {