From 5ed11440fc10cd13b225db6b59238252f8274d86 Mon Sep 17 00:00:00 2001 From: Dave Borowitz Date: Wed, 21 Oct 2015 13:54:25 -0400 Subject: [PATCH] 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 --- .../google/gerrit/gpg/PublicKeyChecker.java | 89 +++++-- .../gerrit/gpg/PushCertificateChecker.java | 1 + .../gerrit/gpg/PublicKeyCheckerTest.java | 81 +++++- .../gpg/PushCertificateCheckerTest.java | 25 ++ .../google/gerrit/gpg/testutil/TestKeys.java | 241 ++++++++++++++++++ 5 files changed, 418 insertions(+), 19 deletions(-) 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 3bbad9baf0..e4c81dfd0a 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 org.slf4j.LoggerFactory; 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 @@ public class PublicKeyChecker { private PublicKeyStore store; private Map trusted; private int maxTrustDepth; + private Date effectiveTime = new Date(); /** * Enable web-of-trust checks. @@ -109,6 +111,24 @@ public class PublicKeyChecker { return this; } + /** + * Set the effective time for checking the key. + *

+ * 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. * @@ -141,7 +161,7 @@ public class PublicKeyChecker { private CheckResult check(PGPPublicKey key, int depth, boolean expand, Set 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 @@ public class PublicKeyChecker { return CheckResult.create(status, problems); } - private CheckResult checkBasic(PGPPublicKey key) { + private CheckResult checkBasic(PGPPublicKey key, Date now) { List 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 problems) { + private void gatherRevocationProblems(PGPPublicKey key, Date now, + List problems) { try { List revocations = new ArrayList<>(); Map 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 @@ public class PublicKeyChecker { } } - 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 revocations, Map revokers) throws PGPException { @SuppressWarnings("unchecked") @@ -221,7 +259,10 @@ public class PublicKeyChecker { 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 @@ public class PublicKeyChecker { 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 @@ public class PublicKeyChecker { 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 @@ public class PublicKeyChecker { Iterator 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 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 e87a0ee6dd..0a0fff769f 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 @@ public abstract class PushCertificateChecker { } 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 a611ec9484..576ffbd488 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 @@ package com.google.gerrit.gpg; 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.Rule; 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 @@ public class PublicKeyCheckerTest { @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 @@ -201,6 +215,24 @@ public class PublicKeyCheckerTest { assertProblems(kr.getPublicKey()); } + @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()); @@ -221,6 +253,49 @@ public class PublicKeyCheckerTest { "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 @@ public class PublicKeyCheckerTest { 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 9b1c058c2e..977895859d 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.ArmoredOutputStream; 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.ByteArrayInputStream; 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 @@ public class PushCertificateCheckerTest { + ":\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 @@ public class PushCertificateCheckerTest { 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 @@ public class PushCertificateCheckerTest { 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 97a94b90d2..ad944c51d7 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 @@ public class TestKeys { + "-----END PGP PRIVATE KEY BLOCK-----\n"); } + /** + * Key revoked by an expired key, after that key's expiration. + *

+ * Revoked by {@link #expiredKey()}. + * + *

+   * 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>
+   * 
+ */ + 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. + *

+ * Revoked by {@link #expiredKey()}. + * + *

+   * 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>
+   * 
+ */ + 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"); + } }