10. Extensions du protocole SMTP

Au-delà des extensions de service ESMTP normalisées répertoriées dans Fonctionnalités prises en charge et Index des RFC, Pepsi définit deux champs d’en-tête de message qui lui sont propres :

  • l’en-tête de preuve d’origine Pepsi-Origin:, apposé sur le courrier sortant ; et

  • l’en-tête de paiement Taler:, qui annonce à un wallet une demande de paiement de péage à l’envoi.

Aucun des deux n’est enregistré auprès de l’IANA au titre de la RFC 3864. Ce sont tous deux des extensions privées que seul un déploiement Pepsi (et, pour l’en-tête de paiement, un wallet compatible GNU Taler) interprète, et tous deux sont des champs facultatifs au sens de la RFC 5322 §3.6.8 : un nom de champ en US-ASCII imprimable suivi d’une valeur non structurée, que tout MTA conforme relaie intact et que tout lecteur conforme ignore s’il ne le reconnaît pas.

Pepsi nomme ses champs d’en-tête d’après leur fonction. Les deux champs de protocole ci-dessus circulent entre déploiements et ne portent pas de préfixe X- : la RFC 6648 déprécie X- parce qu’un champ qui réussit doit être renommé, ce qui casse toute implémentation qui l’a adopté tôt.

Les champs qui ne font qu’annoter un message pour son destinataire local ou portent une demande d’un client de messagerie local — X-Pepsi-Crypto, X-Pepsi-Detected-Languages, X-Pepsi-Sign et les autres — partagent l’espace de noms X-Pepsi-*, qui n’est jamais destiné à atteindre un autre déploiement. pepsi-stage-decrypt retire tout cet espace de noms du courrier entrant, de sorte qu’aucun expéditeur distant ne peut falsifier un verdict local. La même règle explique pourquoi Pepsi-Origin: doit rester en dehors : une preuve d’origine dans cet espace de noms serait retirée précisément sur le rebond de retour, là où elle est nécessaire. Les champs locaux sont documentés avec l’étape qui les écrit ou les lit, pas ici.

10.1. L’en-tête de preuve d’origine Pepsi-Origin:

Lorsque Pepsi relaie un message sortant vers l’extérieur, il l’estampille d’un en-tête Pepsi-Origin: qui prouve cryptographiquement que ce déploiement est à l’origine du message et enregistre lequel de ses expéditeurs autorisés l’a émis. Cela permet de faire confiance à un rebond de retour : un DSN qui revient des jours plus tard intègre (une copie du) message original — et donc l’en-tête Pepsi-Origin: — dans son corps de rapport, de sorte que pepsi-stage-anti-spam peut récupérer cet en-tête et confirmer que le rebond est une réponse à un courrier que Pepsi a réellement envoyé, plutôt qu’un backscatter ou un rebond falsifié visant la barrière de péage à l’envoi.

10.1.1. Syntaxe du champ

La valeur de l’en-tête est une liste de champs key=value séparés par ; :

Pepsi-Origin: v=1; host=mail.example.org; sender=alice@example.org;
 nonce=<base64url>; ts=<epoch-seconds>; mac=<base64url>

Champ

Signification

v

Version du format ; un vérificateur n’accepte que 1.

host

Le nom d’hôte du déploiement d’origine ([pepsi-ingress] HOSTNAME), en clair.

sender

Le compte expéditeur d’enveloppe autorisé dont le message est issu.

nonce

Un nonce aléatoire de 128 bits, encodé en base64url (RFC 4648, sans remplissage).

ts

L’horodatage Unix (en secondes) auquel l’en-tête a été frappé.

mac

HMAC-SHA256 sur les champs précédents, encodé en base64url.

Le MAC couvre la version, le nom d’hôte, le compte expéditeur, le nonce et l’horodatage, chaque champ étant préfixé de sa longueur u32 en big-endian puis concaténé, de sorte qu’aucune frontière de champ ne peut être déplacée. Le nom d’hôte est à la fois transporté en clair et intégré au MAC : la copie en clair permet à un vérificateur de rejeter à bas coût un rebond frappé pour un autre déploiement Pepsi, avant toute consultation de la base de données, tandis que son intégration au MAC signifie qu’un en-tête capturé ne peut être rejoué contre un déploiement frère qui partagerait par hasard un secret. Comme seul Pepsi génère ou vérifie ces en-têtes, le format sur le fil n’a besoin d’interopérer avec rien.

10.1.2. Frappe et vérification

  • Estampillage. Les deux étapes de relais — pepsi-stage-relay-to-internet et pepsi-stage-relay-to-smarthost — appellent le moteur partagé pepsi-common::origin pour ajouter l’en-tête en tête du message, quel que soit le chemin sortant qu’il emprunte, et notent le nonce fraîchement frappé dans la table pepsi.origin_nonce avec une expiration de deux semaines. L’estampillage se fait au mieux : si la fonctionnalité est désactivée, le message est inchangé, et un échec d’enregistrement du nonce est journalisé mais ne bloque jamais la remise.

  • Vérification. pepsi-stage-anti-spam, sur un rebond de retour, parcourt le message entier (l’en-tête se trouve dans le corps du DSN, pas dans le bloc d’en-têtes propre au rebond), déplie d’éventuelles lignes de continuation et accepte le premier en-tête dont la version et le nom d’hôte correspondent et dont le MAC se vérifie sous le secret. Ce n’est que si la vérification cryptographique à bas coût réussit que la consultation (plus lente) de pepsi.origin_nonce a lieu ; un rebond ne se vérifie que si son nonce est encore suivi. Un rebond qui ne se vérifie pas — un en-tête manquant/falsifié/expiré, ou tout rebond lorsque la preuve d’origine n’est pas configurée — est acheminé vers le BOUNCE_TARGET_STAGE de l’étape (par exemple une étape de quarantaine ou de rejet) lorsqu’une telle étape est câblée, et transféré tel quel vers NEXT_STAGE dans le cas contraire ; un rebond authentique est toujours transféré normalement. Un rebond n’est jamais silencieusement abandonné, ni jamais soumis à une barrière de paiement.

10.1.3. Configuration

Le matériel de clé réside dans la section partagée [pepsi-origin] (SECRET / SECRET_FILE, plus le [pepsi-ingress] HOSTNAME requis qui est intégré à chaque MAC). La fonctionnalité est activée par défaut : lorsqu’aucun secret n’est configuré, pepsi-setup en provisionne un aléatoire au premier lancement. Le secret doit rester stable dans le temps (un rebond renvoyé des jours plus tard doit encore se vérifier) et être identique sur toutes les instances d’un déploiement.

Pour désactiver la fonctionnalité, positionnez ENABLED = no dans [pepsi-origin]. Le courrier sortant n’est alors plus estampillé, chaque rebond est invérifiable (acheminé selon le BOUNCE_TARGET_STAGE de l’étape anti-spam, sinon transmis) et pepsi-setup ne génère aucun secret ; un secrets.d/pepsi-origin.secret existant est laissé en place, de sorte que la réactiver reprend avec la même clé. Supprimer la section n’est pas un interrupteur d’arrêt : le prochain pepsi-setup run ne trouverait aucun secret et en provisionnerait un nouveau. Voir pepsi-stage-anti-spam et pepsi.conf(5).

10.2. L’en-tête de paiement Taler:

Lorsque pepsi-stage-anti-spam retient un message en attente de paiement, il génère une réponse automatique de demande de paiement à l’expéditeur (Auto-Submitted: auto-replied selon la RFC 3834, expéditeur d’enveloppe nul). Cette réponse porte l’URI de paiement GNU Taler

Taler: taler://pay/<backend>/<order-id>/

sous forme de champ d’en-tête, et dans son corps comme lien cliquable et code QR PNG cid: en ligne (la RFC 2392 pour la référence cid:), accompagné d’un pointeur vers https://wallet.taler.net/ pour les expéditeurs sans wallet. L’en-tête est ajouté à côté de la copie du corps, jamais à sa place, de sorte qu’un lecteur humain et un client non-Taler ne sont nullement affectés.

La valeur est exactement l’URI que l’étape frappe, avec order_id == token, de sorte qu’un wallet résout le bon de commande auprès du backend marchand comme il le ferait depuis le lien du corps. taler:// n’est pas un schéma d’URI enregistré à l’IANA (la RFC 7595 en fixe la procédure) ; c’est celui propre à GNU Taler, et la forme sur le fil est documentée par ce projet plutôt qu’ici.

10.2.1. Pourquoi un en-tête et pas seulement le corps

L’en-tête est ce qui rend la demande détectable par une machine, et Pepsi est lui-même la machine qui la lit. pepsi-stage-auto-pay — le pendant côté émission, exécuté sur le chemin entrant — reconnaît une demande de paiement de retour à ce champ : il déplie les lignes de continuation, accepte plusieurs URI dans un même champ et plusieurs champs ``Taler:`` (un message adressé à une liste peut susciter plus d’une demande), et ignore les URI taler:// de tout autre type, de sorte que seules de véritables demandes de paiement sont réglées.

La détection seule n’est pas une autorisation. L’étape ne paie que pour du courrier dont ce déploiement peut prouver qu’il est à l’origine, ce qu’elle établit avec l’en-tête Pepsi-Origin: décrit ci-dessus — récupéré dans le message renvoyé et vérifié contre pepsi.origin_nonce. Le budget est imputé à ce nonce d’origine, de sorte qu’un même message original ne peut être facturé deux fois.

La réponse recopie aussi verbatim l’en-tête Pepsi-Origin: du message original, ce qui permet à la corrélation de survivre à l’aller-retour.

10.2.2. Interaction avec DKIM et ARC

La réponse automatique est injectée à BLOCK_RESPONSE_STAGE : elle est donc signée en DKIM en sortant, comme tout autre message. Le fait que le champ Taler: soit couvert par cette signature suit la configuration h= ordinaire de l’étape (SIGNED_HEADERS, voir pepsi-stage-dkim-sign), dont la valeur par défaut ne l’inclut pas ; il ne fait l’objet d’aucun traitement particulier. Comme la sélection des en-têtes DKIM se fait de bas en haut (RFC 6376 §5.4.2), ajouter le champ ne perturbe aucune signature déjà présente.

10.3. Voir aussi

pepsi-stage-anti-spam, pepsi-stage-auto-pay, pepsi-stage-relay-to-internet, pepsi-stage-relay-to-smarthost, Fonctionnalités prises en charge, Index des RFC.