aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2014-06-17 20:40:26 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2014-06-17 21:23:24 +0200
commit4bff50bffc43c23e08f87ff7c5b19fe790874d01 (patch)
tree7c4446bc75e35ef2294d0d0f33ae563aa39364f4 /OpenKeychain
parent5c47143d64e8ab2e1ef00f5134d9362c08e6f529 (diff)
downloadopen-keychain-4bff50bffc43c23e08f87ff7c5b19fe790874d01.tar.gz
open-keychain-4bff50bffc43c23e08f87ff7c5b19fe790874d01.tar.bz2
open-keychain-4bff50bffc43c23e08f87ff7c5b19fe790874d01.zip
new-edit: add logging to modifySecretKeyRing operation
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java184
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java22
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml19
4 files changed, 158 insertions, 72 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index e08c96dad..bbdbfffd2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -47,6 +47,9 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Primes;
@@ -98,12 +101,6 @@ public class PgpKeyOperation {
}
}
- void updateProgress(int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(current, total);
- }
- }
-
/** Creates new secret key. */
private PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase,
boolean isMasterKey) throws PgpGeneralMsgIdException {
@@ -182,7 +179,9 @@ public class PgpKeyOperation {
}
/** This method introduces a list of modifications specified by a SaveKeyringParcel to a
- * PGPSecretKeyRing.
+ * WrappedSecretKeyRing.
+ *
+ * This method relies on WrappedSecretKeyRing's canonicalization property!
*
* Note that PGPPublicKeyRings can not be directly modified. Instead, the corresponding
* PGPSecretKeyRing must be modified and consequently consolidated with its public counterpart.
@@ -191,8 +190,7 @@ public class PgpKeyOperation {
*
*/
public UncachedKeyRing modifySecretKeyRing(WrappedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
- String passphrase)
- throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException {
+ String passphrase, OperationLog log, int indent) {
/*
* 1. Unlock private key
@@ -205,6 +203,8 @@ public class PgpKeyOperation {
* 6. If requested, change passphrase
*/
+ log.add(LogLevel.START, LogType.MSG_MR, indent);
+ indent += 1;
updateProgress(R.string.progress_building_key, 0, 100);
// We work on bouncycastle object level here
@@ -213,10 +213,16 @@ public class PgpKeyOperation {
PGPSecretKey masterSecretKey = sKR.getSecretKey();
// 1. Unlock private key
+ log.add(LogLevel.DEBUG, LogType.MSG_MR_UNLOCK, indent);
PGPPrivateKey masterPrivateKey; {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
+ masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
+ } catch (PGPException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_UNLOCK_ERROR, indent+1);
+ return null;
+ }
}
if (!Arrays.equals(saveParcel.mFingerprint, sKR.getPublicKey().getFingerprint())) {
return null;
@@ -224,12 +230,14 @@ public class PgpKeyOperation {
updateProgress(R.string.progress_certifying_master_key, 20, 100);
- { // work on master secret key
+ // work on master secret key
+ try {
PGPPublicKey modifiedPublicKey = masterPublicKey;
// 2a. Add certificates for new user ids
for (String userId : saveParcel.addUserIds) {
+ log.add(LogLevel.INFO, LogType.MSG_MR_UID_ADD, indent);
PGPSignature cert = generateUserIdSignature(masterPrivateKey,
masterPublicKey, userId, false);
modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert);
@@ -237,6 +245,7 @@ public class PgpKeyOperation {
// 2b. Add revocations for revoked user ids
for (String userId : saveParcel.revokeUserIds) {
+ log.add(LogLevel.INFO, LogType.MSG_MR_UID_REVOKE, indent);
PGPSignature cert = generateRevocationSignature(masterPrivateKey,
masterPublicKey, userId);
modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert);
@@ -244,6 +253,7 @@ public class PgpKeyOperation {
// 3. If primary user id changed, generate new certificates for both old and new
if (saveParcel.changePrimaryUserId != null) {
+ log.add(LogLevel.INFO, LogType.MSG_MR_UID_PRIMARY, indent);
// todo
}
@@ -254,70 +264,105 @@ public class PgpKeyOperation {
sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
- }
-
// 4a. For each subkey change, generate new subkey binding certificate
- for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) {
- PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
- if (sKey == null) {
- return null;
- }
- PGPPublicKey pKey = sKey.getPublicKey();
+ for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) {
+ log.add(LogLevel.INFO, LogType.MSG_MR_SUBKEY_CHANGE,
+ new String[]{PgpKeyHelper.convertKeyIdToHex(change.mKeyId)}, indent);
+ PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
+ if (sKey == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_SUBKEY_MISSING,
+ new String[]{PgpKeyHelper.convertKeyIdToHex(change.mKeyId)}, indent + 1);
+ return null;
+ }
+ PGPPublicKey pKey = sKey.getPublicKey();
- // generate and add new signature
- PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
- sKey, pKey, change.mFlags, change.mExpiry, passphrase);
- pKey = PGPPublicKey.addCertification(pKey, sig);
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
- }
+ if (change.mExpiry != null && new Date(change.mExpiry).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_SUBKEY_PAST_EXPIRY,
+ new String[]{PgpKeyHelper.convertKeyIdToHex(change.mKeyId)}, indent + 1);
+ return null;
+ }
- // 4b. For each subkey change, generate new subkey binding certificate
- for (long revocation : saveParcel.revokeSubKeys) {
- PGPSecretKey sKey = sKR.getSecretKey(revocation);
- if (sKey == null) {
- return null;
+ // generate and add new signature
+ PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
+ sKey, pKey, change.mFlags, change.mExpiry, passphrase);
+ pKey = PGPPublicKey.addCertification(pKey, sig);
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
- PGPPublicKey pKey = sKey.getPublicKey();
- // generate and add new signature
- PGPSignature sig = generateRevocationSignature(masterPublicKey, masterPrivateKey, pKey);
-
- pKey = PGPPublicKey.addCertification(pKey, sig);
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
- }
-
- // 5. Generate and add new subkeys
- for (SaveKeyringParcel.SubkeyAdd add : saveParcel.addSubKeys) {
- try {
- PGPSecretKey sKey = createKey(add.mAlgorithm, add.mKeysize, passphrase, false);
+ // 4b. For each subkey revocation, generate new subkey revocation certificate
+ for (long revocation : saveParcel.revokeSubKeys) {
+ log.add(LogLevel.INFO, LogType.MSG_MR_SUBKEY_REVOKE,
+ new String[] { PgpKeyHelper.convertKeyIdToHex(revocation) }, indent);
+ PGPSecretKey sKey = sKR.getSecretKey(revocation);
+ if (sKey == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_SUBKEY_MISSING,
+ new String[] { PgpKeyHelper.convertKeyIdToHex(revocation) }, indent+1);
+ return null;
+ }
PGPPublicKey pKey = sKey.getPublicKey();
- PGPSignature cert = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
- sKey, pKey, add.mFlags, add.mExpiry, passphrase);
- pKey = PGPPublicKey.addCertification(pKey, cert);
- sKey = PGPSecretKey.replacePublicKey(sKey, pKey);
+ // generate and add new signature
+ PGPSignature sig = generateRevocationSignature(masterPublicKey, masterPrivateKey, pKey);
+
+ pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
- } catch (PgpGeneralMsgIdException e) {
- return null;
}
- }
- // 6. If requested, change passphrase
- if (saveParcel.newPassphrase != null) {
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
- .get(HashAlgorithmTags.SHA1);
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- // Build key encryptor based on new passphrase
- PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- saveParcel.newPassphrase.toCharArray());
+ // 5. Generate and add new subkeys
+ for (SaveKeyringParcel.SubkeyAdd add : saveParcel.addSubKeys) {
+ try {
+
+ if (add.mExpiry != null && new Date(add.mExpiry).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_SUBKEY_PAST_EXPIRY, indent +1);
+ return null;
+ }
+
+ log.add(LogLevel.INFO, LogType.MSG_MR_SUBKEY_NEW, indent);
+ PGPSecretKey sKey = createKey(add.mAlgorithm, add.mKeysize, passphrase, false);
+ log.add(LogLevel.DEBUG, LogType.MSG_MR_SUBKEY_NEW_ID,
+ new String[] { PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()) }, indent+1);
+
+ PGPPublicKey pKey = sKey.getPublicKey();
+ PGPSignature cert = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
+ sKey, pKey, add.mFlags, add.mExpiry, passphrase);
+ pKey = PGPPublicKey.addCertification(pKey, cert);
+ sKey = PGPSecretKey.replacePublicKey(sKey, pKey);
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
+ } catch (PgpGeneralMsgIdException e) {
+ return null;
+ }
+ }
+
+ // 6. If requested, change passphrase
+ if (saveParcel.newPassphrase != null) {
+ log.add(LogLevel.INFO, LogType.MSG_MR_PASSPHRASE, indent);
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
+ .get(HashAlgorithmTags.SHA1);
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
+ // Build key encryptor based on new passphrase
+ PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
+ PGPEncryptedData.CAST5, sha1Calc)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ saveParcel.newPassphrase.toCharArray());
+
+ sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
+ }
- sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
+ // This one must only be thrown by
+ } catch (IOException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_ERROR_ENCODE, indent+1);
+ return null;
+ } catch (PGPException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_ERROR_PGP, indent+1);
+ return null;
+ } catch (SignatureException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_MR_ERROR_SIG, indent+1);
+ return null;
}
+ log.add(LogLevel.OK, LogType.MSG_MR_SUCCESS, indent);
return new UncachedKeyRing(sKR);
}
@@ -377,7 +422,7 @@ public class PgpKeyOperation {
private static PGPSignature generateSubkeyBindingSignature(
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPSecretKey sKey, PGPPublicKey pKey, int flags, Long expiry, String passphrase)
- throws PgpGeneralMsgIdException, IOException, PGPException, SignatureException {
+ throws IOException, PGPException, SignatureException {
// date for signing
Date todayDate = new Date();
@@ -414,13 +459,10 @@ public class PgpKeyOperation {
if (expiry != null) {
Calendar creationDate = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
creationDate.setTime(pKey.getCreationTime());
- // note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c
- // here we purposefully ignore partial days in each date - long type has
- // no fractional part!
- long numDays = (expiry / 86400000) -
- (creationDate.getTimeInMillis() / 86400000);
- if (numDays <= 0) {
- throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation);
+
+ // (Just making sure there's no programming error here, this MUST have been checked above!)
+ if (new Date(expiry).before(todayDate)) {
+ throw new RuntimeException("Bad subkey creation date, this is a bug!");
}
hashedPacketsGen.setKeyExpirationTime(false, expiry - creationDate.getTimeInMillis());
} else {
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 d3f46a7a4..25a9387f4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -486,7 +487,9 @@ public class KeychainIntentService extends IntentService
String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
WrappedSecretKeyRing secRing = providerHelper.getWrappedSecretKeyRing(masterKeyId);
- UncachedKeyRing ring = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
+ OperationLog log = new OperationLog();
+ UncachedKeyRing ring = keyOperations.modifySecretKeyRing(secRing, saveParcel,
+ passphrase, log, 0);
setProgress(R.string.progress_saving_key_ring, 90, 100);
providerHelper.saveSecretKeyRing(ring);
} catch (ProviderHelper.NotFoundException e) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 0760aadf8..73f552c92 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -215,6 +215,24 @@ public class OperationResultParcel implements Parcelable {
MSG_KC_UID_NO_CERT (R.string.msg_kc_uid_no_cert),
MSG_KC_UID_REVOKE_DUP (R.string.msg_kc_uid_revoke_dup),
MSG_KC_UID_REVOKE_OLD (R.string.msg_kc_uid_revoke_old),
+
+ MSG_MR (R.string.msg_mr),
+ MSG_MR_ERROR_ENCODE (R.string.msg_mr_error_encode),
+ MSG_MR_ERROR_PGP (R.string.msg_mr_error_pgp),
+ MSG_MR_ERROR_SIG (R.string.msg_mr_error_sig),
+ MSG_MR_PASSPHRASE (R.string.msg_mr_passphrase),
+ MSG_MR_SUBKEY_CHANGE (R.string.msg_mr_subkey_change),
+ MSG_MR_SUBKEY_MISSING (R.string.msg_mr_subkey_missing),
+ MSG_MR_SUBKEY_NEW_ID (R.string.msg_mr_subkey_new_id),
+ MSG_MR_SUBKEY_NEW (R.string.msg_mr_subkey_new),
+ MSG_MR_SUBKEY_PAST_EXPIRY (R.string.msg_mr_subkey_past_expiry),
+ MSG_MR_SUBKEY_REVOKE (R.string.msg_mr_subkey_revoke),
+ MSG_MR_SUCCESS (R.string.msg_mr_success),
+ MSG_MR_UID_ADD (R.string.msg_mr_uid_add),
+ MSG_MR_UID_PRIMARY (R.string.msg_mr_uid_primary),
+ MSG_MR_UID_REVOKE (R.string.msg_mr_uid_revoke),
+ MSG_MR_UNLOCK_ERROR (R.string.msg_mr_unlock_error),
+ MSG_MR_UNLOCK (R.string.msg_mr_unlock),
;
private final int mMsgId;
@@ -264,6 +282,10 @@ public class OperationResultParcel implements Parcelable {
add(new OperationResultParcel.LogEntryParcel(level, type, parameters, indent));
}
+ public void add(LogLevel level, LogType type, int indent) {
+ add(new OperationResultParcel.LogEntryParcel(level, type, null, indent));
+ }
+
public boolean containsWarnings() {
for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(iterator())) {
if (entry.mLevel == LogLevel.WARN || entry.mLevel == LogLevel.ERROR) {
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index ed06f983b..bf3333458 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -600,6 +600,25 @@
<string name="msg_kc_uid_revoke_old">Removing outdated revocation certificate for user id "%s"</string>
<string name="msg_kc_uid_no_cert">No valid self-certificate found for user id %s, removing from ring</string>
+ <!-- modifySecretKeyRing -->
+ <string name="msg_mr">Modifying keyring %s</string>
+ <string name="msg_mr_error_encode">Encoding exception!</string>
+ <string name="msg_mr_error_pgp">PGP internal exception!</string>
+ <string name="msg_mr_error_sig">Signature exception!</string>
+ <string name="msg_mr_passphrase">Changing passphrase</string>
+ <string name="msg_mr_subkey_change">Modifying subkey %s</string>
+ <string name="msg_mr_subkey_missing">Tried to operate on missing subkey %s!</string>
+ <string name="msg_mr_subkey_new">Generating new %1$s bit %2$s subkey</string>
+ <string name="msg_mr_subkey_new_id">New subkey id: %s</string>
+ <string name="msg_mr_subkey_past_expiry">Expiry date cannot be in the past!</string>
+ <string name="msg_mr_subkey_revoke">Revoking subkey %s</string>
+ <string name="msg_mr_success">Keyring successfully modified</string>
+ <string name="msg_mr_uid_add">Adding user id %s</string>
+ <string name="msg_mr_uid_primary">Changing primary uid to %s</string>
+ <string name="msg_mr_uid_revoke">Revoking user id %s</string>
+ <string name="msg_mr_unlock_error">Error unlocking keyring!</string>
+ <string name="msg_mr_unlock">Unlocking keyring</string>
+
<!-- unsorted -->
<string name="section_certifier_id">Certifier</string>
<string name="section_cert">Certificate Details</string>