Verify checksums and signatures¶
A self-updating tool downloads a binary and runs it. Verifying what it fetched is the difference between an update mechanism and a remote code execution mechanism.
This module supplies the retrieval half, getting the manifest and signature bytes from the forge. Verifying them is the consumer's job.
Two routes to the same bytes¶
Most releases ship a checksums.txt as an ordinary asset, so the default route
is to find it by name in the asset list. Nothing special is required.
Some sources cannot do that. The direct provider
composes a checksum URL from a template that may point outside any asset listing.
For those, a provider opts into ChecksumProvider:
var cp forge.ChecksumProvider
if forge.As(provider, &cp) {
manifest, err := cp.DownloadChecksumManifest(ctx, rel, forge.DefaultMaxChecksumsSize)
switch {
case err == nil:
return manifest, nil
case errors.Is(err, forge.ErrNotSupported):
// opted out for this configuration — fall through
default:
return nil, err
}
}
// default route: locate checksums.txt among the release assets
Use forge.As rather than a bare type assertion. A decorator that forwards only
the four required Provider methods strips the optional interfaces, and since
absence is a graceful fallback, verification would quietly downgrade instead of
failing.
SignatureProvider mirrors it exactly for a detached signature.
ErrNotSupported is not a failure
Treat "does not implement the interface" and "returned ErrNotSupported"
identically: fall back. Only a different error is fatal. Getting this wrong
turns a working provider into a broken one for every release where the
capability happens to be unconfigured.
Bound the read, always¶
Both methods take a maxBytes cap. Pass one:
These are defaults rather than mandates. Raise them if your tool genuinely ships larger artefacts. The provider enforces whatever you pass, because it is the only code that sees the response before it is buffered; a cap applied afterwards has already let the bytes into memory.
A manifest for a typical multi-OS release is around 1 KiB, so the default is roughly a thousandfold headroom while still stopping a hostile server streaming indefinitely.
What this does not cover¶
forge supplies the retrieval half only. Comparing a hash, verifying a signature
against a key you already trust, and deciding what to do when either fails are
all yours, because a provider returning a manifest has checked nothing. See
what forge does not do.
Checksums also prove nothing about who wrote the manifest: an attacker who can
replace an asset can usually replace checksums.txt beside it. Closing that gap
needs the detached signature.
Related¶
- Verify a release before you trust it: the same ground as a guided tutorial, runnable with no network
- Optional capabilities: why these are opt-in interfaces rather than required methods
- Configuration: the size bounds and who sets them
- Use the direct provider