aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain-Test
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain-Test')
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java400
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java11
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java11
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java6
-rw-r--r--OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java2
5 files changed, 353 insertions, 77 deletions
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index 93aaf05c5..964512617 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -16,8 +16,10 @@ import org.spongycastle.bcpg.SecretSubkeyPacket;
import org.spongycastle.bcpg.SignaturePacket;
import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
@@ -31,6 +33,7 @@ import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -42,7 +45,7 @@ import java.util.Random;
public class PgpKeyOperationTest {
static UncachedKeyRing staticRing;
- static String passphrase;
+ final static String passphrase = genPassphrase();
UncachedKeyRing ring;
PgpKeyOperation op;
@@ -50,28 +53,18 @@ public class PgpKeyOperationTest {
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
- @BeforeClass public static void setUpOnce() throws Exception {
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
- {
- String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
- Random r = new Random();
- StringBuilder passbuilder = new StringBuilder();
- // 20% chance for an empty passphrase
- for(int i = 0, j = r.nextInt(10) > 2 ? r.nextInt(20) : 0; i < j; i++) {
- passbuilder.append(chars.charAt(r.nextInt(chars.length())));
- }
- passphrase = passbuilder.toString();
- System.out.println("Passphrase is '" + passphrase + "'");
- }
-
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.DSA, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -109,50 +102,66 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(256)+255, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(256)+255, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with < 512 bytes keysize should fail", parcel);
+ assertFailure("creating ring with < 512 bytes keysize should fail", parcel,
+ LogType.MSG_CR_ERROR_KEYSIZE_512);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with ElGamal master key should fail", parcel);
+ assertFailure("creating ring with ElGamal master key should fail", parcel,
+ LogType.MSG_CR_ERROR_MASTER_ELGAMAL);
+ }
+
+ {
+ parcel.reset();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ parcel.mAddUserIds.add("lotus");
+ parcel.mNewPassphrase = passphrase;
+
+ assertFailure("creating master key with null expiry should fail", parcel,
+ LogType.MSG_CR_ERROR_NULL_EXPIRY);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- 12345, 1024, KeyFlags.CERTIFY_OTHER, null));
+ 12345, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with bad algorithm choice should fail", parcel);
+ assertFailure("creating ring with bad algorithm choice should fail", parcel,
+ LogType.MSG_CR_ERROR_UNKNOWN_ALGO);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring with non-certifying master key should fail", parcel);
+ assertFailure("creating ring with non-certifying master key should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_CERTIFY);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring without user ids should fail", parcel);
+ assertFailure("creating ring without user ids should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_USER_ID);
}
{
@@ -160,7 +169,8 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("shy");
parcel.mNewPassphrase = passphrase;
- assertFailure("creating ring without subkeys should fail", parcel);
+ assertFailure("creating ring with no master key should fail", parcel,
+ LogType.MSG_CR_ERROR_NO_MASTER);
}
}
@@ -171,7 +181,7 @@ public class PgpKeyOperationTest {
public void testMasterFlags() throws Exception {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("luna");
ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
@@ -233,10 +243,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = ring.getMasterKeyId() -1;
parcel.mFingerprint = ring.getFingerprint();
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with bad master key id should fail",
- secretRing, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_KEYID);
}
{
@@ -245,10 +253,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = null;
parcel.mFingerprint = ring.getFingerprint();
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with null master key id should fail",
- secretRing, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_KEYID);
}
{
@@ -258,10 +264,8 @@ public class PgpKeyOperationTest {
// some byte, off by one
parcel.mFingerprint[5] += 1;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with bad fingerprint should fail",
- secretRing, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_FINGERPRINT);
}
{
@@ -269,10 +273,8 @@ public class PgpKeyOperationTest {
parcel.mMasterKeyId = ring.getMasterKeyId();
parcel.mFingerprint = null;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
-
assertModifyFailure("keyring modification with null fingerprint should fail",
- secretRing, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_FINGERPRINT);
}
{
@@ -280,10 +282,9 @@ public class PgpKeyOperationTest {
if (badphrase.equals(passphrase)) {
badphrase = "a";
}
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
assertModifyFailure("keyring modification with bad passphrase should fail",
- secretRing, parcel, badphrase);
+ ring, parcel, badphrase, LogType.MSG_MF_UNLOCK_ERROR);
}
}
@@ -335,20 +336,27 @@ public class PgpKeyOperationTest {
{ // bad keysize should fail
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, 0L));
+ assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel,
+ LogType.MSG_CR_ERROR_KEYSIZE_512);
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("creating a subkey with keysize < 512 should fail", secretRing, parcel);
+ }
+
+ {
+ parcel.reset();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_NULL_EXPIRY);
}
{ // a past expiry should fail
parcel.reset();
parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA,
new Date().getTime()/1000-10));
-
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("creating subkey with past expiry date should fail", secretRing, parcel);
+ assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
}
@@ -385,6 +393,20 @@ public class PgpKeyOperationTest {
ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
}
+ { // change expiry
+ expiry += 60*60*24;
+
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
+ }
+
{
int flags = KeyFlags.SIGN_DATA | KeyFlags.ENCRYPT_COMMS;
parcel.reset();
@@ -409,25 +431,171 @@ public class PgpKeyOperationTest {
expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
}
+ { // expiry of 0 should be "no expiry"
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertEquals("old packet must be signature",
+ PacketTags.SIGNATURE, onlyA.get(0).tag);
+
+ Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
+ Assert.assertTrue("first new packet must be signature", p instanceof SignaturePacket);
+ Assert.assertEquals("signature type must be subkey binding certificate",
+ PGPSignature.SUBKEY_BINDING, ((SignaturePacket) p).getSignatureType());
+ Assert.assertEquals("signature must have been created by master key",
+ ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
+
+ Assert.assertNull("key must not expire anymore", modified.getPublicKey(keyId).getExpiryTime());
+ }
+
{ // a past expiry should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("setting subkey expiry to a past date should fail", secretRing, parcel);
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
}
- { // modifying nonexistent keyring should fail
+ { // modifying nonexistent subkey should fail
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(123, null, null));
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("modifying non-existent subkey should fail", secretRing, parcel);
+ assertModifyFailure("modifying non-existent subkey should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_SUBKEY_MISSING);
}
}
@Test
+ public void testMasterModify() throws Exception {
+
+ long expiry = new Date().getTime()/1000 + 1024;
+ long keyId = ring.getMasterKeyId();
+
+ UncachedKeyRing modified = ring;
+
+ // to make this check less trivial, we add a user id, change the primary one and revoke one
+ parcel.mAddUserIds.add("aloe");
+ parcel.mChangePrimaryUserId = "aloe";
+ parcel.mRevokeUserIds.add("pink");
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ {
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ // this implies that only the two non-revoked signatures were changed!
+ Assert.assertEquals("two extra packets in original", 2, onlyA.size());
+ Assert.assertEquals("two extra packets in modified", 2, onlyB.size());
+
+ Assert.assertEquals("first original packet must be a signature",
+ PacketTags.SIGNATURE, onlyA.get(0).tag);
+ Assert.assertEquals("second original packet must be a signature",
+ PacketTags.SIGNATURE, onlyA.get(1).tag);
+ Assert.assertEquals("first new packet must be signature",
+ PacketTags.SIGNATURE, onlyB.get(0).tag);
+ Assert.assertEquals("first new packet must be signature",
+ PacketTags.SIGNATURE, onlyB.get(1).tag);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey().getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey().getExpiryTime().getTime() / 1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey().getKeyUsage(), modified.getPublicKey().getKeyUsage());
+ }
+
+ { // change expiry
+ expiry += 60*60*24;
+
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNotNull("modified key must have an expiry date",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("modified key must have expected expiry date",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ Assert.assertEquals("modified key must have same flags as before",
+ ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
+ }
+
+ {
+ int flags = KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA;
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, flags, null));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertEquals("modified key must have expected flags",
+ flags, modified.getPublicKey(keyId).getKeyUsage());
+ Assert.assertNotNull("key must retain its expiry",
+ modified.getPublicKey(keyId).getExpiryTime());
+ Assert.assertEquals("key expiry must be unchanged",
+ expiry, modified.getPublicKey(keyId).getExpiryTime().getTime()/1000);
+ }
+
+ { // expiry of 0 should be "no expiry"
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);
+
+ Assert.assertNull("key must not expire anymore", modified.getPublicKey(keyId).getExpiryTime());
+ }
+
+ { // if we revoke everything, nothing is left to properly sign...
+ parcel.reset();
+ parcel.mRevokeUserIds.add("twi");
+ parcel.mRevokeUserIds.add("pink");
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.CERTIFY_OTHER, null));
+
+ assertModifyFailure("master key modification with all user ids revoked should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_MASTER_NONE);
+ }
+
+ { // any flag not including CERTIFY_OTHER should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, KeyFlags.SIGN_DATA, null));
+
+ assertModifyFailure("setting master key flags without certify should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_NO_CERTIFY);
+ }
+
+ { // a past expiry should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime()/1000-10));
+
+ assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
+ LogType.MSG_MF_ERROR_PAST_EXPIRY);
+ }
+
+ }
+
+ @Test
+ public void testMasterRevoke() throws Exception {
+
+ parcel.reset();
+ parcel.mRevokeSubKeys.add(ring.getMasterKeyId());
+
+ UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
+
+ Assert.assertEquals("no extra packets in original", 0, onlyA.size());
+ Assert.assertEquals("exactly one extra packet in modified", 1, onlyB.size());
+
+ Packet p;
+
+ p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
+ Assert.assertTrue("first new packet must be secret subkey", p instanceof SignaturePacket);
+ Assert.assertEquals("signature type must be subkey binding certificate",
+ PGPSignature.KEY_REVOCATION, ((SignaturePacket) p).getSignatureType());
+ Assert.assertEquals("signature must have been created by master key",
+ ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
+
+ Assert.assertTrue("subkey must actually be revoked",
+ modified.getPublicKey().isRevoked());
+
+ }
+
+ @Test
public void testSubkeyRevoke() throws Exception {
long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);
@@ -542,8 +710,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mChangePrimaryUserId = uid;
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
- assertModifyFailure("setting primary user id to a revoked user id should fail", secretRing, parcel);
+ assertModifyFailure("setting primary user id to a revoked user id should fail", modified, parcel,
+ LogType.MSG_MF_ERROR_REVOKED_PRIMARY);
}
@@ -581,6 +749,14 @@ public class PgpKeyOperationTest {
ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());
}
+ { // revocation of non-existent user id should fail
+ parcel.reset();
+ parcel.mRevokeUserIds.add("nonexistent");
+
+ assertModifyFailure("revocation of nonexistent user id should fail", modified, parcel,
+ LogType.MSG_MF_ERROR_NOEXIST_REVOKE);
+ }
+
}
@Test
@@ -588,8 +764,8 @@ public class PgpKeyOperationTest {
{
parcel.mAddUserIds.add("");
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
- assertModifyFailure("adding an empty user id should fail", secretRing, parcel);
+ assertModifyFailure("adding an empty user id should fail", ring, parcel,
+ LogType.MSG_MF_UID_ERROR_EMPTY);
}
parcel.reset();
@@ -657,21 +833,87 @@ public class PgpKeyOperationTest {
parcel.mChangePrimaryUserId += "A";
}
- CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
assertModifyFailure("changing primary user id to a non-existent one should fail",
- secretRing, parcel);
+ ring, parcel, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY);
}
// check for revoked primary user id already done in revoke test
}
+ @Test
+ public void testPassphraseChange() throws Exception {
+
+ // change passphrase to empty
+ parcel.mNewPassphrase = "";
+ UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
+
+ Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
+ 3, onlyB.size());
+
+ // remember secret key packet with no passphrase for later
+ RawPacket sKeyNoPassphrase = onlyB.get(1);
+ Assert.assertEquals("extracted packet should be a secret subkey",
+ PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
+
+ // modify keyring, change to non-empty passphrase
+ String otherPassphrase = genPassphrase(true);
+ parcel.mNewPassphrase = otherPassphrase;
+ modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, "");
+
+ RawPacket sKeyWithPassphrase = onlyB.get(1);
+ Assert.assertEquals("extracted packet should be a secret subkey",
+ PacketTags.SECRET_SUBKEY, sKeyNoPassphrase.tag);
+
+ String otherPassphrase2 = genPassphrase(true);
+ parcel.mNewPassphrase = otherPassphrase2;
+ {
+ // if we replace a secret key with one without passphrase
+ modified = KeyringTestingHelper.removePacket(modified, sKeyNoPassphrase.position);
+ modified = KeyringTestingHelper.injectPacket(modified, sKeyNoPassphrase.buf, sKeyNoPassphrase.position);
+
+ // we should still be able to modify it (and change its passphrase) without errors
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase);
+ Assert.assertTrue("key modification must succeed", result.success());
+ Assert.assertFalse("log must not contain a warning",
+ result.getLog().containsWarnings());
+ Assert.assertTrue("log must contain an empty passphrase retry notice",
+ result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY));
+ modified = result.getRing();
+ }
+
+ {
+ // if we add one subkey with a different passphrase, that should produce a warning but also work
+ modified = KeyringTestingHelper.removePacket(modified, sKeyWithPassphrase.position);
+ modified = KeyringTestingHelper.injectPacket(modified, sKeyWithPassphrase.buf, sKeyWithPassphrase.position);
+
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase2);
+ Assert.assertTrue("key modification must succeed", result.success());
+ Assert.assertTrue("log must contain a warning",
+ result.getLog().containsWarnings());
+ Assert.assertTrue("log must contain a failed passphrase change warning",
+ result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_FAIL));
+ }
+
+ }
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB) {
- return applyModificationWithChecks(parcel, ring, onlyA, onlyB, true, true);
+ return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
+ }
+
+ private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
+ UncachedKeyRing ring,
+ ArrayList<RawPacket> onlyA,
+ ArrayList<RawPacket> onlyB,
+ String passphrase) {
+ return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
}
// applies a parcel modification while running some integrity checks
@@ -679,6 +921,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB,
+ String passphrase,
boolean canonicalize,
boolean constantCanonicalize) {
@@ -743,31 +986,42 @@ public class PgpKeyOperationTest {
Assert.assertEquals(java.util.Arrays.toString(expected), java.util.Arrays.toString(actual));
}
- private void assertFailure(String reason, SaveKeyringParcel parcel) {
+ private void assertFailure(String reason, SaveKeyringParcel parcel, LogType expected) {
EditKeyResult result = op.createSecretKeyRing(parcel);
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
}
- private void assertModifyFailure(String reason, CanonicalizedSecretKeyRing secretRing,
- SaveKeyringParcel parcel, String passphrase) {
+ private void assertModifyFailure(String reason, UncachedKeyRing ring,
+ SaveKeyringParcel parcel, String passphrase, LogType expected)
+ throws Exception {
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
}
- private void assertModifyFailure(String reason, CanonicalizedSecretKeyRing secretRing, SaveKeyringParcel parcel) {
+ private void assertModifyFailure(String reason, UncachedKeyRing ring, SaveKeyringParcel parcel,
+ LogType expected)
+ throws Exception {
+ CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
EditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());
+ Assert.assertTrue(reason + "(with correct error)",
+ result.getLog().containsType(expected));
}
@@ -782,4 +1036,20 @@ public class PgpKeyOperationTest {
}
+ private static String genPassphrase() {
+ return genPassphrase(false);
+ }
+
+ private static String genPassphrase(boolean noEmpty) {
+ String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
+ Random r = new Random();
+ StringBuilder passbuilder = new StringBuilder();
+ // 20% chance for an empty passphrase
+ for(int i = 0, j = noEmpty || r.nextInt(10) > 2 ? r.nextInt(20)+1 : 0; i < j; i++) {
+ passbuilder.append(chars.charAt(r.nextInt(chars.length())));
+ }
+ System.out.println("Generated passphrase: '" + passbuilder.toString() + "'");
+ return passbuilder.toString();
+ }
+
}
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 535e9d01a..6e3a9814e 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -13,6 +13,7 @@ import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.UserIDPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -34,6 +35,7 @@ import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import java.io.ByteArrayInputStream;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
@@ -60,15 +62,16 @@ public class UncachedKeyringCanonicalizeTest {
@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(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -277,7 +280,7 @@ public class UncachedKeyringCanonicalizeTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("trix");
PgpKeyOperation op = new PgpKeyOperation(null);
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
index 6e9381c06..428206c97 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -10,6 +10,7 @@ import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
@@ -18,6 +19,7 @@ import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import org.sufficientlysecure.keychain.util.ProgressScaler;
+import java.security.Security;
import java.util.ArrayList;
import java.util.Iterator;
@@ -59,14 +61,15 @@ public class UncachedKeyringMergeTest {
@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(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -83,7 +86,7 @@ public class UncachedKeyringMergeTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
// passphrase is tested in PgpKeyOperationTest, just use empty here
@@ -189,7 +192,7 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
index cbd1bc502..581e315a0 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
@@ -37,11 +37,11 @@ public class UncachedKeyringTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, null));
+ PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
index b5708b46f..11bc05c9e 100644
--- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
+++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/util/FileImportCacheTest.java
@@ -25,7 +25,7 @@ public class FileImportCacheTest {
@Test
public void testInputOutput() throws Exception {
- FileImportCache<Bundle> cache = new FileImportCache<Bundle>(Robolectric.application);
+ FileImportCache<Bundle> cache = new FileImportCache<Bundle>(Robolectric.application, "test.pcl");
ArrayList<Bundle> list = new ArrayList<Bundle>();