mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-02-07 10:30:14 -05:00
test: implement a ton of PgpKeyOperation tests
This commit is contained in:
parent
d0ff2c9f28
commit
b406db24b7
@ -1,5 +1,7 @@
|
||||
package org.sufficientlysecure.keychain.tests;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
@ -10,14 +12,18 @@ import org.robolectric.shadows.ShadowLog;
|
||||
import org.spongycastle.bcpg.BCPGInputStream;
|
||||
import org.spongycastle.bcpg.Packet;
|
||||
import org.spongycastle.bcpg.SecretKeyPacket;
|
||||
import org.spongycastle.bcpg.SecretSubkeyPacket;
|
||||
import org.spongycastle.bcpg.SignaturePacket;
|
||||
import org.spongycastle.bcpg.UserIDPacket;
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.Constants.choice.algorithm;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
|
||||
import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
|
||||
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
||||
@ -27,29 +33,34 @@ import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||
import org.sufficientlysecure.keychain.support.TestDataUtil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
||||
public class PgpKeyOperationTest {
|
||||
|
||||
static WrappedSecretKeyRing staticRing;
|
||||
WrappedSecretKeyRing ring;
|
||||
static UncachedKeyRing staticRing;
|
||||
UncachedKeyRing ring;
|
||||
PgpKeyOperation op;
|
||||
|
||||
@BeforeClass public static void setUpOnce() throws Exception {
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.addSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER, null));
|
||||
parcel.addSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
|
||||
parcel.addSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.ENCRYPT_COMMS, null));
|
||||
|
||||
parcel.addUserIds.add("swagerinho");
|
||||
parcel.addUserIds.add("twi");
|
||||
parcel.addUserIds.add("pink");
|
||||
parcel.newPassphrase = "swag";
|
||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||
|
||||
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
||||
UncachedKeyRing ring = op.createSecretKeyRing(parcel, log, 0);
|
||||
staticRing = new WrappedSecretKeyRing(ring.getEncoded(), false, 0);
|
||||
staticRing = op.createSecretKeyRing(parcel, log, 0);
|
||||
}
|
||||
|
||||
@Before public void setUp() throws Exception {
|
||||
@ -57,21 +68,72 @@ public class PgpKeyOperationTest {
|
||||
ShadowLog.stream = System.out;
|
||||
ring = staticRing;
|
||||
|
||||
// setting up some parameters just to reduce code duplication
|
||||
op = new PgpKeyOperation(null);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
// this is a special case since the flags are in user id certificates rather than
|
||||
// subkey binding certificates
|
||||
public void testMasterFlags() throws Exception {
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.addSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, null));
|
||||
parcel.addUserIds.add("luna");
|
||||
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
||||
ring = op.createSecretKeyRing(parcel, log, 0);
|
||||
|
||||
Assert.assertEquals("the keyring should contain only the master key",
|
||||
1, ring.getAvailableSubkeys().size());
|
||||
Assert.assertEquals("first (master) key must have both flags",
|
||||
KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, ring.getPublicKey().getKeyUsage());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatedKey() throws Exception {
|
||||
|
||||
// parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.mMasterKeyId = ring.getMasterKeyId();
|
||||
parcel.mFingerprint = ring.getFingerprint();
|
||||
|
||||
// an empty modification should change nothing. this also ensures the keyring
|
||||
// is constant through canonicalization.
|
||||
applyModificationWithChecks(parcel, ring);
|
||||
|
||||
Assert.assertNotNull("key creation failed", ring);
|
||||
|
||||
Assert.assertEquals("incorrect primary user id",
|
||||
"swagerinho", ring.getPrimaryUserId());
|
||||
Assert.assertNull("primary user id must be empty",
|
||||
ring.getPublicKey().getPrimaryUserId());
|
||||
|
||||
Assert.assertEquals("wrong number of subkeys",
|
||||
1, ring.getUncachedKeyRing().getAvailableSubkeys().size());
|
||||
Assert.assertEquals("number of user ids must be two",
|
||||
2, ring.getPublicKey().getUnorderedUserIds().size());
|
||||
|
||||
Assert.assertNull("expiry must be none",
|
||||
ring.getPublicKey().getExpiryTime());
|
||||
|
||||
Assert.assertEquals("number of subkeys must be three",
|
||||
3, ring.getAvailableSubkeys().size());
|
||||
|
||||
Iterator<UncachedPublicKey> it = ring.getPublicKeys();
|
||||
|
||||
Assert.assertEquals("first (master) key can certify",
|
||||
KeyFlags.CERTIFY_OTHER, it.next().getKeyUsage());
|
||||
|
||||
UncachedPublicKey signingKey = it.next();
|
||||
Assert.assertEquals("second key can sign",
|
||||
KeyFlags.SIGN_DATA, signingKey.getKeyUsage());
|
||||
ArrayList<WrappedSignature> sigs = signingKey.getSignatures().next().getEmbeddedSignatures();
|
||||
Assert.assertEquals("signing key signature should have one embedded signature",
|
||||
1, sigs.size());
|
||||
Assert.assertEquals("embedded signature should be of primary key binding type",
|
||||
PGPSignature.PRIMARYKEY_BINDING, sigs.get(0).getSignatureType());
|
||||
Assert.assertEquals("primary key binding signature issuer should be signing subkey",
|
||||
signingKey.getKeyId(), sigs.get(0).getKeyId());
|
||||
|
||||
Assert.assertEquals("third key can encrypt",
|
||||
KeyFlags.ENCRYPT_COMMS, it.next().getKeyUsage());
|
||||
|
||||
}
|
||||
|
||||
@ -80,24 +142,16 @@ public class PgpKeyOperationTest {
|
||||
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.mMasterKeyId = ring.getMasterKeyId();
|
||||
parcel.mFingerprint = ring.getUncached().getFingerprint();
|
||||
parcel.mFingerprint = ring.getFingerprint();
|
||||
parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
|
||||
|
||||
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
||||
UncachedKeyRing rawModified = op.modifySecretKeyRing(ring, parcel, "swag", log, 0);
|
||||
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring);
|
||||
|
||||
Assert.assertNotNull("key modification failed", rawModified);
|
||||
|
||||
UncachedKeyRing modified = rawModified.canonicalize(log, 0);
|
||||
|
||||
TreeSet<RawPacket> onlyA = new TreeSet<RawPacket>();
|
||||
TreeSet<RawPacket> onlyB = new TreeSet<RawPacket>();
|
||||
Assert.assertTrue("key must be constant through canonicalization",
|
||||
!KeyringTestingHelper.diffKeyrings(
|
||||
modified.getEncoded(), rawModified.getEncoded(), onlyA, onlyB));
|
||||
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
|
||||
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
|
||||
|
||||
Assert.assertTrue("keyring must differ from original", KeyringTestingHelper.diffKeyrings(
|
||||
ring.getUncached().getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||
ring.getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||
|
||||
Assert.assertEquals("no extra packets in original", 0, onlyA.size());
|
||||
Assert.assertEquals("exactly two extra packets in modified", 2, onlyB.size());
|
||||
@ -106,7 +160,7 @@ public class PgpKeyOperationTest {
|
||||
Packet p;
|
||||
|
||||
p = new BCPGInputStream(new ByteArrayInputStream(it.next().buf)).readPacket();
|
||||
Assert.assertTrue("first new packet must be secret subkey", p instanceof SecretKeyPacket);
|
||||
Assert.assertTrue("first new packet must be secret subkey", p instanceof SecretSubkeyPacket);
|
||||
|
||||
p = new BCPGInputStream(new ByteArrayInputStream(it.next().buf)).readPacket();
|
||||
Assert.assertTrue("second new packet must be signature", p instanceof SignaturePacket);
|
||||
@ -117,6 +171,116 @@ public class PgpKeyOperationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserIdAdd() throws Exception {
|
||||
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.mMasterKeyId = ring.getMasterKeyId();
|
||||
parcel.mFingerprint = ring.getFingerprint();
|
||||
parcel.addUserIds.add("rainbow");
|
||||
|
||||
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring);
|
||||
|
||||
Assert.assertTrue("keyring must contain added user id",
|
||||
modified.getPublicKey().getUnorderedUserIds().contains("rainbow"));
|
||||
|
||||
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
|
||||
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
|
||||
|
||||
Assert.assertTrue("keyring must differ from original", KeyringTestingHelper.diffKeyrings(
|
||||
ring.getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||
|
||||
Assert.assertEquals("no extra packets in original", 0, onlyA.size());
|
||||
Assert.assertEquals("exactly two extra packets in modified", 2, onlyB.size());
|
||||
|
||||
Iterator<RawPacket> it = onlyB.iterator();
|
||||
Packet p;
|
||||
|
||||
Assert.assertTrue("keyring must contain added user id",
|
||||
modified.getPublicKey().getUnorderedUserIds().contains("rainbow"));
|
||||
|
||||
p = new BCPGInputStream(new ByteArrayInputStream(it.next().buf)).readPacket();
|
||||
Assert.assertTrue("first new packet must be user id", p instanceof UserIDPacket);
|
||||
Assert.assertEquals("user id packet must match added user id",
|
||||
"rainbow", ((UserIDPacket) p).getID());
|
||||
|
||||
p = new BCPGInputStream(new ByteArrayInputStream(it.next().buf)).readPacket();
|
||||
System.out.println(p.getClass().getName());
|
||||
Assert.assertTrue("second new packet must be signature", p instanceof SignaturePacket);
|
||||
Assert.assertEquals("signature type must be positive certification",
|
||||
PGPSignature.POSITIVE_CERTIFICATION, ((SignaturePacket) p).getSignatureType());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserIdPrimary() throws Exception {
|
||||
|
||||
UncachedKeyRing modified = ring;
|
||||
|
||||
{ // first part, add new user id which is also primary
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.mMasterKeyId = modified.getMasterKeyId();
|
||||
parcel.mFingerprint = modified.getFingerprint();
|
||||
parcel.addUserIds.add("jack");
|
||||
parcel.changePrimaryUserId = "jack";
|
||||
|
||||
modified = applyModificationWithChecks(parcel, modified);
|
||||
|
||||
Assert.assertEquals("primary user id must be the one added",
|
||||
"jack", modified.getPublicKey().getPrimaryUserId());
|
||||
}
|
||||
|
||||
{ // second part, change primary to a different one
|
||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||
parcel.mMasterKeyId = ring.getMasterKeyId();
|
||||
parcel.mFingerprint = ring.getFingerprint();
|
||||
parcel.changePrimaryUserId = "pink";
|
||||
|
||||
modified = applyModificationWithChecks(parcel, modified);
|
||||
|
||||
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
|
||||
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
|
||||
|
||||
Assert.assertTrue("keyring must differ from original", KeyringTestingHelper.diffKeyrings(
|
||||
ring.getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||
|
||||
Assert.assertEquals("old keyring must have one outdated certificate", 1, onlyA.size());
|
||||
Assert.assertEquals("new keyring must have three new packets", 3, onlyB.size());
|
||||
|
||||
Assert.assertEquals("primary user id must be the one changed to",
|
||||
"pink", modified.getPublicKey().getPrimaryUserId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// applies a parcel modification while running some integrity checks
|
||||
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
||||
UncachedKeyRing ring) {
|
||||
try {
|
||||
|
||||
Assert.assertTrue("modified keyring must be secret", ring.isSecret());
|
||||
WrappedSecretKeyRing secretRing = new WrappedSecretKeyRing(ring.getEncoded(), false, 0);
|
||||
|
||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
||||
UncachedKeyRing rawModified = op.modifySecretKeyRing(secretRing, parcel, "swag", log, 0);
|
||||
Assert.assertNotNull("key modification failed", rawModified);
|
||||
UncachedKeyRing modified = rawModified.canonicalize(log, 0);
|
||||
|
||||
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
|
||||
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
|
||||
Assert.assertTrue("key must be constant through canonicalization",
|
||||
!KeyringTestingHelper.diffKeyrings(
|
||||
modified.getEncoded(), rawModified.getEncoded(), onlyA, onlyB)
|
||||
);
|
||||
|
||||
return modified;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new AssertionFailedError("error during encoding!");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVerifySuccess() throws Exception {
|
||||
|
||||
@ -130,8 +294,8 @@ public class PgpKeyOperationTest {
|
||||
throw new AssertionError("Canonicalization failed; messages: [" + log + "]");
|
||||
}
|
||||
|
||||
TreeSet onlyA = new TreeSet<RawPacket>();
|
||||
TreeSet onlyB = new TreeSet<RawPacket>();
|
||||
ArrayList onlyA = new ArrayList<RawPacket>();
|
||||
ArrayList onlyB = new ArrayList<RawPacket>();
|
||||
Assert.assertTrue("keyrings differ", !KeyringTestingHelper.diffKeyrings(
|
||||
expectedKeyRing.getEncoded(), expectedKeyRing.getEncoded(), onlyA, onlyB));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user