From 87004fd0ca3a5178fba3050599a445ba9c64662c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 15 Mar 2014 18:15:39 +0100 Subject: certify: preserve user id certificates when saving secret keys --- .../keychain/pgp/PgpKeyOperation.java | 64 ++++++++++++++++++++-- .../keychain/service/KeychainIntentService.java | 5 +- .../keychain/util/IterableIterator.java | 10 +++- OpenPGP-Keychain/src/main/res/values/strings.xml | 1 + 4 files changed, 73 insertions(+), 7 deletions(-) (limited to 'OpenPGP-Keychain/src/main') diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 78e48b4ab..40a0b72ce 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; @@ -46,6 +47,8 @@ import java.security.*; import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; +import java.util.Iterator; +import java.util.List; import java.util.TimeZone; public class PgpKeyOperation { @@ -198,7 +201,7 @@ public class PgpKeyOperation { public void buildSecretKey(ArrayList userIds, ArrayList keys, ArrayList keysUsages, ArrayList keysExpiryDates, - long masterKeyId, String oldPassPhrase, + PGPPublicKey oldPublicKey, String oldPassPhrase, String newPassPhrase) throws PgpGeneralException, NoSuchProviderException, PGPException, NoSuchAlgorithmException, SignatureException, IOException { @@ -249,9 +252,32 @@ public class PgpKeyOperation { updateProgress(R.string.progress_certifying_master_key, 20, 100); - // TODO: if we are editing a key, keep old certs, don't remake certs we don't have to. - + // re-add old certificates, or create new ones for new uids for (String userId : userIds) { + // re-add certs for this uid, take a note if self-signed cert is in there + boolean foundSelfSign = false; + Iterator it = tmpKey.getSignaturesForID(userId); + if(it != null) for(PGPSignature sig : new IterableIterator(it)) { + if(sig.getKeyID() == masterPublicKey.getKeyID()) { + // already have a self sign? skip this other one, then. + // note: PGPKeyRingGenerator adds one cert for the main user id, which + // will lead to duplicates. unfortunately, if we add any other here + // first, that will change the main user id order... + if(foundSelfSign) + continue; + foundSelfSign = true; + } + Log.d(Constants.TAG, "adding old sig for " + userId + " from " + + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID())); + masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, sig); + } + + // there was an old self-signed certificate for this uid + if(foundSelfSign) + continue; + + Log.d(Constants.TAG, "generating self-signed cert for " + userId); + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); @@ -330,7 +356,7 @@ public class PgpKeyOperation { updateProgress(R.string.progress_adding_sub_keys, 40, 100); for (int i = 1; i < keys.size(); ++i) { - updateProgress(40 + 50 * (i - 1) / (keys.size() - 1), 100); + updateProgress(40 + 40 * (i - 1) / (keys.size() - 1), 100); PGPSecretKey subKey = keys.get(i); PGPPublicKey subPublicKey = subKey.getPublicKey(); @@ -400,8 +426,38 @@ public class PgpKeyOperation { PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); + updateProgress(R.string.progress_re_adding_certs, 80, 100); + + // re-add certificates from old public key + // TODO: this only takes care of user id certificates, what about others? + PGPPublicKey pubkey = publicKeyRing.getPublicKey(); + for(String uid : new IterableIterator(pubkey.getUserIDs())) { + for(PGPSignature sig : new IterableIterator(oldPublicKey.getSignaturesForID(uid), true)) { + // but skip self certificates + if(sig.getKeyID() == pubkey.getKeyID()) + continue; + pubkey = PGPPublicKey.addCertification(pubkey, uid, sig); + } + } + publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, pubkey); + updateProgress(R.string.progress_saving_key_ring, 90, 100); + /* additional handy debug info + Log.d(Constants.TAG, " ------- in private key -------"); + for(String uid : new IterableIterator(secretKeyRing.getPublicKey().getUserIDs())) { + for(PGPSignature sig : new IterableIterator(secretKeyRing.getPublicKey().getSignaturesForID(uid))) { + Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid); + } + } + Log.d(Constants.TAG, " ------- in public key -------"); + for(String uid : new IterableIterator(publicKeyRing.getPublicKey().getUserIDs())) { + for(PGPSignature sig : new IterableIterator(publicKeyRing.getPublicKey().getSignaturesForID(uid))) { + Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid); + } + } + */ + ProviderHelper.saveKeyRing(mContext, secretKeyRing); ProviderHelper.saveKeyRing(mContext, publicKeyRing); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 506ff2735..daaff5d54 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -543,8 +543,9 @@ public class KeychainIntentService extends IntentService ProviderHelper.getPGPSecretKeyRingByKeyId(this, masterKeyId), oldPassPhrase, newPassPhrase); } else { - keyOperations.buildSecretKey(userIds, keys, keysUsages, keysExpiryDates, masterKeyId, - oldPassPhrase, newPassPhrase); + PGPPublicKey pubkey = ProviderHelper.getPGPPublicKeyByKeyId(this, masterKeyId); + keyOperations.buildSecretKey(userIds, keys, keysUsages, keysExpiryDates, + pubkey, oldPassPhrase, newPassPhrase); } PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassPhrase); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java index caaa07524..40105df4f 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java @@ -16,13 +16,21 @@ package org.sufficientlysecure.keychain.util; +import java.util.ArrayList; import java.util.Iterator; public class IterableIterator implements Iterable { private Iterator mIter; - public IterableIterator(Iterator iter) { + public IterableIterator(Iterator iter, boolean failsafe) { mIter = iter; + if(failsafe && mIter == null) { + // is there a better way? + mIter = new ArrayList().iterator(); + } + } + public IterableIterator(Iterator iter) { + this(iter, false); } public Iterator iterator() { diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index 0520a414b..265bcc6db 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -466,5 +466,6 @@ available unavailable User IDs to sign + Reapplying certificates -- cgit v1.2.3