summaryrefslogtreecommitdiffstats
path: root/javatests/com/google/gerrit/gpg/PushCertificateCheckerTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'javatests/com/google/gerrit/gpg/PushCertificateCheckerTest.java')
-rw-r--r--javatests/com/google/gerrit/gpg/PushCertificateCheckerTest.java204
1 files changed, 204 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/gpg/PushCertificateCheckerTest.java b/javatests/com/google/gerrit/gpg/PushCertificateCheckerTest.java
new file mode 100644
index 0000000000..266f8684fa
--- /dev/null
+++ b/javatests/com/google/gerrit/gpg/PushCertificateCheckerTest.java
@@ -0,0 +1,204 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.gpg;
+
+import static com.google.gerrit.gpg.PublicKeyStore.keyIdToString;
+import static com.google.gerrit.gpg.PublicKeyStore.keyToString;
+import static com.google.gerrit.gpg.testing.TestKeys.expiredKey;
+import static com.google.gerrit.gpg.testing.TestKeys.validKeyWithExpiration;
+import static com.google.gerrit.gpg.testing.TestKeys.validKeyWithoutExpiration;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.gpg.testing.TestKey;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+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;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PushCertificate;
+import org.eclipse.jgit.transport.PushCertificateIdent;
+import org.eclipse.jgit.transport.PushCertificateParser;
+import org.eclipse.jgit.transport.SignedPushConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PushCertificateCheckerTest {
+ private InMemoryRepository repo;
+ private PublicKeyStore store;
+ private SignedPushConfig signedPushConfig;
+ private PushCertificateChecker checker;
+
+ @Before
+ public void setUp() throws Exception {
+ TestKey key1 = validKeyWithoutExpiration();
+ TestKey key3 = expiredKey();
+ repo = new InMemoryRepository(new DfsRepositoryDescription("repo"));
+ store = new PublicKeyStore(repo);
+ store.add(key1.getPublicKeyRing());
+ store.add(key3.getPublicKeyRing());
+
+ PersonIdent ident = new PersonIdent("A U Thor", "author@example.com");
+ CommitBuilder cb = new CommitBuilder();
+ cb.setAuthor(ident);
+ cb.setCommitter(ident);
+ assertEquals(RefUpdate.Result.NEW, store.save(cb));
+
+ signedPushConfig = new SignedPushConfig();
+ signedPushConfig.setCertNonceSeed("sekret");
+ signedPushConfig.setCertNonceSlopLimit(60 * 24);
+ checker = newChecker(true);
+ }
+
+ private PushCertificateChecker newChecker(boolean checkNonce) {
+ PublicKeyChecker keyChecker = new PublicKeyChecker().setStore(store);
+ return new PushCertificateChecker(keyChecker) {
+ @Override
+ protected Repository getRepository() {
+ return repo;
+ }
+
+ @Override
+ protected boolean shouldClose(Repository repo) {
+ return false;
+ }
+ }.setCheckNonce(checkNonce);
+ }
+
+ @Test
+ public void validCert() throws Exception {
+ PushCertificate cert = newSignedCert(validNonce(), validKeyWithoutExpiration());
+ assertNoProblems(cert);
+ }
+
+ @Test
+ public void invalidNonce() throws Exception {
+ PushCertificate cert = newSignedCert("invalid-nonce", validKeyWithoutExpiration());
+ assertProblems(cert, "Invalid nonce");
+ }
+
+ @Test
+ public void invalidNonceNotChecked() throws Exception {
+ checker = newChecker(false);
+ PushCertificate cert = newSignedCert("invalid-nonce", validKeyWithoutExpiration());
+ assertNoProblems(cert);
+ }
+
+ @Test
+ public void missingKey() throws Exception {
+ TestKey key2 = validKeyWithExpiration();
+ PushCertificate cert = newSignedCert(validNonce(), key2);
+ assertProblems(cert, "No public keys found for key ID " + keyIdToString(key2.getKeyId()));
+ }
+
+ @Test
+ public void invalidKey() throws Exception {
+ TestKey key3 = expiredKey();
+ PushCertificate cert = newSignedCert(validNonce(), key3);
+ assertProblems(
+ cert, "Invalid public key " + keyToString(key3.getPublicKey()) + ":\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);
+ assertNoProblems(cert);
+ }
+
+ private String validNonce() {
+ return signedPushConfig
+ .getNonceGenerator()
+ .createNonce(repo, System.currentTimeMillis() / 1000);
+ }
+
+ 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"
+ + "pusher "
+ + ident.getRaw()
+ + "\n"
+ + "pushee test://localhost/repo.git\n"
+ + "nonce "
+ + nonce
+ + "\n"
+ + "\n"
+ + "0000000000000000000000000000000000000000"
+ + " deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
+ + " refs/heads/master\n";
+ 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();
+
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try (BCPGOutputStream out = new BCPGOutputStream(new ArmoredOutputStream(bout))) {
+ sig.encode(out);
+ }
+
+ String cert = payload + new String(bout.toByteArray(), UTF_8);
+ Reader reader = new InputStreamReader(new ByteArrayInputStream(cert.getBytes(UTF_8)), UTF_8);
+ PushCertificateParser parser = new PushCertificateParser(repo, signedPushConfig);
+ return parser.parse(reader);
+ }
+
+ private void assertProblems(PushCertificate cert, String first, String... rest) throws Exception {
+ List<String> expected = new ArrayList<>();
+ expected.add(first);
+ expected.addAll(Arrays.asList(rest));
+ CheckResult result = checker.check(cert).getCheckResult();
+ assertEquals(expected, result.getProblems());
+ }
+
+ private void assertNoProblems(PushCertificate cert) {
+ CheckResult result = checker.check(cert).getCheckResult();
+ assertEquals(Collections.emptyList(), result.getProblems());
+ }
+}