PublicKeyChecker: Support checking at a given effective date
When checking push certificates, we only care about whether the key
used for signing was valid at the time the signature was created; it
may have since expired or been superseded, and that's ok. Add an
optional setter to PublicKeyChecker to tell it to use a different
effective date, only considering revocations and expirations prior to
that date.
There are some cases where we explicitly do not want to respect this
effective date:
- If a key is compromised, all signatures made with that key are
invalid.
- Allow after-the-fact web-of-trust assertions, so for example the
push certificate stored in a PatchSet can go from OK to TRUSTED
simply by adding the proper certification today.
Change-Id: I078fd0f4b431af8279948961a99e340f932229b7
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PublicKeyChecker.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PublicKeyChecker.java
index 3bbad9b..e4c81df 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PublicKeyChecker.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PublicKeyChecker.java
@@ -46,6 +46,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -64,6 +65,7 @@
private PublicKeyStore store;
private Map<Long, Fingerprint> trusted;
private int maxTrustDepth;
+ private Date effectiveTime = new Date();
/**
* Enable web-of-trust checks.
@@ -110,6 +112,24 @@
}
/**
+ * Set the effective time for checking the key.
+ * <p>
+ * If set, check whether the key should be considered valid (e.g. unexpired)
+ * as of this time.
+ *
+ * @param effectiveTime effective time.
+ * @return a reference to this object.
+ */
+ public PublicKeyChecker setEffectiveTime(Date effectiveTime) {
+ this.effectiveTime = effectiveTime;
+ return this;
+ }
+
+ protected Date getEffectiveTime() {
+ return effectiveTime;
+ }
+
+ /**
* Check a public key.
*
* @param key the public key.
@@ -141,7 +161,7 @@
private CheckResult check(PGPPublicKey key, int depth, boolean expand,
Set<Fingerprint> seen) {
- CheckResult basicResult = checkBasic(key);
+ CheckResult basicResult = checkBasic(key, effectiveTime);
CheckResult customResult = checkCustom(key, depth);
CheckResult trustResult = checkWebOfTrust(key, store, depth, seen);
if (!expand && !trustResult.isTrusted()) {
@@ -176,28 +196,32 @@
return CheckResult.create(status, problems);
}
- private CheckResult checkBasic(PGPPublicKey key) {
+ private CheckResult checkBasic(PGPPublicKey key, Date now) {
List<String> problems = new ArrayList<>(2);
- gatherRevocationProblems(key, problems);
+ gatherRevocationProblems(key, now, problems);
- long validSecs = key.getValidSeconds();
- if (validSecs != 0) {
- long createdSecs = key.getCreationTime().getTime() / 1000;
- long nowSecs = System.currentTimeMillis() / 1000;
- if (nowSecs - createdSecs > validSecs) {
+ long validMs = key.getValidSeconds() * 1000;
+ if (validMs != 0) {
+ long msSinceCreation = now.getTime() - key.getCreationTime().getTime();
+ if (msSinceCreation > validMs) {
problems.add("Key is expired");
}
}
return CheckResult.create(problems);
}
- private void gatherRevocationProblems(PGPPublicKey key, List<String> problems) {
+ private void gatherRevocationProblems(PGPPublicKey key, Date now,
+ List<String> problems) {
try {
List<PGPSignature> revocations = new ArrayList<>();
Map<Long, RevocationKey> revokers = new HashMap<>();
- PGPSignature selfRevocation = scanRevocations(key, revocations, revokers);
+ PGPSignature selfRevocation =
+ scanRevocations(key, now, revocations, revokers);
if (selfRevocation != null) {
- problems.add(reasonToString(getRevocationReason(selfRevocation)));
+ RevocationReason reason = getRevocationReason(selfRevocation);
+ if (isRevocationValid(selfRevocation, reason, now)) {
+ problems.add(reasonToString(reason));
+ }
} else {
checkRevocations(key, revocations, revokers, problems);
}
@@ -206,7 +230,21 @@
}
}
- private PGPSignature scanRevocations(PGPPublicKey key,
+ private static boolean isRevocationValid(PGPSignature revocation,
+ RevocationReason reason, Date now) {
+ // RFC4880 states:
+ // "If a key has been revoked because of a compromise, all signatures
+ // created by that key are suspect. However, if it was merely superseded or
+ // retired, old signatures are still valid."
+ //
+ // Note that GnuPG does not implement this correctly, as it does not
+ // consider the revocation reason and timestamp when checking whether a
+ // signature (data or certification) is valid.
+ return reason.getRevocationReason() == KEY_COMPROMISED
+ || revocation.getCreationTime().before(now);
+ }
+
+ private PGPSignature scanRevocations(PGPPublicKey key, Date now,
List<PGPSignature> revocations, Map<Long, RevocationKey> revokers)
throws PGPException {
@SuppressWarnings("unchecked")
@@ -221,7 +259,10 @@
return sig;
}
} else {
- revocations.add(sig);
+ RevocationReason reason = getRevocationReason(sig);
+ if (reason != null && isRevocationValid(sig, reason, now)) {
+ revocations.add(sig);
+ }
}
break;
case DIRECT_KEY:
@@ -263,9 +304,8 @@
continue; // Not a designated revoker.
}
byte[] rfp = revoker.getFingerprint();
- PGPPublicKeyRing rkr = store.get(rfp);
- if (rkr == null
- || rkr.getPublicKey().getAlgorithm() != revoker.getAlgorithm()) {
+ PGPPublicKeyRing revokerKeyRing = store.get(rfp);
+ if (revokerKeyRing == null) {
// Revoker is authorized and there is a revocation signature by this
// revoker, but the key is not in the store so we can't verify the
// signature.
@@ -275,8 +315,16 @@
problems.add(reasonToString(getRevocationReason(revocation)));
continue;
}
- revocation.init(
- new BcPGPContentVerifierBuilderProvider(), rkr.getPublicKey());
+ PGPPublicKey rk = revokerKeyRing.getPublicKey();
+ if (rk.getAlgorithm() != revoker.getAlgorithm()) {
+ continue;
+ }
+ if (!checkBasic(rk, revocation.getCreationTime()).isOk()) {
+ // Revoker's key was expired or revoked at time of revocation, so the
+ // revocation is invalid.
+ continue;
+ }
+ revocation.init(new BcPGPContentVerifierBuilderProvider(), rk);
if (revocation.verifyCertification(key)) {
problems.add(reasonToString(getRevocationReason(revocation)));
}
@@ -353,8 +401,13 @@
Iterator<String> userIds = key.getUserIDs();
while (userIds.hasNext()) {
String userId = userIds.next();
+
+ // Don't check the timestamp of these certifications. This allows admins
+ // to correct untrusted keys by signing them with a trusted key, such that
+ // older signatures created by those keys retroactively appear valid.
@SuppressWarnings("unchecked")
Iterator<PGPSignature> sigs = key.getSignaturesForID(userId);
+
while (sigs.hasNext()) {
PGPSignature sig = sigs.next();
// TODO(dborowitz): Handle CERTIFICATION_REVOCATION.
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java
index e87a0ee..0a0fff7 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java
@@ -210,6 +210,7 @@
}
CheckResult result = publicKeyChecker
.setStore(store)
+ .setEffectiveTime(sig.getCreationTime())
.check(signer);
if (!result.getProblems().isEmpty()) {
StringBuilder err = new StringBuilder("Invalid public key ")
diff --git a/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PublicKeyCheckerTest.java b/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PublicKeyCheckerTest.java
index a611ec9..576ffbd 100644
--- a/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PublicKeyCheckerTest.java
+++ b/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PublicKeyCheckerTest.java
@@ -16,6 +16,8 @@
import static com.google.gerrit.gpg.PublicKeyStore.keyToString;
import static com.google.gerrit.gpg.testutil.TestKeys.expiredKey;
+import static com.google.gerrit.gpg.testutil.TestKeys.keyRevokedByExpiredKeyAfterExpiration;
+import static com.google.gerrit.gpg.testutil.TestKeys.keyRevokedByExpiredKeyBeforeExpiration;
import static com.google.gerrit.gpg.testutil.TestKeys.revokedCompromisedKey;
import static com.google.gerrit.gpg.testutil.TestKeys.revokedNoLongerUsedKey;
import static com.google.gerrit.gpg.testutil.TestKeys.selfRevokedKey;
@@ -51,7 +53,9 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import java.text.SimpleDateFormat;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -88,7 +92,17 @@
@Test
public void keyExpiringInFuture() throws Exception {
- assertProblems(validKeyWithExpiration());
+ TestKey k = validKeyWithExpiration();
+
+ PublicKeyChecker checker = new PublicKeyChecker()
+ .setStore(store);
+ assertProblems(checker, k);
+
+ checker.setEffectiveTime(parseDate("2015-07-10 12:00:00 -0400"));
+ assertProblems(checker, k);
+
+ checker.setEffectiveTime(parseDate("2075-07-10 12:00:00 -0400"));
+ assertProblems(checker, k, "Key is expired");
}
@Test
@@ -202,6 +216,24 @@
}
@Test
+ public void revokedKeyDueToCompromiseRevokesKeyRetroactively()
+ throws Exception {
+ TestKey k = add(revokedCompromisedKey());
+ add(validKeyWithoutExpiration());
+ save();
+
+ String problem =
+ "Key is revoked (key material has been compromised): test6 compromised";
+ assertProblems(k, problem);
+
+ SimpleDateFormat df = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
+ PublicKeyChecker checker = new PublicKeyChecker()
+ .setStore(store)
+ .setEffectiveTime(df.parse("2010-01-01 12:00:00"));
+ assertProblems(checker, k, problem);
+ }
+
+ @Test
public void revokedByKeyNotPresentInStore() throws Exception {
TestKey k = add(revokedCompromisedKey());
save();
@@ -221,6 +253,49 @@
"Key is revoked (retired and no longer valid): test7 not used");
}
+ @Test
+ public void revokedKeyDueToNoLongerBeingUsedDoesNotRevokeKeyRetroactively()
+ throws Exception {
+ TestKey k = add(revokedNoLongerUsedKey());
+ add(validKeyWithoutExpiration());
+ save();
+
+ assertProblems(k,
+ "Key is revoked (retired and no longer valid): test7 not used");
+
+ PublicKeyChecker checker = new PublicKeyChecker()
+ .setStore(store)
+ .setEffectiveTime(parseDate("2010-01-01 12:00:00 -0400"));
+ assertProblems(checker, k);
+ }
+
+ @Test
+ public void keyRevokedByExpiredKeyAfterExpirationIsNotRevoked()
+ throws Exception {
+ TestKey k = add(keyRevokedByExpiredKeyAfterExpiration());
+ add(expiredKey());
+ save();
+
+ PublicKeyChecker checker = new PublicKeyChecker().setStore(store);
+ assertProblems(checker, k);
+ }
+
+ @Test
+ public void keyRevokedByExpiredKeyBeforeExpirationIsRevoked()
+ throws Exception {
+ TestKey k = add(keyRevokedByExpiredKeyBeforeExpiration());
+ add(expiredKey());
+ save();
+
+ PublicKeyChecker checker = new PublicKeyChecker().setStore(store);
+ assertProblems(checker, k,
+ "Key is revoked (retired and no longer valid): test9 not used");
+
+ // Set time between key creation and revocation.
+ checker.setEffectiveTime(parseDate("2005-08-01 13:00:00 -0400"));
+ assertProblems(checker, k);
+ }
+
private PGPPublicKeyRing removeRevokers(PGPPublicKeyRing kr) {
PGPPublicKey k = kr.getPublicKey();
@SuppressWarnings("unchecked")
@@ -288,4 +363,8 @@
return "Certification by " + keyToString(k.getPublicKey())
+ " is valid, but key is not trusted";
}
+
+ private static Date parseDate(String str) throws Exception {
+ return new SimpleDateFormat("YYYY-MM-dd HH:mm:ss Z").parse(str);
+ }
}
diff --git a/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PushCertificateCheckerTest.java b/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PushCertificateCheckerTest.java
index 9b1c058..9778958 100644
--- a/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PushCertificateCheckerTest.java
+++ b/gerrit-gpg/src/test/java/com/google/gerrit/gpg/PushCertificateCheckerTest.java
@@ -28,6 +28,7 @@
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
+import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
@@ -47,7 +48,9 @@
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.text.SimpleDateFormat;
import java.util.Arrays;
+import java.util.Date;
public class PushCertificateCheckerTest {
private InMemoryRepository repo;
@@ -130,6 +133,15 @@
+ ":\n Key is expired");
}
+ @Test
+ public void signatureByExpiredKeyBeforeExpiration() throws Exception {
+ TestKey key3 = expiredKey();
+ Date now = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss Z")
+ .parse("2005-07-10 12:00:00 -0400");
+ PushCertificate cert = newSignedCert(validNonce(), key3, now);
+ assertProblems(cert);
+ }
+
private String validNonce() {
return signedPushConfig.getNonceGenerator()
.createNonce(repo, System.currentTimeMillis() / 1000);
@@ -137,6 +149,11 @@
private PushCertificate newSignedCert(String nonce, TestKey signingKey)
throws Exception {
+ return newSignedCert(nonce, signingKey, null);
+ }
+
+ private PushCertificate newSignedCert(String nonce, TestKey signingKey,
+ Date now) throws Exception {
PushCertificateIdent ident = new PushCertificateIdent(
signingKey.getFirstUserId(), System.currentTimeMillis(), -7 * 60);
String payload = "certificate version 0.1\n"
@@ -150,6 +167,14 @@
PGPSignatureGenerator gen = new PGPSignatureGenerator(
new BcPGPContentSignerBuilder(
signingKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1));
+
+ if (now != null) {
+ PGPSignatureSubpacketGenerator subGen =
+ new PGPSignatureSubpacketGenerator();
+ subGen.setSignatureCreationTime(false, now);
+ gen.setHashedSubpackets(subGen.generate());
+ }
+
gen.init(PGPSignature.BINARY_DOCUMENT, signingKey.getPrivateKey());
gen.update(payload.getBytes(UTF_8));
PGPSignature sig = gen.generate();
diff --git a/gerrit-gpg/src/test/java/com/google/gerrit/gpg/testutil/TestKeys.java b/gerrit-gpg/src/test/java/com/google/gerrit/gpg/testutil/TestKeys.java
index 97a94b9..ad944c5 100644
--- a/gerrit-gpg/src/test/java/com/google/gerrit/gpg/testutil/TestKeys.java
+++ b/gerrit-gpg/src/test/java/com/google/gerrit/gpg/testutil/TestKeys.java
@@ -784,4 +784,245 @@
+ "-----END PGP PRIVATE KEY BLOCK-----\n");
}
+ /**
+ * Key revoked by an expired key, after that key's expiration.
+ * <p>
+ * Revoked by {@link #expiredKey()}.
+ *
+ * <pre>
+ * pub 2048R/78BF7D7E 2005-08-01 [revoked: 2015-10-20]
+ * Key fingerprint = 916F AB22 5BE7 7585 F59A 994C 001A DF8B 78BF 7D7E
+ * uid Testuser Eight <test8@example.com>
+ * </pre>
+ */
+ public static TestKey keyRevokedByExpiredKeyAfterExpiration() throws Exception {
+ return new TestKey("-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
+ + "Version: GnuPG v1\n"
+ + "\n"
+ + "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\n"
+ + "0d0PyzZT3676mQwmFoebMR9vACAeHjvDxD4F\n"
+ + "=ihWb\n"
+ + "-----END PGP PUBLIC KEY BLOCK-----\n",
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----\n"
+ + "Version: GnuPG v1\n"
+ + "\n"
+ + "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\n"
+ + "DCYWh5sxH28AIB4eO8PEPgU=\n"
+ + "=cSfw\n"
+ + "-----END PGP PRIVATE KEY BLOCK-----\n");
+ }
+
+ /**
+ * Key revoked by an expired key, before that key's expiration.
+ * <p>
+ * Revoked by {@link #expiredKey()}.
+ *
+ * <pre>
+ * pub 2048R/C43BF2E1 2005-08-01 [revoked: 2005-08-01]
+ * Key fingerprint = 916D 6AD6 36A5 CBA6 B5A6 7274 6040 8661 C43B F2E1
+ * uid Testuser Nine <test9@example.com>
+ * </pre>
+ */
+ public static TestKey keyRevokedByExpiredKeyBeforeExpiration() throws Exception {
+ return new TestKey("-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
+ + "Version: GnuPG v1\n"
+ + "\n"
+ + "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\n"
+ + "REW68wsnWjwTtrPG8bqo6cCsOzqGYVt81eU=\n"
+ + "=FnZg\n"
+ + "-----END PGP PUBLIC KEY BLOCK-----\n",
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----\n"
+ + "Version: GnuPG v1\n"
+ + "\n"
+ + "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\n"
+ + "s8bxuqjpwKw7OoZhW3zV5Q==\n"
+ + "=JxsF\n"
+ + "-----END PGP PRIVATE KEY BLOCK-----\n");
+ }
}