Sign with the local backend¶
Sign a checksums manifest using a private key held in a PEM file on disk, via
the reference local backend. This is the library path; in production, release
signing is normally driven by a CLI such as gtb sign, which wraps these same
calls.
The local backend is the lightweight default. It is ideal for onboarding,
local development, and reproducible examples — but a private key on disk is a
weaker posture than a KMS or HSM. For production you typically
implement a custom backend (AWS KMS, GCP,
Azure, HSM) instead.
Activate the backend¶
Backends register themselves on import. Blank-import the local package so its
init() registers the name "local":
import (
"context"
"gitlab.com/phpboyscout/signing"
_ "gitlab.com/phpboyscout/signing/local" // registers "local"
"gitlab.com/phpboyscout/signing/openpgpkey"
)
Point at a PEM key¶
Generate (or reuse) an unencrypted RSA private key of at least 3072 bits:
The keyID you pass to the local backend is simply the path to this PEM
file.
Supported formats:
- PKCS#1 —
-----BEGIN RSA PRIVATE KEY----- - PKCS#8 —
-----BEGIN PRIVATE KEY-----
Limitations (all surface as typed sentinels from the local package):
- Encrypted PEM is unsupported —
local.ErrEncryptedPEMUnsupported. Decrypt out of band first, or use a KMS/HSM backend. - Non-RSA keys are unsupported —
local.ErrUnsupportedKeyType. - A file with no PEM block yields
local.ErrMissingPEMBlock.
Resolve, sign, publish¶
Resolve the backend through the registry, build a crypto.Signer from the PEM
path, then mint the public key and sign the manifest:
backend, err := signing.Get("local") // requires the blank import above
if err != nil {
return err // e.g. signing.ErrUnknownBackend if not imported
}
signer, err := backend.NewSigner(context.Background(), "release.pem") // keyID = PEM path
if err != nil {
return err // e.g. local.ErrEncryptedPEMUnsupported
}
now := time.Now()
pub, err := openpgpkey.ArmoredPublicKey(signer, "Release", "[email protected]", now)
if err != nil {
return err
}
manifest := []byte("sha256 ffmpeg.wasm 0xc0ffee\n")
sig, err := openpgpkey.DetachSign(signer, pub, bytes.NewReader(manifest), now)
if err != nil {
return err
}
// publish: manifest, sig (ASCII-armoured detached signature), and pub
Ship manifest, sig, and pub with your release assets. Consumers embed
pub and run the verify recipe.
Note that ArmoredPublicKey and DetachSign take any crypto.Signer — the
exact same code signs whether the key lives in a PEM file or a remote KMS. Only
the backend differs.
See also¶
- Implement a custom backend — for KMS/HSM signing in production.
- Dependency inversion — why backends are injected rather than bundled.
- The full API and runnable
Exampletests: pkg.go.dev/gitlab.com/phpboyscout/signing/local.