161 lines
6.5 KiB
Java
161 lines
6.5 KiB
Java
/*
|
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
|
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package org.sufficientlysecure.keychain.pgp;
|
|
|
|
import org.junit.Assert;
|
|
import org.junit.Before;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.robolectric.RobolectricGradleTestRunner;
|
|
import org.robolectric.RobolectricTestRunner;
|
|
import org.robolectric.annotation.Config;
|
|
import org.robolectric.shadows.ShadowLog;
|
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
|
import org.sufficientlysecure.keychain.BuildConfig;
|
|
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
|
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
|
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.Passphrase;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.util.Iterator;
|
|
import java.util.Random;
|
|
|
|
@RunWith(RobolectricGradleTestRunner.class)
|
|
@Config(constants = BuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")
|
|
public class UncachedKeyringTest {
|
|
|
|
static UncachedKeyRing staticRing, staticPubRing;
|
|
UncachedKeyRing ring, pubRing;
|
|
|
|
@BeforeClass
|
|
public static void setUpOnce() throws Exception {
|
|
ShadowLog.stream = System.out;
|
|
|
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
|
|
|
parcel.mAddUserIds.add("twi");
|
|
parcel.mAddUserIds.add("pink");
|
|
{
|
|
Random r = new Random();
|
|
int type = r.nextInt(110)+1;
|
|
byte[] data = new byte[r.nextInt(2000)];
|
|
new Random().nextBytes(data);
|
|
|
|
WrappedUserAttribute uat = WrappedUserAttribute.fromSubpacket(type, data);
|
|
parcel.mAddUserAttribute.add(uat);
|
|
}
|
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
|
parcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase());
|
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
|
|
|
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
|
|
staticRing = result.getRing();
|
|
staticPubRing = staticRing.extractPublicKeyRing();
|
|
|
|
Assert.assertNotNull("initial test key creation must succeed", staticRing);
|
|
|
|
// we sleep here for a second, to make sure all new certificates have different timestamps
|
|
Thread.sleep(1000);
|
|
}
|
|
|
|
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
// show Log.x messages in system.out
|
|
ShadowLog.stream = System.out;
|
|
ring = staticRing;
|
|
pubRing = staticPubRing;
|
|
}
|
|
|
|
@Test(expected = UnsupportedOperationException.class)
|
|
public void testPublicKeyItRemove() throws Exception {
|
|
Iterator<UncachedPublicKey> it = ring.getPublicKeys();
|
|
it.remove();
|
|
}
|
|
|
|
@Test(expected = PgpGeneralException.class)
|
|
public void testDecodeFromEmpty() throws Exception {
|
|
UncachedKeyRing.decodeFromData(new byte[0]);
|
|
}
|
|
|
|
@Test
|
|
public void testArmorIdentity() throws Exception {
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
ring.encodeArmored(out, "OpenKeychain");
|
|
|
|
Assert.assertArrayEquals("armor encoded and decoded ring should be identical to original",
|
|
ring.getEncoded(),
|
|
UncachedKeyRing.decodeFromData(out.toByteArray()).getEncoded());
|
|
}
|
|
|
|
@Test(expected = PgpGeneralException.class)
|
|
public void testDecodeEncodeMulti() throws Exception {
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
// encode secret and public ring in here
|
|
ring.encodeArmored(out, "OpenKeychain");
|
|
pubRing.encodeArmored(out, "OpenKeychain");
|
|
|
|
IteratorWithIOThrow<UncachedKeyRing> it =
|
|
UncachedKeyRing.fromStream(new ByteArrayInputStream(out.toByteArray()));
|
|
Assert.assertTrue("there should be two rings in the stream", it.hasNext());
|
|
Assert.assertArrayEquals("first ring should be the first we put in",
|
|
ring.getEncoded(), it.next().getEncoded());
|
|
Assert.assertTrue("there should be two rings in the stream", it.hasNext());
|
|
Assert.assertArrayEquals("second ring should be the second we put in",
|
|
pubRing.getEncoded(), it.next().getEncoded());
|
|
Assert.assertFalse("there should be two rings in the stream", it.hasNext());
|
|
|
|
// this should fail with PgpGeneralException, since it expects exactly one ring
|
|
UncachedKeyRing.decodeFromData(out.toByteArray());
|
|
}
|
|
|
|
@Test(expected = RuntimeException.class)
|
|
public void testPublicExtractPublic() throws Exception {
|
|
// can't do this, either!
|
|
pubRing.extractPublicKeyRing();
|
|
}
|
|
|
|
@Test(expected = IOException.class)
|
|
public void testBrokenVersionCert() throws Throwable {
|
|
// this is a test for one of the patches we use on top of stock bouncycastle, which
|
|
// returns an IOException rather than a RuntimeException in case of a bad certificate
|
|
// version byte
|
|
readRingFromResource("/test-keys/broken_cert_version.asc");
|
|
}
|
|
|
|
UncachedKeyRing readRingFromResource(String name) throws Throwable {
|
|
return UncachedKeyRing.fromStream(UncachedKeyringTest.class.getResourceAsStream(name)).next();
|
|
}
|
|
|
|
}
|