aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2014-06-16 23:52:06 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2014-06-18 00:30:45 +0200
commitb4974d922e0a5472932e211d6a87b3ea901dfae6 (patch)
treeea01a1916e14ae2659d8770e3936a160c3596236
parentadf15d4d16cd6e9943f535f2beed63b72ec5e6b4 (diff)
downloadopen-keychain-b4974d922e0a5472932e211d6a87b3ea901dfae6.tar.gz
open-keychain-b4974d922e0a5472932e211d6a87b3ea901dfae6.tar.bz2
open-keychain-b4974d922e0a5472932e211d6a87b3ea901dfae6.zip
consolidate: first draft
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java117
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java2
2 files changed, 115 insertions, 4 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 78620405f..5f1c2cac3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -27,6 +27,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
@@ -178,7 +179,8 @@ public class UncachedKeyRing {
return result;
}
- /** "Canonicalizes" a key, removing inconsistencies in the process.
+ /** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
+ * applied to public keyrings only.
*
* More specifically:
* - Remove all non-verifying self-certificates
@@ -193,13 +195,18 @@ public class UncachedKeyRing {
* - If a subkey retains no valid subkey binding certificate, remove it
* - If a user id retains no valid self certificate, remove it
* - If the key is a secret key, remove all certificates by foreign keys
+ * - If no valid user id remains, log an error and return null
*
* This operation writes an OperationLog which can be used as part of a OperationResultParcel.
*
- * @return A canonicalized key
+ * @return A canonicalized key, or null on fatal error
*
*/
- public UncachedKeyRing canonicalize(OperationLog log, int indent) {
+ public UncachedKeyRing canonicalizePublic(OperationLog log, int indent) {
+ if (isSecret()) {
+ throw new RuntimeException("Tried to public-canonicalize non-public keyring. " +
+ "This is a programming error and should never happen!");
+ }
log.add(LogLevel.START, isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC,
new String[]{PgpKeyHelper.convertKeyIdToHex(getMasterKeyId())}, indent);
@@ -627,4 +634,108 @@ public class UncachedKeyRing {
return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
+ /** This operation consolidates a list of UncachedKeyRings into a single, combined
+ * UncachedKeyRing.
+ *
+ * The combined keyring contains the subkeys and user ids of all input keyrings. Even if all
+ * input keyrings were canonicalized at some point, the resulting keyring will not necessarily
+ * have that property.
+ *
+ * TODO work with secret keys
+ *
+ * @return A consolidated UncachedKeyRing with the data of all input keyrings.
+ *
+ */
+ public static UncachedKeyRing consolidate(List<UncachedKeyRing> list,
+ OperationLog log, int indent) {
+
+ long masterKeyId = list.get(0).getMasterKeyId();
+ for (UncachedKeyRing ring : new IterableIterator<UncachedKeyRing>(list.iterator())) {
+ if (ring.getMasterKeyId() != masterKeyId) {
+ // log.add(LogLevel.ERROR, LogType.MSG_KO, null, indent);
+ return null;
+ }
+ }
+
+ // log.add(LogLevel.START, LogType.MSG_KO,
+ // new String[]{PgpKeyHelper.convertKeyIdToHex(masterKeyId)}, indent);
+ indent += 1;
+
+ // remember which certs we already added
+ HashSet<Integer> certs = new HashSet<Integer>();
+
+ try {
+ PGPPublicKeyRing result = null;
+ for (UncachedKeyRing uring : new IterableIterator<UncachedKeyRing>(list.iterator())) {
+ PGPPublicKeyRing ring = (PGPPublicKeyRing) uring.mRing;
+ if (result == null) {
+ result = ring;
+ continue;
+ }
+
+ for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(ring.getPublicKeys())) {
+
+ final PGPPublicKey resultkey = result.getPublicKey(key.getKeyID());
+ if (resultkey == null) {
+ log.add(LogLevel.DEBUG, LogType.MSG_KO_NEW_SUBKEY, null, indent);
+ result = PGPPublicKeyRing.insertPublicKey(result, key);
+ continue;
+ }
+
+ // The key old key, which we merge stuff into
+ PGPPublicKey modified = resultkey;
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getSignatures())) {
+ int type = cert.getSignatureType();
+ // Disregard certifications on user ids, we will deal with those later
+ if (type == PGPSignature.NO_CERTIFICATION
+ || type == PGPSignature.DEFAULT_CERTIFICATION
+ || type == PGPSignature.CASUAL_CERTIFICATION
+ || type == PGPSignature.POSITIVE_CERTIFICATION
+ || type == PGPSignature.CERTIFICATION_REVOCATION) {
+ continue;
+ }
+
+ int hash = Arrays.hashCode(cert.getEncoded());
+ // Known cert, skip it
+ if (certs.contains(hash)) {
+ continue;
+ }
+ certs.add(hash);
+ modified = PGPPublicKey.addCertification(modified, cert);
+ }
+
+ // If this is a subkey, stop here
+ if (!key.isMasterKey()) {
+ result = PGPPublicKeyRing.insertPublicKey(result, modified);
+ continue;
+ }
+
+ // Copy over all user id certificates
+ for (String userId : new IterableIterator<String>(key.getUserIDs())) {
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getSignaturesForID(userId))) {
+ int hash = Arrays.hashCode(cert.getEncoded());
+ // Known cert, skip it
+ if (certs.contains(hash)) {
+ continue;
+ }
+ certs.add(hash);
+ modified = PGPPublicKey.addCertification(modified, userId, cert);
+ }
+ }
+ // If anything changed, save the updated (sub)key
+ if (modified != resultkey) {
+ result = PGPPublicKeyRing.insertPublicKey(result, modified);
+ }
+ }
+
+ }
+
+ return new UncachedKeyRing(result);
+
+ } catch (IOException e) {
+ return null;
+ }
+
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index dbcc4a1c6..22454b20f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -285,7 +285,7 @@ public class ProviderHelper {
mIndent += 1;
// Canonicalize this key, to assert a number of assumptions made about it.
- keyRing = keyRing.canonicalize(mLog, mIndent);
+ keyRing = keyRing.canonicalizePublic(mLog, mIndent);
if (keyRing == null) {
return SaveKeyringResult.RESULT_ERROR;
}