85.1.45. pepsi-keydisc¶
find a correspondent’s public key or certificate
- Section du manuel:
1
85.1.45.1.1. Nom¶
pepsi-keydisc - découverte de clés asynchrone, un service par méthode.
85.1.45.1.2. Synopsis¶
pepsi-keydisc [GLOBAL-OPTIONS] serve METHOD
pepsi-keydisc [GLOBAL-OPTIONS] probe ADDRESS
85.1.45.1.3. Description¶
pepsi-keydisc trouve la clé OpenPGP ou le certificat S/MIME d’un correspondant, note d’où il vient et ce que vaut cette source, et le met en cache dans pepsi.peer_key (voir pepsi-keys(1)). Trouver une clé est facile ; savoir s’il faut y croire est tout le problème : chaque résultat porte donc sa source et l’indication de si la consultation qui l’a produit était validée DNSSEC, et la politique de l’étape consommatrice décide de ce qui est suffisant.
La découverte est asynchrone et vit hors des étapes. Une étape qui a besoin d’une clé absente du cache ne fait jamais d’E/S réseau propre : elle valide le travail qu’elle peut conserver, met le message en pause et met une demande en file dans pepsi.key_request ; une instance de pepsi-keydisc répond à la demande et, dans le même aller-retour qui stocke la clé, libère chaque message garé sur cette adresse
stage cache hit -> use the key
fresh negative -> the no-key path, at once
cache miss -> park: commit, pause, enqueue
pepsi-keydisc@... LISTEN key_request -> look up -> store the key AND
release every parked message
Ce qui est validé au moment du garage relève de la décision de l’étape, non de ce programme. En particulier, pepsi-stage-decrypt(1) gare un message S/MIME avec le texte clair déchiffré validé — la signature imbriquée survit comme une couche MIME ordinaire — mais gare un message OpenPGP inchangé, parce qu’une signature OpenPGP ne vit qu’à l’intérieur du flux de paquets et que valider le texte clair détruirait la preuve même que la clé est allée chercher.
Cela supprime entièrement « un serveur de clés lent immobilise un worker d’étape » plutôt que de le borner. La demande est indexée sur l”adresse : cent messages vers un même correspondant coûtent donc une seule consultation et sont libérés ensemble. Une demande qui se conclut sans clé libère ceux qui l’attendent exactement comme une demande qui a trouvé une clé : les services trouvent les clés, les étapes décident du courrier.
Ce n’est pas une étape. Il se connecte à la base de données partagée via la section [pepsi-postgres] et se configure entièrement par [pepsi-keydiscovery] (voir pepsi.conf(5)).
85.1.45.1.4. Une instance par méthode¶
Il y a un binaire et une section de configuration, mais un processus par méthode de découverte, démarré depuis l’unité gabarit systemd pepsi-keydisc@.service :
pepsi-keydisc@daneOPENPGPKEYDNS (RFC 7929) etSMIMEA(RFC 8162), sous une partie locale hachée. Les deux sont refusés sans le bit AD DNSSEC du résolveur.pepsi-keydisc@wkd-advancedLe Web Key Directory à
openpgpkey.<domain>, sous/.well-known/openpgpkey/<domain>/hu/<hash>.pepsi-keydisc@wkd-directLe Web Key Directory au domaine lui-même, sous
/.well-known/openpgpkey/hu/<hash>.pepsi-keydisc@vksLes serveurs de clés vérificateurs de
VKS_SERVERS, à/vks/v1/by-email/<address>.pepsi-keydisc@ldapL’annuaire LDAP configuré ; uniquement dans un build comportant la fonctionnalité
ldap.
pepsi.target démarre les quatre premières, qui constituent les SOURCES par défaut.
C’est ce découpage qui procure l’isolation : un bind LDAP bloqué ne peut pas caler WKD, et désactiver une méthode se fait par systemctl mask --now pepsi-keydisc@vks (en la retirant aussi de SOURCES) plutôt que par le redémarrage de quelque chose de partagé. Les deux méthodes Web Key Directory sont des rangs distincts, et donc des instances distinctes qui s’exécutent simultanément — jamais une chaîne de repli, puisque n’exécuter la méthode directe que « si l’avancée échoue » accepterait silencieusement la réponse la plus faible chaque fois que la plus forte serait simplement lente.
C’est un écart délibéré au §3.1 de draft-koch-openpgp-webkey-service, qui exige que la méthode avancée soit essayée en premier et que la directe ne soit utilisée que là où le sous-domaine openpgpkey n’existe pas du tout. L’ordre du draft porte sur la confiance plutôt que sur la vitesse : le /.well-known/openpgpkey/ de l’apex est servi par ce qui fait tourner le site web du domaine, souvent une partie différente de son opérateur de courrier ; un domaine qui publie correctement sous openpgpkey.<domain> voit donc tout de même son apex consulté ici — et une réponse venue de là est stockée au rang wkd-direct, au-dessus de LDAP, de VKS et de tout ce qui est moissonné dans le courrier. Là où cela compte, SOURCES peut lister wkd-advanced sans wkd-direct.
Une instance dont la méthode n’apparaît pas dans [pepsi-keydiscovery] SOURCES refuse de démarrer, avec un message nommant ce que SOURCES liste effectivement. Ce n’est pas de la pédanterie : la règle d’arrêt à délai de grâce par rang n’attend que les méthodes nommées par SOURCES, de sorte qu’une instance non listée répondrait à une demande que personne n’attend.
Moissonner des clés dans le courrier entrant (parties application/pgp-keys, certificats de signataire S/MIME, en-tête Autocrypt:) n’est pas un service de découverte et n’a pas d’instance. Cela s’exécute en ligne là où le message se trouve déjà, dans pepsi-stage-autocrypt-learn(1), ne coûte aucune E/S réseau et écrit par le même chemin — de sorte qu’une clé moissonnée libère elle aussi tout ce qui est garé sur cette adresse. inbound est par conséquent refusé dans SOURCES.
Il en va de même de gossip, les clés que cette étape lit dans les champs Autocrypt-Gossip: à l’intérieur d’un message arrivé chiffré (Autocrypt Level 1 §5.3). C’est un second échelon en ligne plutôt qu’une variante d”inbound, parce que ces clés sont celles de tiers plutôt que celle de l’expéditeur, et que l’échelle doit pouvoir les distinguer.
Notez où se situe l”« en ligne » : pepsi-stage-decrypt(1) extrait les certificats que porte un message afin de vérifier sa signature, puis les abandonne — il ne stocke rien. Un pipeline sans étape pepsi-stage-autocrypt-learn n’apprend jamais aucune clé depuis le courrier, quelle que soit la quantité de matériel qui arrive, et aucune configuration de [stage-decrypt] n’y change quoi que ce soit.
85.1.45.1.5. Quelle clé l’emporte en cas de conflit¶
Une clé dont l”empreinte est déjà stockée pour la même adresse et le même protocole n’est pas du tout un conflit : la ligne est mise à jour sur place (sa source, sa validité, son expiration et sa date d’effet Autocrypt sont reportées, la source ne pouvant que s’améliorer) et la réponse est refreshed. Cela se produit avant chacun des tests ci-dessous, de sorte que revoir une clé épinglée rafraîchit tout de même ce que l’on sait d’elle.
Lorsqu’une clé découverte diffère de tout ce qui est stocké pour cette adresse et ce protocole, le magasin décide en une seule étape côté serveur, dans cet ordre :
une ligne épinglée n’est jamais délogée, quoi qu’il arrive ;
une source strictement mieux classée remplace tout ce qui est stocké — de sorte que WKD déloge une clé moissonnée, une entrée d’opérateur déloge WKD, et une clé apprise par gossip ne déloge rien du tout ;
le plus récent l’emporte à l’intérieur du palier Autocrypt (ci-dessous) ;
sinon la clé stockée est conservée, la nouvelle n’est pas stockée, et la réponse est rapportée comme
rejected.
85.1.45.1.5.1. Le plus récent l’emporte dans le palier Autocrypt¶
La mise à jour de l’état des pairs d’Autocrypt Level 1 est le plus jeune l’emporte : un client stocke la clé du plus jeune message qu’il ait vu portant un en-tête Autocrypt:. La règle 2 seule ne peut exprimer cela — elle refuserait la deuxième clé Autocrypt jamais vue pour une adresse et garderait la première à jamais, de sorte qu’un correspondant qui réinstalle son client, change d’appareil ou renouvelle sa clé continuerait de recevoir du courrier chiffré vers une clé qu’il ne détient plus, ce qui est exactement l’échec du courrier illisible qu’Autocrypt existe pour éviter.
La règle 3 laisse donc une clé plus récente l’emporter, et elle est confinée de sorte qu’elle ne puisse jamais trancher qu’entre des prétentions de même nature. Elle s’applique lorsque toutes ces conditions sont réunies :
la source entrante est
inboundougossip; etchaque clé actuellement stockée pour cette adresse et ce protocole est aussi
inboundougossip— rien de ce qu’un propriétaire ou un opérateur a publié n’est jamais en jeu ; etla source entrante se classe au moins aussi haut que la source stockée, de sorte qu”
inboundremplaceinboundet quegossipremplacegossip, mais que la présentation par un tiers ne puisse jamais retirer la ligne à ce que le propriétaire de l’adresse a dit de lui-même ; etla date d’effet du message entrant est strictement plus récente que celle qui est stockée.
La date d’effet est l’en-tête Date: du message, plafonné de sorte qu’il ne puisse jamais être dans le futur, et l’heure de réception lorsque l’en-tête est absent ou inanalysable — la définition propre du Level 1. Des dates égales relèvent donc du premier arrivé (un message redistribué ne peut pas faire basculer la ligne), et une clé qui ne porte aucune date d’effet — toute méthode réseau — ne déloge jamais rien.
Le prix de la règle est ce qu’elle remet à un attaquant. La moisson est indexée sur l’en-tête From:, que l’expéditeur écrit, et l’authentification entrante est fail-open : un From: falsifié peut donc déloger une clé qui n’était elle-même jamais que de la confiance au premier usage. C’est le compromis propre à Autocrypt — il défend contre la collecte passive, non contre un attaquant actif sur le chemin — et il est borné des quatre côtés ci-dessus : rien de ce qui est publié par le domaine (WKD, DANE), par un serveur de clés, par un annuaire ou par l’opérateur ne peut être touché, ni une ligne épinglée. Un opérateur qui n’en veut pas règle [pepsi-keydiscovery] MIN_TRUST au-dessus du palier, ou épingle les clés qui comptent avec pepsi-keys peer pin (voir pepsi-keys(1)) ; notez qu’une adresse pour laquelle ce déploiement détient une identité reçoit sa réponse de cette identité et jamais du cache des pairs.
Un remplacement au titre de la règle 3 est rapporté comme rotated plutôt que replaced et écrit une ligne key.peer.rotate dans le journal d’audit dans la même instruction, de sorte qu’une rotation ne peut avoir lieu sans sa trace. Le seul appelant qui puisse en déclencher une — l’apprentissage entrant, pepsi-stage-autocrypt-learn(1) — envoie aussi un courrier aux destinataires locaux du message, et peut restreindre la règle avec ACCEPT_ROTATION = expired (chaque clé stockée doit être enregistrée comme révoquée ou expirée), auquel cas une rotation refusée est rapportée comme held et auditée comme key.peer.rotate.held. Les méthodes réseau n’atteignent jamais la règle 3.
La même empreinte revue est un rafraîchissement, non un conflit, et la ligne reprend la meilleure des deux sources. Un tel rafraîchissement est rapporté à part : une clé stockée depuis gossip que le propre message de son propriétaire (source inbound) porte désormais est rapportée comme promoted et auditée comme key.peer.promote, jamais comme une rotation — la promotion hors du gossip du §5.3 d’Autocrypt Level 1.
85.1.45.1.6. Commandes¶
- serve METHOD
Exécute l’instance de service d’une méthode jusqu’à interruption. METHOD vaut
dane,wkd-advanced,wkd-direct,vksouldap— le nom d’instance du gabarit systemd — et doit figurer dans[pepsi-keydiscovery] SOURCES.L’instance fait un
LISTENsur le canalkey_request, dont la charge utile est l’identifiant de demande, répond à chaque demande dont cette méthode est encore redevable, et effectue un balayage au démarrage et à chaque reconnexion du listener, de sorte que rien de ce qui a été soulevé en son absence ne soit perdu. Entre les notifications, elle cadence un court balayage de règlement : une fenêtre de grâce par rang est un instant, il faut donc que quelque chose regarde l’horloge, et un déploiement exécutant la moindre instance dispose donc de ce balayage. Une consultation isolée en échec est consignée sur la demande (ce qui sélectionne le courtERROR_TTLplutôt que le longNEGATIVE_TTL) et ne fait jamais tomber le listener.- probe ADDRESS
Exécute une fois l”intégralité de l’éventail pour une adresse et affiche ce que chaque méthode a trouvé — le protocole, l’empreinte, la taille, et
dnssecpour une réponse DANE validée par AD — ou l’erreur rencontrée, ou qu’elle n’a rien trouvé.Délibérément en lecture seule : il ne stocke rien, ni la clé ni une entrée de cache négatif. Un opérateur qui diagnostique « pourquoi ce correspondant n’a-t-il pas de clé » veut voir la réponse de chaque méthode, et non qu’un diagnostic écrive une entrée négative qui supprimerait ensuite la vraie consultation pendant une journée. Pour consulter une adresse et stocker le résultat, utilisez
pepsi-keys peer refresh --address(voir pepsi-keys(1)).Une adresse exclue par
ALLOW_DOMAINS/DENY_DOMAINSest signalée comme telle et n’est pas interrogée.
85.1.45.1.7. Privilèges¶
Les services s’exécutent sous leur propre compte non privilégié, pepsi-keydisc — non l’utilisateur de service pepsi ni pepsi-crypto. Ce démon analyse du matériel de clé récupéré sur l’internet ouvert (un corps WKD hostile, une réponse de serveur de clés, un enregistrement DNS), ce qui en fait le processus le plus susceptible d’être compromis ici : pepsi-setup(1) lui donne donc le rôle de base de données le plus étroit du déploiement :
SELECT/INSERT/UPDATE/DELETEsurpepsi.peer_key— remplir le cache est tout son travail, et la règle de conflit doit pouvoir remplacer une ligne ;SELECT/INSERT/UPDATEsurpepsi.key_request— la file de travail à laquelle il répond ;EXECUTEsur les fonctionskeydisc_*et les deux helperscrypto_*qu’elles appellent ;sur
pepsi.workqueue,SELECTplus unUPDATE (status, timeout)au niveau colonne — et rien d’autre.
Ces deux colonnes suffisent exactement à faire passer une ligne garée de paused à pending, ce qui se produit dans keydisc_resolve/keydisc_sweep. Avec un droit au niveau table, ce compte pourrait réécrire les destinataires d’un message ou son corps ; avec ces deux colonnes, il ne peut que réveiller un message. Il n’a aucune portée sur pepsi.crypto_identity, et donc aucune sur la moindre clé privée.
Le programme ne porte aucun bit setuid ou setgid et est plié dans le binaire multi-appel pepsi. Lancé en tant que root, il devient le compte pepsi-keydisc avant de se connecter (la configuration, et tout fragment @inline-secret@, est lue d’abord, en tant qu’utilisateur appelant), de sorte qu’il peut être lancé depuis un shell root pour des tests sans sudo -u.
85.1.45.1.8. LDAP est une fonctionnalité décidée à la compilation¶
Le client LDAP est derrière la fonctionnalité cargo ldap et est désactivé par défaut : il ajoute une dépendance, et un déploiement sans annuaire ne devrait pas en lier une. Un build sans la fonctionnalité refuse de démarrer pepsi-keydisc@ldap avec un message le disant, plutôt que de répondre silencieusement « pas de clé » à jamais, et pepsi-setup(1) rejette sur un tel build une configuration qui liste ldap dans SOURCES — comme il rejette celle qui liste ldap sans LDAP_URL et LDAP_BASE.
85.1.45.1.9. Options globales¶
Ces options globales précèdent la sous-commande (un indicateur placé à la fin est rejeté).
- -c FILE, –config FILE
Lit la configuration depuis FILE au lieu de parcourir les emplacements par défaut.
- -L LOGLEVEL, –log LOGLEVEL
Règle la verbosité de journalisation. LOGLEVEL est l’un de
error,warn,info,debugoutrace(par défaut :info).- -v, –verbose
Affiche les messages de journal de toutes les sources, y compris les bibliothèques tierces.
- -h, –help
Affiche un résumé d’utilisation et quitte.
- -V, –version
Affiche la version et quitte.
85.1.45.1.10. Signaux¶
- SIGINT, SIGTERM
Cesser de prendre de nouvelles demandes et quitter. Rien n’est perdu : une demande sans réponse reste
pendingdanspepsi.key_requestet est reprise par le balayage de démarrage de l’instance suivante, ou se conclut d’elle-même à son échéance.
85.1.45.1.11. Code de sortie¶
- 0
Arrêt propre, ou un probe achevé.
- 1
Une erreur s’est produite : une configuration malformée, une méthode que
[pepsi-keydiscovery] SOURCESne liste pas,ldapdans un build sans la fonctionnalité, ou une connexion à la base de données échouée. Les échecs de consultation individuels ne sont pas des erreurs — ils sont consignés sur la demande et le service continue de tourner.
85.1.45.1.12. Exemples¶
pepsi.target démarre l’ensemble de méthodes par défaut (dane wkd-advanced wkd-direct vks). Sans la cible, démarrez-les à la main
systemctl enable --now pepsi-keydisc@dane pepsi-keydisc@wkd-advanced \
pepsi-keydisc@wkd-direct pepsi-keydisc@vks
Désactiver une méthode sans toucher à la configuration des autres
systemctl mask --now pepsi-keydisc@vks
(puis réglez [pepsi-keydiscovery] SOURCES = dane wkd-advanced wkd-direct, afin que la règle d’arrêt cesse d’attendre une réponse qui ne viendra jamais). mask plutôt que disable : pepsi.target redémarre une instance simplement désactivée.
Découvrir ce que chaque méthode dit d’une adresse, sans rien changer
pepsi-keydisc -c /etc/pepsi/pepsi.conf probe bob@example.com
Exécuter une instance au premier plan, avec la journalisation complète, pour voir pourquoi une adresse ne donne aucune clé
pepsi-keydisc -c /etc/pepsi/pepsi.conf -L debug serve wkd-advanced
85.1.45.1.13. Voir aussi¶
pepsi-keys(1), pepsi-setup(1), pepsi.conf(5), pepsi.state(7), pepsi-dispatch(1), pepsi-config(1)
85.1.45.1.14. Bogues¶
Signalez les bogues au gestionnaire de tickets de Pepsi.