Skip to content

Add basic support for gpgp - #685

Merged
vyskocilm merged 10 commits into
gomoni:mainfrom
miska:main
Oct 22, 2026
Merged

vyskocilm merged 10 commits into
gomoni:mainfrom
miska:main

Conversation

@miska

@miska miska commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Hallucinated using LLM, but tested and works 🤷

vyskocilm and others added 2 commits October 22, 2026 16:36
Decrypt: gpg 2.5 sends `PKDECRYPT --kem=PGP` (and `--kem=PQC-PGP` for a
Kyber subkey); the proxy forwarded a bare PKDECRYPT, so every 2.5
decryption failed with "Wrong secret key used". Forward the option,
allowlisted to the forms gpg 2.4.4/2.5.24 send. Accept
`SETKEY --another` for composite PQC subkeys.

Proxy holes, each reproduced against gpg-agent 2.5.24:
- decrypt scope was a signing oracle: the agent keeps one selected key
  for SIGKEY and SETKEY, so SETKEY <grip> + PKSIGN signed. Track the
  selecting verb per session; PKSIGN needs SIGKEY, PKDECRYPT needs
  SETKEY.
- INQUIRE answer injection: a non-D line aborted the inquire and the
  following lines ran unfiltered (returned unpinned keygrips and the
  agent socket path). Accept only D/END/CAN/CANCEL, else end the
  session. Relay only INQUIRE CIPHERTEXT; answer other inquiries
  upstream.
- OPTION forwarded: ttyname=<host path> made pinentry-curses overwrite
  a host file; pinentry-mode=loopback allowed passphrase guessing.
  Answer OPTION locally, never forward.
- SETKEYDESC sandbox text reached the host pinentry; the proxy now
  writes its own.
- UPDATESTARTUPTTY on every upstream connection rewrote the agent's
  startup env; removed.
- primary key pinned for sign = certification oracle
  (`gpg --quick-add-uid` added a UID). Pin signing/encryption subkeys
  only; a key without a signing subkey is refused with the
  `gpg --quick-add-key <fp> ed25519 sign` hint.
- GETINFO forwarded pid/socket_name/std_*_env/getenv; allowlist it,
  forward version (a fixed 2.4.8 made gpg 2.5 warn on every call).

Also: refusals answer `ERR 67109115 Forbidden` (agent's own code, not
ERR 0); exact END/CAN and OK/ERR matching; maxReply overflow and bad
inquire answers end the session; Close ends live connections (new
internal/unixserve, shared with sshproxy, which had the same hang);
bounded upstream dial; SHA-512 sign-probe digest (SHA-256 under id 10
was refused by brainpoolP384r1); HAVEKEY answers OK when any named grip
is pinned, as the agent does.

Policy: ~/.gnupg is a 0700 tmpfs authored by Resolve (gpg warned
"unsafe permissions on homedir" on every call); a profile grant of the
host's ~/.gnupg is refused rather than masked; decrypt-only pins author
no ~/.gitconfig. --dry-run, --json and `profile show` name the key and
scope. gofmt resolve_test.go.

Tests: unit (fake agent + real gpg-agent), goldens, integration
(test/integration/identitygpg_test.go); CI installs gnupg.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vyskocilm

Copy link
Copy Markdown
Contributor

@miska Claude found a lot of funny corner cases and found gpg 2.4 vs 2.5 have changed. I tried to keep it compatible with 2.4, however please check.

vyskocilm and others added 2 commits October 22, 2026 19:00
gomoni#687 profile-file placeholders enumerate every identity key, so the
refusal now names identity.gpg.fingerprint and identity.gpg.scope.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Proxy writes CAN upstream, closes, and answers client ERR without
waiting for agent to read it. Test drained client then read agent log
before agent goroutine recorded line: CI saw `the agent saw [] for
"d abc"`. waitDecryptInquire polls until a terminator is recorded
(5s cap). 900 runs, -cpu 1,2,8: pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vyskocilm
vyskocilm merged commit 9ef504a into gomoni:main Oct 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants