Merge branch 'development' into linked-identities

Conflicts:
	Graphics/update-drawables.sh
	OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
	OpenKeychain/build.gradle
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
This commit is contained in:
Vincent Breitmoser
2015-04-24 14:18:01 +02:00
257 changed files with 7154 additions and 5101 deletions

View File

@@ -5,7 +5,7 @@ buildscript {
dependencies {
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
classpath 'com.novoda:gradle-android-test-plugin:0.10.1'
classpath 'com.novoda:gradle-android-test-plugin:0.10.4'
}
}

View File

@@ -46,6 +46,7 @@ import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyActio
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.util.InputData;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -152,8 +153,8 @@ public class CertifyOperationTest {
@Test
public void testCertifyId() throws Exception {
CertifyOperation op = operationWithFakePassphraseCache(
mStaticRing1.getMasterKeyId(), mStaticRing1.getMasterKeyId(), mKeyPhrase1);
CertifyOperation op = new CertifyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application), null, null);
{
CanonicalizedPublicKeyRing ring = new ProviderHelper(Robolectric.application)
@@ -164,8 +165,8 @@ public class CertifyOperationTest {
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds(), null));
CertifyResult result = op.certify(actions, null);
mStaticRing2.getPublicKey().getUnorderedUserIds()));
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null);
Assert.assertTrue("certification must succeed", result.success());
@@ -180,8 +181,8 @@ public class CertifyOperationTest {
@Test
public void testCertifyAttribute() throws Exception {
CertifyOperation op = operationWithFakePassphraseCache(
mStaticRing1.getMasterKeyId(), mStaticRing1.getMasterKeyId(), mKeyPhrase1);
CertifyOperation op = new CertifyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application), null, null);
{
CanonicalizedPublicKeyRing ring = new ProviderHelper(Robolectric.application)
@@ -193,7 +194,7 @@ public class CertifyOperationTest {
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), null,
mStaticRing2.getPublicKey().getUnorderedUserAttributes()));
CertifyResult result = op.certify(actions, null);
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null);
Assert.assertTrue("certification must succeed", result.success());
@@ -209,14 +210,14 @@ public class CertifyOperationTest {
@Test
public void testCertifySelf() throws Exception {
CertifyOperation op = operationWithFakePassphraseCache(
mStaticRing1.getMasterKeyId(), mStaticRing1.getMasterKeyId(), mKeyPhrase1);
CertifyOperation op = new CertifyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application), null, null);
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds(), null));
CertifyResult result = op.certify(actions, null);
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null);
Assert.assertFalse("certification with itself must fail!", result.success());
Assert.assertTrue("error msg must be about self certification",
@@ -226,7 +227,8 @@ public class CertifyOperationTest {
@Test
public void testCertifyNonexistent() throws Exception {
CertifyOperation op = operationWithFakePassphraseCache(null, null, mKeyPhrase1);
CertifyOperation op = new CertifyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application), null, null);
{
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
@@ -234,7 +236,7 @@ public class CertifyOperationTest {
uids.add("nonexistent");
actions.add(new CertifyAction(1234L, uids, null));
CertifyResult result = op.certify(actions, null);
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null);
Assert.assertFalse("certification of nonexistent key must fail", result.success());
Assert.assertTrue("must contain error msg about not found",
@@ -246,7 +248,7 @@ public class CertifyOperationTest {
actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds(), null));
CertifyResult result = op.certify(actions, null);
CertifyResult result = op.certify(actions, new CryptoInputParcel(mKeyPhrase1), null);
Assert.assertFalse("certification of nonexistent key must fail", result.success());
Assert.assertTrue("must contain error msg about not found",
@@ -255,29 +257,4 @@ public class CertifyOperationTest {
}
private CertifyOperation operationWithFakePassphraseCache(
final Long checkMasterKeyId, final Long checkSubKeyId, final Passphrase passphrase) {
return new CertifyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application),
null, null) {
@Override
public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId)
throws NoSecretKeyException {
if (checkMasterKeyId != null) {
Assert.assertEquals("requested passphrase should be for expected master key id",
(long) checkMasterKeyId, masterKeyId);
}
if (checkSubKeyId != null) {
Assert.assertEquals("requested passphrase should be for expected sub key id",
(long) checkSubKeyId, subKeyId);
}
if (passphrase == null) {
return null;
}
return passphrase;
}
};
}
}

View File

@@ -27,9 +27,12 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
@@ -101,7 +104,7 @@ public class PromoteKeyOperationTest {
PromoteKeyOperation op = new PromoteKeyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application), null, null);
PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId());
PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId(), null);
Assert.assertTrue("promotion must succeed", result.success());
@@ -113,15 +116,35 @@ public class PromoteKeyOperationTest {
Iterator<UncachedPublicKey> it = mStaticRing.getPublicKeys();
while (it.hasNext()) {
long keyId = it.next().getKeyId();
Assert.assertEquals("all subkeys must be divert-to-card",
Assert.assertEquals("all subkeys must be gnu dummy",
SecretKeyType.GNU_DUMMY, ring.getSecretKeyType(keyId));
}
}
// second attempt should fail
result = op.execute(mStaticRing.getMasterKeyId());
Assert.assertFalse("promotion of secret key must fail", result.success());
}
@Test
public void testPromoteDivert() throws Exception {
PromoteKeyOperation op = new PromoteKeyOperation(Robolectric.application,
new ProviderHelper(Robolectric.application), null, null);
byte[] aid = Hex.decode("D2760001240102000000012345670000");
PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId(), aid);
Assert.assertTrue("promotion must succeed", result.success());
{
CanonicalizedSecretKeyRing ring = new ProviderHelper(Robolectric.application)
.getCanonicalizedSecretKeyRing(mStaticRing.getMasterKeyId());
for (CanonicalizedSecretKey key : ring.secretKeyIterator()) {
Assert.assertEquals("all subkeys must be divert-to-card",
SecretKeyType.DIVERT_TO_CARD, key.getSecretKeyType());
Assert.assertArrayEquals("all subkeys must have correct iv",
aid, key.getIv());
}
}
}
}

View File

@@ -37,6 +37,8 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Passphrase;
@@ -48,7 +50,6 @@ import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.security.Security;
import java.util.Arrays;
import java.util.HashSet;
@RunWith(RobolectricTestRunner.class)
@@ -138,11 +139,11 @@ public class PgpEncryptDecryptTest {
InputData data = new InputData(in, in.available());
PgpSignEncryptInput b = new PgpSignEncryptInput();
PgpSignEncryptInputParcel b = new PgpSignEncryptInputParcel();
b.setSymmetricPassphrase(mPassphrase);
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
PgpSignEncryptResult result = op.execute(b, data, out);
PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
Assert.assertTrue("encryption must succeed", result.success());
@@ -159,8 +160,7 @@ public class PgpEncryptDecryptTest {
new ProviderHelper(Robolectric.application),
null, // new DummyPassphraseCache(mPassphrase, 0L),
data, out);
b.setPassphrase(mPassphrase);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel(mPassphrase));
Assert.assertTrue("decryption must succeed", result.success());
Assert.assertArrayEquals("decrypted ciphertext should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -182,8 +182,8 @@ public class PgpEncryptDecryptTest {
new ProviderHelper(Robolectric.application),
null, // new DummyPassphraseCache(mPassphrase, 0L),
data, out);
b.setPassphrase(new Passphrase(Arrays.toString(mPassphrase.getCharArray()) + "x"));
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel(
new Passphrase(new String(mPassphrase.getCharArray()) + "x")));
Assert.assertFalse("decryption must succeed", result.success());
Assert.assertEquals("decrypted plaintext should be empty", 0, out.size());
Assert.assertNull("signature should be an error", result.getSignatureResult());
@@ -200,7 +200,7 @@ public class PgpEncryptDecryptTest {
new ProviderHelper(Robolectric.application),
null, // new DummyPassphraseCache(mPassphrase, 0L),
data, out);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertFalse("decryption must succeed", result.success());
Assert.assertEquals("decrypted plaintext should be empty", 0, out.size());
Assert.assertNull("signature should be an error", result.getSignatureResult());
@@ -222,11 +222,11 @@ public class PgpEncryptDecryptTest {
new ProviderHelper(Robolectric.application), null);
InputData data = new InputData(in, in.available());
PgpSignEncryptInput b = new PgpSignEncryptInput();
PgpSignEncryptInputParcel b = new PgpSignEncryptInputParcel();
b.setEncryptionMasterKeyIds(new long[]{ mStaticRing1.getMasterKeyId() });
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
PgpSignEncryptResult result = op.execute(b, data, out);
PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -238,10 +238,8 @@ public class PgpEncryptDecryptTest {
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
InputData data = new InputData(in, in.available());
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out, null, null, null);
b.setPassphrase(mKeyPhrase1);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel(mKeyPhrase1));
Assert.assertTrue("decryption with provided passphrase must succeed", result.success());
Assert.assertArrayEquals("decrypted ciphertext with provided passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -264,7 +262,7 @@ public class PgpEncryptDecryptTest {
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
mKeyPhrase1, mStaticRing1.getMasterKeyId(), null);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertTrue("decryption with cached passphrase must succeed", result.success());
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -279,11 +277,11 @@ public class PgpEncryptDecryptTest {
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
null, mStaticRing1.getMasterKeyId(), null);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertFalse("decryption with no passphrase must return pending", result.success());
Assert.assertTrue("decryption with no passphrase should return pending", result.isPending());
Assert.assertEquals("decryption with no passphrase should return pending passphrase",
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, result.getResult());
RequiredInputType.PASSPHRASE, result.getRequiredInputParcel().mType);
}
}
@@ -303,14 +301,14 @@ public class PgpEncryptDecryptTest {
InputData data = new InputData(in, in.available());
PgpSignEncryptInput b = new PgpSignEncryptInput();
PgpSignEncryptInputParcel b = new PgpSignEncryptInputParcel();
b.setEncryptionMasterKeyIds(new long[] {
mStaticRing1.getMasterKeyId(),
mStaticRing2.getMasterKeyId()
});
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
PgpSignEncryptResult result = op.execute(b, data, out);
PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -325,7 +323,7 @@ public class PgpEncryptDecryptTest {
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
mKeyPhrase1, mStaticRing1.getMasterKeyId(), null);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertTrue("decryption with cached passphrase must succeed for the first key", result.success());
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -343,7 +341,7 @@ public class PgpEncryptDecryptTest {
InputData data = new InputData(in, in.available());
// allow only the second to decrypt
HashSet<Long> allowed = new HashSet<Long>();
HashSet<Long> allowed = new HashSet<>();
allowed.add(mStaticRing2.getMasterKeyId());
// provide passphrase for the second, and check that the first is never asked for!
@@ -351,7 +349,7 @@ public class PgpEncryptDecryptTest {
mKeyPhrase2, mStaticRing2.getMasterKeyId(), null);
b.setAllowedKeyIds(allowed);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertTrue("decryption with cached passphrase must succeed for the first key", result.success());
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -372,7 +370,7 @@ public class PgpEncryptDecryptTest {
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
mKeyPhrase2, mStaticRing2.getMasterKeyId(), null);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertTrue("decryption with cached passphrase must succeed", result.success());
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -395,7 +393,7 @@ public class PgpEncryptDecryptTest {
new ProviderHelper(Robolectric.application), null);
InputData data = new InputData(in, in.available());
PgpSignEncryptInput b = new PgpSignEncryptInput();
PgpSignEncryptInputParcel b = new PgpSignEncryptInputParcel();
b.setEncryptionMasterKeyIds(new long[] {
mStaticRing1.getMasterKeyId(),
@@ -403,10 +401,9 @@ public class PgpEncryptDecryptTest {
});
b.setSignatureMasterKeyId(mStaticRing1.getMasterKeyId());
b.setSignatureSubKeyId(KeyringTestingHelper.getSubkeyId(mStaticRing1, 1));
b.setSignaturePassphrase(mKeyPhrase1);
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
PgpSignEncryptResult result = op.execute(b, data, out);
PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(mKeyPhrase1), data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -421,7 +418,7 @@ public class PgpEncryptDecryptTest {
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
mKeyPhrase1, mStaticRing1.getMasterKeyId(), null);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertTrue("decryption with cached passphrase must succeed for the first key", result.success());
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -447,7 +444,7 @@ public class PgpEncryptDecryptTest {
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
mKeyPhrase2, mStaticRing2.getMasterKeyId(), null);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel());
Assert.assertTrue("decryption with cached passphrase must succeed", result.success());
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
out.toByteArray(), plaintext.getBytes());
@@ -477,14 +474,14 @@ public class PgpEncryptDecryptTest {
new ProviderHelper(Robolectric.application), null);
InputData data = new InputData(in, in.available());
PgpSignEncryptInput b = new PgpSignEncryptInput();
PgpSignEncryptInputParcel b = new PgpSignEncryptInputParcel();
b.setEncryptionMasterKeyIds(new long[]{ mStaticRing1.getMasterKeyId() });
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
// this only works with ascii armored output!
b.setEnableAsciiArmorOutput(true);
b.setCharset("iso-2022-jp");
PgpSignEncryptResult result = op.execute(b, data, out);
PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -497,8 +494,7 @@ public class PgpEncryptDecryptTest {
InputData data = new InputData(in, in.available());
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out, null, null, null);
b.setPassphrase(mKeyPhrase1);
DecryptVerifyResult result = b.build().execute();
DecryptVerifyResult result = b.build().execute(new CryptoInputParcel(mKeyPhrase1));
Assert.assertTrue("decryption with provided passphrase must succeed", result.success());
Assert.assertArrayEquals("decrypted ciphertext should equal plaintext bytes",
out.toByteArray(), plaindata);

View File

@@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.support.KeyringBuilder;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
@@ -81,6 +82,8 @@ public class PgpKeyOperationTest {
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
static CryptoInputParcel cryptoInput;
@BeforeClass
public static void setUpOnce() throws Exception {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
@@ -108,6 +111,9 @@ public class PgpKeyOperationTest {
// we sleep here for a second, to make sure all new certificates have different timestamps
Thread.sleep(1000);
cryptoInput = new CryptoInputParcel(new Date(), passphrase);
}
@Before public void setUp() throws Exception {
@@ -300,9 +306,16 @@ public class PgpKeyOperationTest {
if (badphrase.equals(passphrase)) {
badphrase = new Passphrase("a");
}
parcel.mAddUserIds.add("allure");
assertModifyFailure("keyring modification with bad passphrase should fail",
ring, parcel, badphrase, LogType.MSG_MF_UNLOCK_ERROR);
ring, parcel, new CryptoInputParcel(badphrase), LogType.MSG_MF_UNLOCK_ERROR);
}
{
parcel.reset();
assertModifyFailure("no-op should fail",
ring, parcel, cryptoInput, LogType.MSG_MF_ERROR_NOOP);
}
}
@@ -646,7 +659,7 @@ public class PgpKeyOperationTest {
parcel.mRevokeSubKeys.add(123L);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, parcel, passphrase).getRing();
UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, cryptoInput, parcel).getRing();
Assert.assertNull("revoking a nonexistent subkey should fail", otherModified);
@@ -657,7 +670,8 @@ public class PgpKeyOperationTest {
parcel.reset();
parcel.mRevokeSubKeys.add(keyId);
modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB,
new CryptoInputParcel(new Date(), passphrase));
Assert.assertEquals("no extra packets in original", 0, onlyA.size());
Assert.assertEquals("exactly one extra packet in modified", 1, onlyB.size());
@@ -777,7 +791,7 @@ public class PgpKeyOperationTest {
{ // we should be able to change the stripped/divert status of subkeys without passphrase
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, null));
modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB, null);
modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB, new CryptoInputParcel());
Assert.assertEquals("one extra packet in modified", 1, onlyB.size());
Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
Assert.assertEquals("new packet should have GNU_DUMMY S2K type",
@@ -793,7 +807,7 @@ public class PgpKeyOperationTest {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, serial));
modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB, null);
modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB, new CryptoInputParcel());
Assert.assertEquals("one extra packet in modified", 1, onlyB.size());
Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
Assert.assertEquals("new packet should have GNU_DUMMY S2K type",
@@ -970,12 +984,12 @@ public class PgpKeyOperationTest {
Assert.assertEquals("signature type must be positive certification",
PGPSignature.POSITIVE_CERTIFICATION, ((SignaturePacket) p).getSignatureType());
// make sure packets can be distinguished by timestamp
Thread.sleep(1000);
// applying the same modification AGAIN should not add more certifications but drop those
// as duplicates
modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, passphrase, true, false);
modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB,
new CryptoInputParcel(new Date(), passphrase), true, false);
Assert.assertEquals("duplicate modification: one extra packet in original", 1, onlyA.size());
Assert.assertEquals("duplicate modification: one extra packet in modified", 1, onlyB.size());
@@ -1039,8 +1053,7 @@ public class PgpKeyOperationTest {
// change passphrase to empty
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
// note that canonicalization here necessarily strips the empty notation packet
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB,
passphrase);
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB, cryptoInput);
Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
3, onlyB.size());
@@ -1052,8 +1065,10 @@ public class PgpKeyOperationTest {
// modify keyring, change to non-empty passphrase
Passphrase otherPassphrase = TestingUtils.genPassphrase(true);
CryptoInputParcel otherCryptoInput = new CryptoInputParcel(otherPassphrase);
parcel.mNewUnlock = new ChangeUnlockParcel(otherPassphrase);
modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB, new Passphrase());
modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB,
new CryptoInputParcel(new Date(), new Passphrase()));
Assert.assertEquals("exactly three packets should have been modified (the secret keys)",
3, onlyB.size());
@@ -1086,7 +1101,7 @@ public class PgpKeyOperationTest {
// 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);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, otherCryptoInput, parcel);
Assert.assertTrue("key modification must succeed", result.success());
Assert.assertFalse("log must not contain a warning",
result.getLog().containsWarnings());
@@ -1102,7 +1117,7 @@ public class PgpKeyOperationTest {
PgpKeyOperation op = new PgpKeyOperation(null);
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, otherPassphrase2);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(otherPassphrase2), parcel);
Assert.assertTrue("key modification must succeed", result.success());
Assert.assertTrue("log must contain a failed passphrase change warning",
result.getLog().containsType(LogType.MSG_MF_PASSPHRASE_FAIL));
@@ -1140,7 +1155,7 @@ public class PgpKeyOperationTest {
{
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase("phrayse"), null);
applyModificationWithChecks(parcel, modified, onlyA, onlyB, pin, true, false);
applyModificationWithChecks(parcel, modified, onlyA, onlyB, new CryptoInputParcel(pin), true, false);
Assert.assertEquals("exactly four packets should have been removed (the secret keys + notation packet)",
4, onlyA.size());
@@ -1157,7 +1172,7 @@ public class PgpKeyOperationTest {
parcel.mAddUserIds.add("discord");
PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date()), parcel);
Assert.assertFalse("non-restricted operations should fail without passphrase", result.success());
}
@@ -1165,15 +1180,15 @@ public class PgpKeyOperationTest {
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB) {
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, cryptoInput, true, true);
}
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB,
Passphrase passphrase) {
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, passphrase, true, true);
CryptoInputParcel cryptoInput) {
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, cryptoInput, true, true);
}
// applies a parcel modification while running some integrity checks
@@ -1181,7 +1196,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB,
Passphrase passphrase,
CryptoInputParcel cryptoInput,
boolean canonicalize,
boolean constantCanonicalize) {
@@ -1191,7 +1206,7 @@ public class PgpKeyOperationTest {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
PgpKeyOperation op = new PgpKeyOperation(null);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
Assert.assertTrue("key modification must succeed", result.success());
UncachedKeyRing rawModified = result.getRing();
Assert.assertNotNull("key modification must not return null", rawModified);
@@ -1258,11 +1273,11 @@ public class PgpKeyOperationTest {
}
private void assertModifyFailure(String reason, UncachedKeyRing ring,
SaveKeyringParcel parcel, Passphrase passphrase, LogType expected)
SaveKeyringParcel parcel, CryptoInputParcel cryptoInput, LogType expected)
throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());
@@ -1276,7 +1291,7 @@ public class PgpKeyOperationTest {
throws Exception {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, passphrase);
PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
Assert.assertFalse(reason, result.success());
Assert.assertNull(reason, result.getRing());

View File

@@ -59,6 +59,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
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;
@@ -549,7 +550,10 @@ public class UncachedKeyringCanonicalizeTest {
CanonicalizedSecretKey masterSecretKey = canonicalized.getSecretKey();
masterSecretKey.unlock(new Passphrase());
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
CryptoInputParcel cryptoInput = new CryptoInputParcel();
PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature(
PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), cryptoInput),
cryptoInput.getSignatureTime(),
masterPublicKey, masterSecretKey.getPrivateKey(), masterSecretKey.getPrivateKey(),
masterPublicKey, masterSecretKey.getKeyUsage(), 0);
PGPPublicKey subPubKey = PGPPublicKey.addSubkeyBindingCertification(masterPublicKey, cert);

View File

@@ -35,9 +35,12 @@ 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;
@@ -46,6 +49,7 @@ 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;
@@ -186,11 +190,11 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddUserIds.add("flim");
modifiedA = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
parcel.reset();
parcel.mAddUserIds.add("flam");
modifiedB = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
}
{ // merge A into base
@@ -227,8 +231,8 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
modifiedA = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
modifiedB = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
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);
@@ -269,7 +273,7 @@ public class UncachedKeyringMergeTest {
parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(ringA, 1));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), false, 0);
modified = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
}
{
@@ -295,8 +299,13 @@ public class UncachedKeyringMergeTest {
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
modified = secretKey.certifyUserIds(publicRing, publicRing.getPublicKey().getUnorderedUserIds(), null, null);
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();
}
{
@@ -363,7 +372,7 @@ public class UncachedKeyringMergeTest {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), false, 0);
modified = op.modifySecretKeyRing(secretRing, parcel, new Passphrase()).getRing();
modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
}
{