Get certificates by raw user ids, be more liberal about accepted user id encodings

This commit is contained in:
Dominik Schürmann 2014-09-13 19:05:53 +02:00
parent 974dc47d69
commit 9e37522bdd
5 changed files with 72 additions and 39 deletions

View File

@ -59,6 +59,10 @@ public abstract class CanonicalizedKeyRing extends KeyRing {
return getPublicKey().getPrimaryUserIdWithFallback();
}
public ArrayList<byte[]> getUnorderedRawUserIds() {
return getPublicKey().getUnorderedRawUserIds();
}
public ArrayList<String> getUnorderedUserIds() {
return getPublicKey().getUnorderedUserIds();
}

View File

@ -33,6 +33,7 @@ import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.spongycastle.util.Strings;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.results.OperationResultParcel.LogLevel;
@ -361,23 +362,25 @@ public class UncachedKeyRing {
}
}
ArrayList<String> processedUserIds = new ArrayList<String>();
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
ArrayList<byte[]> processedUserIds = new ArrayList<byte[]>();
for (byte[] rawUserId : new IterableIterator<byte[]>(masterKey.getRawUserIDs())) {
String userId = Strings.fromUTF8ByteArray(rawUserId);
// check for duplicate user ids
if (processedUserIds.contains(userId)) {
if (processedUserIds.contains(rawUserId)) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_DUP,
indent, userId);
// strip out the first found user id with this name
modified = PGPPublicKey.removeCertification(modified, userId);
modified = PGPPublicKey.removeCertification(modified, rawUserId);
}
processedUserIds.add(userId);
processedUserIds.add(rawUserId);
PGPSignature selfCert = null;
revocation = null;
// look through signatures for this specific user id
@SuppressWarnings("unchecked")
Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForID(userId);
Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForID(rawUserId);
if (signaturesIt != null) {
for (PGPSignature zert : new IterableIterator<PGPSignature>(signaturesIt)) {
WrappedSignature cert = new WrappedSignature(zert);
@ -391,7 +394,7 @@ public class UncachedKeyRing {
&& type != PGPSignature.CERTIFICATION_REVOCATION) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_TYPE,
indent, "0x" + Integer.toString(zert.getSignatureType(), 16));
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
badCerts += 1;
continue;
}
@ -399,7 +402,7 @@ public class UncachedKeyRing {
if (cert.getCreationTime().after(now)) {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_TIME, indent);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
badCerts += 1;
continue;
}
@ -407,7 +410,7 @@ public class UncachedKeyRing {
if (cert.isLocal()) {
// Creation date in the future? No way!
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_LOCAL, indent);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
badCerts += 1;
continue;
}
@ -418,7 +421,7 @@ public class UncachedKeyRing {
if (isSecret()) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_FOREIGN,
indent, PgpKeyHelper.convertKeyIdToHex(certId));
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
badCerts += 1;
}
continue;
@ -427,17 +430,17 @@ public class UncachedKeyRing {
// Otherwise, first make sure it checks out
try {
cert.init(masterKey);
if (!cert.verifySignature(masterKey, userId)) {
if (!cert.verifySignature(masterKey, rawUserId)) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
badCerts += 1;
continue;
}
} catch (PgpGeneralException e) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_ERR,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
badCerts += 1;
continue;
}
@ -452,13 +455,13 @@ public class UncachedKeyRing {
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, selfCert);
redundantCerts += 1;
selfCert = zert;
} else {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
redundantCerts += 1;
}
// If there is a revocation certificate, and it's older than this, drop it
@ -466,7 +469,7 @@ public class UncachedKeyRing {
&& revocation.getCreationTime().before(selfCert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, revocation);
modified = PGPPublicKey.removeCertification(modified, rawUserId, revocation);
revocation = null;
redundantCerts += 1;
}
@ -477,7 +480,7 @@ public class UncachedKeyRing {
if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
redundantCerts += 1;
continue;
}
@ -488,13 +491,13 @@ public class UncachedKeyRing {
} else if (revocation.getCreationTime().before(cert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, revocation);
modified = PGPPublicKey.removeCertification(modified, rawUserId, revocation);
redundantCerts += 1;
revocation = zert;
} else {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
redundantCerts += 1;
}
break;
@ -506,7 +509,7 @@ public class UncachedKeyRing {
if (selfCert == null && revocation == null) {
log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REMOVE,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId);
modified = PGPPublicKey.removeCertification(modified, rawUserId);
}
}
@ -817,9 +820,9 @@ public class UncachedKeyRing {
}
// Copy over all user id certificates
for (String userId : new IterableIterator<String>(key.getUserIDs())) {
for (byte[] rawUserId : new IterableIterator<byte[]>(key.getRawUserIDs())) {
@SuppressWarnings("unchecked")
Iterator<PGPSignature> signaturesIt = key.getSignaturesForID(userId);
Iterator<PGPSignature> signaturesIt = key.getSignaturesForID(rawUserId);
// no signatures for this User ID, skip it
if (signaturesIt == null) {
continue;
@ -836,7 +839,7 @@ public class UncachedKeyRing {
}
newCerts += 1;
certs.add(encoded);
modified = PGPPublicKey.addCertification(modified, userId, cert);
modified = PGPPublicKey.addCertification(modified, rawUserId, cert);
}
}
// If anything changed, save the updated (sub)key

View File

@ -28,11 +28,13 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.util.Strings;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -126,14 +128,14 @@ public class UncachedPublicKey {
*
*/
public String getPrimaryUserId() {
String found = null;
byte[] found = null;
PGPSignature foundSig = null;
// noinspection unchecked
for (String userId : new IterableIterator<String>(mPublicKey.getUserIDs())) {
for (byte[] rawUserId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) {
PGPSignature revocation = null;
@SuppressWarnings("unchecked")
Iterator<PGPSignature> signaturesIt = mPublicKey.getSignaturesForID(userId);
Iterator<PGPSignature> signaturesIt = mPublicKey.getSignaturesForID(rawUserId);
// no signatures for this User ID
if (signaturesIt == null) {
continue;
@ -147,10 +149,10 @@ public class UncachedPublicKey {
// make sure it's actually valid
sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
if (!sig.verifyCertification(userId, mPublicKey)) {
if (!sig.verifyCertification(rawUserId, mPublicKey)) {
continue;
}
if (found != null && found.equals(userId)) {
if (found != null && Arrays.equals(found, rawUserId)) {
found = null;
}
revocation = sig;
@ -169,8 +171,8 @@ public class UncachedPublicKey {
// make sure it's actually valid
sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
if (sig.verifyCertification(userId, mPublicKey)) {
found = userId;
if (sig.verifyCertification(rawUserId, mPublicKey)) {
found = rawUserId;
foundSig = sig;
// this one can't be relevant anymore at this point
revocation = null;
@ -182,7 +184,11 @@ public class UncachedPublicKey {
}
}
}
return found;
if (found != null) {
return Strings.fromUTF8ByteArray(found);
} else {
return null;
}
}
/**
@ -204,6 +210,14 @@ public class UncachedPublicKey {
return userIds;
}
public ArrayList<byte[]> getUnorderedRawUserIds() {
ArrayList<byte[]> userIds = new ArrayList<byte[]>();
for (byte[] userId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) {
userIds.add(userId);
}
return userIds;
}
public boolean isElGamalEncrypt() {
return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT;
}
@ -320,8 +334,8 @@ public class UncachedPublicKey {
};
}
public Iterator<WrappedSignature> getSignaturesForId(String userId) {
final Iterator<PGPSignature> it = mPublicKey.getSignaturesForID(userId);
public Iterator<WrappedSignature> getSignaturesForRawId(byte[] rawUserId) {
final Iterator<PGPSignature> it = mPublicKey.getSignaturesForID(rawUserId);
if (it != null) {
return new Iterator<WrappedSignature>() {
public void remove() {

View File

@ -187,8 +187,16 @@ public class WrappedSignature {
}
}
public boolean verifySignature(UncachedPublicKey key, String uid) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), uid);
boolean verifySignature(PGPPublicKey key, byte[] rawUserId) throws PgpGeneralException {
try {
return mSig.verifyCertification(rawUserId, key);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
}
public boolean verifySignature(UncachedPublicKey key, byte[] rawUserId) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), rawUserId);
}
public boolean verifySignature(CanonicalizedPublicKey key, String uid) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), uid);

View File

@ -28,6 +28,7 @@ import android.net.Uri;
import android.os.RemoteException;
import android.support.v4.util.LongSparseArray;
import org.spongycastle.util.Strings;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
@ -434,8 +435,11 @@ public class ProviderHelper {
}
mIndent += 1;
List<UserIdItem> uids = new ArrayList<UserIdItem>();
for (String userId : new IterableIterator<String>(
masterKey.getUnorderedUserIds().iterator())) {
for (byte[] rawUserId : new IterableIterator<byte[]>(
masterKey.getUnorderedRawUserIds().iterator())) {
String userId = Strings.fromUTF8ByteArray(rawUserId);
Log.d(Constants.TAG, "userId: "+userId);
UserIdItem item = new UserIdItem();
uids.add(item);
item.userId = userId;
@ -446,7 +450,7 @@ public class ProviderHelper {
mIndent += 1;
// look through signatures for this specific key
for (WrappedSignature cert : new IterableIterator<WrappedSignature>(
masterKey.getSignaturesForId(userId))) {
masterKey.getSignaturesForRawId(rawUserId))) {
long certId = cert.getKeyId();
try {
// self signature
@ -469,7 +473,7 @@ public class ProviderHelper {
if (trustedKeys.indexOfKey(certId) >= 0) {
CanonicalizedPublicKey trustedKey = trustedKeys.get(certId);
cert.init(trustedKey);
if (cert.verifySignature(masterKey, userId)) {
if (cert.verifySignature(masterKey, rawUserId)) {
item.trustedCerts.add(cert);
log(LogLevel.INFO, LogType.MSG_IP_UID_CERT_GOOD,
PgpKeyHelper.convertKeyIdToHexShort(trustedKey.getKeyId())