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