import java.security.Security;
import java.text.MessageFormat;
import java.time.Instant;
-import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.bouncycastle.util.encoders.Hex;
import org.eclipse.jgit.annotations.NonNull;
-import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.AbstractGpgSignatureVerifier;
import org.eclipse.jgit.lib.GpgConfig;
import org.eclipse.jgit.lib.GpgSignatureVerifier;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevObject;
-import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.util.LRUMap;
-import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.StringUtils;
/**
* A {@link GpgSignatureVerifier} to verify GPG signatures using BouncyCastle.
*/
-public class BouncyCastleGpgSignatureVerifier implements GpgSignatureVerifier {
+public class BouncyCastleGpgSignatureVerifier
+ extends AbstractGpgSignatureVerifier {
private static void registerBouncyCastleProviderIfNecessary() {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
return "bc"; //$NON-NLS-1$
}
- @Override
- @Nullable
- public SignatureVerification verifySignature(@NonNull RevObject object,
- @NonNull GpgConfig config) throws IOException {
- if (object instanceof RevCommit) {
- RevCommit commit = (RevCommit) object;
- byte[] signatureData = commit.getRawGpgSignature();
- if (signatureData == null) {
- return null;
- }
- byte[] raw = commit.getRawBuffer();
- // Now remove the GPG signature
- byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' };
- int start = RawParseUtils.headerStart(header, raw, 0);
- if (start < 0) {
- return null;
- }
- int end = RawParseUtils.headerEnd(raw, start);
- // start is at the beginning of the header's content
- start -= header.length + 1;
- // end is on the terminating LF; we need to skip that, too
- if (end < raw.length) {
- end++;
- }
- byte[] data = new byte[raw.length - (end - start)];
- System.arraycopy(raw, 0, data, 0, start);
- System.arraycopy(raw, end, data, start, raw.length - end);
- return verify(data, signatureData);
- } else if (object instanceof RevTag) {
- RevTag tag = (RevTag) object;
- byte[] signatureData = tag.getRawGpgSignature();
- if (signatureData == null) {
- return null;
- }
- byte[] raw = tag.getRawBuffer();
- // The signature is just tacked onto the end of the message, which
- // is last in the buffer.
- byte[] data = Arrays.copyOfRange(raw, 0,
- raw.length - signatureData.length);
- return verify(data, signatureData);
- }
- return null;
- }
-
static PGPSignature parseSignature(InputStream in)
throws IOException, PGPException {
try (InputStream sigIn = PGPUtil.getDecoderStream(in)) {
}
@Override
- public SignatureVerification verify(byte[] data, byte[] signatureData)
+ public SignatureVerification verify(@NonNull GpgConfig config, byte[] data,
+ byte[] signatureData)
throws IOException {
PGPSignature signature = null;
String fingerprint = null;
verified, expired, trust, null);
}
+ @Override
+ public SignatureVerification verify(byte[] data, byte[] signatureData)
+ throws IOException {
+ throw new UnsupportedOperationException(
+ "Call verify(GpgConfig, byte[], byte[]) instead."); //$NON-NLS-1$
+ }
+
private TrustLevel parseGpgTrustPacket(byte[] packet) {
if (packet == null || packet.length < 6) {
// A GPG trust packet has at least 6 bytes.
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/lib/GpgSignatureVerifier.java" type="org.eclipse.jgit.lib.GpgSignatureVerifier">
+ <filter id="404000815">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.GpgSignatureVerifier"/>
+ <message_argument value="verify(GpgConfig, byte[], byte[])"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/storage/pack/PackConfig.java" type="org.eclipse.jgit.storage.pack.PackConfig">
<filter id="336658481">
<message_arguments>
--- /dev/null
+/*
+ * Copyright (C) 2024, Thomas Wolf <twolf@apache.org> and others
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Distribution License v. 1.0 which is available at
+* https://www.eclipse.org/org/documents/edl-v10.php.
+*
+* SPDX-License-Identifier: BSD-3-Clause
+*/
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * Provides a base implementation of
+ * {@link GpgSignatureVerifier#verifySignature(RevObject, GpgConfig)}.
+ *
+ * @since 6.9
+ */
+public abstract class AbstractGpgSignatureVerifier
+ implements GpgSignatureVerifier {
+
+ @Override
+ public SignatureVerification verifySignature(RevObject object,
+ GpgConfig config) throws IOException {
+ if (object instanceof RevCommit) {
+ RevCommit commit = (RevCommit) object;
+ byte[] signatureData = commit.getRawGpgSignature();
+ if (signatureData == null) {
+ return null;
+ }
+ byte[] raw = commit.getRawBuffer();
+ // Now remove the GPG signature
+ byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' };
+ int start = RawParseUtils.headerStart(header, raw, 0);
+ if (start < 0) {
+ return null;
+ }
+ int end = RawParseUtils.nextLfSkippingSplitLines(raw, start);
+ // start is at the beginning of the header's content
+ start -= header.length + 1;
+ // end is on the terminating LF; we need to skip that, too
+ if (end < raw.length) {
+ end++;
+ }
+ byte[] data = new byte[raw.length - (end - start)];
+ System.arraycopy(raw, 0, data, 0, start);
+ System.arraycopy(raw, end, data, start, raw.length - end);
+ return verify(config, data, signatureData);
+ } else if (object instanceof RevTag) {
+ RevTag tag = (RevTag) object;
+ byte[] signatureData = tag.getRawGpgSignature();
+ if (signatureData == null) {
+ return null;
+ }
+ byte[] raw = tag.getRawBuffer();
+ // The signature is just tacked onto the end of the message, which
+ // is last in the buffer.
+ byte[] data = Arrays.copyOfRange(raw, 0,
+ raw.length - signatureData.length);
+ return verify(config, data, signatureData);
+ }
+ return null;
+ }
+}
/*
- * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
import org.eclipse.jgit.revwalk.RevObject;
/**
- * A {@code GpgVerifier} can verify GPG signatures on git commits and tags.
+ * A {@code GpgSignatureVerifier} can verify GPG signatures on git commits and
+ * tags.
*
* @since 5.11
*/
SignatureVerification verifySignature(@NonNull RevObject object,
@NonNull GpgConfig config) throws IOException;
+ /**
+ * Verifies a given signature for given data.
+ *
+ * @param config
+ * the {@link GpgConfig}
+ * @param data
+ * the signature is for
+ * @param signatureData
+ * the ASCII-armored signature
+ * @return a {@link SignatureVerification} describing the outcome
+ * @throws IOException
+ * if the signature cannot be parsed
+ * @throws JGitInternalException
+ * if signature verification fails
+ * @since 6.9
+ */
+ default SignatureVerification verify(@NonNull GpgConfig config, byte[] data,
+ byte[] signatureData) throws IOException {
+ // Default implementation for backwards compatibility; override as
+ // appropriate
+ return verify(data, signatureData);
+ }
/**
* Verifies a given signature for given data.
* if the signature cannot be parsed
* @throws JGitInternalException
* if signature verification fails
+ * @deprecated since 6.9, use {@link #verify(GpgConfig, byte[], byte[])}
+ * instead
*/
+ @Deprecated
public SignatureVerification verify(byte[] data, byte[] signatureData)
throws IOException;