diff options
Diffstat (limited to 'OpenKeychain-Test/src')
4 files changed, 237 insertions, 6 deletions
diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java new file mode 100644 index 000000000..40ade064b --- /dev/null +++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java @@ -0,0 +1,126 @@ +/* + * 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.operations; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.shadows.ShadowLog; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; +import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; +import org.sufficientlysecure.keychain.util.ProgressScaler; +import org.sufficientlysecure.keychain.util.TestingUtils; + +import java.io.PrintStream; +import java.security.Security; +import java.util.Iterator; + +@RunWith(RobolectricTestRunner.class) +@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19 +public class PromoteKeyOperationTest { + + static UncachedKeyRing mStaticRing; + static String mKeyPhrase1 = TestingUtils.genPassphrase(true); + + static PrintStream oldShadowStream; + + @BeforeClass + public static void setUpOnce() throws Exception { + Security.insertProviderAt(new BouncyCastleProvider(), 1); + oldShadowStream = ShadowLog.stream; + // ShadowLog.stream = System.out; + + PgpKeyOperation op = new PgpKeyOperation(null); + + { + 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.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L)); + parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd( + Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L)); + parcel.mAddUserIds.add("derp"); + parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1); + + PgpEditKeyResult result = op.createSecretKeyRing(parcel); + Assert.assertTrue("initial test key creation must succeed", result.success()); + Assert.assertNotNull("initial test key creation must succeed", result.getRing()); + + mStaticRing = result.getRing(); + } + + } + + @Before + public void setUp() throws Exception { + ProviderHelper providerHelper = new ProviderHelper(Robolectric.application); + + // don't log verbosely here, we're not here to test imports + ShadowLog.stream = oldShadowStream; + + providerHelper.savePublicKeyRing(mStaticRing.extractPublicKeyRing(), new ProgressScaler()); + + // ok NOW log verbosely! + ShadowLog.stream = System.out; + } + + @Test + public void testPromote() throws Exception { + PromoteKeyOperation op = new PromoteKeyOperation(Robolectric.application, + new ProviderHelper(Robolectric.application), null, null); + + PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId()); + + Assert.assertTrue("promotion must succeed", result.success()); + + { + CachedPublicKeyRing ring = new ProviderHelper(Robolectric.application) + .getCachedPublicKeyRing(mStaticRing.getMasterKeyId()); + Assert.assertTrue("key must have a secret now", ring.hasAnySecret()); + + Iterator<UncachedPublicKey> it = mStaticRing.getPublicKeys(); + while (it.hasNext()) { + long keyId = it.next().getKeyId(); + Assert.assertEquals("all subkeys must be divert-to-card", + 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()); + + } + +} diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java index 008edcda4..b8205a792 100644 --- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java +++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java @@ -438,6 +438,60 @@ public class PgpEncryptDecryptTest { } + @Test + public void testForeignEncoding () throws Exception { + String plaintext = "ウィキペディア"; + byte[] plaindata = plaintext.getBytes("iso-2022-jp"); + + { // some quick sanity checks + Assert.assertEquals(plaintext, new String(plaindata, "iso-2022-jp")); + Assert.assertNotEquals(plaintext, new String(plaindata, "utf-8")); + } + + byte[] ciphertext; + { // encrypt data with a given passphrase + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(plaindata); + + InputData data = new InputData(in, in.available()); + Builder b = new PgpSignEncrypt.Builder( + Robolectric.application, + new ProviderHelper(Robolectric.application), + null, // new DummyPassphraseCache(mPassphrase, 0L), + data, out); + + 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"); + SignEncryptResult result = b.build().execute(); + Assert.assertTrue("encryption must succeed", result.success()); + + ciphertext = out.toByteArray(); + } + + { // decryption with provided passphrase should yield the same result + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + 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(); + Assert.assertTrue("decryption with provided passphrase must succeed", result.success()); + Assert.assertArrayEquals("decrypted ciphertext should equal plaintext bytes", + out.toByteArray(), plaindata); + Assert.assertEquals("charset should be read correctly", + "iso-2022-jp", result.getCharset()); + Assert.assertEquals("decrypted ciphertext should equal plaintext", + new String(out.toByteArray(), result.getCharset()), plaintext); + Assert.assertNull("signature be empty", result.getSignatureResult()); + } + + } + private PgpDecryptVerify.Builder builderWithFakePassphraseCache ( InputData data, OutputStream out, final String passphrase, final Long checkMasterKeyId, final Long checkSubKeyId) { 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 3ea88aac6..0288d2937 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 @@ -659,7 +659,8 @@ public class PgpKeyOperationTest { { // re-add second subkey parcel.reset(); - parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, null)); + // re-certify the revoked subkey + parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true)); modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB); @@ -701,7 +702,7 @@ public class PgpKeyOperationTest { public void testSubkeyStrip() throws Exception { long keyId = KeyringTestingHelper.getSubkeyId(ring, 1); - parcel.mStripSubKeys.add(keyId); + parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, null)); applyModificationWithChecks(parcel, ring, onlyA, onlyB); Assert.assertEquals("one extra packet in original", 1, onlyA.size()); @@ -727,7 +728,7 @@ public class PgpKeyOperationTest { public void testMasterStrip() throws Exception { long keyId = ring.getMasterKeyId(); - parcel.mStripSubKeys.add(keyId); + parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, null)); applyModificationWithChecks(parcel, ring, onlyA, onlyB); Assert.assertEquals("one extra packet in original", 1, onlyA.size()); @@ -746,6 +747,44 @@ public class PgpKeyOperationTest { Assert.assertEquals("new packet secret key data should have length zero", 0, ((SecretKeyPacket) p).getSecretKeyData().length); Assert.assertNull("new packet should have no iv data", ((SecretKeyPacket) p).getIV()); + } + + @Test + public void testRestrictedStrip() throws Exception { + + long keyId = KeyringTestingHelper.getSubkeyId(ring, 1); + UncachedKeyRing modified; + + { // 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); + 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", + S2K.GNU_DUMMY_S2K, ((SecretKeyPacket) p).getS2K().getType()); + Assert.assertEquals("new packet should have GNU_DUMMY protection mode stripped", + S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY, ((SecretKeyPacket) p).getS2K().getProtectionMode()); + } + + { // and again, changing to divert-to-card + parcel.reset(); + byte[] serial = new byte[] { + 0x6a, 0x6f, 0x6c, 0x6f, 0x73, 0x77, 0x61, 0x67, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, serial)); + modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB, null); + 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", + S2K.GNU_DUMMY_S2K, ((SecretKeyPacket) p).getS2K().getType()); + Assert.assertEquals("new packet should have GNU_DUMMY protection mode divert-to-card", + S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD, ((SecretKeyPacket) p).getS2K().getProtectionMode()); + Assert.assertArrayEquals("new packet should have correct serial number as iv", + serial, ((SecretKeyPacket) p).getIV()); + + } } @@ -1092,6 +1131,17 @@ public class PgpKeyOperationTest { } + @Test + public void testRestricted () throws Exception { + + CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0); + + parcel.mAddUserIds.add("discord"); + PgpKeyOperation op = new PgpKeyOperation(null); + PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, parcel, null); + Assert.assertFalse("non-restricted operations should fail without passphrase", result.success()); + } + private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel, UncachedKeyRing ring, ArrayList<RawPacket> onlyA, diff --git a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java index e4a1d62ae..171ecc377 100644 --- a/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java +++ b/OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/provider/ProviderHelperSaveTest.java @@ -106,8 +106,8 @@ public class ProviderHelperSaveTest { UncachedKeyRing pub = readRingFromResource("/test-keys/mailvelope_07_no_key_flags.asc"); long keyId = pub.getMasterKeyId(); - Assert.assertNull("key flags should be null", - pub.canonicalize(new OperationLog(), 0).getPublicKey().getKeyUsage()); + Assert.assertEquals("key flags should be zero", + 0, (long) pub.canonicalize(new OperationLog(), 0).getPublicKey().getKeyUsage()); mProviderHelper.savePublicKeyRing(pub); @@ -117,7 +117,8 @@ public class ProviderHelperSaveTest { Assert.assertEquals("master key should be encryption key", keyId, pubRing.getEncryptId()); Assert.assertEquals("master key should be encryption key (cached)", keyId, cachedRing.getEncryptId()); - Assert.assertNull("canonicalized key flags should be null", pubRing.getPublicKey().getKeyUsage()); + Assert.assertEquals("canonicalized key flags should be zero", + 0, (long) pubRing.getPublicKey().getKeyUsage()); Assert.assertTrue("master key should be able to certify", pubRing.getPublicKey().canCertify()); Assert.assertTrue("master key should be allowed to sign", pubRing.getPublicKey().canSign()); Assert.assertTrue("master key should be able to encrypt", pubRing.getPublicKey().canEncrypt()); |