blob: 8a633ae661fda8f04d0d6301fc4b9d349aaa0099 [file] [log] [blame]
// 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());
}
}