Allow configuring trusted keys during signed push checking
Admins can specify key fingerprints in gerrit.config with
receive.trustedKey, which get passed to the public key web of trust
checker from the previous commit.
Change-Id: Ic44b83fd5ed2a9399fce23e55d312bafebd85cc1
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index c648725..1b497a9 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2982,6 +2982,14 @@
+
Common unit suffixes of 'k', 'm', or 'g' are supported.
+[[receive.maxTrustDepth]]receive.maxTrustDepth::
++
+If signed push validation is link:#receive.enableSignedPush[enabled],
+set to the maximum depth to search when checking if a key is
+link:#receive.trustedKey[trusted].
++
+Default is 0, meaning only explicitly trusted keys are allowed.
+
[[receive.threadPoolSize]]receive.threadPoolSize::
+
Maximum size of the thread pool in which the change data in received packs is
@@ -3000,6 +3008,25 @@
Default is 2 minutes. If no unit is specified, milliseconds
is assumed.
+[[receive.trustedKey]]receive.trustedKey::
++
+List of GPG key fingerprints that should be considered trust roots by
+the server when signed push validation is
+link:#receive.enableSignedPush[enabled]. A key is trusted by the server
+if it is either in this list, or a path of trust signatures leads from
+the key to a configured trust root. The maximum length of the path is
+determined by link:#receive.maxTrustDepth[`receive.maxTrustDepth`].
++
+Key fingerprints can be displayed with `gpg --list-keys
+--with-fingerprint`.
++
+Trust signatures can be added to a key using the `tsign` command to
+link:https://www.gnupg.org/documentation/manuals/gnupg/OpenPGP-Key-Management.html[
+`gpg --edit-key`], after which the signed key should be re-uploaded.
++
+If no keys are specified, web-of-trust checks are disabled. This is the
+default behavior.
+
[[repository]]
=== Section repository
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
index 8a8269f..0680a14 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
@@ -17,13 +17,16 @@
import static com.google.gerrit.gpg.PublicKeyStore.keyIdToString;
import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_GPGKEY;
+import com.google.common.base.CharMatcher;
import com.google.common.base.MoreObjects;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Ordering;
+import com.google.common.io.BaseEncoding;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -32,10 +35,12 @@
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.transport.PushCertificateIdent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
@@ -56,10 +61,26 @@
private final String webUrl;
private final Provider<IdentifiedUser> userProvider;
+ private static List<Fingerprint> getTrustedFingerprints(Config cfg) {
+ String[] strs = cfg.getStringList("receive", null, "trustedKey");
+ if (strs == null || strs.length == 0) {
+ return null;
+ }
+ List<Fingerprint> fps = new ArrayList<>(strs.length);
+ for (String str : strs) {
+ str = CharMatcher.WHITESPACE.removeFrom(str).toUpperCase();
+ fps.add(new Fingerprint(BaseEncoding.base16().decode(str)));
+ }
+ return fps;
+ }
+
@Inject
GerritPublicKeyChecker(
+ @GerritServerConfig Config cfg,
@CanonicalWebUrl String webUrl,
Provider<IdentifiedUser> userProvider) {
+ super(cfg.getInt("receive", null, "maxTrustDepth", 0),
+ getTrustedFingerprints(cfg));
this.webUrl = webUrl;
this.userProvider = userProvider;
}