diff options
author | David Hook <dgh@cryptoworkshop.com> | 2014-05-04 12:16:34 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2014-05-04 12:16:34 +0400 |
commit | b510c177ed036de78315b8165a505897db77b16e (patch) | |
tree | d2327a3b90bbec2e3247108f0787047d586e4049 /pg | |
parent | 6a8950309c15bec575c3c7bd955926cc21809458 (diff) |
added support for handling raw IDs for dealing with key rings without UTF8 encoded IDs.
Diffstat (limited to 'pg')
10 files changed, 311 insertions, 20 deletions
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java index 15ae71b1..7fd79186 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java @@ -2,6 +2,7 @@ package org.bouncycastle.bcpg; import java.io.IOException; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; /** @@ -24,12 +25,37 @@ public class UserIDPacket { this.idData = Strings.toUTF8ByteArray(id); } - + + public UserIDPacket(byte[] rawID) + { + this.idData = Arrays.clone(rawID); + } + public String getID() { return Strings.fromUTF8ByteArray(idData); } - + + public byte[] getRawID() + { + return Arrays.clone(idData); + } + + public boolean equals(Object o) + { + if (o instanceof UserIDPacket) + { + return Arrays.areEqual(this.idData, ((UserIDPacket)o).idData); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(this.idData); + } + public void encode( BCPGOutputStream out) throws IOException diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java index e12da58c..413e1af9 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java @@ -79,7 +79,7 @@ public abstract class PGPKeyRing if (obj instanceof UserIDPacket) { UserIDPacket id = (UserIDPacket)obj; - ids.add(id.getID()); + ids.add(id); } else { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java index a8b6692b..11b96ac1 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java @@ -365,7 +365,7 @@ public class PGPPublicKey /** * Return the strength of the key in bits. * - * @return bit strenght of key. + * @return bit strength of key. */ public int getBitStrength() { @@ -383,15 +383,36 @@ public class PGPPublicKey for (int i = 0; i != ids.size(); i++) { - if (ids.get(i) instanceof String) + if (ids.get(i) instanceof UserIDPacket) { - temp.add(ids.get(i)); + temp.add(((UserIDPacket)ids.get(i)).getID()); } } return temp.iterator(); } - + + /** + * Return any userIDs associated with the key in raw byte form. No attempt is made + * to convert the IDs into Strings. + * + * @return an iterator of Strings. + */ + public Iterator getRawUserIDs() + { + List temp = new ArrayList(); + + for (int i = 0; i != ids.size(); i++) + { + if (ids.get(i) instanceof UserIDPacket) + { + temp.add(((UserIDPacket)ids.get(i)).getRawID()); + } + } + + return temp.iterator(); + } + /** * Return any user attribute vectors associated with the key. * @@ -421,6 +442,24 @@ public class PGPPublicKey public Iterator getSignaturesForID( String id) { + return getSignaturesForID(new UserIDPacket(id)); + } + + /** + * Return any signatures associated with the passed in id. + * + * @param rawID the id to be matched in raw byte form. + * @return an iterator of PGPSignature objects. + */ + public Iterator getSignaturesForID( + byte[] rawID) + { + return getSignaturesForID(new UserIDPacket(rawID)); + } + + private Iterator getSignaturesForID( + UserIDPacket id) + { for (int i = 0; i != ids.size(); i++) { if (id.equals(ids.get(i))) @@ -428,10 +467,10 @@ public class PGPPublicKey return ((ArrayList)idSigs.get(i)).iterator(); } } - + return null; } - + /** * Return an iterator of signatures associated with the passed in user attributes. * @@ -548,11 +587,11 @@ public class PGPPublicKey for (int i = 0; i != ids.size(); i++) { - if (ids.get(i) instanceof String) + if (ids.get(i) instanceof UserIDPacket) { - String id = (String)ids.get(i); + UserIDPacket id = (UserIDPacket)ids.get(i); - out.writePacket(new UserIDPacket(id)); + out.writePacket(id); } else { @@ -630,7 +669,7 @@ public class PGPPublicKey String id, PGPSignature certification) { - return addCert(key, id, certification); + return addCert(key, new UserIDPacket(id), certification); } /** @@ -708,7 +747,21 @@ public class PGPPublicKey PGPPublicKey key, String id) { - return removeCert(key, id); + return removeCert(key, new UserIDPacket(id)); + } + + /** + * Remove any certifications associated with a given id on a key. + * + * @param key the key the certifications are to be removed from. + * @param rawID the id that is to be removed in raw byte form. + * @return the re-certified key, null if the id was not found on the key. + */ + public static PGPPublicKey removeCertification( + PGPPublicKey key, + byte[] rawID) + { + return removeCert(key, new UserIDPacket(rawID)); } private static PGPPublicKey removeCert( @@ -739,6 +792,22 @@ public class PGPPublicKey /** * Remove a certification associated with a given id on a key. + * + * @param key the key the certifications are to be removed from. + * @param id the id that the certification is to be removed from (in its raw byte form) + * @param certification the certification to be removed. + * @return the re-certified key, null if the certification was not found. + */ + public static PGPPublicKey removeCertification( + PGPPublicKey key, + byte[] id, + PGPSignature certification) + { + return removeCert(key, new UserIDPacket(id), certification); + } + + /** + * Remove a certification associated with a given id on a key. * * @param key the key the certifications are to be removed from. * @param id the id that the certification is to be removed from. @@ -750,7 +819,7 @@ public class PGPPublicKey String id, PGPSignature certification) { - return removeCert(key, id, certification); + return removeCert(key, new UserIDPacket(id), certification); } /** @@ -860,13 +929,13 @@ public class PGPPublicKey { for (Iterator it = key.getUserIDs(); it.hasNext();) { - String id = (String)it.next(); + UserIDPacket id = (UserIDPacket)it.next(); for (Iterator sIt = key.getSignaturesForID(id); sIt.hasNext();) { if (certification == sIt.next()) { found = true; - returnKey = PGPPublicKey.removeCertification(returnKey, id, certification); + returnKey = PGPPublicKey.removeCertification(returnKey, id.getRawID(), certification); } } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java index 7d1a9e38..bd0931df 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java @@ -520,11 +520,11 @@ public class PGPSecretKey for (int i = 0; i != pub.ids.size(); i++) { - if (pub.ids.get(i) instanceof String) + if (pub.ids.get(i) instanceof UserIDPacket) { - String id = (String)pub.ids.get(i); + UserIDPacket id = (UserIDPacket)pub.ids.get(i); - out.writePacket(new UserIDPacket(id)); + out.writePacket(id); } else { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java index 4bd7ea0a..77597049 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java @@ -311,6 +311,37 @@ public class PGPSignature } /** + * Verify the signature as certifying the passed in public key as associated + * with the passed in rawID. + * + * @param rawID id the key was stored under in its raw byte form. + * @param key the key to be verified. + * @return true if the signature matches, false otherwise. + * @throws PGPException + */ + public boolean verifyCertification( + byte[] rawID, + PGPPublicKey key) + throws PGPException + { + if (verifier == null) + { + throw new PGPException("PGPSignature not initialised - call init()."); + } + + updateWithPublicKey(key); + + // + // hash in the rawID + // + updateWithIdData(0xb4, rawID); + + addTrailer(); + + return verifier.verify(this.getSignature()); + } + + /** * Verify a certification for the passed in key against the passed in * master key. * diff --git a/pg/src/main/java/org/bouncycastle/openpgp/bc/BcPGPPublicKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/bc/BcPGPPublicKeyRing.java new file mode 100644 index 00000000..4023be76 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/bc/BcPGPPublicKeyRing.java @@ -0,0 +1,26 @@ +package org.bouncycastle.openpgp.bc; + +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; + +public class BcPGPPublicKeyRing + extends PGPPublicKeyRing +{ + private static KeyFingerPrintCalculator fingerPrintCalculator = new BcKeyFingerprintCalculator(); + + public BcPGPPublicKeyRing(byte[] encoding) + throws IOException + { + super(encoding, fingerPrintCalculator); + } + + public BcPGPPublicKeyRing(InputStream in) + throws IOException + { + super(in, fingerPrintCalculator); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/bc/BcPGPSecretKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/bc/BcPGPSecretKeyRing.java new file mode 100644 index 00000000..8dac1d5e --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/bc/BcPGPSecretKeyRing.java @@ -0,0 +1,27 @@ +package org.bouncycastle.openpgp.bc; + +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; + +public class BcPGPSecretKeyRing + extends PGPSecretKeyRing +{ + private static KeyFingerPrintCalculator fingerPrintCalculator = new BcKeyFingerprintCalculator(); + + public BcPGPSecretKeyRing(byte[] encoding) + throws IOException, PGPException + { + super(encoding, fingerPrintCalculator); + } + + public BcPGPSecretKeyRing(InputStream in) + throws IOException, PGPException + { + super(in, fingerPrintCalculator); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/jcajce/JcaPGPPublicKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/jcajce/JcaPGPPublicKeyRing.java new file mode 100644 index 00000000..b2281d28 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/jcajce/JcaPGPPublicKeyRing.java @@ -0,0 +1,26 @@ +package org.bouncycastle.openpgp.jcajce; + +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; + +public class JcaPGPPublicKeyRing + extends PGPPublicKeyRing +{ + private static KeyFingerPrintCalculator fingerPrintCalculator = new JcaKeyFingerprintCalculator(); + + public JcaPGPPublicKeyRing(byte[] encoding) + throws IOException + { + super(encoding, fingerPrintCalculator); + } + + public JcaPGPPublicKeyRing(InputStream in) + throws IOException + { + super(in, fingerPrintCalculator); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/jcajce/JcaPGPSecretKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/jcajce/JcaPGPSecretKeyRing.java new file mode 100644 index 00000000..735d4e57 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/jcajce/JcaPGPSecretKeyRing.java @@ -0,0 +1,27 @@ +package org.bouncycastle.openpgp.jcajce; + +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; + +public class JcaPGPSecretKeyRing + extends PGPSecretKeyRing +{ + private static KeyFingerPrintCalculator fingerPrintCalculator = new JcaKeyFingerprintCalculator(); + + public JcaPGPSecretKeyRing(byte[] encoding) + throws IOException, PGPException + { + super(encoding, fingerPrintCalculator); + } + + public JcaPGPSecretKeyRing(InputStream in) + throws IOException, PGPException + { + super(in, fingerPrintCalculator); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java index 3b3dfde8..e78026d4 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java @@ -24,6 +24,7 @@ import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRing; import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection; import org.bouncycastle.openpgp.jcajce.JcaPGPSecretKeyRingCollection; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; @@ -35,6 +36,7 @@ import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBu import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -1166,6 +1168,31 @@ public class PGPKeyRingTest "tXV/Z3H/Ot4u3E7H+6fHPElFYbQUdGVzdCA8dGVzdEBrZXkudGVzdD4=" ); + private static final byte[] problemUserID = Base64.decode( + "mQGiBDfzC2IRBADjnqYxAM1LPqFZCpF9ULb4G7L88E/p4sNo4k1LkzGtNOiroEHcacEAcTeP" + + "ljhgTA06l9jpnwx/dE0MEAiEtYexvkBv3LR2qXvuF67TKKlvanB32g0AmxNijHDdN2d+79ZA" + + "heZ4rY702W6DZh6FuKMAsTBfAFW5jLCWyJ4FwsLILwCg/3mjYePND5l0UcxaV0RKRBGnhqsE" + + "AIb9PJyWxSa8uzYQ+/APMg16Rrbti21zEQorFoc6yrC2hWbS7ro5yEVJxJa14s7VKlR+IAhg" + + "vR2+Q6jF6uvE1NZXzX6bvGaK3IpWMZdYcUY63EsHnutV+xON6Xd9C06xjAssvRQnxSuLXCg4" + + "md1Cr2kiKWaBExzxniKeql5lrqXKBACPcHbwZ8Efgt1TLG4yUf8nIQZwDeAhUPqJVWXurpWx" + + "r36ET4oQWb5HhO9GEe+2dttyJgV+stZJbZrPVmxmY1hUTZxIZ1ygGcMvrsVZZO0C9QsvMCyy" + + "xx4RzmTqomkC6Gtl3KtrZ4X28FQFDZi7MQaSXKEu2yS/NKJu2iT2BNKnE7QjTGFzc2UgTb5y" + + "a2VkYWhsIExhcnNlbiA8bG1sQGdyMy5kaz6ISwQQEQIACwUCN/MLYgQLAwIBAAoJEKg2SsWJ" + + "xEiGFbcAnA/ka/KE0Mnli7ybUhSrbESR/fZlAJ9SxU2foiRHMF8pF7I8KIJ9AQKSZLkCDQQ3" + + "8wtiEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt" + + "90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/" + + "Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8" + + "Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaG" + + "xAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAgf/cugy" + + "0nyWpA6GxoNqpdky1oCEbgII/lFKkGfQb/sHLgHURjmiaDXSuRJDRXC6YVC0HWqA+bfknR5m" + + "o1cvohu4GL/oul1eD85UfU29vg5Hr6f601o6xWVCiHF14B24JvO7jhYMd1MQRl7PVzH0a1Gp" + + "4hSoEvsUjU1HhGUhmMpUxwGJyIFt4RTkqKWK15omuJf4TLT47T58n9uClTNyxpx+oJGaiD0O" + + "SiEn9d4w5XFewhyXFQhisr99979dLq+buvH1QueMkVDExF4D8LN5gid8JPy/RqFxnHE8AcSF" + + "XHz9ou8m936pkyKYIMQkCwdw7/Wv7MK64ZED2zOnXnSb/JWY2YhGBBgRAgAGBQI38wtiAAoJ" + + "EKg2SsWJxEiGJdcAoIQOLuHGGS01Gz5WUpiQZYRtRMIYAKDuYx6bfQngRMs3/gEG0zoSGohY" + + "lQ==" + ); + public void test1() throws Exception { @@ -2624,6 +2651,37 @@ public class PGPKeyRingTest } } + // test for key ring with non-UTF8 User ID. + private void testBadUserID() + throws Exception + { + PGPPublicKeyRing pgpRing = new JcaPGPPublicKeyRing(problemUserID); + + byte[] enc = pgpRing.getEncoded(); + + if (!Arrays.areEqual(problemUserID, enc)) + { + fail("encoded key does not match original"); + } + + PGPPublicKey pubKey = pgpRing.getPublicKey(); + + Iterator it = pubKey.getRawUserIDs(); + + byte[] rawID = (byte[])it.next(); + + it = pubKey.getSignaturesForID(rawID); + + PGPSignature sig = (PGPSignature)it.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), pubKey); + + if (!sig.verifyCertification(rawID, pubKey)) + { + fail("Certification not validated for rawID"); + } + } + public void performTest() throws Exception { @@ -2649,6 +2707,7 @@ public class PGPKeyRingTest testSecretKeyRingWithPersonalCertificate(); insertMasterTest(); testUmlaut(); + testBadUserID(); } catch (PGPException e) { |