skip to content

What does PGP signature verification in Gradle's dependency verification feature actually verify, and how does it differ from a checksum?

level: juniorimportance: must knowfreq 45%

answer

  1. checksum = integrity only
  2. PGP = integrity + authenticity
  3. .asc detached signature
  4. private signs / public verifies
  5. fallback to checksum when no .asc

basics

~10 s

PGP verification checks that a dependency's .asc signature file was produced by a trusted publisher's private key, proving authenticity. A checksum only proves the bytes match a recorded hash, not who produced them.

solid answer

~50 s

Gradle dependency verification supports two mechanisms recorded in `verification-metadata.xml`: checksums and PGP signatures. A **checksum** (sha256, etc.) only confirms the artifact's bytes equal a value you trust — it proves integrity but says nothing about *who* published it; if an attacker swaps both the artifact and your recorded checksum, you'd never know. **PGP** verifies a detached signature file (the artifact's `.asc`) against the publisher's public key. Because only the holder of the private key can produce a valid signature, a passing check proves both integrity *and* authenticity — the bytes came from someone holding the trusted key. In practice you list `<trusted-keys>` (by long key ID/fingerprint) and Gradle downloads each `.asc`, fetches the public key from a key server or local keyring, and validates the signature. Artifacts without a `.asc` fall back to checksum verification.

code

xml · 6 lines
xml
<configuration>
  <verify-signatures>true</verify-signatures>
</configuration>
<trusted-keys>
  <trusted-key id="ABCDEF0123456789ABCDEF0123456789ABCDEF01" group="com.example"/>
</trusted-keys>

go deeper

for a junior

Know the one-line distinction: checksum = integrity, PGP = integrity + authenticity via a .asc signature and a trusted public key.

for a middle

Explain the .asc detached signature, public/private key roles, and the checksum fallback when no signature is published.

for a senior

Discuss trust scoping (group/module), key sourcing (key server vs keyring), and why both mechanisms coexist in one metadata file.

for a principal

Frame PGP within a supply-chain threat model: what attacks it stops vs. doesn't (e.g. trusting a malicious key), and org policy for which keys are trusted.

## What problem this solves When Gradle resolves a dependency it downloads a binary (a JAR, POM, etc.) from a repository. **Dependency verification** lets you assert, ahead of time, that every artifact you consume is exactly what you expect — defending against a compromised mirror, a hijacked account, or a man-in-the-middle swapping bytes. Gradle records these expectations in a file at `gradle/verification-metadata.xml`. There are two complementary mechanisms: ### Checksums A checksum is a cryptographic hash (e.g. `sha256`) of the artifact's bytes. You record the expected value; Gradle recomputes the hash on download and fails if it differs. This proves **integrity** (the bytes were not altered) but not **authenticity** — a hash carries no notion of an author. If an attacker can alter the artifact *and* the recorded hash (e.g. by compromising the same supply chain), the check passes. ### PGP signatures PGP (Pretty Good Privacy) uses asymmetric cryptography. A publisher signs the artifact with their **private key**, producing a small detached signature file published alongside the artifact with a `.asc` extension (e.g. `foo-1.0.jar.asc`). Anyone can verify that signature using the publisher's **public key**: a valid signature could only have been produced by the private-key holder, so it proves **both integrity and authenticity**. In `verification-metadata.xml` you express trust in keys: ```xml <configuration> <verify-metadata>true</verify-metadata> <verify-signatures>true</verify-signatures> </configuration> <trusted-keys> <trusted-key id="ABCDEF0123456789ABCDEF0123456789ABCDEF01" group="com.example"/> </trusted-keys> ``` When `verify-signatures` is true, for each artifact Gradle: 1. Downloads the artifact's `.asc` detached signature (if the repository publishes one). 2. Obtains the signing public key — from a configured **key server** (e.g. `keyserver.ubuntu.com`) or a **local keyring** file (`gradle/verification-keyring.keys` / `.gpg`). 3. Validates the signature; if it's made by a `<trusted-key>` (matched by fingerprint, optionally scoped to a `group`/`module`), the artifact passes. Artifacts that have **no** `.asc` published can't be PGP-verified, so Gradle falls back to the recorded checksum for those. This is why real-world metadata files contain a mix of `<pgp>` and `<sha256>` entries. ### Key identifiers Keys are referenced by their **fingerprint** (40 hex chars) or **long key ID** (last 16 hex). Always prefer the full fingerprint: short key IDs are vulnerable to collision attacks where an attacker crafts a different key with the same short ID. ### Bottom line Use PGP where publishers sign (most Maven Central artifacts do), and checksums everywhere else. PGP raises the bar from "these bytes match what I saw" to "these bytes were signed by a party I chose to trust."

  • If an artifact has no .asc file published, what happens under signature verification?
    Gradle cannot PGP-verify it and falls back to the recorded checksum for that artifact, so the metadata file ends up mixing <pgp> and <sha256> entries.
  • Why prefer a full fingerprint over a short/long key ID in <trusted-key>?
    Short key IDs (and to a lesser extent long IDs) are susceptible to collision attacks where an attacker forges a different key sharing the same ID. The 40-char fingerprint is collision-resistant.

A checksum is like comparing a parcel against a photo of the contents — right contents, but anyone could have sent it. A PGP signature is a tamper-evident wax seal stamped with a signet ring only the sender owns: it proves both the contents and the sender.

saying these in an interview costs you the question

  • Claiming a checksum proves who published an artifact (it only proves integrity).
  • Saying PGP verification re-hashes the artifact like a checksum — it validates an asymmetric signature instead.

context