diff options
Diffstat (limited to 'gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java')
-rw-r--r-- | gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java | 217 |
1 files changed, 0 insertions, 217 deletions
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 deleted file mode 100644 index 95b89d08b8..0000000000 --- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java +++ /dev/null @@ -1,217 +0,0 @@ -// 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.extensions.common.GpgKeyInfo.Status.BAD; -import static com.google.gerrit.extensions.common.GpgKeyInfo.Status.OK; -import static com.google.gerrit.extensions.common.GpgKeyInfo.Status.TRUSTED; -import static com.google.gerrit.gpg.PublicKeyStore.keyIdToString; -import static com.google.gerrit.gpg.PublicKeyStore.keyToString; - -import com.google.common.base.Joiner; -import com.google.gerrit.extensions.common.GpgKeyInfo.Status; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.bouncycastle.bcpg.ArmoredInputStream; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPObjectFactory; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureList; -import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.transport.PushCertificate; -import org.eclipse.jgit.transport.PushCertificate.NonceStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** Checker for push certificates. */ -public abstract class PushCertificateChecker { - private static final Logger log = LoggerFactory.getLogger(PushCertificateChecker.class); - - public static class Result { - private final PGPPublicKey key; - private final CheckResult checkResult; - - private Result(PGPPublicKey key, CheckResult checkResult) { - this.key = key; - this.checkResult = checkResult; - } - - public PGPPublicKey getPublicKey() { - return key; - } - - public CheckResult getCheckResult() { - return checkResult; - } - } - - private final PublicKeyChecker publicKeyChecker; - - private boolean checkNonce; - - protected PushCertificateChecker(PublicKeyChecker publicKeyChecker) { - this.publicKeyChecker = publicKeyChecker; - checkNonce = true; - } - - /** Set whether to check the status of the nonce; defaults to true. */ - public PushCertificateChecker setCheckNonce(boolean checkNonce) { - this.checkNonce = checkNonce; - return this; - } - - /** - * Check a push certificate. - * - * @return result of the check. - */ - public final Result check(PushCertificate cert) { - if (checkNonce && cert.getNonceStatus() != NonceStatus.OK) { - return new Result(null, CheckResult.bad("Invalid nonce")); - } - List<CheckResult> results = new ArrayList<>(2); - Result sigResult = null; - try { - PGPSignature sig = readSignature(cert); - if (sig != null) { - @SuppressWarnings("resource") - Repository repo = getRepository(); - try (PublicKeyStore store = new PublicKeyStore(repo)) { - sigResult = checkSignature(sig, cert, store); - results.add(checkCustom(repo)); - } finally { - if (shouldClose(repo)) { - repo.close(); - } - } - } else { - results.add(CheckResult.bad("Invalid signature format")); - } - } catch (PGPException | IOException e) { - String msg = "Internal error checking push certificate"; - log.error(msg, e); - results.add(CheckResult.bad(msg)); - } - - return combine(sigResult, results); - } - - private static Result combine(Result sigResult, List<CheckResult> results) { - // Combine results: - // - If any input result is BAD, the final result is bad. - // - If sigResult is TRUSTED and no other result is BAD, the final result - // is TRUSTED. - // - Otherwise, the result is OK. - List<String> problems = new ArrayList<>(); - boolean bad = false; - for (CheckResult result : results) { - problems.addAll(result.getProblems()); - bad |= result.getStatus() == BAD; - } - Status status = bad ? BAD : OK; - - PGPPublicKey key; - if (sigResult != null) { - key = sigResult.getPublicKey(); - CheckResult cr = sigResult.getCheckResult(); - problems.addAll(cr.getProblems()); - if (cr.getStatus() == BAD) { - status = BAD; - } else if (!bad && cr.getStatus() == TRUSTED) { - status = TRUSTED; - } - } else { - key = null; - } - return new Result(key, CheckResult.create(status, problems)); - } - - /** - * Get the repository that this checker should operate on. - * - * <p>This method is called once per call to {@link #check(PushCertificate)}. - * - * @return the repository. - * @throws IOException if an error occurred reading the repository. - */ - protected abstract Repository getRepository() throws IOException; - - /** - * @param repo a repository previously returned by {@link #getRepository()}. - * @return whether this repository should be closed before returning from {@link - * #check(PushCertificate)}. - */ - protected abstract boolean shouldClose(Repository repo); - - /** - * Perform custom checks. - * - * <p>Default implementation reports no problems, but may be overridden by subclasses. - * - * @param repo a repository previously returned by {@link #getRepository()}. - * @return the result of the custom check. - */ - protected CheckResult checkCustom(Repository repo) { - return CheckResult.ok(); - } - - private PGPSignature readSignature(PushCertificate cert) throws IOException { - ArmoredInputStream in = - new ArmoredInputStream(new ByteArrayInputStream(Constants.encode(cert.getSignature()))); - PGPObjectFactory factory = new BcPGPObjectFactory(in); - Object obj; - while ((obj = factory.nextObject()) != null) { - if (obj instanceof PGPSignatureList) { - PGPSignatureList sigs = (PGPSignatureList) obj; - if (!sigs.isEmpty()) { - return sigs.get(0); - } - } - } - return null; - } - - private Result checkSignature(PGPSignature sig, PushCertificate cert, PublicKeyStore store) - throws PGPException, IOException { - PGPPublicKeyRingCollection keys = store.get(sig.getKeyID()); - if (!keys.getKeyRings().hasNext()) { - return new Result( - null, - CheckResult.bad("No public keys found for key ID " + keyIdToString(sig.getKeyID()))); - } - PGPPublicKey signer = PublicKeyStore.getSigner(keys, sig, Constants.encode(cert.toText())); - if (signer == null) { - return new Result( - null, CheckResult.bad("Signature by " + keyIdToString(sig.getKeyID()) + " is not valid")); - } - CheckResult result = - publicKeyChecker.setStore(store).setEffectiveTime(sig.getCreationTime()).check(signer); - if (!result.getProblems().isEmpty()) { - StringBuilder err = - new StringBuilder("Invalid public key ") - .append(keyToString(signer)) - .append(":\n ") - .append(Joiner.on("\n ").join(result.getProblems())); - return new Result(signer, CheckResult.create(result.getStatus(), err.toString())); - } - return new Result(signer, result); - } -} |