Updated Branches:
  refs/heads/camel-2.12.x cbd7cb001 -> c09ae2fe5

CAMEL-7192 Supported the Sub-Key in PGPDataFormat with thanks to Franz


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

Branch: refs/heads/camel-2.12.x
Commit: c09ae2fe548c85d6dacc6c9ed84536d418cdcaa9
Parents: cbd7cb0
Author: Willem Jiang <willem.ji...@gmail.com>
Authored: Wed Feb 12 11:18:11 2014 +0800
Committer: Willem Jiang <willem.ji...@gmail.com>
Committed: Wed Feb 12 11:22:31 2014 +0800

----------------------------------------------------------------------
 .../camel/converter/crypto/PGPDataFormat.java   |  16 ++
 .../converter/crypto/PGPDataFormatUtil.java     | 197 ++++++++++++++-----
 .../converter/crypto/PGPDataFormatTest.java     |  55 +++++-
 .../camel/component/crypto/pubringSubKeys.gpg   | Bin 0 -> 2020 bytes
 .../camel/component/crypto/secringSubKeys.gpg   | Bin 0 -> 4087 bytes
 5 files changed, 209 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/c09ae2fe/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
----------------------------------------------------------------------
diff --git 
a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
 
b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
index 0157088..d7e92b2 100644
--- 
a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
+++ 
b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
@@ -94,6 +94,18 @@ public class PGPDataFormat extends ServiceSupport implements 
DataFormat {
     public static final String SIGNATURE_HASH_ALGORITHM = 
"CamelPGPDataFormatSignatureHashAlgorithm";
     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.
+     */
+    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
+     * type Integer.
+     */
+    public static final String NUMBER_OF_SIGNING_KEYS = 
"CamelPGPDataFormatNumberOfSigningKeys";
+
     private static final Logger LOG = 
LoggerFactory.getLogger(PGPDataFormat.class);
 
     private static final String BC = "BC";
@@ -210,6 +222,7 @@ public class PGPDataFormat extends ServiceSupport 
implements DataFormat {
             throw new IllegalArgumentException("Cannot PGP encrypt message. No 
public encryption key found for the User Ids " + userids
                     + " in the public keyring. Either specify other User IDs 
or add correct public keys to the keyring.");
         }
+        exchange.getOut().setHeader(NUMBER_OF_ENCRYPTION_KEYS, 
Integer.valueOf(keys.size()));
 
         InputStream input = ExchangeHelper.convertToMandatoryType(exchange, 
InputStream.class, graph);
 
@@ -324,6 +337,8 @@ public class PGPDataFormat extends ServiceSupport 
implements DataFormat {
         List<PGPSecretKeyAndPrivateKeyAndUserId> 
sigSecretKeysWithPrivateKeyAndUserId = 
determineSecretKeysWithPrivateKeyAndUserId(
                 exchange, sigKeyFileName, sigKeyUserids, sigKeyPassword, 
sigKeyRing);
 
+        exchange.getOut().setHeader(NUMBER_OF_SIGNING_KEYS, 
Integer.valueOf(sigSecretKeysWithPrivateKeyAndUserId.size()));
+
         List<PGPSignatureGenerator> sigGens = new 
ArrayList<PGPSignatureGenerator>();
         for (PGPSecretKeyAndPrivateKeyAndUserId 
sigSecretKeyWithPrivateKeyAndUserId : sigSecretKeysWithPrivateKeyAndUserId) {
             PGPPrivateKey sigPrivateKey = 
sigSecretKeyWithPrivateKeyAndUserId.getPrivateKey();
@@ -342,6 +357,7 @@ public class PGPDataFormat extends ServiceSupport 
implements DataFormat {
         return sigGens;
     }
 
+
     public List<PGPSecretKeyAndPrivateKeyAndUserId> 
determineSecretKeysWithPrivateKeyAndUserId(Exchange exchange, String 
sigKeyFileName,
             List<String> sigKeyUserids, String sigKeyPassword, byte[] 
sigKeyRing) throws IOException, PGPException, NoSuchProviderException {
 

http://git-wip-us.apache.org/repos/asf/camel/blob/c09ae2fe/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 3408a4a..b09ebe8 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
@@ -31,6 +31,7 @@ import java.util.Set;
 import org.apache.camel.CamelContext;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ResourceHelper;
+import org.bouncycastle.bcpg.sig.KeyFlags;
 import org.bouncycastle.openpgp.PGPEncryptedDataList;
 import org.bouncycastle.openpgp.PGPException;
 import org.bouncycastle.openpgp.PGPObjectFactory;
@@ -42,6 +43,8 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
 import org.bouncycastle.openpgp.PGPSecretKey;
 import org.bouncycastle.openpgp.PGPSecretKeyRing;
 import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
 import org.bouncycastle.openpgp.PGPUtil;
 import 
org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
 import org.slf4j.Logger;
@@ -54,7 +57,7 @@ import static 
org.bouncycastle.bcpg.PublicKeyAlgorithmTags.RSA_GENERAL;
 import static org.bouncycastle.bcpg.PublicKeyAlgorithmTags.RSA_SIGN;
 
 public final class PGPDataFormatUtil {
-    
+
     private static final Logger LOG = 
LoggerFactory.getLogger(PGPDataFormatUtil.class);
 
     private PGPDataFormatUtil() {
@@ -86,7 +89,7 @@ public final class PGPDataFormatUtil {
     }
 
     public static List<PGPPublicKey> findPublicKeys(CamelContext context, 
String filename, byte[] keyRing, List<String> userids,
-        boolean forEncryption) throws IOException, PGPException, 
NoSuchProviderException {
+            boolean forEncryption) throws IOException, PGPException, 
NoSuchProviderException {
         InputStream is = determineKeyRingInputStream(context, filename, 
keyRing, forEncryption);
         try {
             return findPublicKeys(is, userids, forEncryption);
@@ -96,7 +99,7 @@ public final class PGPDataFormatUtil {
     }
 
     public static PGPPublicKey findPublicKeyWithKeyId(CamelContext context, 
String filename, byte[] keyRing, long keyid,
-        boolean forEncryption) throws IOException, PGPException, 
NoSuchProviderException {
+            boolean forEncryption) throws IOException, PGPException, 
NoSuchProviderException {
         InputStream is = determineKeyRingInputStream(context, filename, 
keyRing, forEncryption);
         PGPPublicKey pubKey;
         try {
@@ -108,8 +111,8 @@ public final class PGPDataFormatUtil {
     }
 
     public static PGPPrivateKey findPrivateKeyWithKeyId(CamelContext context, 
String filename, byte[] secretKeyRing, long keyid,
-        String passphrase, PGPPassphraseAccessor passpraseAccessor, String 
provider) throws IOException, PGPException,
-        NoSuchProviderException {
+            String passphrase, PGPPassphraseAccessor passpraseAccessor, String 
provider) throws IOException, PGPException,
+            NoSuchProviderException {
         InputStream is = determineKeyRingInputStream(context, filename, 
secretKeyRing, true);
         try {
             return findPrivateKeyWithKeyId(is, keyid, passphrase, 
passpraseAccessor, provider);
@@ -120,31 +123,30 @@ public final class PGPDataFormatUtil {
 
     @SuppressWarnings("unchecked")
     private static PGPPrivateKey findPrivateKeyWithKeyId(InputStream 
keyringInput, long keyid, String passphrase,
-        PGPPassphraseAccessor passphraseAccessor, String provider) throws 
IOException, PGPException {
+            PGPPassphraseAccessor passphraseAccessor, String provider) throws 
IOException, PGPException {
         PGPSecretKeyRingCollection pgpSec = new 
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
         for (Iterator<?> i = pgpSec.getKeyRings(); i.hasNext();) {
             Object data = i.next();
             if (data instanceof PGPSecretKeyRing) {
                 PGPSecretKeyRing keyring = (PGPSecretKeyRing) data;
-                for (Iterator<PGPSecretKey> secKeys = keyring.getSecretKeys(); 
secKeys.hasNext();) {
-                    PGPSecretKey secKey = secKeys.next();
-                    if (secKey != null && keyid == secKey.getKeyID()) {
-                        if (passphrase == null && passphraseAccessor != null) {
-                            // get passphrase from accessor
-                            Iterator<String> userIDs = secKey.getUserIDs();
-                            while (passphrase == null && userIDs.hasNext()) {
-                                passphrase = 
passphraseAccessor.getPassphrase(userIDs.next());
-                            }
+                PGPSecretKey secKey = keyring.getSecretKey(keyid);
+                if (secKey != null) {
+                    if (passphrase == null && passphraseAccessor != null) {
+                        // get passphrase from accessor // only primary/master 
key has user IDS
+                        Iterator<String> userIDs = 
keyring.getSecretKey().getUserIDs();
+                        while (passphrase == null && userIDs.hasNext()) {
+                            passphrase = 
passphraseAccessor.getPassphrase(userIDs.next());
                         }
-                        if (passphrase != null) {
-                            PGPPrivateKey privateKey = 
secKey.extractPrivateKey(new 
JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(
-                                    passphrase.toCharArray()));
-                            if (privateKey != null) {
-                                return privateKey;
-                            }
+                    }
+                    if (passphrase != null) {
+                        PGPPrivateKey privateKey = 
secKey.extractPrivateKey(new 
JcePBESecretKeyDecryptorBuilder().setProvider(provider)
+                                .build(passphrase.toCharArray()));
+                        if (privateKey != null) {
+                            return privateKey;
                         }
                     }
                 }
+
             }
         }
         return null;
@@ -173,24 +175,24 @@ public final class PGPDataFormatUtil {
 
     @SuppressWarnings("unchecked")
     private static PGPPublicKey findPublicKeyWithKeyId(InputStream input, long 
keyid) throws IOException, PGPException,
-        NoSuchProviderException {
+            NoSuchProviderException {
         PGPPublicKeyRingCollection pgpSec = new 
PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
 
         for (Iterator<PGPPublicKeyRing> keyRingIter = pgpSec.getKeyRings(); 
keyRingIter.hasNext();) {
-            PGPPublicKeyRing keyRing = keyRingIter.next();           
+            PGPPublicKeyRing keyRing = keyRingIter.next();
             PGPPublicKey key = keyRing.getPublicKey(keyid);
             if (key != null) {
                 return key;
             }
 
         }
-        
+
         return null;
     }
 
     @SuppressWarnings("unchecked")
     private static List<PGPPublicKey> findPublicKeys(InputStream input, 
List<String> userids, boolean forEncryption) throws IOException,
-        PGPException, NoSuchProviderException {
+            PGPException, NoSuchProviderException {
         List<PGPPublicKey> result = new ArrayList<PGPPublicKey>(3);
 
         PGPPublicKeyRingCollection pgpSec = new 
PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
@@ -203,11 +205,15 @@ public final class PGPDataFormatUtil {
                 for (String useridPart : userids) {
                     for (String keyUserId : keyUserIds) {
                         if (keyUserId != null && 
keyUserId.contains(useridPart)) {
-                            if (forEncryption && key.isEncryptionKey()) {
-                                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 {} 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 });
@@ -221,6 +227,24 @@ public final class PGPDataFormatUtil {
         return result;
     }
 
+    private static boolean isEncryptionKey(PGPPublicKey key) {
+        if (!key.isEncryptionKey()) {
+            return false;
+        }
+        //check keyflags
+        Boolean hasEncryptionKeyFlags = hasOneOfExpectedKeyFlags(key, new 
int[] {KeyFlags.ENCRYPT_COMMS, KeyFlags.ENCRYPT_STORAGE });
+        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()) });
+            return false;
+        } else {
+            // also without keyflags (hasEncryptionKeyFlags = null), true is 
returned!
+            return true;
+        }
+
+    }
+
     // Within a public 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
@@ -238,6 +262,21 @@ public final class PGPDataFormatUtil {
         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;
+    }
+
     private static boolean isSignatureKey(PGPPublicKey key) {
         int algorithm = key.getAlgorithm();
         return algorithm == RSA_GENERAL || algorithm == RSA_SIGN || algorithm 
== DSA || algorithm == ECDSA || algorithm == ELGAMAL_GENERAL;
@@ -251,14 +290,14 @@ public final class PGPDataFormatUtil {
 
     @Deprecated
     public static PGPPrivateKey findPrivateKey(CamelContext context, String 
keychainFilename, byte[] secKeyRing,
-        InputStream encryptedInput, String passphrase, String provider) throws 
IOException, PGPException, NoSuchProviderException {
+            InputStream encryptedInput, String passphrase, String provider) 
throws IOException, PGPException, NoSuchProviderException {
         return findPrivateKey(context, keychainFilename, secKeyRing, 
encryptedInput, passphrase, null, provider);
     }
 
     @Deprecated
     public static PGPPrivateKey findPrivateKey(CamelContext context, String 
keychainFilename, byte[] secKeyRing,
-        InputStream encryptedInput, String passphrase, PGPPassphraseAccessor 
passphraseAccessor, String provider) throws IOException,
-        PGPException, NoSuchProviderException {
+            InputStream encryptedInput, String passphrase, 
PGPPassphraseAccessor passphraseAccessor, String provider) throws IOException,
+            PGPException, NoSuchProviderException {
 
         InputStream keyChainInputStream = determineKeyRingInputStream(context, 
keychainFilename, secKeyRing, true);
         PGPPrivateKey privKey = null;
@@ -272,7 +311,7 @@ public final class PGPDataFormatUtil {
 
     @Deprecated
     private static PGPPrivateKey findPrivateKey(InputStream keyringInput, 
InputStream encryptedInput, String passphrase,
-        PGPPassphraseAccessor passphraseAccessor, String provider) throws 
IOException, PGPException, NoSuchProviderException {
+            PGPPassphraseAccessor passphraseAccessor, String provider) throws 
IOException, PGPException, NoSuchProviderException {
         PGPSecretKeyRingCollection pgpSec = new 
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
         PGPObjectFactory factory = new 
PGPObjectFactory(PGPUtil.getDecoderStream(encryptedInput));
         PGPEncryptedDataList enc;
@@ -313,13 +352,13 @@ public final class PGPDataFormatUtil {
 
     @Deprecated
     public static PGPSecretKey findSecretKey(CamelContext context, String 
keychainFilename, String passphrase) throws IOException,
-        PGPException, NoSuchProviderException {
+            PGPException, NoSuchProviderException {
         return findSecretKey(context, keychainFilename, null, passphrase, 
"BC");
     }
 
     @Deprecated
     public static PGPSecretKey findSecretKey(CamelContext context, String 
keychainFilename, byte[] secKeyRing, String passphrase,
-        String userId, String provider) throws IOException, PGPException, 
NoSuchProviderException {
+            String userId, String provider) throws IOException, PGPException, 
NoSuchProviderException {
         InputStream keyChainInputStream = determineKeyRingInputStream(context, 
keychainFilename, secKeyRing, false);
         try {
             List<PGPSecretKeyAndPrivateKeyAndUserId> secKeys = 
findSecretKeysWithPrivateKeyAndUserId(keyChainInputStream,
@@ -334,8 +373,8 @@ public final class PGPDataFormatUtil {
     }
 
     public static List<PGPSecretKeyAndPrivateKeyAndUserId> 
findSecretKeysWithPrivateKeyAndUserId(CamelContext context,
-        String keychainFilename, byte[] secKeyRing, Map<String, String> 
sigKeyUserId2Password, String provider) throws IOException,
-        PGPException, NoSuchProviderException {
+            String keychainFilename, byte[] secKeyRing, Map<String, String> 
sigKeyUserId2Password, String provider) throws IOException,
+            PGPException, NoSuchProviderException {
         InputStream keyChainInputStream = determineKeyRingInputStream(context, 
keychainFilename, secKeyRing, false);
         try {
             return findSecretKeysWithPrivateKeyAndUserId(keyChainInputStream, 
sigKeyUserId2Password, provider);
@@ -346,14 +385,14 @@ public final class PGPDataFormatUtil {
 
     @Deprecated
     public static PGPSecretKey findSecretKey(CamelContext context, String 
keychainFilename, byte[] secKeyRing, String passphrase,
-        String provider) throws IOException, PGPException, 
NoSuchProviderException {
+            String provider) throws IOException, PGPException, 
NoSuchProviderException {
 
         return findSecretKey(context, keychainFilename, secKeyRing, 
passphrase, null, provider);
     }
 
     @SuppressWarnings("unchecked")
     private static List<PGPSecretKeyAndPrivateKeyAndUserId> 
findSecretKeysWithPrivateKeyAndUserId(InputStream keyringInput,
-        Map<String, String> sigKeyUserId2Password, String provider) throws 
IOException, PGPException, NoSuchProviderException {
+            Map<String, String> sigKeyUserId2Password, String provider) throws 
IOException, PGPException, NoSuchProviderException {
         List<PGPSecretKeyAndPrivateKeyAndUserId> result = new 
ArrayList<PGPDataFormatUtil.PGPSecretKeyAndPrivateKeyAndUserId>(
                 sigKeyUserId2Password.size());
         PGPSecretKeyRingCollection pgpSec = new 
PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
@@ -361,19 +400,23 @@ public final class PGPDataFormatUtil {
             Object data = i.next();
             if (data instanceof PGPSecretKeyRing) {
                 PGPSecretKeyRing keyring = (PGPSecretKeyRing) data;
-                PGPSecretKey secKey = keyring.getSecretKey();
-                for (String userIdPart : sigKeyUserId2Password.keySet()) {
-                    for (Iterator<String> iterator = secKey.getUserIDs(); 
iterator.hasNext();) {
-                        String keyUserId = iterator.next();
-                        // there can be serveral user IDs!
-                        if (keyUserId != null && 
keyUserId.contains(userIdPart)) {
-                            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});
+                Set<String> keyUserIds = getUserIds(keyring);
 
+                for (String userIdPart : sigKeyUserId2Password.keySet()) {
+                    for (String keyUserId : keyUserIds) {
+                        if (keyUserId.contains(userIdPart)) {
+                            for (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 });
+
+                                    }
+                                }
                             }
                         }
                     }
@@ -383,6 +426,58 @@ public final class PGPDataFormatUtil {
         return result;
     }
 
+    private static boolean isSigningKey(PGPSecretKey secKey) {
+        if (!secKey.isSigningKey()) {
+            return false;
+        }
+        Boolean hasSigningKeyFlag = 
hasOneOfExpectedKeyFlags(secKey.getPublicKey(), new int[] {KeyFlags.SIGN_DATA 
});
+        if (hasSigningKeyFlag != null && !hasSigningKeyFlag) {
+            // not a signing key --> ignore
+            LOG.debug(
+                    "Secret key with key ID {} found for specified user ID 
part. But this key will not be used for signing because of its key flags.",
+                    Long.toString(secKey.getKeyID()));
+            return false;
+        } else {
+            // also if there are not any keyflags (hasSigningKeyFlag=null),  
true is returned!
+            return true;
+        }
+
+    }
+
+    /**
+     * Checks whether one of the signatures of the key has one of the expected
+     * key flags
+     * 
+     * @param key
+     * @return {@link Boolean#TRUE} if key has one of the expected flag,
+     *         <code>null</code> if the key does not have any key flags,
+     *         {@link Boolean#FALSE} if the key has none of the expected flags
+     */
+    private static Boolean hasOneOfExpectedKeyFlags(PGPPublicKey key, int[] 
expectedKeyFlags) {
+        boolean containsKeyFlags = false;
+        for (@SuppressWarnings("unchecked")
+        Iterator<PGPSignature> itsig = key.getSignatures(); itsig.hasNext();) {
+            PGPSignature sig = itsig.next();
+            PGPSignatureSubpacketVector subPacks = sig.getHashedSubPackets();
+            if (subPacks != null) {
+                int keyFlag = subPacks.getKeyFlags();
+                if (keyFlag > 0 && !containsKeyFlags) {
+                    containsKeyFlags = true;
+                }
+                for (int expectdKeyFlag : expectedKeyFlags) {
+                    int result = keyFlag & expectdKeyFlag;
+                    if (result == expectdKeyFlag) {
+                        return Boolean.TRUE;
+                    }
+                }
+            }
+        }
+        if (containsKeyFlags) {
+            return Boolean.FALSE;
+        }
+        return null; // no key flag
+    }
+
     public static class PGPSecretKeyAndPrivateKeyAndUserId {
 
         private final PGPSecretKey secretKey;

http://git-wip-us.apache.org/repos/asf/camel/blob/c09ae2fe/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 b815882..1aa7f7f 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
@@ -27,12 +27,14 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.util.IOHelper;
 import org.bouncycastle.bcpg.CompressionAlgorithmTags;
 import org.bouncycastle.bcpg.HashAlgorithmTags;
 import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.sig.KeyFlags;
 import org.junit.Test;
 
 public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
@@ -120,7 +122,7 @@ public class PGPDataFormatTest extends 
AbstractPGPDataFormatTest {
     public void testSeveralSignerKeys() throws Exception {
         doRoundTripEncryptionTests("direct:several-signer-keys");
     }
-    
+
     @Test
     public void testOneUserIdWithServeralKeys() throws Exception {
         doRoundTripEncryptionTests("direct:one-userid-several-keys");
@@ -142,7 +144,6 @@ public class PGPDataFormatTest extends 
AbstractPGPDataFormatTest {
         assertTrue(e.getMessage().contains("No public key found fitting to the 
signature key Id"));
 
     }
-    
 
     @Test
     public void 
testVerifyExceptionNoPassphraseSpecifiedForSignatureKeyUserId() throws 
Exception {
@@ -163,11 +164,35 @@ public class PGPDataFormatTest extends 
AbstractPGPDataFormatTest {
         assertTrue(e.getMessage().contains("No passphrase specified for 
signature key user ID"));
 
     }
-    
- 
 
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
+    /**
+     * You get three keys with the UserId "keyflag", a primary key and its two
+     * sub-keys. The sub-key with KeyFlag {@link KeyFlags#SIGN_DATA} should be
+     * used for signing and the sub-key with KeyFlag
+     * {@link KeyFlags#ENCRYPT_COMMS} or {@link KeyFlags#ENCRYPT_COMMS} or
+     * {@link KeyFlags#ENCRYPT_STORAGE} should be used for decryption.
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testKeyFlagSelectsCorrectKey() throws Exception {
+        MockEndpoint mockKeyFlag = getMockEndpoint("mock:encrypted_keyflag");
+        mockKeyFlag.setExpectedMessageCount(1);
+        template.sendBody("direct:keyflag", "Test Message");
+        assertMockEndpointsSatisfied();
+
+        List<Exchange> exchanges = mockKeyFlag.getExchanges();
+        assertEquals(1, exchanges.size());
+        Exchange exchange = exchanges.get(0);
+        Message inMess = exchange.getIn();
+        assertNotNull(inMess);
+        // must contain exactly one encryption key and one signature
+        assertEquals(1, 
inMess.getHeader(PGPDataFormat.NUMBER_OF_ENCRYPTION_KEYS));
+        assertEquals(1, 
inMess.getHeader(PGPDataFormat.NUMBER_OF_SIGNING_KEYS));
+    }
+
+    protected RouteBuilder[] createRouteBuilders() {
+        return new RouteBuilder[] {new RouteBuilder() {
             public void configure() throws Exception {
 
                 
onException(IllegalArgumentException.class).handled(true).to("mock:exception");
@@ -231,7 +256,7 @@ public class PGPDataFormatTest extends 
AbstractPGPDataFormatTest {
 
                 // test verifying exception, no public key found corresponding 
to signature key userIds
                 
from("direct:verify_exception_sig_userids").marshal(pgpSignAndEncrypt).to("mock:encrypted")
-                        
.setHeader(PGPDataFormat.SIGNATURE_KEY_USERIDS).constant(Arrays.asList(new 
String[] {"wrong1", "wrong2"}))
+                        
.setHeader(PGPDataFormat.SIGNATURE_KEY_USERIDS).constant(Arrays.asList(new 
String[] {"wrong1", "wrong2" }))
                         
.setHeader(PGPDataFormat.SIGNATURE_KEY_USERID).constant("wrongUserID").unmarshal(pgpVerifyAndDecrypt)
                         .to("mock:unencrypted");
 
@@ -349,9 +374,23 @@ public class PGPDataFormatTest extends 
AbstractPGPDataFormatTest {
                         // only specify one expected signature key, to check 
the second signature
                         
.setHeader(PGPDataFormat.SIGNATURE_KEY_USERID).constant("Third (comment third) 
<em...@third.com>")
                         
.unmarshal(pgpVerifyAndDecryptOneUserIdWithServeralKeys).to("mock:unencrypted");
+
             }
 
-        };
+        }, new RouteBuilder() {
+            public void configure() throws 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("org/apache/camel/component/crypto/pubringSubKeys.gpg");
+                
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");
+            }
+        } };
     }
 
     public static byte[] getPublicKeyRing() throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/c09ae2fe/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubringSubKeys.gpg
----------------------------------------------------------------------
diff --git 
a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubringSubKeys.gpg
 
b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubringSubKeys.gpg
new file mode 100644
index 0000000..93dbdf0
Binary files /dev/null and 
b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubringSubKeys.gpg
 differ

http://git-wip-us.apache.org/repos/asf/camel/blob/c09ae2fe/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secringSubKeys.gpg
----------------------------------------------------------------------
diff --git 
a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secringSubKeys.gpg
 
b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secringSubKeys.gpg
new file mode 100644
index 0000000..2ecf6ee
Binary files /dev/null and 
b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secringSubKeys.gpg
 differ

Reply via email to