70.1.28. pepsi-stage-vks-confirm¶
follow a key server’s address-verification link, safely
- Manual section:
1
70.1.28.1.1. Name¶
pepsi-stage-vks-confirm - the key-server confirmation stage of the Pepsi pipeline.
70.1.28.1.2. Synopsis¶
pepsi-stage-vks-confirm [GLOBAL-OPTIONS] worker
70.1.28.1.3. Description¶
pepsi-stage-vks-confirm is a stage program run by pepsi-dispatch(1) as a persistent worker reading message ids on standard input.
A key uploaded to a verifying key server is stored but not findable by address until somebody follows a link in a mail the server sends to that address. Doing that by hand for every user’s key does not scale, so this stage does it — and because “fetch a URL found in inbound mail” is a genuinely dangerous primitive, it is a separate program rather than behaviour bolted onto pepsi-keys(1) or a cryptography stage. The dangerous part is isolated in one small, unprivileged program whose position in the pipeline is visible in the configuration.
Place it on the inbound path, anywhere before local delivery. Placement is
forgiving: everything the stage does not act on is advanced to NEXT_STAGE
untouched, which is nearly all mail.
70.1.28.1.4. What it refuses to act on¶
Every condition below must hold before a single byte is fetched. A message that fails any of them is advanced untouched, so the failure mode is that the user receives the mail and can click the link themselves — which is why the conditions can afford to be strict.
The envelope sender’s domain is exactly
VKS_HOST. Not a substring, not a subdomain, and not theFrom:header:keys.example.org.evil.testends with the right string,notkeys.example.orgcontains it, and neither is the key server.SPF or DMARC passed (
REQUIRE_AUTHENTICATION, on by default). AMAIL FROMis a claim; this is what makes it evidence. Note thatdkim=passdeliberately does not count — it says a signature verified, not whose, and an attacker signing with their own domain gets one for free.Every
http(s)link in the body points at that same host. A message naming any other host is refused entirely rather than having the foreign link skipped. A genuine verification mail links to the key server and nowhere else, so a foreign link means either the mail is not what it claims or the key server changed its mail in a way worth looking at before acting on it automatically. The host is read after any userinfo, becausehttps://keys.example.org@evil.test/is a request toevil.testand reads at a glance as the opposite.A recipient is an address we are actually waiting on: a published, active OpenPGP identity that has been uploaded and is not verified yet. An unsolicited verification mail — for an address we never uploaded, or one whose confirmation already arrived — is delivered, not clicked. This is also what stops a stranger making Pepsi issue requests by mailing a served address.
At most
MAX_LINKSlinks are followed per message.The fetch itself goes through the same hardened client key discovery uses: HTTPS only, certificates verified, the peer address resolved here and vetted (so a name resolving to loopback, a private range, link-local or the cloud metadata address is refused), the body capped while streaming, and at most one same-host redirect.
70.1.28.1.5. Confirming is not assumed¶
A 200 from the confirmation URL is the server’s answer to a request, not a
statement that the address is now published. So after following the links the
stage asks the key server whether it now serves our key for the address, and
only a fingerprint match records the identity as verified. Marking it on the
200 alone would stop pepsi-keys(1)’s retry job from ever trying again.
70.1.28.1.6. Audit trail¶
Every decision — accepted, refused and why, each link followed and the status it
returned, and the resulting verdict — is logged at info on the
vks-confirm target. That is deliberately complete rather than sampled: a
program that fetches URLs found in mail must leave a record of every fetch it
made.
70.1.28.1.7. Configuration¶
[stage-<name>] with PROGRAM = pepsi-stage-vks-confirm:
- NEXT_STAGE (required)
Where every message this stage does not consume goes — which is nearly all of them. Required precisely because of that: a stage on the inbound path that silently dropped what it did not recognise would lose ordinary mail. pepsi-setup(1) checks the target resolves.
- VKS_HOST (default: the host of
[pepsi-keys] VKS_SERVER) The one host this stage will accept a verification mail from and follow a link to.
- MAX_LINKS (default 3)
How many links one message may cost. A genuine verification mail carries one; the bound is what stops a message that got past every other check from becoming an arbitrary number of requests.
- DISCARD_CONFIRMED (default
yes) Delete a confirmation mail the stage has acted on instead of delivering it. It is machine mail about an action Pepsi took, addressed to a mailbox whose owner did not ask for it, and it has already been acted on by the time it would arrive. Set it to
noto deliver it as well.- REQUIRE_AUTHENTICATION (default
yes) Require SPF or DMARC
pass, not merely the right envelope sender.
There is no BOUNCE_STAGE: the stage never fails a message.
70.1.28.1.8. Message data¶
The stage loads the full message (Load::Full) because the links are in the
body. It never rewrites the message, never pauses or fails it, and leaves
state untouched, so state.dsn and every other verdict survive.
70.1.28.1.9. Commands¶
- worker
Read message ids on standard input and process each. The only run mode; the dispatcher starts and stops these workers.
70.1.28.1.10. Global Options¶
- -c FILE, –config FILE
Read the configuration from FILE instead of searching the default locations. Must come before the subcommand.
- -L LOGLEVEL, –log LOGLEVEL
Set the logging verbosity (default
info).- -v, –verbose
Show log messages from all sources.
- -h, –help; -V, –version
Print a usage summary / the version and exit.
70.1.28.1.11. Exit Status¶
- 0
The worker exited cleanly.
- 1
An error occurred (a malformed configuration file, an unresolvable stage section, or a failed database connection). The reason is written to the log.
70.1.28.1.12. Examples¶
An inbound pipeline that confirms key-server mail before local delivery:
[stage-vks-confirm]
PROGRAM = pepsi-stage-vks-confirm
NEXT_STAGE = local
VKS_HOST = keys.openpgp.org
Process one message by hand:
echo 4711 | pepsi-stage-vks-confirm -c /etc/pepsi/pepsi.conf worker
70.1.28.1.13. See Also¶
pepsi-keys(1), pepsi-httpd(1), pepsi-keydisc(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7)
70.1.28.1.14. Bugs¶
Report bugs to the Pepsi issue tracker.