aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2014-06-18 19:39:16 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2014-06-18 19:39:16 +0200
commit134f8471c05724c312085ce5b8eae2aec8cb8a52 (patch)
treeb3f079c63587df5841cac99f645e0d337d91b458 /OpenKeychain/src
parentf80228a08dbb6c9cfa350f9f9f71d76ff8f313c2 (diff)
downloadopen-keychain-134f8471c05724c312085ce5b8eae2aec8cb8a52.tar.gz
open-keychain-134f8471c05724c312085ce5b8eae2aec8cb8a52.tar.bz2
open-keychain-134f8471c05724c312085ce5b8eae2aec8cb8a52.zip
consolidate: add key import routines with consolidation
Diffstat (limited to 'OpenKeychain/src')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java209
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java2
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml6
7 files changed, 198 insertions, 53 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index 3681d62d8..9b070175c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -149,7 +149,8 @@ public class PgpImportExport {
SaveKeyringResult result;
if (key.isSecret()) {
- result = mProviderHelper.saveSecretKeyRing(key);
+ result = mProviderHelper.saveSecretKeyRing(key,
+ new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
} else {
result = mProviderHelper.savePublicKeyRing(key,
new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
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 c06255830..0f0d7cca3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -58,10 +58,18 @@ public class UncachedKeyRing {
final PGPKeyRing mRing;
final boolean mIsSecret;
+ final boolean mIsCanonicalized;
UncachedKeyRing(PGPKeyRing ring) {
mRing = ring;
mIsSecret = ring instanceof PGPSecretKeyRing;
+ mIsCanonicalized = false;
+ }
+
+ private UncachedKeyRing(PGPKeyRing ring, boolean canonicalized) {
+ mRing = ring;
+ mIsSecret = ring instanceof PGPSecretKeyRing;
+ mIsCanonicalized = canonicalized;
}
public long getMasterKeyId() {
@@ -92,6 +100,10 @@ public class UncachedKeyRing {
return mIsSecret;
}
+ public boolean isCanonicalized() {
+ return mIsCanonicalized;
+ }
+
public byte[] getEncoded() throws IOException {
return mRing.getEncoded();
}
@@ -606,7 +618,7 @@ public class UncachedKeyRing {
log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS, null, indent);
}
- return new UncachedKeyRing(ring);
+ return new UncachedKeyRing(ring, true);
}
/** This operation merges information from a different keyring, returning a combined
@@ -688,6 +700,11 @@ public class UncachedKeyRing {
continue;
}
+ // Don't merge foreign stuff into secret keys
+ if (cert.getKeyID() != masterKeyId && isSecret()) {
+ continue;
+ }
+
byte[] encoded = cert.getEncoded();
// Known cert, skip it
if (certs.contains(encoded)) {
@@ -709,6 +726,10 @@ public class UncachedKeyRing {
// Copy over all user id certificates
for (String userId : new IterableIterator<String>(key.getUserIDs())) {
for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getSignaturesForID(userId))) {
+ // Don't merge foreign stuff into secret keys
+ if (cert.getKeyID() != masterKeyId && isSecret()) {
+ continue;
+ }
byte[] encoded = cert.getEncoded();
// Known cert, skip it
if (certs.contains(encoded)) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
index 632a04fc3..6f3068261 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
@@ -101,4 +101,8 @@ public abstract class WrappedKeyRing extends KeyRing {
abstract public IterableIterator<WrappedPublicKey> publicKeyIterator();
+ public UncachedKeyRing getUncached() {
+ return new UncachedKeyRing(getRing());
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
index 9591cf8bc..d7148f710 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
@@ -154,8 +154,4 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
});
}
- public UncachedKeyRing getUncached() {
- return new UncachedKeyRing(mRing);
- }
-
}
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 457ef1ec8..36b4b4ac7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -275,21 +276,15 @@ public class ProviderHelper {
log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
return SaveKeyringResult.RESULT_ERROR;
}
+ if (!keyRing.isCanonicalized()) {
+ log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
+ return SaveKeyringResult.RESULT_ERROR;
+ }
// start with ok result
int result = SaveKeyringResult.SAVED_PUBLIC;
long masterKeyId = keyRing.getMasterKeyId();
- log(LogLevel.START, LogType.MSG_IP,
- new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
- mIndent += 1;
-
- // Canonicalize this key, to assert a number of assumptions made about it.
- keyRing = keyRing.canonicalize(mLog, mIndent);
- if (keyRing == null) {
- return SaveKeyringResult.RESULT_ERROR;
- }
-
UncachedPublicKey masterKey = keyRing.getPublicKey();
ArrayList<ContentProviderOperation> operations;
@@ -569,11 +564,16 @@ public class ProviderHelper {
/** Saves an UncachedKeyRing of the secret variant into the db.
* This method will fail if no corresponding public keyring is in the database!
*/
- private SaveKeyringResult internalSaveSecretKeyRing(UncachedKeyRing keyRing) {
+ private int internalSaveSecretKeyRing(UncachedKeyRing keyRing) {
if (!keyRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return SaveKeyringResult.RESULT_ERROR;
+ }
+
+ if (!keyRing.isCanonicalized()) {
+ log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
+ return SaveKeyringResult.RESULT_ERROR;
}
long masterKeyId = keyRing.getMasterKeyId();
@@ -584,7 +584,7 @@ public class ProviderHelper {
// Canonicalize this key, to assert a number of assumptions made about it.
keyRing = keyRing.canonicalize(mLog, mIndent);
if (keyRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return SaveKeyringResult.RESULT_ERROR;
}
// IF this is successful, it's a secret key
@@ -599,12 +599,12 @@ public class ProviderHelper {
Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
if (mContentResolver.insert(uri, values) == null) {
log(LogLevel.ERROR, LogType.MSG_IS_DB_EXCEPTION);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return SaveKeyringResult.RESULT_ERROR;
}
} catch (IOException e) {
Log.e(Constants.TAG, "Failed to encode key!", e);
log(LogLevel.ERROR, LogType.MSG_IS_IO_EXCPTION);
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ return SaveKeyringResult.RESULT_ERROR;
}
{
@@ -648,11 +648,12 @@ public class ProviderHelper {
}
log(LogLevel.OK, LogType.MSG_IS_SUCCESS);
- return new SaveKeyringResult(result, mLog);
+ return result;
}
+ @Deprecated
public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) {
return savePublicKeyRing(keyRing, new Progressable() {
@Override
@@ -669,54 +670,176 @@ public class ProviderHelper {
});
}
- public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing, Progressable progress) {
+ /** Save a public keyring into the database.
+ *
+ * This is a high level method, which takes care of merging all new information into the old and
+ * keep public and secret keyrings in sync.
+ */
+ public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress) {
- // IF there is a secret key, preserve it!
- UncachedKeyRing secretRing;
try {
- secretRing = getWrappedSecretKeyRing(keyRing.getMasterKeyId()).getUncached();
- log(LogLevel.DEBUG, LogType.MSG_IP_PRESERVING_SECRET);
- progress.setProgress(LogType.MSG_IP_PRESERVING_SECRET.getMsgId(), 10, 100);
+ long masterKeyId = publicRing.getMasterKeyId();
+ log(LogLevel.START, LogType.MSG_IP,
+ new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
+
mIndent += 1;
- // Merge data from new public ring into secret one
- secretRing = secretRing.merge(keyRing, mLog, mIndent);
- if (secretRing == null) {
+ // IF there is a secret key, preserve it!
+ try {
+ UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncached();
+
+ // Merge data from new public ring into the old one
+ publicRing = oldPublicRing.merge(publicRing, mLog, mIndent);
+
+ if (publicRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ // Early breakout if nothing changed
+ if (Arrays.hashCode(publicRing.getEncoded())
+ == Arrays.hashCode(oldPublicRing.getEncoded())) {
+ log(LogLevel.OK, LogType.MSG_IP,
+ new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_OK, mLog);
+ }
+ } catch (NotFoundException e) {
+ // not an issue, just means we are dealing with a new keyring
+ }
+
+ // Canonicalize this keyring, to assert a number of assumptions made about it.
+ publicRing = publicRing.canonicalize(mLog, mIndent);
+ if (publicRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
- // NOTE that the info from this secret keyring will implicitly be merged into the
- // new public keyring, since that one is merged with the old public keyring.
+ // IF there is a secret key, preserve it!
+ UncachedKeyRing secretRing;
+ try {
+ secretRing = getWrappedSecretKeyRing(publicRing.getMasterKeyId()).getUncached();
+ log(LogLevel.DEBUG, LogType.MSG_IP_PRESERVING_SECRET);
+ progress.setProgress(LogType.MSG_IP_PRESERVING_SECRET.getMsgId(), 10, 100);
+ mIndent += 1;
- mIndent -= 1;
+ // Merge data from new public ring into secret one
+ secretRing = secretRing.merge(publicRing, mLog, mIndent);
+ if (secretRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ mIndent -= 1;
+
+ } catch (NotFoundException e) {
+ secretRing = null;
+ }
+
+ int result = internalSavePublicKeyRing(publicRing, progress, secretRing != null);
+
+ // Save the saved keyring (if any)
+ if (secretRing != null) {
+ log(LogLevel.DEBUG, LogType.MSG_IP_REINSERT_SECRET);
+ progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
+ mIndent += 1;
+ secretRing = secretRing.canonicalize(mLog, mIndent);
+ internalSaveSecretKeyRing(secretRing);
+ result |= SaveKeyringResult.SAVED_SECRET;
+ mIndent -= 1;
+ }
+
+ return new SaveKeyringResult(result, mLog);
- } catch (NotFoundException e) {
- secretRing = null;
+ } catch (IOException e) {
+ return null;
}
- int result = internalSavePublicKeyRing(keyRing, progress, secretRing != null);
+ }
+
+ public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress) {
+
+ try {
+ long masterKeyId = secretRing.getMasterKeyId();
+ log(LogLevel.START, LogType.MSG_IS,
+ new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
- // Save the saved keyring (if any)
- if (secretRing != null) {
- log(LogLevel.DEBUG, LogType.MSG_IP_REINSERT_SECRET);
- progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
mIndent += 1;
- internalSaveSecretKeyRing(secretRing);
- result |= SaveKeyringResult.SAVED_SECRET;
- mIndent -= 1;
- }
- return new SaveKeyringResult(result, mLog);
+ // If there is a secret key, merge it.
+ try {
+ UncachedKeyRing oldSecretRing = getWrappedSecretKeyRing(masterKeyId).getUncached();
- }
+ // Merge data from new public ring into the old one
+ secretRing = oldSecretRing.merge(secretRing, mLog, mIndent);
+
+ if (secretRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ // Early breakout if nothing changed
+ if (Arrays.hashCode(secretRing.getEncoded())
+ == Arrays.hashCode(oldSecretRing.getEncoded())) {
+ log(LogLevel.OK, LogType.MSG_IS,
+ new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_OK, mLog);
+ }
+ } catch (NotFoundException e) {
+ // not an issue, just means we are dealing with a new keyring
+ }
+
+ // Canonicalize this keyring, to assert a number of assumptions made about it.
+ secretRing = secretRing.canonicalize(mLog, mIndent);
+ if (secretRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ // Merge new data into public keyring as well, if there is any
+ try {
+ UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncached();
+ log(LogLevel.DEBUG, LogType.MSG_IP_PRESERVING_SECRET);
+ progress.setProgress(LogType.MSG_IP_PRESERVING_SECRET.getMsgId(), 10, 100);
+ mIndent += 1;
+
+ // Merge data from new public ring into secret one
+ UncachedKeyRing publicRing = oldPublicRing.merge(secretRing, mLog, mIndent);
+ if (publicRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ // Early breakout if nothing changed
+ if (Arrays.hashCode(publicRing.getEncoded())
+ != Arrays.hashCode(oldPublicRing.getEncoded())) {
+
+ log(LogLevel.OK, LogType.MSG_IS,
+ new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
+
+ publicRing = publicRing.canonicalize(mLog, mIndent);
+ if (publicRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ int result = internalSavePublicKeyRing(publicRing, progress, true);
+
+ }
+
+ mIndent -= 1;
+
+ } catch (NotFoundException e) {
+ // TODO, this WILL error out later because secret rings cannot be inserted without
+ // public ones
+ }
+
+ progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
+ int result = internalSaveSecretKeyRing(secretRing);
+ return new SaveKeyringResult(result, mLog);
+
+ } catch (IOException e) {
+ return null;
+ }
- public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing keyRing) {
- return internalSaveSecretKeyRing(keyRing);
}
/**
* Saves (or updates) a pair of public and secret KeyRings in the database
*/
+ @Deprecated // scheduled for deletion after merge with new-edit branch
public void savePairedKeyRing(UncachedKeyRing pubRing, UncachedKeyRing secRing) throws IOException {
long masterKeyId = pubRing.getMasterKeyId();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index e30d48ce5..5358f36e8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -513,7 +513,7 @@ public class KeychainIntentService extends IntentService
UncachedKeyRing newKeyRing =
keyRing.changeSecretKeyPassphrase(oldPassphrase, newPassphrase);
setProgress(R.string.progress_saving_key_ring, 50, 100);
- providerHelper.saveSecretKeyRing(newKeyRing);
+ // providerHelper.saveSecretKeyRing(newKeyRing);
setProgress(R.string.progress_done, 100, 100);
} else {
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100));
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 4282d6abd..d9c033a96 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -583,7 +583,7 @@
<string name="msg_kc_sub_revoke_bad_err">Removing bad subkey revocation key</string>
<string name="msg_kc_sub_revoke_bad">Removing bad subkey revocation key</string>
<string name="msg_kc_sub_revoke_dup">Removing redundant keyring revocation key</string>
- <string name="msg_kc_success">Keyring canonicalization successful</string>
+ <string name="msg_kc_success">Keyring canonicalization successful, no changes</string>
<string name="msg_kc_success_bad">Keyring canonicalization successful, removed %s erroneous certificates</string>
<string name="msg_kc_success_bad_and_red">Keyring canonicalization successful, removed %1$s erroneous and %2$s redundant certificates</string>
<string name="msg_kc_success_redundant">Keyring canonicalization successful, removed %s redundant certificates</string>
@@ -600,8 +600,8 @@
<!-- Keyring merging log entries -->
- <string name="msg_mg_public">Merging into secret keyring %s</string>
- <string name="msg_mg_secret">Merging into public keyring %s</string>
+ <string name="msg_mg_public">Merging into public keyring %s</string>
+ <string name="msg_mg_secret">Merging into secret keyring %s</string>
<string name="msg_mg_fatal_encode">Fatal error encoding signature</string>
<string name="msg_mg_heterogeneous">Tried to consolidate heterogeneous keyrings</string>
<string name="msg_mg_new_subkey">Adding new subkey %s</string>