From sneak's ruling on the signature scheme decisions (#82 (comment)): pure Go crypto, never a gpg subprocess. Between the two pure-Go options he named neither, so the recommendation stands: OpenPGP, which keeps existing PGP keys and the README's key-fingerprint URL idea.
Problem
mfer/gpg.go signs, exports keys and verifies by running the gpg binary. The library therefore does not work where gpg is not installed, including this repo's own FROM scratch image.
Decided here (standing rulings and the code's design; not for sneak)
Library: github.com/ProtonMail/go-crypto/openpgp. golang.org/x/crypto/openpgp is frozen and deprecated.
No pure-Go library reads gpg-agent's secret key store, so --sign-key (and MFER_SIGN_KEY) names a file holding an OpenPGP secret key, armored or binary, as gpg --export-secret-keys writes it. A file holding more than one primary key is refused. A key held only on a smartcard cannot sign; the README says so.
A protected key's passphrase comes from MFER_SIGN_KEY_PASSPHRASE. Otherwise mfer prompts on the terminal (golang.org/x/term) when there is one, and fails naming that variable when there is not.
The signature stays an armored detached OpenPGP signature over the same canonical string. signingPubKey holds the armored public key. signer holds the primary key's fingerprint in upper-case hex, as today.
SigningOptions carries the secret key's bytes and the passphrase; GPGKeyID goes. The public API exposes no type from the OpenPGP library.
Definition of done
No code runs gpg; mfer/gpg.go's subprocess code, its timeouts and its status-line parsing are gone.
Verification runs in process and keeps every rule from the --require-signature fix (#167): one primary key in the embedded block, exactly one good signature, made by that key or one of its subkeys, and signer equal to its fingerprint. Its tests are kept and pass without gpg.
gen and freshen sign with a key file, protected or not. A manifest signed by the old gpg code (the signed seed in mfer/testdata/fuzz/FuzzNewManifestFromReader) still loads and verifies.
Tests make their keys in process and need no gpg binary.
The --sign-key help text, the README and every line of docs/FORMAT.md that names GPG as the tool say OpenPGP and the key file. The rest of the Signature Scheme section is corrected under the specification work (#84).
make check passes.
Model: opus-5-5
From sneak's ruling on the signature scheme decisions (https://git.eeqj.de/sneak/mfer/issues/82#issuecomment-132656): pure Go crypto, never a `gpg` subprocess. Between the two pure-Go options he named neither, so the recommendation stands: OpenPGP, which keeps existing PGP keys and the README's key-fingerprint URL idea.
## Problem
`mfer/gpg.go` signs, exports keys and verifies by running the `gpg` binary. The library therefore does not work where `gpg` is not installed, including this repo's own `FROM scratch` image.
## Decided here (standing rulings and the code's design; not for sneak)
- Library: `github.com/ProtonMail/go-crypto/openpgp`. `golang.org/x/crypto/openpgp` is frozen and deprecated.
- No pure-Go library reads gpg-agent's secret key store, so `--sign-key` (and `MFER_SIGN_KEY`) names a file holding an OpenPGP secret key, armored or binary, as `gpg --export-secret-keys` writes it. A file holding more than one primary key is refused. A key held only on a smartcard cannot sign; the README says so.
- A protected key's passphrase comes from `MFER_SIGN_KEY_PASSPHRASE`. Otherwise mfer prompts on the terminal (`golang.org/x/term`) when there is one, and fails naming that variable when there is not.
- The signature stays an armored detached OpenPGP signature over the same canonical string. `signingPubKey` holds the armored public key. `signer` holds the primary key's fingerprint in upper-case hex, as today.
- `SigningOptions` carries the secret key's bytes and the passphrase; `GPGKeyID` goes. The public API exposes no type from the OpenPGP library.
## Definition of done
- No code runs `gpg`; `mfer/gpg.go`'s subprocess code, its timeouts and its status-line parsing are gone.
- Verification runs in process and keeps every rule from the `--require-signature` fix (https://git.eeqj.de/sneak/mfer/issues/167): one primary key in the embedded block, exactly one good signature, made by that key or one of its subkeys, and `signer` equal to its fingerprint. Its tests are kept and pass without `gpg`.
- `gen` and `freshen` sign with a key file, protected or not. A manifest signed by the old `gpg` code (the signed seed in `mfer/testdata/fuzz/FuzzNewManifestFromReader`) still loads and verifies.
- Tests make their keys in process and need no `gpg` binary.
- The `--sign-key` help text, the README and every line of `docs/FORMAT.md` that names GPG as the tool say OpenPGP and the key file. The rest of the Signature Scheme section is corrected under the specification work (https://git.eeqj.de/sneak/mfer/issues/84).
- `make check` passes.
Model: opus-5-5
Implemented in #183. mfer now signs and verifies manifests itself with OpenPGP, without running gpg. --sign-key names a secret key file, and a protected key's passphrase comes from MFER_SIGN_KEY_PASSPHRASE or the terminal. Loading keeps the rules from #167; the embedded block's key count now also counts secret key packets. Judgement calls are in the PR body.
Model: opus-5-5
Implemented in https://git.eeqj.de/sneak/mfer/pulls/183. mfer now signs and verifies manifests itself with OpenPGP, without running `gpg`. `--sign-key` names a secret key file, and a protected key's passphrase comes from `MFER_SIGN_KEY_PASSPHRASE` or the terminal. Loading keeps the rules from https://git.eeqj.de/sneak/mfer/issues/167; the embedded block's key count now also counts secret key packets. Judgement calls are in the PR body.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
From sneak's ruling on the signature scheme decisions (#82 (comment)): pure Go crypto, never a
gpgsubprocess. Between the two pure-Go options he named neither, so the recommendation stands: OpenPGP, which keeps existing PGP keys and the README's key-fingerprint URL idea.Problem
mfer/gpg.gosigns, exports keys and verifies by running thegpgbinary. The library therefore does not work wheregpgis not installed, including this repo's ownFROM scratchimage.Decided here (standing rulings and the code's design; not for sneak)
github.com/ProtonMail/go-crypto/openpgp.golang.org/x/crypto/openpgpis frozen and deprecated.--sign-key(andMFER_SIGN_KEY) names a file holding an OpenPGP secret key, armored or binary, asgpg --export-secret-keyswrites it. A file holding more than one primary key is refused. A key held only on a smartcard cannot sign; the README says so.MFER_SIGN_KEY_PASSPHRASE. Otherwise mfer prompts on the terminal (golang.org/x/term) when there is one, and fails naming that variable when there is not.signingPubKeyholds the armored public key.signerholds the primary key's fingerprint in upper-case hex, as today.SigningOptionscarries the secret key's bytes and the passphrase;GPGKeyIDgoes. The public API exposes no type from the OpenPGP library.Definition of done
gpg;mfer/gpg.go's subprocess code, its timeouts and its status-line parsing are gone.--require-signaturefix (#167): one primary key in the embedded block, exactly one good signature, made by that key or one of its subkeys, andsignerequal to its fingerprint. Its tests are kept and pass withoutgpg.genandfreshensign with a key file, protected or not. A manifest signed by the oldgpgcode (the signed seed inmfer/testdata/fuzz/FuzzNewManifestFromReader) still loads and verifies.gpgbinary.--sign-keyhelp text, the README and every line ofdocs/FORMAT.mdthat names GPG as the tool say OpenPGP and the key file. The rest of the Signature Scheme section is corrected under the specification work (#84).make checkpasses.Model: opus-5-5
Implemented in #183. mfer now signs and verifies manifests itself with OpenPGP, without running
gpg.--sign-keynames a secret key file, and a protected key's passphrase comes fromMFER_SIGN_KEY_PASSPHRASEor the terminal. Loading keeps the rules from #167; the embedded block's key count now also counts secret key packets. Judgement calls are in the PR body.Model: opus-5-5