aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java')
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java493
1 files changed, 0 insertions, 493 deletions
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
deleted file mode 100644
index 755a0b00d..000000000
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.pgp;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.shadows.ShadowLog;
-import org.spongycastle.bcpg.BCPGInputStream;
-import org.spongycastle.bcpg.PacketTags;
-import org.spongycastle.bcpg.S2K;
-import org.spongycastle.bcpg.SecretKeyPacket;
-import org.spongycastle.bcpg.sig.KeyFlags;
-import org.spongycastle.jce.provider.BouncyCastleProvider;
-import org.spongycastle.util.Strings;
-import org.sufficientlysecure.keychain.operations.results.OperationResult;
-import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
-import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
-import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
-import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
-import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
-import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
-import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
-import org.sufficientlysecure.keychain.util.Passphrase;
-import org.sufficientlysecure.keychain.util.ProgressScaler;
-
-import java.io.ByteArrayInputStream;
-import java.security.Security;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Random;
-
-/** Tests for the UncachedKeyring.merge method.
- *
- * This is another complex, crypto-related method. It merges information from one keyring into
- * another, keeping information from the base (ie, called object) keyring in case of conflicts.
- * The types of keys may be Public or Secret and can be mixed, For mixed types the result type
- * will be the same as the base keyring.
- *
- * Test cases:
- * - Merging keyrings with different masterKeyIds should fail
- * - Merging a key with itself should be a no-operation
- * - Merging a key with an extra revocation certificate, it should have that certificate
- * - Merging a key with an extra user id, it should have that extra user id and its certificates
- * - Merging a key with an extra user id certificate, it should have that certificate
- * - Merging a key with an extra subkey, it should have that subkey
- * - Merging a key with an extra subkey certificate, it should have that certificate
- * - All of the above operations should work regardless of the key types. This means in particular
- * that for new subkeys, an equivalent subkey of the proper type must be generated.
- * - In case of two secret keys with the same id but different S2K, the key of the base keyring
- * should be preferred (TODO or should it?)
- *
- * Note that the merge operation does not care about certificate validity, a bad certificate or
- * packet will be copied regardless. Filtering out bad packets is done with canonicalization.
- *
- */
-@RunWith(RobolectricTestRunner.class)
-@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
-public class UncachedKeyringMergeTest {
-
- static UncachedKeyRing staticRingA, staticRingB;
- UncachedKeyRing ringA, ringB;
- ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
- ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
- OperationResult.OperationLog log = new OperationResult.OperationLog();
- PgpKeyOperation op;
- SaveKeyringParcel parcel;
-
- @BeforeClass
- public static void setUpOnce() throws Exception {
- Security.insertProviderAt(new BouncyCastleProvider(), 1);
- ShadowLog.stream = System.out;
-
- {
- SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
-
- parcel.mAddUserIds.add("twi");
- parcel.mAddUserIds.add("pink");
- {
- WrappedUserAttribute uat = WrappedUserAttribute.fromSubpacket(100,
- "sunshine, sunshine, ladybugs awake~".getBytes());
- parcel.mAddUserAttribute.add(uat);
- }
-
- // passphrase is tested in PgpKeyOperationTest, just use empty here
- parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
- PgpKeyOperation op = new PgpKeyOperation(null);
-
- OperationResult.OperationLog log = new OperationResult.OperationLog();
-
- PgpEditKeyResult result = op.createSecretKeyRing(parcel);
- staticRingA = result.getRing();
- staticRingA = staticRingA.canonicalize(new OperationLog(), 0).getUncachedKeyRing();
- }
-
- {
- SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
-
- parcel.mAddUserIds.add("shy");
- // passphrase is tested in PgpKeyOperationTest, just use empty here
- parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
- PgpKeyOperation op = new PgpKeyOperation(null);
-
- OperationResult.OperationLog log = new OperationResult.OperationLog();
- PgpEditKeyResult result = op.createSecretKeyRing(parcel);
- staticRingB = result.getRing();
- staticRingB = staticRingB.canonicalize(new OperationLog(), 0).getUncachedKeyRing();
- }
-
- Assert.assertNotNull("initial test key creation must succeed", staticRingA);
- Assert.assertNotNull("initial test key creation must succeed", staticRingB);
-
- // we sleep here for a second, to make sure all new certificates have different timestamps
- Thread.sleep(1000);
- }
-
- @Before
- public void setUp() throws Exception {
- // show Log.x messages in system.out
- ShadowLog.stream = System.out;
- ringA = staticRingA;
- ringB = staticRingB;
-
- // setting up some parameters just to reduce code duplication
- op = new PgpKeyOperation(new ProgressScaler(null, 0, 100, 100));
-
- // set this up, gonna need it more than once
- parcel = new SaveKeyringParcel();
- parcel.mMasterKeyId = ringA.getMasterKeyId();
- parcel.mFingerprint = ringA.getFingerprint();
- }
-
- public void testSelfNoOp() throws Exception {
-
- UncachedKeyRing merged = mergeWithChecks(ringA, ringA, null);
- Assert.assertArrayEquals("keyring merged with itself must be identical",
- ringA.getEncoded(), merged.getEncoded()
- );
-
- }
-
- @Test
- public void testDifferentMasterKeyIds() throws Exception {
-
- Assert.assertNotEquals("generated key ids must be different",
- ringA.getMasterKeyId(), ringB.getMasterKeyId());
-
- Assert.assertNull("merging keys with differing key ids must fail",
- ringA.merge(ringB, log, 0));
- Assert.assertNull("merging keys with differing key ids must fail",
- ringB.merge(ringA, log, 0));
-
- }
-
- @Test
- public void testAddedUserId() throws Exception {
-
- UncachedKeyRing modifiedA, modifiedB; {
- CanonicalizedSecretKeyRing secretRing =
- new CanonicalizedSecretKeyRing(ringA.getEncoded(), false, 0);
-
- parcel.reset();
- parcel.mAddUserIds.add("flim");
- modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
-
- parcel.reset();
- parcel.mAddUserIds.add("flam");
- modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
- }
-
- { // merge A into base
- UncachedKeyRing merged = mergeWithChecks(ringA, modifiedA);
-
- Assert.assertEquals("merged keyring must have lost no packets", 0, onlyA.size());
- Assert.assertEquals("merged keyring must have gained two packets", 2, onlyB.size());
- Assert.assertTrue("merged keyring must contain new user id",
- merged.getPublicKey().getUnorderedUserIds().contains("flim"));
- }
-
- { // merge A into B
- UncachedKeyRing merged = mergeWithChecks(modifiedA, modifiedB, ringA);
-
- Assert.assertEquals("merged keyring must have lost no packets", 0, onlyA.size());
- Assert.assertEquals("merged keyring must have gained four packets", 4, onlyB.size());
- Assert.assertTrue("merged keyring must contain first new user id",
- merged.getPublicKey().getUnorderedUserIds().contains("flim"));
- Assert.assertTrue("merged keyring must contain second new user id",
- merged.getPublicKey().getUnorderedUserIds().contains("flam"));
-
- }
-
- }
-
- @Test
- public void testAddedSubkeyId() throws Exception {
-
- UncachedKeyRing modifiedA, modifiedB;
- long subKeyIdA, subKeyIdB;
- {
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ringA.getEncoded(), false, 0);
-
- parcel.reset();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
- modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
- modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
-
- subKeyIdA = KeyringTestingHelper.getSubkeyId(modifiedA, 2);
- subKeyIdB = KeyringTestingHelper.getSubkeyId(modifiedB, 2);
-
- }
-
- {
- UncachedKeyRing merged = mergeWithChecks(ringA, modifiedA);
-
- Assert.assertEquals("merged keyring must have lost no packets", 0, onlyA.size());
- Assert.assertEquals("merged keyring must have gained two packets", 2, onlyB.size());
-
- long mergedKeyId = KeyringTestingHelper.getSubkeyId(merged, 2);
- Assert.assertEquals("merged keyring must contain the new subkey", subKeyIdA, mergedKeyId);
- }
-
- {
- UncachedKeyRing merged = mergeWithChecks(modifiedA, modifiedB, ringA);
-
- Assert.assertEquals("merged keyring must have lost no packets", 0, onlyA.size());
- Assert.assertEquals("merged keyring must have gained four packets", 4, onlyB.size());
-
- Iterator<UncachedPublicKey> it = merged.getPublicKeys();
- it.next(); it.next();
- Assert.assertEquals("merged keyring must contain the new subkey",
- subKeyIdA, it.next().getKeyId());
- Assert.assertEquals("merged keyring must contain both new subkeys",
- subKeyIdB, it.next().getKeyId());
- }
-
- }
-
- @Test
- public void testAddedKeySignature() throws Exception {
-
- final UncachedKeyRing modified; {
- parcel.reset();
- parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(ringA, 1));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
- ringA.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
- }
-
- {
- UncachedKeyRing merged = ringA.merge(modified, log, 0);
- Assert.assertNotNull("merge must succeed", merged);
- Assert.assertFalse(
- "merging keyring with extra signatures into its base should yield that same keyring",
- KeyringTestingHelper.diffKeyrings(merged.getEncoded(), modified.getEncoded(), onlyA, onlyB)
- );
- }
-
- }
-
- @Test
- public void testAddedUserIdSignature() throws Exception {
-
- final UncachedKeyRing pubRing = ringA.extractPublicKeyRing();
-
- final UncachedKeyRing modified; {
- CanonicalizedPublicKeyRing publicRing = new CanonicalizedPublicKeyRing(
- pubRing.getEncoded(), 0);
-
- CanonicalizedSecretKey secretKey = new CanonicalizedSecretKeyRing(
- ringB.getEncoded(), false, 0).getSecretKey();
- secretKey.unlock(new Passphrase());
- PgpCertifyOperation op = new PgpCertifyOperation();
- CertifyAction action = new CertifyAction(pubRing.getMasterKeyId(), publicRing.getPublicKey().getUnorderedUserIds());
- // sign all user ids
- PgpCertifyResult result = op.certify(secretKey, publicRing, new OperationLog(), 0, action, null, new Date());
- Assert.assertTrue("certification must succeed", result.success());
- Assert.assertNotNull("certification must yield result", result.getCertifiedRing());
- modified = result.getCertifiedRing();
- }
-
- {
- UncachedKeyRing merged = ringA.merge(modified, log, 0);
- Assert.assertNotNull("merge must succeed", merged);
- Assert.assertArrayEquals("foreign signatures should not be merged into secret key",
- ringA.getEncoded(), merged.getEncoded()
- );
- }
-
- {
- byte[] sig = KeyringTestingHelper.getNth(
- modified.getPublicKey().getSignaturesForRawId(Strings.toUTF8ByteArray("twi")), 1).getEncoded();
-
- // inject the (foreign!) signature into subkey signature position
- UncachedKeyRing moreModified = KeyringTestingHelper.injectPacket(modified, sig, 1);
-
- UncachedKeyRing merged = ringA.merge(moreModified, log, 0);
- Assert.assertNotNull("merge must succeed", merged);
- Assert.assertArrayEquals("foreign signatures should not be merged into secret key",
- ringA.getEncoded(), merged.getEncoded()
- );
-
- merged = pubRing.merge(moreModified, log, 0);
- Assert.assertNotNull("merge must succeed", merged);
- Assert.assertTrue(
- "merged keyring should contain new signature",
- KeyringTestingHelper.diffKeyrings(pubRing.getEncoded(), merged.getEncoded(), onlyA, onlyB)
- );
- Assert.assertEquals("merged keyring should be missing no packets", 0, onlyA.size());
- Assert.assertEquals("merged keyring should contain exactly two more packets", 2, onlyB.size());
- Assert.assertEquals("first added packet should be a signature",
- PacketTags.SIGNATURE, onlyB.get(0).tag);
- Assert.assertEquals("first added packet should be in the position we injected it at",
- 1, onlyB.get(0).position);
- Assert.assertEquals("second added packet should be a signature",
- PacketTags.SIGNATURE, onlyB.get(1).tag);
-
- }
-
- {
- UncachedKeyRing merged = pubRing.merge(modified, log, 0);
- Assert.assertNotNull("merge must succeed", merged);
- Assert.assertFalse(
- "merging keyring with extra signatures into its base should yield that same keyring",
- KeyringTestingHelper.diffKeyrings(merged.getEncoded(), modified.getEncoded(), onlyA, onlyB)
- );
- }
- }
-
- @Test
- public void testAddedUserAttributeSignature() throws Exception {
-
- final UncachedKeyRing modified; {
- parcel.reset();
-
- Random r = new Random();
- int type = r.nextInt(110)+1;
- byte[] data = new byte[r.nextInt(2000)];
- new Random().nextBytes(data);
-
- WrappedUserAttribute uat = WrappedUserAttribute.fromSubpacket(type, data);
- parcel.mAddUserAttribute.add(uat);
-
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
- ringA.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
- }
-
- {
- UncachedKeyRing merged = ringA.merge(modified, log, 0);
- Assert.assertNotNull("merge must succeed", merged);
- Assert.assertFalse(
- "merging keyring with extra user attribute into its base should yield that same keyring",
- KeyringTestingHelper.diffKeyrings(merged.getEncoded(), modified.getEncoded(), onlyA, onlyB)
- );
- }
-
- }
-
- private UncachedKeyRing mergeWithChecks(UncachedKeyRing a, UncachedKeyRing b)
- throws Exception {
- return mergeWithChecks(a, b, a);
- }
-
- private UncachedKeyRing mergeWithChecks(UncachedKeyRing a, UncachedKeyRing b,
- UncachedKeyRing base)
- throws Exception {
-
- Assert.assertTrue("merging keyring must be secret type", a.isSecret());
- Assert.assertTrue("merged keyring must be secret type", b.isSecret());
-
- final UncachedKeyRing resultA;
- UncachedKeyRing resultB;
-
- { // sec + sec
- resultA = a.merge(b, log, 0);
- Assert.assertNotNull("merge must succeed as sec(a)+sec(b)", resultA);
-
- resultB = b.merge(a, log, 0);
- Assert.assertNotNull("merge must succeed as sec(b)+sec(a)", resultB);
-
- // check commutativity, if requested
- Assert.assertFalse("result of merge must be commutative",
- KeyringTestingHelper.diffKeyrings(
- resultA.getEncoded(), resultB.getEncoded(), onlyA, onlyB)
- );
- }
-
- final UncachedKeyRing pubA = a.extractPublicKeyRing();
- final UncachedKeyRing pubB = b.extractPublicKeyRing();
-
- { // sec + pub
-
- // this one is special, because GNU_DUMMY keys might be generated!
-
- resultB = a.merge(pubB, log, 0);
- Assert.assertNotNull("merge must succeed as sec(a)+pub(b)", resultA);
-
- // these MAY diff
- KeyringTestingHelper.diffKeyrings(resultA.getEncoded(), resultB.getEncoded(),
- onlyA, onlyB);
-
- Assert.assertEquals("sec(a)+pub(b): results must have equal number of packets",
- onlyA.size(), onlyB.size());
-
- for (int i = 0; i < onlyA.size(); i++) {
- Assert.assertEquals("sec(a)+pub(c): old packet must be secret subkey",
- PacketTags.SECRET_SUBKEY, onlyA.get(i).tag);
- Assert.assertEquals("sec(a)+pub(c): new packet must be dummy secret subkey",
- PacketTags.SECRET_SUBKEY, onlyB.get(i).tag);
-
- SecretKeyPacket pA = (SecretKeyPacket) new BCPGInputStream(new ByteArrayInputStream(onlyA.get(i).buf)).readPacket();
- SecretKeyPacket pB = (SecretKeyPacket) new BCPGInputStream(new ByteArrayInputStream(onlyB.get(i).buf)).readPacket();
-
- Assert.assertArrayEquals("sec(a)+pub(c): both packets must have equal pubkey parts",
- pA.getPublicKeyPacket().getEncoded(), pB.getPublicKeyPacket().getEncoded()
- );
-
- Assert.assertEquals("sec(a)+pub(c): new packet should have GNU_DUMMY S2K type",
- S2K.GNU_DUMMY_S2K, pB.getS2K().getType());
- Assert.assertEquals("sec(a)+pub(c): new packet should have GNU_DUMMY protection mode 0x1",
- 0x1, pB.getS2K().getProtectionMode());
- Assert.assertEquals("sec(a)+pub(c): new packet secret key data should have length zero",
- 0, pB.getSecretKeyData().length);
- Assert.assertNull("sec(a)+pub(c): new packet should have no iv data", pB.getIV());
-
- }
-
- }
-
- { // pub + sec, and pub + pub
- final UncachedKeyRing pubResult = resultA.extractPublicKeyRing();
-
- resultB = pubA.merge(b, log, 0);
- Assert.assertNotNull("merge must succeed as pub(a)+sec(b)", resultA);
-
- Assert.assertFalse("result of pub(a)+sec(b) must be same as pub(sec(a)+sec(b))",
- KeyringTestingHelper.diffKeyrings(
- pubResult.getEncoded(), resultB.getEncoded(), onlyA, onlyB)
- );
-
- resultB = pubA.merge(pubB, log, 0);
- Assert.assertNotNull("merge must succeed as pub(a)+pub(b)", resultA);
-
- Assert.assertFalse("result of pub(a)+pub(b) must be same as pub(sec(a)+sec(b))",
- KeyringTestingHelper.diffKeyrings(
- pubResult.getEncoded(), resultB.getEncoded(), onlyA, onlyB)
- );
-
- }
-
- if (base != null) {
- // set up onlyA and onlyB to be a diff to the base
- Assert.assertTrue("merged keyring must differ from base",
- KeyringTestingHelper.diffKeyrings(
- base.getEncoded(), resultA.getEncoded(), onlyA, onlyB)
- );
- }
-
- return resultA;
-
- }
-
-}