mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Merge branch 'master' into yubikey
This commit is contained in:
commit
2f5c73746d
3
.gitignore
vendored
3
.gitignore
vendored
@ -14,6 +14,9 @@ ant.properties
|
|||||||
.gradle
|
.gradle
|
||||||
build
|
build
|
||||||
gradle.properties
|
gradle.properties
|
||||||
|
# this is in here because the prepare-tests thing modifies it, and we DON'T
|
||||||
|
# want this to be commited. use git add -f to work on this file.
|
||||||
|
settings.gradle
|
||||||
|
|
||||||
#Maven
|
#Maven
|
||||||
target
|
target
|
||||||
|
@ -12,7 +12,7 @@ before_install:
|
|||||||
# Install required Android components.
|
# Install required Android components.
|
||||||
#- echo "y" | android update sdk -a --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force
|
#- echo "y" | android update sdk -a --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force
|
||||||
- ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --no-ui --all --force --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository
|
- ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --no-ui --all --force --filter build-tools-19.1.0,android-19,platform-tools,extra-android-support,extra-android-m2repository
|
||||||
- ./install-custom-gradle-test-plugin.sh
|
- ./prepare-tests.sh
|
||||||
install: echo "Installation done"
|
install: echo "Installation done"
|
||||||
script:
|
script:
|
||||||
- gradle assemble -S -q
|
- gradle assemble -S -q
|
||||||
|
@ -1,5 +1,20 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
// need this for com.novoda:gradle-android-test-plugin:0.9.9-SNAPSHOT below (0.9.3 in repos doesn't work!)
|
||||||
|
// run ./install-custom-gradle-test-plugin.sh to pull the thing into the local repository
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
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.9.9-SNAPSHOT'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'android-test'
|
apply plugin: 'android-test'
|
||||||
|
apply plugin: 'jacoco'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile 'junit:junit:4.11'
|
testCompile 'junit:junit:4.11'
|
||||||
@ -31,6 +46,29 @@ android {
|
|||||||
projectUnderTest ':OpenKeychain'
|
projectUnderTest ':OpenKeychain'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jacoco {
|
||||||
|
toolVersion = "0.7.0.201403182114"
|
||||||
|
}
|
||||||
|
|
||||||
|
coverageSourceDirs = [
|
||||||
|
'../OpenKeychain/src/main/java',
|
||||||
|
'../OpenKeychain/src/gen',
|
||||||
|
'../OpenKeychain/build/source/apt/debug',
|
||||||
|
'../OpenKeychain/build/source/generated/buildConfig/debug',
|
||||||
|
'../OpenKeychain/build/source/generated/r/debug'
|
||||||
|
]
|
||||||
|
|
||||||
|
jacocoTestReport {
|
||||||
|
reports {
|
||||||
|
xml.enabled = true
|
||||||
|
html.destination "${buildDir}/jacocoHtml"
|
||||||
|
}
|
||||||
|
// class R is used, but usage will not be covered, so ignore this class from report
|
||||||
|
classDirectories = fileTree(dir: '../OpenKeychain/build/intermediates/classes/debug/org/sufficientlysecure/keychain', exclude: 'R*.class')
|
||||||
|
additionalSourceDirs = files(coverageSourceDirs)
|
||||||
|
executionData = files('build/jacoco/testDebug.exec')
|
||||||
|
}
|
||||||
|
|
||||||
// new workaround to force add custom output dirs for android studio
|
// new workaround to force add custom output dirs for android studio
|
||||||
task addTest {
|
task addTest {
|
||||||
def file = file(project.name + ".iml")
|
def file = file(project.name + ".iml")
|
||||||
|
@ -21,6 +21,7 @@ import android.content.Context;
|
|||||||
import org.spongycastle.util.Arrays;
|
import org.spongycastle.util.Arrays;
|
||||||
import org.sufficientlysecure.keychain.pgp.NullProgressable;
|
import org.sufficientlysecure.keychain.pgp.NullProgressable;
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults;
|
import org.sufficientlysecure.keychain.service.OperationResults;
|
||||||
|
|
||||||
@ -68,6 +69,11 @@ public class KeyringTestingHelper {
|
|||||||
return saveSuccess;
|
return saveSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UncachedKeyRing removePacket(UncachedKeyRing ring, int position)
|
||||||
|
throws IOException, PgpGeneralException {
|
||||||
|
return UncachedKeyRing.decodeFromData(removePacket(ring.getEncoded(), position));
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] removePacket(byte[] ring, int position) throws IOException {
|
public static byte[] removePacket(byte[] ring, int position) throws IOException {
|
||||||
Iterator<RawPacket> it = parseKeyring(ring);
|
Iterator<RawPacket> it = parseKeyring(ring);
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(ring.length);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(ring.length);
|
||||||
@ -76,6 +82,7 @@ public class KeyringTestingHelper {
|
|||||||
while(it.hasNext()) {
|
while(it.hasNext()) {
|
||||||
// at the right position, skip the packet
|
// at the right position, skip the packet
|
||||||
if(i++ == position) {
|
if(i++ == position) {
|
||||||
|
it.next();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// write the old one
|
// write the old one
|
||||||
@ -89,6 +96,11 @@ public class KeyringTestingHelper {
|
|||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UncachedKeyRing injectPacket(UncachedKeyRing ring, byte[] inject, int position)
|
||||||
|
throws IOException, PgpGeneralException {
|
||||||
|
return UncachedKeyRing.decodeFromData(injectPacket(ring.getEncoded(), inject, position));
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] injectPacket(byte[] ring, byte[] inject, int position) throws IOException {
|
public static byte[] injectPacket(byte[] ring, byte[] inject, int position) throws IOException {
|
||||||
|
|
||||||
Iterator<RawPacket> it = parseKeyring(ring);
|
Iterator<RawPacket> it = parseKeyring(ring);
|
||||||
|
@ -0,0 +1,213 @@
|
|||||||
|
package org.sufficientlysecure.keychain.tests;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.shadows.ShadowLog;
|
||||||
|
import org.spongycastle.bcpg.BCPGInputStream;
|
||||||
|
import org.spongycastle.bcpg.Packet;
|
||||||
|
import org.spongycastle.bcpg.PacketTags;
|
||||||
|
import org.spongycastle.bcpg.UserIDPacket;
|
||||||
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
|
||||||
|
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
||||||
|
public class UncachedKeyringCanonicalizeTest {
|
||||||
|
|
||||||
|
static UncachedKeyRing staticRing;
|
||||||
|
static int totalPackets;
|
||||||
|
UncachedKeyRing ring;
|
||||||
|
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
|
||||||
|
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
|
||||||
|
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpOnce() throws Exception {
|
||||||
|
ShadowLog.stream = System.out;
|
||||||
|
|
||||||
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
|
Constants.choice.algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER, null));
|
||||||
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
|
Constants.choice.algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
|
||||||
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
|
Constants.choice.algorithm.rsa, 1024, KeyFlags.ENCRYPT_COMMS, null));
|
||||||
|
|
||||||
|
parcel.mAddUserIds.add("twi");
|
||||||
|
parcel.mAddUserIds.add("pink");
|
||||||
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
||||||
|
parcel.mNewPassphrase = "";
|
||||||
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||||
|
|
||||||
|
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
||||||
|
staticRing = op.createSecretKeyRing(parcel, log, 0);
|
||||||
|
|
||||||
|
Assert.assertNotNull("initial test key creation must succeed", staticRing);
|
||||||
|
|
||||||
|
// just for later reference
|
||||||
|
totalPackets = 9;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testGeneratedRingStructure() throws Exception {
|
||||||
|
|
||||||
|
Iterator<RawPacket> it = KeyringTestingHelper.parseKeyring(ring.getEncoded());
|
||||||
|
|
||||||
|
Assert.assertEquals("packet #1 should be secret key",
|
||||||
|
PacketTags.SECRET_KEY, it.next().tag);
|
||||||
|
|
||||||
|
Assert.assertEquals("packet #2 should be user id",
|
||||||
|
PacketTags.USER_ID, it.next().tag);
|
||||||
|
Assert.assertEquals("packet #3 should be signature",
|
||||||
|
PacketTags.SIGNATURE, it.next().tag);
|
||||||
|
|
||||||
|
Assert.assertEquals("packet #4 should be user id",
|
||||||
|
PacketTags.USER_ID, it.next().tag);
|
||||||
|
Assert.assertEquals("packet #5 should be signature",
|
||||||
|
PacketTags.SIGNATURE, it.next().tag);
|
||||||
|
|
||||||
|
Assert.assertEquals("packet #6 should be secret subkey",
|
||||||
|
PacketTags.SECRET_SUBKEY, it.next().tag);
|
||||||
|
Assert.assertEquals("packet #7 should be signature",
|
||||||
|
PacketTags.SIGNATURE, it.next().tag);
|
||||||
|
|
||||||
|
Assert.assertEquals("packet #8 should be secret subkey",
|
||||||
|
PacketTags.SECRET_SUBKEY, it.next().tag);
|
||||||
|
Assert.assertEquals("packet #9 should be signature",
|
||||||
|
PacketTags.SIGNATURE, it.next().tag);
|
||||||
|
|
||||||
|
Assert.assertFalse("exactly 9 packets total", it.hasNext());
|
||||||
|
|
||||||
|
Assert.assertArrayEquals("created keyring should be constant through canonicalization",
|
||||||
|
ring.getEncoded(), ring.canonicalize(log, 0).getEncoded());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testBrokenSignature() throws Exception {
|
||||||
|
|
||||||
|
byte[] brokenSig;
|
||||||
|
{
|
||||||
|
UncachedPublicKey masterKey = ring.getPublicKey();
|
||||||
|
WrappedSignature sig = masterKey.getSignaturesForId("twi").next();
|
||||||
|
brokenSig = sig.getEncoded();
|
||||||
|
// break the signature
|
||||||
|
brokenSig[brokenSig.length - 5] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] reng = ring.getEncoded();
|
||||||
|
for(int i = 0; i < totalPackets; i++) {
|
||||||
|
|
||||||
|
byte[] brokenBytes = KeyringTestingHelper.injectPacket(reng, brokenSig, i);
|
||||||
|
Assert.assertEquals("broken ring must be original + injected size",
|
||||||
|
reng.length + brokenSig.length, brokenBytes.length);
|
||||||
|
|
||||||
|
try {
|
||||||
|
UncachedKeyRing brokenRing = UncachedKeyRing.decodeFromData(brokenBytes);
|
||||||
|
|
||||||
|
brokenRing = brokenRing.canonicalize(log, 0);
|
||||||
|
if (brokenRing == null) {
|
||||||
|
System.out.println("ok, canonicalization failed.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertArrayEquals("injected bad signature must be gone after canonicalization",
|
||||||
|
ring.getEncoded(), brokenRing.getEncoded());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("ok, rejected with: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testUidSignature() throws Exception {
|
||||||
|
|
||||||
|
UncachedPublicKey masterKey = ring.getPublicKey();
|
||||||
|
final WrappedSignature sig = masterKey.getSignaturesForId("twi").next();
|
||||||
|
|
||||||
|
byte[] raw = sig.getEncoded();
|
||||||
|
// destroy the signature
|
||||||
|
raw[raw.length - 5] += 1;
|
||||||
|
final WrappedSignature brokenSig = WrappedSignature.fromBytes(raw);
|
||||||
|
|
||||||
|
{ // bad certificates get stripped
|
||||||
|
UncachedKeyRing modified = KeyringTestingHelper.injectPacket(ring, brokenSig.getEncoded(), 3);
|
||||||
|
modified = modified.canonicalize(log, 0);
|
||||||
|
|
||||||
|
Assert.assertTrue("canonicalized keyring with invalid extra sig must be same as original one",
|
||||||
|
!KeyringTestingHelper.diffKeyrings(
|
||||||
|
ring.getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove user id certificate for one user
|
||||||
|
final UncachedKeyRing base = KeyringTestingHelper.removePacket(ring, 2);
|
||||||
|
|
||||||
|
{ // user id without certificate should be removed
|
||||||
|
UncachedKeyRing modified = base.canonicalize(log, 0);
|
||||||
|
Assert.assertTrue("canonicalized keyring must differ", KeyringTestingHelper.diffKeyrings(
|
||||||
|
ring.getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||||
|
|
||||||
|
Assert.assertEquals("two packets should be stripped after canonicalization", 2, onlyA.size());
|
||||||
|
Assert.assertEquals("no new packets after canonicalization", 0, onlyB.size());
|
||||||
|
|
||||||
|
Packet p;
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(onlyA.get(0).buf)).readPacket();
|
||||||
|
Assert.assertTrue("first stripped packet must be user id", p instanceof UserIDPacket);
|
||||||
|
Assert.assertEquals("missing user id must be the expected one",
|
||||||
|
"twi", ((UserIDPacket) p).getID());
|
||||||
|
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(onlyA.get(1).buf)).readPacket();
|
||||||
|
Assert.assertArrayEquals("second stripped packet must be signature we removed",
|
||||||
|
sig.getEncoded(), onlyA.get(1).buf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // add error to signature
|
||||||
|
|
||||||
|
UncachedKeyRing modified = KeyringTestingHelper.injectPacket(base, brokenSig.getEncoded(), 3);
|
||||||
|
modified = modified.canonicalize(log, 0);
|
||||||
|
|
||||||
|
Assert.assertTrue("canonicalized keyring must differ", KeyringTestingHelper.diffKeyrings(
|
||||||
|
ring.getEncoded(), modified.getEncoded(), onlyA, onlyB));
|
||||||
|
|
||||||
|
Assert.assertEquals("two packets should be missing after canonicalization", 2, onlyA.size());
|
||||||
|
Assert.assertEquals("no new packets after canonicalization", 0, onlyB.size());
|
||||||
|
|
||||||
|
Packet p;
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(onlyA.get(0).buf)).readPacket();
|
||||||
|
Assert.assertTrue("first stripped packet must be user id", p instanceof UserIDPacket);
|
||||||
|
Assert.assertEquals("missing user id must be the expected one",
|
||||||
|
"twi", ((UserIDPacket) p).getID());
|
||||||
|
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(onlyA.get(1).buf)).readPacket();
|
||||||
|
Assert.assertArrayEquals("second stripped packet must be signature we removed",
|
||||||
|
sig.getEncoded(), onlyA.get(1).buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,106 +0,0 @@
|
|||||||
package org.sufficientlysecure.keychain.tests;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.shadows.ShadowLog;
|
|
||||||
import org.spongycastle.bcpg.BCPGInputStream;
|
|
||||||
import org.spongycastle.bcpg.Packet;
|
|
||||||
import org.spongycastle.bcpg.PacketTags;
|
|
||||||
import org.spongycastle.bcpg.UserIDPacket;
|
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
|
|
||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@org.robolectric.annotation.Config(emulateSdk = 18) // Robolectric doesn't yet support 19
|
|
||||||
public class UncachedKeyringTest {
|
|
||||||
|
|
||||||
static UncachedKeyRing staticRing;
|
|
||||||
UncachedKeyRing ring;
|
|
||||||
ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
|
|
||||||
ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
|
|
||||||
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void setUpOnce() throws Exception {
|
|
||||||
ShadowLog.stream = System.out;
|
|
||||||
|
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
||||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER, null));
|
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
||||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
|
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
||||||
Constants.choice.algorithm.rsa, 1024, KeyFlags.ENCRYPT_COMMS, null));
|
|
||||||
|
|
||||||
parcel.mAddUserIds.add("twi");
|
|
||||||
parcel.mAddUserIds.add("pink");
|
|
||||||
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
|
||||||
parcel.mNewPassphrase = "";
|
|
||||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
|
||||||
|
|
||||||
OperationResultParcel.OperationLog log = new OperationResultParcel.OperationLog();
|
|
||||||
staticRing = op.createSecretKeyRing(parcel, log, 0);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testGeneratedRingStructure() throws Exception {
|
|
||||||
|
|
||||||
Iterator<RawPacket> it = KeyringTestingHelper.parseKeyring(ring.getEncoded());
|
|
||||||
|
|
||||||
Assert.assertEquals("packet #1 should be secret key",
|
|
||||||
PacketTags.SECRET_KEY, it.next().tag);
|
|
||||||
|
|
||||||
Assert.assertEquals("packet #2 should be secret key",
|
|
||||||
PacketTags.USER_ID, it.next().tag);
|
|
||||||
Assert.assertEquals("packet #3 should be secret key",
|
|
||||||
PacketTags.SIGNATURE, it.next().tag);
|
|
||||||
|
|
||||||
Assert.assertEquals("packet #4 should be secret key",
|
|
||||||
PacketTags.USER_ID, it.next().tag);
|
|
||||||
Assert.assertEquals("packet #5 should be secret key",
|
|
||||||
PacketTags.SIGNATURE, it.next().tag);
|
|
||||||
|
|
||||||
Assert.assertEquals("packet #6 should be secret key",
|
|
||||||
PacketTags.SECRET_SUBKEY, it.next().tag);
|
|
||||||
Assert.assertEquals("packet #7 should be secret key",
|
|
||||||
PacketTags.SIGNATURE, it.next().tag);
|
|
||||||
|
|
||||||
Assert.assertEquals("packet #8 should be secret key",
|
|
||||||
PacketTags.SECRET_SUBKEY, it.next().tag);
|
|
||||||
Assert.assertEquals("packet #9 should be secret key",
|
|
||||||
PacketTags.SIGNATURE, it.next().tag);
|
|
||||||
|
|
||||||
Assert.assertFalse("exactly 9 packets total", it.hasNext());
|
|
||||||
|
|
||||||
Assert.assertArrayEquals("created keyring should be constant through canonicalization",
|
|
||||||
ring.getEncoded(), ring.canonicalize(log, 0).getEncoded());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
apply plugin: 'android'
|
apply plugin: 'android'
|
||||||
apply plugin: 'robolectric'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
|
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
|
||||||
|
@ -599,6 +599,7 @@ public class PgpKeyOperation {
|
|||||||
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
|
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
|
||||||
return null;
|
return null;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
|
Log.e(Constants.TAG, "encountered pgp error while modifying key", e);
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
|
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
|
||||||
return null;
|
return null;
|
||||||
} catch (SignatureException e) {
|
} catch (SignatureException e) {
|
||||||
|
@ -232,7 +232,7 @@ public class UncachedKeyRing {
|
|||||||
|
|
||||||
PGPPublicKey modified = masterKey;
|
PGPPublicKey modified = masterKey;
|
||||||
PGPSignature revocation = null;
|
PGPSignature revocation = null;
|
||||||
for (PGPSignature zert : new IterableIterator<PGPSignature>(masterKey.getSignatures())) {
|
for (PGPSignature zert : new IterableIterator<PGPSignature>(masterKey.getKeySignatures())) {
|
||||||
int type = zert.getSignatureType();
|
int type = zert.getSignatureType();
|
||||||
|
|
||||||
// Disregard certifications on user ids, we will deal with those later
|
// Disregard certifications on user ids, we will deal with those later
|
||||||
@ -241,6 +241,10 @@ public class UncachedKeyRing {
|
|||||||
|| type == PGPSignature.CASUAL_CERTIFICATION
|
|| type == PGPSignature.CASUAL_CERTIFICATION
|
||||||
|| type == PGPSignature.POSITIVE_CERTIFICATION
|
|| type == PGPSignature.POSITIVE_CERTIFICATION
|
||||||
|| type == PGPSignature.CERTIFICATION_REVOCATION) {
|
|| type == PGPSignature.CERTIFICATION_REVOCATION) {
|
||||||
|
// These should not be here...
|
||||||
|
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE_UID, indent);
|
||||||
|
modified = PGPPublicKey.removeCertification(modified, zert);
|
||||||
|
badCerts += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
WrappedSignature cert = new WrappedSignature(zert);
|
WrappedSignature cert = new WrappedSignature(zert);
|
||||||
@ -432,7 +436,7 @@ public class UncachedKeyRing {
|
|||||||
// If no valid certificate (if only a revocation) remains, drop it
|
// If no valid certificate (if only a revocation) remains, drop it
|
||||||
if (selfCert == null && revocation == null) {
|
if (selfCert == null && revocation == null) {
|
||||||
modified = PGPPublicKey.removeCertification(modified, userId);
|
modified = PGPPublicKey.removeCertification(modified, userId);
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REVOKE_DUP,
|
log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REMOVE,
|
||||||
indent, userId);
|
indent, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.openpgp.PGPException;
|
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
@ -11,7 +9,6 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.security.SignatureException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -202,6 +202,7 @@ public class OperationResultParcel implements Parcelable {
|
|||||||
MSG_KC_REVOKE_BAD_LOCAL (R.string.msg_kc_revoke_bad_local),
|
MSG_KC_REVOKE_BAD_LOCAL (R.string.msg_kc_revoke_bad_local),
|
||||||
MSG_KC_REVOKE_BAD_TIME (R.string.msg_kc_revoke_bad_time),
|
MSG_KC_REVOKE_BAD_TIME (R.string.msg_kc_revoke_bad_time),
|
||||||
MSG_KC_REVOKE_BAD_TYPE (R.string.msg_kc_revoke_bad_type),
|
MSG_KC_REVOKE_BAD_TYPE (R.string.msg_kc_revoke_bad_type),
|
||||||
|
MSG_KC_REVOKE_BAD_TYPE_UID (R.string.msg_kc_revoke_bad_type_uid),
|
||||||
MSG_KC_REVOKE_BAD (R.string.msg_kc_revoke_bad),
|
MSG_KC_REVOKE_BAD (R.string.msg_kc_revoke_bad),
|
||||||
MSG_KC_REVOKE_DUP (R.string.msg_kc_revoke_dup),
|
MSG_KC_REVOKE_DUP (R.string.msg_kc_revoke_dup),
|
||||||
MSG_KC_SUB (R.string.msg_kc_sub),
|
MSG_KC_SUB (R.string.msg_kc_sub),
|
||||||
@ -233,6 +234,7 @@ public class OperationResultParcel implements Parcelable {
|
|||||||
MSG_KC_UID_NO_CERT (R.string.msg_kc_uid_no_cert),
|
MSG_KC_UID_NO_CERT (R.string.msg_kc_uid_no_cert),
|
||||||
MSG_KC_UID_REVOKE_DUP (R.string.msg_kc_uid_revoke_dup),
|
MSG_KC_UID_REVOKE_DUP (R.string.msg_kc_uid_revoke_dup),
|
||||||
MSG_KC_UID_REVOKE_OLD (R.string.msg_kc_uid_revoke_old),
|
MSG_KC_UID_REVOKE_OLD (R.string.msg_kc_uid_revoke_old),
|
||||||
|
MSG_KC_UID_REMOVE (R.string.msg_kc_uid_remove),
|
||||||
|
|
||||||
|
|
||||||
// keyring consolidation
|
// keyring consolidation
|
||||||
|
@ -592,6 +592,7 @@
|
|||||||
<string name="msg_kc_revoke_bad_local">Removing keyring revocation certificate with "local" flag</string>
|
<string name="msg_kc_revoke_bad_local">Removing keyring revocation certificate with "local" flag</string>
|
||||||
<string name="msg_kc_revoke_bad_time">Removing keyring revocation certificate with future timestamp</string>
|
<string name="msg_kc_revoke_bad_time">Removing keyring revocation certificate with future timestamp</string>
|
||||||
<string name="msg_kc_revoke_bad_type">Removing master key certificate of unknown type (%s)</string>
|
<string name="msg_kc_revoke_bad_type">Removing master key certificate of unknown type (%s)</string>
|
||||||
|
<string name="msg_kc_revoke_bad_type_uid">Removing user id certification in bad position</string>
|
||||||
<string name="msg_kc_revoke_bad">Removing bad keyring revocation certificate</string>
|
<string name="msg_kc_revoke_bad">Removing bad keyring revocation certificate</string>
|
||||||
<string name="msg_kc_revoke_dup">Removing redundant keyring revocation certificate</string>
|
<string name="msg_kc_revoke_dup">Removing redundant keyring revocation certificate</string>
|
||||||
<string name="msg_kc_sub">Processing subkey %s</string>
|
<string name="msg_kc_sub">Processing subkey %s</string>
|
||||||
@ -629,6 +630,7 @@
|
|||||||
<string name="msg_kc_uid_revoke_dup">Removing redundant revocation certificate for user id "%s"</string>
|
<string name="msg_kc_uid_revoke_dup">Removing redundant revocation certificate for user id "%s"</string>
|
||||||
<string name="msg_kc_uid_revoke_old">Removing outdated revocation certificate for user id "%s"</string>
|
<string name="msg_kc_uid_revoke_old">Removing outdated revocation certificate for user id "%s"</string>
|
||||||
<string name="msg_kc_uid_no_cert">No valid self-certificate found for user id %s, removing from ring</string>
|
<string name="msg_kc_uid_no_cert">No valid self-certificate found for user id %s, removing from ring</string>
|
||||||
|
<string name="msg_kc_uid_remove">Removing invalid user id %s</string>
|
||||||
|
|
||||||
<!-- Keyring merging log entries -->
|
<!-- Keyring merging log entries -->
|
||||||
<string name="msg_mg_public">Merging into public keyring %s</string>
|
<string name="msg_mg_public">Merging into public keyring %s</string>
|
||||||
|
20
README.md
20
README.md
@ -37,10 +37,13 @@ Expand the Tools directory and select "Android SDK Build-tools (Version 19.1)".
|
|||||||
Expand the Extras directory and install "Android Support Repository"
|
Expand the Extras directory and install "Android Support Repository"
|
||||||
Select everything for the newest SDK Platform (API-Level 19)
|
Select everything for the newest SDK Platform (API-Level 19)
|
||||||
4. Export ANDROID_HOME pointing to your Android SDK
|
4. Export ANDROID_HOME pointing to your Android SDK
|
||||||
5. Use OpenJDK 7 instead of Oracle JDK (this is required for OpenKeychain's tests based on Bouncy Castle)
|
5. Execute ``./gradlew build``
|
||||||
6. Execute ``./install-custom-gradle-test-plugin.sh``
|
6. You can install the app with ``adb install -r OpenKeychain/build/outputs/apk/OpenKeychain-debug-unaligned.apk``
|
||||||
7. Execute ``./gradlew build``
|
|
||||||
8. You can install the app with ``adb install -r OpenKeychain/build/outputs/apk/OpenKeychain-debug-unaligned.apk``
|
### Run Tests
|
||||||
|
1. Use OpenJDK instead of Oracle JDK
|
||||||
|
2. Execute ``./prepare-tests.sh``
|
||||||
|
3. Execute ``./gradlew build``
|
||||||
|
|
||||||
### Build API Demo with Gradle
|
### Build API Demo with Gradle
|
||||||
|
|
||||||
@ -50,13 +53,10 @@ Select everything for the newest SDK Platform (API-Level 19)
|
|||||||
|
|
||||||
### Development with Android Studio
|
### Development with Android Studio
|
||||||
|
|
||||||
I am using the newest [Android Studio](http://developer.android.com/sdk/installing/studio.html) for development. Development with Eclipse is currently not possible because I am using the new [project structure](http://developer.android.com/sdk/installing/studio-tips.html).
|
We are using the newest [Android Studio](http://developer.android.com/sdk/installing/studio.html) for development. Development with Eclipse is currently not possible because we are using the new [project structure](http://developer.android.com/sdk/installing/studio-tips.html).
|
||||||
|
|
||||||
1. Clone the project from github
|
1. Clone the project from Github
|
||||||
2. From Android Studio: File -> Import Project -> ...
|
2. From Android Studio: File -> Import Project -> Select the cloned top folder
|
||||||
* Select the cloned top folder if you want to develop on the main project
|
|
||||||
* Select the "OpenKeychain-API" folder if you want to develop on the API example
|
|
||||||
3. Import project from external model -> choose Gradle
|
|
||||||
|
|
||||||
## OpenKeychain's API
|
## OpenKeychain's API
|
||||||
|
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
// need this for com.novoda:gradle-android-test-plugin:0.9.9-SNAPSHOT below (0.9.3 in repos doesn't work!)
|
|
||||||
// run ./install-custom-gradle-test-plugin.sh to pull the thing into the local repository
|
|
||||||
mavenLocal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
|
// 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.android.tools.build:gradle:0.12.0'
|
classpath 'com.android.tools.build:gradle:0.12.0'
|
||||||
classpath 'org.robolectric:robolectric-gradle-plugin:0.11.0'
|
|
||||||
classpath 'com.novoda:gradle-android-test-plugin:0.9.9-SNAPSHOT'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
mkdir temp
|
|
||||||
cd temp
|
|
||||||
|
|
||||||
git clone https://github.com/nenick/gradle-android-test-plugin.git
|
|
||||||
cd gradle-android-test-plugin
|
|
||||||
|
|
||||||
echo "rootProject.name = 'gradle-android-test-plugin-parent'" > settings.gradle
|
|
||||||
echo "include ':gradle-android-test-plugin'" >> settings.gradle
|
|
||||||
|
|
||||||
./gradlew :gradle-android-test-plugin:install
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
cd ..
|
|
30
prepare-tests.sh
Executable file
30
prepare-tests.sh
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script installs a plugin which is necessary to run OpenKeychain's tests
|
||||||
|
# into the local maven repository, then puts a line to include the -Test
|
||||||
|
# subproject into settings.gradle
|
||||||
|
|
||||||
|
echo "checking jdk runtime.."
|
||||||
|
if ! java -version 2>&1 | grep OpenJDK; then
|
||||||
|
echo "tests will only run on openjdk, see readme for details!" >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmpdir="$(mktemp -d)"
|
||||||
|
(
|
||||||
|
cd "$tmpdir";
|
||||||
|
git clone https://github.com/nenick/gradle-android-test-plugin.git
|
||||||
|
cd gradle-android-test-plugin
|
||||||
|
echo "rootProject.name = 'gradle-android-test-plugin-parent'" > settings.gradle
|
||||||
|
echo "include ':gradle-android-test-plugin'" >> settings.gradle
|
||||||
|
./gradlew :gradle-android-test-plugin:install
|
||||||
|
)
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
|
||||||
|
echo -n "ok, adding tests to include list.. "
|
||||||
|
if grep OpenKeychain-Test settings.gradle >/dev/null ; then
|
||||||
|
echo " already in."
|
||||||
|
else
|
||||||
|
echo "include ':OpenKeychain-Test'" >> settings.gradle
|
||||||
|
echo "ok"
|
||||||
|
fi
|
@ -1,5 +1,4 @@
|
|||||||
include ':OpenKeychain'
|
include ':OpenKeychain'
|
||||||
include ':OpenKeychain-Test'
|
|
||||||
include ':extern:openpgp-api-lib'
|
include ':extern:openpgp-api-lib'
|
||||||
include ':extern:openkeychain-api-lib'
|
include ':extern:openkeychain-api-lib'
|
||||||
include ':extern:html-textview'
|
include ':extern:html-textview'
|
||||||
@ -14,4 +13,4 @@ include ':extern:AppMsg:library'
|
|||||||
include ':extern:SuperToasts:supertoasts'
|
include ':extern:SuperToasts:supertoasts'
|
||||||
include ':extern:minidns'
|
include ':extern:minidns'
|
||||||
include ':extern:KeybaseLib:Lib'
|
include ':extern:KeybaseLib:Lib'
|
||||||
include ':extern:openpgp-card-nfc-lib:library'
|
include ':extern:openpgp-card-nfc-lib:library'
|
||||||
|
Loading…
Reference in New Issue
Block a user