aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-06-18 00:03:19 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-06-18 00:03:19 +0200
commit4d34361590b759c0e252fa36cff140a9708e2b5e (patch)
tree92b9cc2c0f85d5855e194731788bb649bc2a3d59 /OpenKeychain
parent8c7a360d6ed6875774c912e070cb18807e0e831d (diff)
parent0013199b2de670b0bc3f28add5996a799525b9a2 (diff)
downloadopen-keychain-4d34361590b759c0e252fa36cff140a9708e2b5e.tar.gz
open-keychain-4d34361590b759c0e252fa36cff140a9708e2b5e.tar.bz2
open-keychain-4d34361590b759c0e252fa36cff140a9708e2b5e.zip
Merge branch 'master' of github.com:open-keychain/open-keychain
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java168
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java104
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java13
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml33
7 files changed, 265 insertions, 109 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 e1967429a..3681d62d8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLo
import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -130,6 +131,7 @@ public class PgpImportExport {
int newKeys = 0, oldKeys = 0, badKeys = 0;
int position = 0;
+ int progSteps = 100 / entries.size();
for (ParcelableKeyRing entry : entries) {
try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@@ -149,7 +151,8 @@ public class PgpImportExport {
if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key);
} else {
- result = mProviderHelper.savePublicKeyRing(key);
+ result = mProviderHelper.savePublicKeyRing(key,
+ new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
}
if (!result.success()) {
badKeys += 1;
@@ -165,7 +168,6 @@ public class PgpImportExport {
}
// update progress
position++;
- updateProgress(position / entries.size() * 100, 100);
}
OperationLog log = mProviderHelper.getLog();
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 e309ed632..78620405f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -178,18 +178,21 @@ public class UncachedKeyRing {
return result;
}
- /** "Canonicalizes" a key, removing inconsistencies in the process. This operation can be
- * applied to public keyrings only.
+ /** "Canonicalizes" a key, removing inconsistencies in the process.
*
* More specifically:
* - Remove all non-verifying self-certificates
* - Remove all "future" self-certificates
* - Remove all certificates flagged as "local"
- * - Remove all certificates which are superseded by a newer one on the same target
- *
- * After this cleaning, a number of checks are done: TODO implement
- * - See if each subkey retains a valid self certificate
- * - See if each user id retains a valid self certificate
+ * - Remove all certificates which are superseded by a newer one on the same target,
+ * including revocations with later re-certifications.
+ * - Remove all certificates of unknown type:
+ * - key revocation signatures on the master key
+ * - subkey binding signatures for subkeys
+ * - certifications and certification revocations for user ids
+ * - 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
*
* This operation writes an OperationLog which can be used as part of a OperationResultParcel.
*
@@ -197,20 +200,16 @@ public class UncachedKeyRing {
*
*/
public UncachedKeyRing canonicalize(OperationLog log, int indent) {
- if (isSecret()) {
- throw new RuntimeException("Tried to canonicalize non-secret keyring. " +
- "This is a programming error and should never happen!");
- }
- log.add(LogLevel.START, LogType.MSG_KC,
+ log.add(LogLevel.START, isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC,
new String[]{PgpKeyHelper.convertKeyIdToHex(getMasterKeyId())}, indent);
indent += 1;
final Date now = new Date();
- int removedCerts = 0;
+ int redundantCerts = 0, badCerts = 0;
- PGPPublicKeyRing ring = (PGPPublicKeyRing) mRing;
+ PGPKeyRing ring = mRing;
PGPPublicKey masterKey = mRing.getPublicKey();
final long masterKeyId = masterKey.getKeyID();
@@ -240,7 +239,7 @@ public class UncachedKeyRing {
"0x" + Integer.toString(type, 16)
}, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
@@ -248,7 +247,7 @@ public class UncachedKeyRing {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, null, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
@@ -256,7 +255,7 @@ public class UncachedKeyRing {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, null, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
@@ -265,13 +264,13 @@ public class UncachedKeyRing {
if (!cert.verifySignature(masterKey)) {
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD, null, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
} catch (PgpGeneralException e) {
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_ERR, null, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
@@ -281,12 +280,12 @@ public class UncachedKeyRing {
// more revocations? at least one is superfluous, then.
} else if (revocation.getCreationTime().before(zert.getCreationTime())) {
modified = PGPPublicKey.removeCertification(modified, revocation);
- removedCerts += 1;
+ redundantCerts += 1;
log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, null, indent);
revocation = zert;
} else {
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ redundantCerts += 1;
log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, null, indent);
}
}
@@ -312,14 +311,14 @@ public class UncachedKeyRing {
"0x" + Integer.toString(zert.getSignatureType(), 16)
}, indent);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
- removedCerts += 1;
+ badCerts += 1;
}
if (cert.getCreationTime().after(now)) {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, null, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
@@ -327,12 +326,19 @@ public class UncachedKeyRing {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, null, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
- // If this is a foreign signature, never mind any further
+ // If this is a foreign signature, ...
if (certId != masterKeyId) {
+ // never mind any further for public keys, but remove them from secret ones
+ if (isSecret()) {
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_FOREIGN,
+ new String[] { PgpKeyHelper.convertKeyIdToHex(certId) }, indent);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ badCerts += 1;
+ }
continue;
}
@@ -343,14 +349,14 @@ public class UncachedKeyRing {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD,
new String[] { userId }, indent);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
} catch (PgpGeneralException e) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_ERR,
new String[] { userId }, indent);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
- removedCerts += 1;
+ badCerts += 1;
continue;
}
@@ -363,14 +369,14 @@ public class UncachedKeyRing {
selfCert = zert;
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
- removedCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_UID_DUP,
+ redundantCerts += 1;
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
new String[] { userId }, indent);
selfCert = zert;
} else {
modified = PGPPublicKey.removeCertification(modified, userId, zert);
- removedCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_UID_DUP,
+ redundantCerts += 1;
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
new String[] { userId }, indent);
}
// If there is a revocation certificate, and it's older than this, drop it
@@ -378,8 +384,8 @@ public class UncachedKeyRing {
&& revocation.getCreationTime().before(selfCert.getCreationTime())) {
modified = PGPPublicKey.removeCertification(modified, userId, revocation);
revocation = null;
- removedCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_UID_REVOKE_OLD,
+ redundantCerts += 1;
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
new String[] { userId }, indent);
}
break;
@@ -388,8 +394,8 @@ public class UncachedKeyRing {
// If this is older than the (latest) self cert, drop it
if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
modified = PGPPublicKey.removeCertification(modified, userId, zert);
- removedCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_UID_REVOKE_OLD,
+ redundantCerts += 1;
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
new String[] { userId }, indent);
continue;
}
@@ -399,14 +405,14 @@ public class UncachedKeyRing {
// more revocations? at least one is superfluous, then.
} else if (revocation.getCreationTime().before(cert.getCreationTime())) {
modified = PGPPublicKey.removeCertification(modified, userId, revocation);
- removedCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_UID_REVOKE_DUP,
+ redundantCerts += 1;
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
new String[] { userId }, indent);
revocation = zert;
} else {
modified = PGPPublicKey.removeCertification(modified, userId, zert);
- removedCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_UID_REVOKE_DUP,
+ redundantCerts += 1;
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
new String[] { userId }, indent);
}
break;
@@ -414,12 +420,23 @@ public class UncachedKeyRing {
}
}
+
+ // If no valid certificate (if only a revocation) remains, drop it
+ if (selfCert == null && revocation == null) {
+ modified = PGPPublicKey.removeCertification(modified, userId);
+ log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REVOKE_DUP,
+ new String[] { userId }, indent);
+ }
}
- // Replace modified key in the keyring
- ring = PGPPublicKeyRing.insertPublicKey(ring, modified);
+ // If NO user ids remain, error out!
+ if (!modified.getUserIDs().hasNext()) {
+ log.add(LogLevel.ERROR, LogType.MSG_KC_FATAL_NO_UID, null, indent);
+ return null;
+ }
- log.add(LogLevel.DEBUG, LogType.MSG_KC_MASTER_SUCCESS, null, indent);
+ // Replace modified key in the keyring
+ ring = replacePublicKey(ring, modified);
indent -= 1;
}
@@ -437,18 +454,17 @@ public class UncachedKeyRing {
// certificate.
PGPPublicKey modified = key;
PGPSignature selfCert = null, revocation = null;
- uids: for (PGPSignature zig : new IterableIterator<PGPSignature>(key.getSignatures())) {
+ uids: for (PGPSignature zert : new IterableIterator<PGPSignature>(key.getSignatures())) {
// remove from keyring (for now)
- modified = PGPPublicKey.removeCertification(modified, zig);
- // add this too, easier than adding it for every single "continue" case
- removedCerts += 1;
+ modified = PGPPublicKey.removeCertification(modified, zert);
- WrappedSignature cert = new WrappedSignature(zig);
+ WrappedSignature cert = new WrappedSignature(zert);
int type = cert.getSignatureType();
// filter out bad key types...
if (cert.getKeyId() != masterKey.getKeyID()) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_KEYID, null, indent);
+ badCerts += 1;
continue;
}
@@ -456,18 +472,21 @@ public class UncachedKeyRing {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_TYPE, new String[]{
"0x" + Integer.toString(type, 16)
}, indent);
+ badCerts += 1;
continue;
}
if (cert.getCreationTime().after(now)) {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_TIME, null, indent);
+ badCerts += 1;
continue;
}
if (cert.isLocal()) {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_LOCAL, null, indent);
+ badCerts += 1;
continue;
}
@@ -478,20 +497,22 @@ public class UncachedKeyRing {
cert.init(masterKey);
if (!cert.verifySignature(masterKey, key)) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD, null, indent);
+ badCerts += 1;
continue;
}
} catch (PgpGeneralException e) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_BAD_ERR, null, indent);
+ badCerts += 1;
continue;
}
- if (zig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
- int flags = ((KeyFlags) zig.getHashedSubPackets()
+ if (zert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
+ int flags = ((KeyFlags) zert.getHashedSubPackets()
.getSubpacket(SignatureSubpacketTags.KEY_FLAGS)).getFlags();
// If this subkey is allowed to sign data,
if ((flags & PGPKeyFlags.CAN_SIGN) == PGPKeyFlags.CAN_SIGN) {
try {
- PGPSignatureList list = zig.getUnhashedSubPackets().getEmbeddedSignatures();
+ PGPSignatureList list = zert.getUnhashedSubPackets().getEmbeddedSignatures();
boolean ok = false;
for (int i = 0; i < list.size(); i++) {
WrappedSignature subsig = new WrappedSignature(list.get(i));
@@ -501,16 +522,19 @@ public class UncachedKeyRing {
ok = true;
} else {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD, null, indent);
+ badCerts += 1;
continue uids;
}
}
}
if (!ok) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, null, indent);
+ badCerts += 1;
continue;
}
} catch (Exception e) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD_ERR, null, indent);
+ badCerts += 1;
continue;
}
}
@@ -518,10 +542,11 @@ public class UncachedKeyRing {
// if we already have a cert, and this one is not newer: skip it
if (selfCert != null && selfCert.getCreationTime().before(cert.getCreationTime())) {
+ redundantCerts += 1;
continue;
}
- selfCert = zig;
+ selfCert = zert;
// if this is newer than a possibly existing revocation, drop that one
if (revocation != null && selfCert.getCreationTime().after(revocation.getCreationTime())) {
revocation = null;
@@ -535,48 +560,56 @@ public class UncachedKeyRing {
cert.init(masterKey);
if (!cert.verifySignature(key)) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD, null, indent);
+ badCerts += 1;
continue;
}
} catch (PgpGeneralException e) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD_ERR, null, indent);
+ badCerts += 1;
continue;
}
// if there is no binding (yet), or the revocation is newer than the binding: keep it
- if (selfCert == null || selfCert.getCreationTime().before(cert.getCreationTime())) {
- revocation = zig;
+ if (selfCert != null && selfCert.getCreationTime().after(cert.getCreationTime())) {
+ redundantCerts += 1;
+ continue;
}
+
+ revocation = zert;
}
}
// it is not properly bound? error!
if (selfCert == null) {
- ring = PGPPublicKeyRing.removePublicKey(ring, modified);
+ ring = replacePublicKey(ring, modified);
log.add(LogLevel.ERROR, LogType.MSG_KC_SUB_NO_CERT,
- new String[]{PgpKeyHelper.convertKeyIdToHex(key.getKeyID())}, indent);
+ new String[]{ PgpKeyHelper.convertKeyIdToHex(key.getKeyID()) }, indent);
indent -= 1;
continue;
}
// re-add certification
modified = PGPPublicKey.addCertification(modified, selfCert);
- removedCerts -= 1;
// add revocation, if any
if (revocation != null) {
modified = PGPPublicKey.addCertification(modified, revocation);
- removedCerts -= 1;
}
// replace pubkey in keyring
- ring = PGPPublicKeyRing.insertPublicKey(ring, modified);
-
- log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_SUCCESS, null, indent);
+ ring = replacePublicKey(ring, modified);
indent -= 1;
}
- if (removedCerts > 0) {
- log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_REMOVED,
- new String[] { Integer.toString(removedCerts) }, indent);
+ if (badCerts > 0 && redundantCerts > 0) {
+ log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_BAD_AND_RED,
+ new String[] { Integer.toString(badCerts),
+ Integer.toString(redundantCerts) }, indent);
+ } else if (badCerts > 0) {
+ log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_BAD,
+ new String[] { Integer.toString(badCerts) }, indent);
+ } else if (redundantCerts > 0) {
+ log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS_REDUNDANT,
+ new String[] { Integer.toString(redundantCerts) }, indent);
} else {
log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS, null, indent);
}
@@ -584,5 +617,14 @@ public class UncachedKeyRing {
return new UncachedKeyRing(ring);
}
+ private static PGPKeyRing replacePublicKey(PGPKeyRing ring, PGPPublicKey key) {
+ if (ring instanceof PGPPublicKeyRing) {
+ return PGPPublicKeyRing.insertPublicKey((PGPPublicKeyRing) ring, key);
+ }
+ PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
+ PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
+ sKey = PGPSecretKey.replacePublicKey(sKey, key);
+ return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
index be7f960a9..196ac1dee 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -179,7 +179,8 @@ public class WrappedSignature {
}
public boolean isLocal() {
- if (!mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.EXPORTABLE)) {
+ if (!mSig.hasSubpackets()
+ || !mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.EXPORTABLE)) {
return false;
}
SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket(SignatureSubpacketTags.EXPORTABLE);
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 102c8e6d0..0218b457b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -29,6 +29,7 @@ import android.support.v4.util.LongSparseArray;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.WrappedPublicKey;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
@@ -259,11 +260,29 @@ public class ProviderHelper {
}
}
+ public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) {
+ return savePublicKeyRing(keyRing, new Progressable() {
+ @Override
+ public void setProgress(String message, int current, int total) {
+ return;
+ }
+
+ @Override
+ public void setProgress(int resourceId, int current, int total) {
+ return;
+ }
+
+ @Override
+ public void setProgress(int current, int total) {
+ return;
+ }
+ });
+ }
/**
* Saves PGPPublicKeyRing with its keys and userIds in DB
*/
@SuppressWarnings("unchecked")
- public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) {
+ public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing, Progressable progress) {
if (keyRing.isSecret()) {
log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
@@ -279,6 +298,9 @@ 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);
+ }
UncachedPublicKey masterKey = keyRing.getPublicKey();
@@ -287,6 +309,7 @@ public class ProviderHelper {
try {
secretRing = getWrappedSecretKeyRing(masterKeyId).getUncached();
log(LogLevel.DEBUG, LogType.MSG_IP_PRESERVING_SECRET);
+ progress.setProgress(LogType.MSG_IP_PRESERVING_SECRET.getMsgId(), 30, 100);
} catch (NotFoundException e) {
secretRing = null;
}
@@ -302,7 +325,6 @@ public class ProviderHelper {
log(LogLevel.INFO, LogType.MSG_IP_INSERT_KEYRING);
{ // insert keyring
- // insert new version of this keyRing
ContentValues values = new ContentValues();
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
try {
@@ -317,13 +339,15 @@ public class ProviderHelper {
}
log(LogLevel.INFO, LogType.MSG_IP_INSERT_SUBKEYS);
+ progress.setProgress(LogType.MSG_IP_INSERT_SUBKEYS.getMsgId(), 40, 100);
mIndent += 1;
{ // insert subkeys
Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId));
int rank = 0;
for (UncachedPublicKey key : new IterableIterator<UncachedPublicKey>(keyRing.getPublicKeys())) {
- log(LogLevel.DEBUG, LogType.MSG_IP_SUBKEY, new String[]{
- PgpKeyHelper.convertKeyIdToHex(key.getKeyId())
+ long keyId = key.getKeyId();
+ log(LogLevel.DEBUG, keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY, new String[]{
+ PgpKeyHelper.convertKeyIdToHex(keyId)
});
mIndent += 1;
@@ -341,21 +365,41 @@ public class ProviderHelper {
values.put(Keys.CAN_ENCRYPT, e);
values.put(Keys.CAN_SIGN, s);
values.put(Keys.IS_REVOKED, key.isRevoked());
- if (c) {
- if (e) {
- log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_CES
- : LogType.MSG_IP_SUBKEY_FLAGS_CEX, null);
+ if (masterKeyId == keyId) {
+ if (c) {
+ if (e) {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_CES
+ : LogType.MSG_IP_MASTER_FLAGS_CEX, null);
+ } else {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_CXS
+ : LogType.MSG_IP_MASTER_FLAGS_CXX, null);
+ }
} else {
- log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_CXS
- : LogType.MSG_IP_SUBKEY_FLAGS_CXX, null);
+ if (e) {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_XES
+ : LogType.MSG_IP_MASTER_FLAGS_XEX, null);
+ } else {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_MASTER_FLAGS_XXS
+ : LogType.MSG_IP_MASTER_FLAGS_XXX, null);
+ }
}
} else {
- if (e) {
- log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_XES
- : LogType.MSG_IP_SUBKEY_FLAGS_XEX, null);
+ if (c) {
+ if (e) {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_CES
+ : LogType.MSG_IP_SUBKEY_FLAGS_CEX, null);
+ } else {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_CXS
+ : LogType.MSG_IP_SUBKEY_FLAGS_CXX, null);
+ }
} else {
- log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_XXS
- : LogType.MSG_IP_SUBKEY_FLAGS_XXX, null);
+ if (e) {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_XES
+ : LogType.MSG_IP_SUBKEY_FLAGS_XEX, null);
+ } else {
+ log(LogLevel.DEBUG, s ? LogType.MSG_IP_SUBKEY_FLAGS_XXS
+ : LogType.MSG_IP_SUBKEY_FLAGS_XXX, null);
+ }
}
}
@@ -365,13 +409,13 @@ public class ProviderHelper {
if (expiryDate != null) {
values.put(Keys.EXPIRY, expiryDate.getTime() / 1000);
if (key.isExpired()) {
- log(LogLevel.DEBUG, LogType.MSG_IP_SUBKEY_EXPIRED, new String[]{
- expiryDate.toString()
- });
+ log(LogLevel.DEBUG, keyId == masterKeyId ?
+ LogType.MSG_IP_MASTER_EXPIRED : LogType.MSG_IP_SUBKEY_EXPIRED,
+ new String[]{ expiryDate.toString() });
} else {
- log(LogLevel.DEBUG, LogType.MSG_IP_SUBKEY_EXPIRES, new String[]{
- expiryDate.toString()
- });
+ log(LogLevel.DEBUG, keyId == masterKeyId ?
+ LogType.MSG_IP_MASTER_EXPIRES : LogType.MSG_IP_SUBKEY_EXPIRES,
+ new String[] { expiryDate.toString() });
}
}
@@ -415,10 +459,9 @@ public class ProviderHelper {
if (!cert.isRevocation()) {
item.selfCert = cert;
item.isPrimary = cert.isPrimaryUserId();
- log(LogLevel.DEBUG, LogType.MSG_IP_UID_SELF_GOOD);
} else {
item.isRevoked = true;
- log(LogLevel.DEBUG, LogType.MSG_IP_UID_REVOKED);
+ log(LogLevel.INFO, LogType.MSG_IP_UID_REVOKED);
}
}
@@ -457,6 +500,7 @@ public class ProviderHelper {
}
mIndent -= 1;
+ progress.setProgress(LogType.MSG_IP_UID_REORDER.getMsgId(), 80, 100);
log(LogLevel.DEBUG, LogType.MSG_IP_UID_REORDER);
// primary before regular before revoked (see UserIdItem.compareTo)
// this is a stable sort, so the order of keys is otherwise preserved.
@@ -479,7 +523,6 @@ public class ProviderHelper {
}
}
- log(LogLevel.DEBUG, LogType.MSG_IP_PREPARE_SUCCESS);
mIndent -= 1;
} catch (IOException e) {
@@ -501,6 +544,7 @@ public class ProviderHelper {
}
log(LogLevel.DEBUG, LogType.MSG_IP_APPLY_BATCH);
+ progress.setProgress(LogType.MSG_IP_APPLY_BATCH.getMsgId(), 90, 100);
mContentResolver.applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
// Save the saved keyring (if any)
@@ -514,6 +558,7 @@ public class ProviderHelper {
mIndent -= 1;
log(LogLevel.OK, LogType.MSG_IP_SUCCESS);
+ progress.setProgress(LogType.MSG_IP_SUCCESS.getMsgId(), 100, 100);
return new SaveKeyringResult(result, mLog);
} catch (RemoteException e) {
@@ -564,6 +609,12 @@ public class ProviderHelper {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
+ // 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);
+ }
+
long masterKeyId = keyRing.getMasterKeyId();
log(LogLevel.START, LogType.MSG_IS,
new String[]{ PgpKeyHelper.convertKeyIdToHex(masterKeyId) });
@@ -579,7 +630,10 @@ public class ProviderHelper {
values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
// insert new version of this keyRing
Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
- mContentResolver.insert(uri, values);
+ if (mContentResolver.insert(uri, values) == null) {
+ log(LogLevel.ERROR, LogType.MSG_IS_DB_EXCEPTION);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
} catch (IOException e) {
Log.e(Constants.TAG, "Failed to encode key!", e);
log(LogLevel.ERROR, LogType.MSG_IS_IO_EXCPTION);
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 b5f01ce4d..f1f6c304a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -16,6 +16,7 @@ import java.util.ArrayList;
* list (ie, enum) of all possible log types, which should in all cases be tied
* to string resource ids.
*
+ *
*/
public class OperationResultParcel implements Parcelable {
/** Holds the overall result, the number specifying varying degrees of success. The first bit
@@ -101,6 +102,23 @@ public class OperationResultParcel implements Parcelable {
}
+ /** This is an enum of all possible log events.
+ *
+ * Element names should generally be prefixed with MSG_XX_ where XX is an
+ * identifier based on the related activity.
+ *
+ * Log messages should occur for each distinguishable action group. For
+ * each such group, one message is displayed followed by warnings or
+ * errors, and optionally subactions. The granularity should generally be
+ * optimistic: No "success" messages are printed except for the outermost
+ * operations - the success of an action group is indicated by the
+ * beginning message of the next action group.
+ *
+ * Log messages should be in present tense, There should be no trailing
+ * punctuation, except for error messages which may end in an exclamation
+ * mark.
+ *
+ */
public static enum LogType {
// import public
@@ -114,15 +132,24 @@ public class OperationResultParcel implements Parcelable {
MSG_IP_FAIL_OP_EX (R.string.msg_ip_fail_op_ex),
MSG_IP_FAIL_REMOTE_EX (R.string.msg_ip_fail_remote_ex),
MSG_IP_INSERT_KEYRING (R.string.msg_ip_insert_keyring),
- MSG_IP_INSERT_SUBKEYS (R.string.msg_ip_insert_subkeys),
+ MSG_IP_INSERT_SUBKEYS (R.string.msg_ip_insert_keys),
MSG_IP_PREPARE (R.string.msg_ip_prepare),
- MSG_IP_PREPARE_SUCCESS(R.string.msg_ip_prepare_success),
MSG_IP_PRESERVING_SECRET (R.string.msg_ip_preserving_secret),
MSG_IP_REINSERT_SECRET (R.string.msg_ip_reinsert_secret),
+ MSG_IP_MASTER (R.string.msg_ip_master),
+ MSG_IP_MASTER_EXPIRED (R.string.msg_ip_master_expired),
+ MSG_IP_MASTER_EXPIRES (R.string.msg_ip_master_expires),
+ MSG_IP_MASTER_FLAGS_CES (R.string.msg_ip_master_flags_ces),
+ MSG_IP_MASTER_FLAGS_CEX (R.string.msg_ip_master_flags_cex),
+ MSG_IP_MASTER_FLAGS_CXS (R.string.msg_ip_master_flags_cxs),
+ MSG_IP_MASTER_FLAGS_XES (R.string.msg_ip_master_flags_xes),
+ MSG_IP_MASTER_FLAGS_CXX (R.string.msg_ip_master_flags_cxx),
+ MSG_IP_MASTER_FLAGS_XEX (R.string.msg_ip_master_flags_xex),
+ MSG_IP_MASTER_FLAGS_XXS (R.string.msg_ip_master_flags_xxs),
+ MSG_IP_MASTER_FLAGS_XXX (R.string.msg_ip_master_flags_xxx),
MSG_IP_SUBKEY (R.string.msg_ip_subkey),
MSG_IP_SUBKEY_EXPIRED (R.string.msg_ip_subkey_expired),
MSG_IP_SUBKEY_EXPIRES (R.string.msg_ip_subkey_expires),
- MSG_IP_SUBKEY_FLAGS (R.string.msg_ip_subkey_flags),
MSG_IP_SUBKEY_FLAGS_CES (R.string.msg_ip_subkey_flags_ces),
MSG_IP_SUBKEY_FLAGS_CEX (R.string.msg_ip_subkey_flags_cex),
MSG_IP_SUBKEY_FLAGS_CXS (R.string.msg_ip_subkey_flags_cxs),
@@ -140,11 +167,11 @@ public class OperationResultParcel implements Parcelable {
MSG_IP_UID_REORDER(R.string.msg_ip_uid_reorder),
MSG_IP_UID_PROCESSING (R.string.msg_ip_uid_processing),
MSG_IP_UID_REVOKED (R.string.msg_ip_uid_revoked),
- MSG_IP_UID_SELF_GOOD (R.string.msg_ip_uid_self_good),
// import secret
MSG_IS(R.string.msg_is),
MSG_IS_BAD_TYPE_PUBLIC (R.string.msg_is_bad_type_public),
+ MSG_IS_DB_EXCEPTION (R.string.msg_is_db_exception),
MSG_IS_IMPORTING_SUBKEYS (R.string.msg_is_importing_subkeys),
MSG_IS_IO_EXCPTION (R.string.msg_is_io_excption),
MSG_IS_SUBKEY_NONEXISTENT (R.string.msg_is_subkey_nonexistent),
@@ -153,9 +180,10 @@ public class OperationResultParcel implements Parcelable {
MSG_IS_SUCCESS (R.string.msg_is_success),
// keyring canonicalization
- MSG_KC (R.string.msg_kc),
+ MSG_KC_PUBLIC (R.string.msg_kc_public),
+ MSG_KC_SECRET (R.string.msg_kc_secret),
+ MSG_KC_FATAL_NO_UID (R.string.msg_kc_fatal_no_uid),
MSG_KC_MASTER (R.string.msg_kc_master),
- MSG_KC_MASTER_SUCCESS (R.string.msg_kc_master_success),
MSG_KC_REVOKE_BAD_ERR (R.string.msg_kc_revoke_bad_err),
MSG_KC_REVOKE_BAD_LOCAL (R.string.msg_kc_revoke_bad_local),
MSG_KC_REVOKE_BAD_TIME (R.string.msg_kc_revoke_bad_time),
@@ -176,8 +204,9 @@ public class OperationResultParcel implements Parcelable {
MSG_KC_SUB_REVOKE_BAD_ERR (R.string.msg_kc_sub_revoke_bad_err),
MSG_KC_SUB_REVOKE_BAD (R.string.msg_kc_sub_revoke_bad),
MSG_KC_SUB_REVOKE_DUP (R.string.msg_kc_sub_revoke_dup),
- MSG_KC_SUB_SUCCESS (R.string.msg_kc_sub_success),
- MSG_KC_SUCCESS_REMOVED (R.string.msg_kc_success_removed),
+ MSG_KC_SUCCESS_BAD (R.string.msg_kc_success_bad),
+ MSG_KC_SUCCESS_BAD_AND_RED (R.string.msg_kc_success_bad_and_red),
+ MSG_KC_SUCCESS_REDUNDANT (R.string.msg_kc_success_redundant),
MSG_KC_SUCCESS (R.string.msg_kc_success),
MSG_KC_UID_BAD_ERR (R.string.msg_kc_uid_bad_err),
MSG_KC_UID_BAD_LOCAL (R.string.msg_kc_uid_bad_local),
@@ -185,6 +214,8 @@ public class OperationResultParcel implements Parcelable {
MSG_KC_UID_BAD_TYPE (R.string.msg_kc_uid_bad_type),
MSG_KC_UID_BAD (R.string.msg_kc_uid_bad),
MSG_KC_UID_DUP (R.string.msg_kc_uid_dup),
+ MSG_KC_UID_FOREIGN (R.string.msg_kc_uid_foreign),
+ 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),
;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index c3ca0334f..1912b6e7d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -56,6 +56,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
+import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout.TabColorizer;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
@@ -121,6 +122,18 @@ public class ViewKeyActivity extends ActionBarActivity implements
mViewPager = (ViewPager) findViewById(R.id.view_key_pager);
mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout);
+ mSlidingTabLayout.setCustomTabColorizer(new TabColorizer() {
+ @Override
+ public int getIndicatorColor(int position) {
+ return position == TAB_CERTS || position == TAB_KEYS ? 0xFFFF4444 : 0xFFAA66CC;
+ }
+
+ @Override
+ public int getDividerColor(int position) {
+ return 0;
+ }
+ });
+
int switchToTab = TAB_MAIN;
Intent intent = getIntent();
if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) {
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 1b0b1ad03..5393ccca3 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -511,14 +511,23 @@
<string name="msg_ip_fail_remote_ex">Operation failed due to internal error</string>
<string name="msg_ip">Importing public keyring %s</string>
<string name="msg_ip_insert_keyring">Encoding keyring data</string>
- <string name="msg_ip_insert_subkeys">Evaluating subkeys</string>
+ <string name="msg_ip_insert_keys">Parsing keys</string>
<string name="msg_ip_prepare">Preparing database operations</string>
- <string name="msg_ip_prepare_success">OK</string>
<string name="msg_ip_preserving_secret">Preserving available secret key</string>
+ <string name="msg_ip_master">Processing master key %s</string>
+ <string name="msg_ip_master_expired">Keyring expired on %s</string>
+ <string name="msg_ip_master_expires">Keyring expires on %s</string>
+ <string name="msg_ip_master_flags_ces">Master key flags: certify, encrypt, sign</string>
+ <string name="msg_ip_master_flags_cex">Master key flags: certify, encrypt</string>
+ <string name="msg_ip_master_flags_cxs">Master key flags: certify, sign</string>
+ <string name="msg_ip_master_flags_xes">Master key flags: encrypt, sign</string>
+ <string name="msg_ip_master_flags_cxx">Master key flags: certify</string>
+ <string name="msg_ip_master_flags_xex">Master key flags: encrypt</string>
+ <string name="msg_ip_master_flags_xxs">Master key flags: sign</string>
+ <string name="msg_ip_master_flags_xxx">Master key flags: none</string>
<string name="msg_ip_subkey">Processing subkey %s</string>
<string name="msg_ip_subkey_expired">Subkey expired on %s</string>
<string name="msg_ip_subkey_expires">Subkey expires on %s</string>
- <string name="msg_ip_subkey_flags">Subkey flags: %s</string>
<string name="msg_ip_subkey_flags_ces">Subkey flags: certify, encrypt, sign</string>
<string name="msg_ip_subkey_flags_cex">Subkey flags: certify, encrypt</string>
<string name="msg_ip_subkey_flags_cxs">Subkey flags: certify, sign</string>
@@ -531,17 +540,17 @@
<string name="msg_ip_reinsert_secret">Re-inserting secret key</string>
<string name="msg_ip_uid_cert_bad">Encountered bad certificate!</string>
<string name="msg_ip_uid_cert_error">Error processing certificate!</string>
- <string name="msg_ip_uid_cert_good">Found good certificate from %1$s (%2$s)</string>
+ <string name="msg_ip_uid_cert_good">User id is certified by %1$s (%2$s)</string>
<string name="msg_ip_uid_certs_unknown">Ignoring %s certificates from unknown pubkeys</string>
<string name="msg_ip_uid_classifying">Classifying user ids, using %s trusted signatures</string>
<string name="msg_ip_uid_reorder">Re-ordering user ids</string>
<string name="msg_ip_uid_processing">Processing user id %s</string>
- <string name="msg_ip_uid_revoked">Found uid revocation certificate</string>
- <string name="msg_ip_uid_self_good">Found good self certificate</string>
+ <string name="msg_ip_uid_revoked">User id is revoked</string>
<string name="msg_is_bad_type_public">Tried to import public keyring as secret. This is a bug, please file a report!</string>
<!-- Import Secret log entries -->
<string name="msg_is">Importing secret key %s</string>
+ <string name="msg_is_db_exception">Database error!</string>
<string name="msg_is_importing_subkeys">Processing secret subkeys</string>
<string name="msg_is_io_excption">Error encoding keyring</string>
<string name="msg_is_subkey_nonexistent">Subkey %s unavailable in public key</string>
@@ -550,9 +559,10 @@
<string name="msg_is_success">Successfully imported secret keyring</string>
<!-- Keyring Canonicalization log entries -->
- <string name="msg_kc">Canonicalizing keyring %s</string>
+ <string name="msg_kc_public">Canonicalizing public keyring %s</string>
+ <string name="msg_kc_secret">Canonicalizing secret keyring %s</string>
+ <string name="msg_kc_fatal_no_uid">Keyring canonicalization failed: Keyring has no valid user ids</string>
<string name="msg_kc_master">Processing master key</string>
- <string name="msg_kc_master_success">OK</string>
<string name="msg_kc_revoke_bad_err">Removing bad keyring revocation certificate</string>
<string name="msg_kc_revoke_bad_local">Removing keyring revocation certificate with "local" flag</string>
<string name="msg_kc_revoke_bad_time">Removing keyring revocation certificate with future timestamp</string>
@@ -573,17 +583,20 @@
<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_sub_success">Subkey binding OK</string>
<string name="msg_kc_success">Keyring canonicalization successful</string>
- <string name="msg_kc_success_removed">Keyring canonicalization successful, removed %s certificates</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>
<string name="msg_kc_uid_bad_err">Removing bad self certificate for user id %s</string>
<string name="msg_kc_uid_bad_local">Removing user id certificate with "local" flag</string>
<string name="msg_kc_uid_bad_time">Removing user id with future timestamp</string>
<string name="msg_kc_uid_bad_type">Removing user id certificate of unknown type (%s)</string>
<string name="msg_kc_uid_bad">Removing bad self certificate for user id "%s"</string>
<string name="msg_kc_uid_dup">Removing outdated self certificate for user id "%s"</string>
+ <string name="msg_kc_uid_foreign">Removing foreign user id certificate by %s</string>
<string name="msg_kc_uid_revoke_dup">Removing redundant revocation certificate for user id "%s"</string>
<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>
<!-- unsorted -->
<string name="section_certifier_id">Certifier</string>