mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-03-04 19:29:41 -05:00
consolidate: first draft
This commit is contained in:
parent
adf15d4d16
commit
b4974d922e
@ -27,6 +27,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -178,7 +179,8 @@ public class UncachedKeyRing {
|
|||||||
return result;
|
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:
|
* More specifically:
|
||||||
* - Remove all non-verifying self-certificates
|
* - 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 subkey retains no valid subkey binding certificate, remove it
|
||||||
* - If a user id retains no valid self 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 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.
|
* 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,
|
log.add(LogLevel.START, isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC,
|
||||||
new String[]{PgpKeyHelper.convertKeyIdToHex(getMasterKeyId())}, indent);
|
new String[]{PgpKeyHelper.convertKeyIdToHex(getMasterKeyId())}, indent);
|
||||||
@ -627,4 +634,108 @@ public class UncachedKeyRing {
|
|||||||
return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ public class ProviderHelper {
|
|||||||
mIndent += 1;
|
mIndent += 1;
|
||||||
|
|
||||||
// Canonicalize this key, to assert a number of assumptions made about it.
|
// 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) {
|
if (keyRing == null) {
|
||||||
return SaveKeyringResult.RESULT_ERROR;
|
return SaveKeyringResult.RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user