.. This file is part of PEPSI. Copyright (C) 2026 Pepsi contributors PEPSI is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. ============= pepsi-keydisc ============= *Find a correspondent's public key or certificate, and record how much its source is worth.* Role ==== ``pepsi-keydisc`` is the key-**discovery** layer: given an e-mail address it finds the correspondent's OpenPGP key or S/MIME certificate, records where it came from and whether the lookup was DNSSEC-validated, and caches it in ``pepsi.peer_key``. It is **not** a stage. It connects through ``[pepsi-postgres]`` and is configured entirely by ``[pepsi-keydiscovery]``. Discovery is **asynchronous and outside the stages**. A stage that needs a key it does not have in cache performs no network I/O: it commits the work it has already done, pauses the message and enqueues a request in ``pepsi.key_request``; a discovery instance answers the request and, in the same round-trip that stores the key, releases every message parked on that address. So no stage worker ever waits on a key server, a hundred messages to one correspondent cost one lookup, and a request that settles *without* a key releases its waiters just the same — the services find keys, the stages decide about mail. Reference: :manpage:`pepsi-keydisc(1)`. The chapter :doc:`../key-management` explains the trust ranking these results are judged by, and how the discovery layer relates to the key store as a whole. Features ======== * **One process per method**, from the systemd template ``pepsi-keydisc@.service``: ``@dane``, ``@wkd-advanced``, ``@wkd-direct``, ``@vks`` and (in a build with the ``ldap`` cargo feature) ``@ldap``. A hung LDAP bind cannot stall WKD, and turning a method off is ``systemctl disable pepsi-keydisc@ldap``. An instance whose method is absent from ``[pepsi-keydiscovery] SOURCES`` **refuses to start**, because the stop rule waits only for the methods ``SOURCES`` names. * **The two WKD methods are separate ranks**, and therefore separate instances run concurrently rather than a fallback chain — running direct only "if advanced fails" would accept the weaker answer whenever the stronger one was merely slow. * **DANE is AD-gated.** ``OPENPGPKEY`` (RFC 7929) and ``SMIMEA`` (RFC 8162) are refused outright without the resolver's DNSSEC AD bit: an unvalidated DNS answer is not a weaker answer, it is no answer. * **A hardened fetch** for WKD and VKS: HTTPS only, certificate validation with no insecure mode, at most one HTTPS-to-HTTPS redirect to the same host, refusal to connect to loopback/private/link-local addresses, a byte cap enforced *while streaming*, a deadline on every step, and IDNA A-label conversion. A returned key whose User ID does not name the queried address is discarded. * **probe** — run the whole fan-out for one address and print what each method found, storing nothing (not even a negative-cache entry), as a diagnostic. * **The narrowest database role in the deployment**, provisioned by :doc:`pepsi-setup`: ``peer_key``, ``key_request``, the ``keydisc_*`` functions, and on ``pepsi.ingress`` only ``SELECT`` plus a column-level ``UPDATE (status, timeout)`` — enough to wake a parked message and nothing more. It runs as its own ``pepsi-keydisc`` account with no setuid or setgid bit. See also ======== :doc:`pepsi-keys`, :doc:`pepsi-setup`, :doc:`../key-management`, :doc:`../rfc-index`, :manpage:`pepsi-keydisc(1)`, :manpage:`pepsi-keys(1)`, :manpage:`pepsi.conf(5)`.