diff options
author | Vincent Breitmoser <valodim@mugenguild.com> | 2014-06-16 23:52:06 +0200 |
---|---|---|
committer | Vincent Breitmoser <valodim@mugenguild.com> | 2014-06-18 00:30:45 +0200 |
commit | b4974d922e0a5472932e211d6a87b3ea901dfae6 (patch) | |
tree | ea01a1916e14ae2659d8770e3936a160c3596236 | |
parent | adf15d4d16cd6e9943f535f2beed63b72ec5e6b4 (diff) | |
download | open-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.java | 117 | ||||
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java | 2 |
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; } |