From d7888d46668a68a138743e30c64be45b35b5211a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 26 Feb 2015 18:52:54 +0100 Subject: ignore revoked user ids for primary key expiry --- .../keychain/pgp/CanonicalizedKeyRing.java | 5 +- .../keychain/pgp/CanonicalizedPublicKey.java | 74 ++++++++++++++++++++++ .../keychain/pgp/PgpKeyOperation.java | 4 +- .../keychain/pgp/UncachedPublicKey.java | 18 ------ .../keychain/pgp/WrappedSignature.java | 4 ++ 5 files changed, 82 insertions(+), 23 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java index bbf136dac..4adacaf23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -79,9 +79,8 @@ public abstract class CanonicalizedKeyRing extends KeyRing { public boolean isExpired() { // Is the master key expired? - Date creationDate = getRing().getPublicKey().getCreationTime(); - Date expiryDate = getRing().getPublicKey().getValidSeconds() > 0 - ? new Date(creationDate.getTime() + getRing().getPublicKey().getValidSeconds() * 1000) : null; + Date creationDate = getPublicKey().getCreationTime(); + Date expiryDate = getPublicKey().getExpiryTime(); Date now = new Date(); return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java index b026d9257..303070333 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java @@ -20,8 +20,16 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Iterator; /** Wrapper for a PGPPublicKey. * @@ -100,6 +108,72 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { return false; } + public boolean isRevoked() { + return mPublicKey.getSignaturesOfType(isMasterKey() + ? PGPSignature.KEY_REVOCATION + : PGPSignature.SUBKEY_REVOCATION).hasNext(); + } + + public boolean isExpired () { + Date expiry = getExpiryTime(); + return expiry != null && expiry.before(new Date()); + } + + public long getValidSeconds() { + + long seconds; + + // the getValidSeconds method is unreliable for master keys. we need to iterate all + // user ids, then use the most recent certification from a non-revoked user id + if (isMasterKey()) { + Date latestCreation = null; + seconds = 0; + + for (byte[] rawUserId : getUnorderedRawUserIds()) { + Iterator sigs = getSignaturesForRawId(rawUserId); + + // there is always a certification, so this call is safe + WrappedSignature sig = sigs.next(); + + // we know a user id has at most two sigs: one certification, one revocation. + // if the sig is a revocation, or there is another sig (which is a revocation), + // the data in this uid is not relevant + if (sig.isRevocation() || sigs.hasNext()) { + continue; + } + + // this is our revocation, UNLESS there is a newer certificate! + if (latestCreation == null || latestCreation.before(sig.getCreationTime())) { + latestCreation = sig.getCreationTime(); + seconds = sig.getKeyExpirySeconds(); + } + } + } else { + seconds = mPublicKey.getValidSeconds(); + } + + return seconds; + } + + public Date getExpiryTime() { + long seconds = getValidSeconds(); + + if (seconds > Integer.MAX_VALUE) { + Log.e(Constants.TAG, "error, expiry time too large"); + return null; + } + if (seconds == 0) { + // no expiry + return null; + } + Date creationDate = getCreationTime(); + Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(creationDate); + calendar.add(Calendar.SECOND, (int) seconds); + + return calendar.getTime(); + } + /** Same method as superclass, but we make it public. */ public Integer getKeyUsage() { return super.getKeyUsage(); 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 aebb52a03..1a251eb79 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -439,8 +439,8 @@ public class PgpKeyOperation { // since this is the master key, this contains at least CERTIFY_OTHER PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); int masterKeyFlags = readKeyFlags(masterPublicKey) | KeyFlags.CERTIFY_OTHER; - long masterKeyExpiry = masterPublicKey.getValidSeconds() == 0L ? 0L : - masterPublicKey.getCreationTime().getTime() / 1000 + masterPublicKey.getValidSeconds(); + Date expiryTime = wsKR.getPublicKey().getExpiryTime(); + long masterKeyExpiry = expiryTime != null ? expiryTime.getTime() / 1000 : 0L; return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 0fe1ccdb6..d29169cc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -60,24 +60,6 @@ public class UncachedPublicKey { return mPublicKey.getCreationTime(); } - public Date getExpiryTime() { - long seconds = mPublicKey.getValidSeconds(); - if (seconds > Integer.MAX_VALUE) { - Log.e(Constants.TAG, "error, expiry time too large"); - return null; - } - if (seconds == 0) { - // no expiry - return null; - } - Date creationDate = getCreationTime(); - Calendar calendar = GregorianCalendar.getInstance(); - calendar.setTime(creationDate); - calendar.add(Calendar.SECOND, (int) seconds); - - return calendar.getTime(); - } - public boolean isExpired() { Date creationDate = mPublicKey.getCreationTime(); Date expiryDate = mPublicKey.getValidSeconds() > 0 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 ade075d55..c6fad1a73 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -78,6 +78,10 @@ public class WrappedSignature { return mSig.getCreationTime(); } + public long getKeyExpirySeconds() { + return mSig.getHashedSubPackets().getKeyExpirationTime(); + } + public ArrayList getEmbeddedSignatures() { ArrayList sigs = new ArrayList<>(); if (!mSig.hasSubpackets()) { -- cgit v1.2.3