Java tutorial
// 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.REFS_GPG_KEYS; import static com.google.gerrit.gpg.PublicKeyStore.keyIdToString; import static com.google.gerrit.gpg.PublicKeyStore.keyToString; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import com.google.gerrit.gpg.testutil.TestKey; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.BCPGOutputStream; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; 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.junit.TestRepository; 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; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.Arrays; public class PushCertificateCheckerTest { private TestRepository<?> tr; private SignedPushConfig signedPushConfig; private PushCertificateChecker checker; @Before public void setUp() throws Exception { TestKey key1 = TestKey.key1(); TestKey key3 = TestKey.key3(); tr = new TestRepository<>(new InMemoryRepository(new DfsRepositoryDescription("repo"))); tr.branch(REFS_GPG_KEYS).commit() .add(PublicKeyStore.keyObjectId(key1.getPublicKey().getKeyID()).name(), key1.getPublicKeyArmored()) .add(PublicKeyStore.keyObjectId(key3.getPublicKey().getKeyID()).name(), key3.getPublicKeyArmored()) .create(); signedPushConfig = new SignedPushConfig(); signedPushConfig.setCertNonceSeed("sekret"); signedPushConfig.setCertNonceSlopLimit(60 * 24); checker = new PushCertificateChecker(new PublicKeyChecker()) { @Override protected Repository getRepository() { return tr.getRepository(); } @Override protected boolean shouldClose(Repository repo) { return false; } }; } @Test public void validCert() throws Exception { PushCertificate cert = newSignedCert(validNonce(), TestKey.key1()); assertProblems(cert); } @Test public void invalidNonce() throws Exception { PushCertificate cert = newSignedCert("invalid-nonce", TestKey.key1()); assertProblems(cert, "Invalid nonce"); } @Test public void missingKey() throws Exception { TestKey key2 = TestKey.key2(); 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 = TestKey.key3(); PushCertificate cert = newSignedCert(validNonce(), key3); assertProblems(cert, "Invalid public key " + keyToString(key3.getPublicKey()) + ":\n Key is expired"); } private String validNonce() { return signedPushConfig.getNonceGenerator().createNonce(tr.getRepository(), System.currentTimeMillis() / 1000); } private PushCertificate newSignedCert(String nonce, TestKey signingKey) 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)); 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))); PushCertificateParser parser = new PushCertificateParser(tr.getRepository(), signedPushConfig); return parser.parse(reader); } private void assertProblems(PushCertificate cert, String... expected) throws Exception { CheckResult result = checker.check(cert); assertEquals(Arrays.asList(expected), result.getProblems()); } }