85.1.26. pepsi-stage-autocrypt-learn¶
learn correspondents‘ keys from the mail they send
- Handbuchabschnitt:
1
85.1.26.1.1. Name¶
pepsi-stage-autocrypt-learn - die Schlüssellern-Stage der Pepsi-Pipeline.
85.1.26.1.2. Übersicht¶
pepsi-stage-autocrypt-learn [GLOBAL-OPTIONS] worker
85.1.26.1.3. Beschreibung¶
pepsi-stage-autocrypt-learn ist ein Stage-Programm, das von pepsi-dispatch(1) als persistenter Worker ausgeführt wird, der Nachrichten-IDs von der Standardeingabe liest. Es lädt diesen pepsi.workqueue-Datensatz (und weigert sich zu handeln, sofern sein status nicht running ist) und liest seinen [stage-<stage>]-Abschnitt.
Hier lehrt eine eingehende Nachricht Pepsi einen öffentlichen Schlüssel. Vier Quellen, allesamt Dinge, die ein Korrespondent in eine an uns gesendete Nachricht gelegt hat:
der Autocrypt:-Header des Absenders (Autocrypt Level 1 §2.1);
ein angehängter application/pgp-keys-Teil;
die Zertifikate, die eine S/MIME-Signatur mitführt;
die Autocrypt-Gossip:-Felder einer verschlüsselt eingetroffenen Nachricht, die die Schlüssel der anderen Empfänger einführen (Level 1 §5.3).
Alles, was sie lernt, wird über denselben keydisc_resolve-Pfad, den pepsi-keydisc(1) verwendet, nach pepsi.peer_key geschrieben; ein hier gelernter Schlüssel gibt daher auch jede Nachricht frei, die auf den Schlüssel dieser Adresse wartend geparkt ist.
Die Stage verwirft eine Nachricht nie, pausiert sie nie, erzeugt nie einen Bounce und schreibt sie nie um. Sie lernt und schaltet weiter, daher ist NEXT_STAGE verpflichtend.
Sie hält auch die umgekehrte Richtung fest: dass ein Korrespondent nachweislich einen unserer Schlüssel besitzt (siehe Nachweis, dass ein Korrespondent unseren Schlüssel besitzt).
85.1.26.1.4. Wo sie hingehört¶
Die Platzierung ist es, was hieraus eine eigene Stage macht statt eines Teils von pepsi-stage-decrypt(1); wird sie falsch gewählt, hebt das die Wirkung stillschweigend auf:
Nach
pepsi-stage-decrypt. Gossip-Felder liegen innerhalb des Chiffrats, es gibt also nichts zu lesen, bevor die Nachricht geöffnet wurde.Nach jeder Stage, die eine Nachricht als Junk einstufen kann — pepsi-stage-check-whitelist(1) und jede andere Stage, die
state.spamsetzt. Autocrypt Level 1 §5.3 sagt, dass der Peer-State für eine Nachricht, die der Client für Spam hält, ignoriert werden SOLLTE; eine Stage, die vor dem Entstehen dieser Einschätzung platziert ist, kann das nicht einhalten. pepsi-stage-decrypt(1) läuft auf dem eingehenden Pfad konstruktionsbedingt zuerst, dort existiert diese Einschätzung also noch nicht.Vor allem, was antwortet oder zustellt — pepsi-stage-vacation(1), den Relay-Stages, den lokalen Zustell-Stages. Ein Schlüssel, der nach dem Versand der Antwort gelernt wird, ist zu spät gelernt, um sie damit zu verschlüsseln.
pepsi-setup --wizard platziert sie korrekt, wenn Ende-zu-Ende-Kryptographie aktiviert ist.
85.1.26.1.5. Was sie nicht lernt¶
Die Schranken sind die von Autocrypt Level 1, dazu Pepsis eigene, wo Pepsi bewusst strenger ist. Ein Feld oder Schlüssel, der an einer davon scheitert, wird übersprungen; die Nachricht schlägt deswegen nie fehl.
Überhaupt kein Schlüssel, wenn LEARN_KEYS aus ist: Die Stage lernt nichts, Gossip eingeschlossen — Gossip ist eine Erweiterung dessen, was eine Nachricht lehren darf, und kann daher nicht an sein, während die engere Sprosse aus ist. (Der unter Nachweis, dass ein Korrespondent unseren Schlüssel besitzt beschriebene Nachweis wird dennoch festgehalten.)
Nichts aus einer als Spam bewerteten Nachricht, sofern LEARN_FROM_SPAM nichts anderes sagt.
Nur den eigenen Schlüssel des Absenders aus den ersten drei Quellen: eine Nachricht darf legitim einen Schlüsselbund Dritter mitführen, und diese so zu speichern, als hätte der Absender für sie gebürgt, ließe einen Korrespondenten den Speicher für alle säen. Die Einführung eines Dritten ist die Aufgabe von Gossip, und sie landet auf einer eigenen Sprosse.
Gossip nur aus einer verschlüsselt eingetroffenen Nachricht, und nur, wenn der eintreffende Header-Block kein eigenes
Autocrypt-Gossip:-Feld trug — alles auf dem Zustellpfad kann eines schreiben, eine solche Nachricht lehrt daher überhaupt kein Gossip. Keine der beiden Tatsachen ist am festgeschriebenen Klartext ablesbar, deshalb hält pepsi-stage-decrypt(1) beide unterstate.crypto.infest, und diese Stage liest sie dort. Eine Nachricht, die nie eine Entschlüsselungs-Stage gesehen hat, hat keinen solchen Eintrag, und Fehlen bedeutet Nein: eine solche Installation lernt Header und angehängte Schlüssel, aber kein Gossip.Kein Gossip für eine Adresse, die die Nachricht nicht sichtbar nennt: Das
addreines Feldes muss imTo:,Cc:oderReply-To:der Nachricht selbst vorkommen (die Empfängerregel aus Level 1 §5.3). Ohne sie könnte ein Absender für jede beliebige Adresse der Welt einen Schlüssel einführen, indem er sie in einem Header nennt, den niemand liest.Nie ein per Gossip gelernter Schlüssel für eine Adresse, die dieser Host bedient. Ein Peer-Schlüssel für eine lokale Adresse ist der Schlüssel, mit dem unsere eigene ausgehende Mail an diesen Benutzer verschlüsselt würde; ein Gossip-Feld, das eine solche nennt, ist daher eine Schlüsselersetzung und keine Einführung. Der Test ist
LOCAL_DOMAINS, und er gilt allein für Gossip: Das eigene Material des Absenders wird nach Adresse gefiltert und nicht nach Lokalität (weiter unten steht, was ein gefälschtesFrom:bedeutungslos macht).Nie die eigene Adresse des Absenders per Gossip (sein eigener Schlüssel gehört auf die Sprosse darüber), nie zwei Felder, die dieselbe Adresse nennen (nichts hier kann zwischen zwei Behauptungen über einen Fremden entscheiden), und nichts aus einer Nachricht mit mehr als 50 Gossip-Feldern (sie werden alle ignoriert), wobei jedes Feld höchstens 16 KiB an
keydata=trägt (ein minimaler übertragbarer Schlüssel liegt selbst für RSA-4096 unter 4 kB Base64, das ist also um den Faktor vier großzügig; ein übergroßes Feld wird übersprungen, nicht fatal). Die davon getrennte Grenze von 10 KiB, die manchem Leser begegnet sein wird, ist die Obergrenze aus Autocrypt Level 1 §2.1 für denAutocrypt:-Header selbst und wird nie auf ein Gossip-Feld angewendet.
85.1.26.1.6. Was ein gelernter Schlüssel wert ist¶
Wenig, und das mit Absicht. Geerntete Schlüssel liegen auf Rang inbound, gegossipte auf gossip, den beiden untersten Sprossen der Vertrauensleiter (siehe pepsi-keydisc(1)):
ein solcher Schlüssel kann nie einen aus der Entdeckung oder von einem Operator verdrängen;
eine gegen einen solchen verifizierte Signatur wird bestenfalls als
valid-untrustedgemeldet, nie alsvalid, sie setzt also niestate.signature_verified— den Schlüssel, von dem pepsi-stage-check-whitelist(1) einensignature_required-Datensatz abhängig macht;ein
peer_key-Datensatz wird für eine Adresse, für die dieser Host einecrypto_identityhält, vollständig ignoriert — die Abfrage, die die Krypto-Stages verwenden, ersetzt die zwischengespeicherten Schlüssel einer solchen Adresse durch die öffentliche Hälfte der Identität —, sodass eine Nachricht, dieFrom:eines lokalen Benutzers fälscht, zwar einen Datensatz hinterlassen, ihn aber nie für diesen verwenden lassen kann.
Innerhalb dieser beiden Sprossen lautet die Konfliktregel das Neueste gewinnt, gemessen am Autocrypt-Gültigkeitsdatum der Nachricht; ein Korrespondent, der seinen Client neu installiert, erhält also keine Mail mehr, die auf einen Schlüssel verschlüsselt ist, den er nicht mehr besitzt. Das ist ein bewusster Kompromiss: Er schützt nur gegen einen passiven Angreifer, und mehr beansprucht Autocrypt nicht. Ein Operator, der opportunistische Verschlüsselung, aber keine Einführungen Dritter will, setzt [pepsi-keydiscovery] MIN_TRUST = harvested.
85.1.26.1.7. Wenn sich der Schlüssel eines Korrespondenten ändert¶
Neuester-gewinnt ist auf den From:-Header geschlüsselt, den der Absender schreibt, und die eingehende Authentifizierung ist fail-open — eine Nachricht, die bloß behauptet, von einem Korrespondenten zu stammen, kann also den Schlüssel ersetzen, mit dem wir an ihn verschlüsseln. Autocrypt nimmt das hin; Pepsi nimmt es ebenfalls hin, aber nie stillschweigend:
Ein Audit-Datensatz. Die Datenbank schreibt in derselben Anweisung wie die Ersetzung einen
key.peer.rotate-Datensatz inpepsi.event_log(Schweregradnotice, Akteurautocrypt:inboundoderautocrypt:gossip, Subjekt die Adresse des Korrespondenten), mit dem Protokoll, dem verdrängten und dem neuen Fingerabdruck und beiden Gültigkeitsdaten. Es gibt keine Rotation ohne ihren Datensatz. Er wird vonGET /api/v1/eventsund im Ereignisprotokoll der Konsole aufgeführt und von pepsi-status(1) unter Schlüsseländerungen bei Korrespondenten zusammengefasst.Eine Benachrichtigung an die Betroffenen. Ist RESPONSE_STAGE gesetzt, erhält jeder lokale Umschlagempfänger der Nachricht, die die Änderung verursacht hat — die Personen, an die dieser Korrespondent gerade geschrieben hat und deren Antwort an den neuen Schlüssel verschlüsselt wird —, eine Benachrichtigung per Mail, die den Korrespondenten und beide Fingerabdrücke nennt und angibt, ob der neue Schlüssel der eigene des Korrespondenten war oder per Gossip eingeführt wurde (und von wem). Sie hat den Null-Absender,
Auto-Submitted: auto-generatedundFrom: postmaster@<recipient's domain>, wird aus der Vorlagekey-rotation.<lang>.bodyunter[pepsi] TEMPLATE_DIRfür die erkanntestate.languageder Nachricht mit englischem Rückfall gerendert (dessen Existenz pepsi-setup(1) verlangt) und bei RESPONSE_STAGE eingespeist. „Lokal“ ist ein Empfänger an einerLOCAL_DOMAINS-Domain; niemand anderswo erhält je Mail, und niemandem wird etwas über seine eigene Adresse mitgeteilt. Lokale Benutzer, die mit der Adresse korrespondieren, diese Nachricht aber nicht erhalten haben, werden nicht benachrichtigt: Pepsi führt kein Verzeichnis darüber, wer mit wem korrespondiert, und eines dafür anzulegen wäre der schlechtere Handel. Der Audit-Datensatz deckt sie ab. Eine Benachrichtigung, die nicht eingereiht werden kann (eine nicht lesbare Vorlage, ein Datenbankfehler), wird auf Stufewarnprotokolliert und nicht erneut versucht: Ein zweiter Durchlauf fände den neuen Schlüssel bereits gespeichert und hätte keine Änderung zu melden, sodass der Audit-Datensatz dann die einzige Aufzeichnung ist.Eine Logzeile und ein Telemetrie-Zähler (
autocrypt-rotation).
Eine Ersetzung durch eine streng bessere Quelle — eine WKD- oder DANE-Antwort, die einen geernteten Schlüssel verdrängt, oder der eigene Autocrypt:-Header des Inhabers, der einen per Gossip erhaltenen verdrängt — ist die Leiter, die wie vorgesehen arbeitet, und keine Rotation.
Ein per Gossip erhaltener Schlüssel, den sein Inhaber bestätigt, wird befördert. Wenn der eigene Autocrypt:-Header des Absenders (oder ein angehängter Schlüssel, der ihn nennt) denselben Schlüssel trägt, den Gossip bereits für ihn gespeichert hat, wechselt der Datensatz von der Sprosse gossip zu inbound — die Beförderung nach Autocrypt Level 1 §5.3. Da sich der Schlüssel nicht geändert hat, ist das weder eine Rotation noch zurückgehalten, und niemand erhält eine Benachrichtigung; die Datenbank schreibt in derselben Anweisung einen key.peer.promote-Datensatz (Schweregrad info, Akteur autocrypt:inbound, Detail das Protokoll, der Fingerabdruck, from_source gossip, source inbound und beide Gültigkeitsdaten), und die Stage protokolliert es. Das Gültigkeitsdatum des Datensatzes wird das eigene des Absenders, sodass eine spätere Rotation durch ihn an seiner eigenen Angabe gemessen wird und nicht an dem Datum, das die Nachricht eines Dritten trug. Das Urteil, das eine Signatur erreichen kann, bleibt unverändert — bestenfalls valid-untrusted, wie bei jedem geernteten Schlüssel —, doch der Datensatz verteidigt sich nun auf dem Rang inbound, sodass ein späteres Gossip-Feld, das einen anderen Schlüssel für die Adresse anbietet, abgelehnt wird, und MIN_TRUST = harvested lässt ihn zu. ACCEPT_ROTATION spielt keine Rolle: Nichts wird verdrängt.
ACCEPT_ROTATION = expired verengt die Regel für einen Operator, der lieber eine echte Rotation ablehnt, als eine gefälschte anzunehmen: Der neuere Schlüssel wird nur übernommen, wenn jeder gespeicherte Schlüssel für diese Adresse und dieses Protokoll tot ist — seine Gültigkeit revoked oder expired oder sein expires_at in der Vergangenheit. Andernfalls wird der gespeicherte Schlüssel behalten und das Angebot zurückgehalten: ein key.peer.rotate.held-Datensatz (Schweregrad warning, mit dem behaltenen und dem angebotenen Fingerabdruck), dieselbe Benachrichtigung mit dem Hinweis, dass der neue Schlüssel nicht angenommen wurde, und der Zähler autocrypt-rotation-held. Ob ein Schlüssel tot ist, wird aus dem Gespeicherten gelesen, und jeder gelernte Schlüssel wird mit dem Ablauf gespeichert, den sein eigenes Material angibt — bei OpenPGP das Datum in der aktuellen Selbstsignatur des Primärschlüssels, bei S/MIME das notAfter des Zertifikats —, sodass ein verfallener Schlüssel ab diesem Moment tot ist. Ein Schlüssel ohne angegebenen Ablauf ist erst tot, wenn er als widerrufen oder abgelaufen markiert ist oder ein Operator ihn entfernt (pepsi-keys peer remove) oder den neuen von Hand importiert (pepsi-keys peer import, das die Sprosse der geernteten Schlüssel übertrifft). Die Richtlinie wird über den Stage-Abschnitt gelesen, sodass eine pepsi.settings-Überschreibung für einen Empfänger bei einer in EDITABLE_STAGES aufgeführten Stage gilt.
85.1.26.1.8. Nachweis, dass ein Korrespondent unseren Schlüssel besitzt¶
Mit eingeschaltetem [stage-encrypt] ATTACH_KEYS_AS_FILES hängt pepsi-stage-encrypt(1) den öffentlichen Schlüssel des Absenders als Datei an, bis der Korrespondent ihn nachweislich besitzt. Diese Stage schreibt diesen Nachweis, ein Datensatz je (fingerprint, peer_address) in pepsi.peer_has_own_key, wenn eine eingehende Nachricht ihn zeigt:
sie wurde mit einem unserer Schlüssel entschlüsselt (
state.crypto.in.decryptedunddecrypted_with) und nicht bloß für den eigenen Mail-Client eines Benutzers durchgereicht;sie trägt eine Signatur, deren Urteil
validodervalid-untrustedlautet und die den Klartext abdeckt (signature.covers_plaintext), sodass ein Fremder, der das Chiffrat eines anderen in seine eigene Signatur einhüllt, nichts beweist;der Unterzeichner ist die
From:-Adresse selbst (nie der beim Lernen von Schlüsseln verwendete Rückgriff auf den Umschlag), sodass ein gefälschtesFrom:den Anhang nicht unterdrücken kann.
Der Speicher prüft dann erneut, dass der Fingerabdruck einen aktiven MTA-Schlüssel (custody = local) der Adresse benennt, für die die Nachricht entschlüsselt wurde, und entfernt in derselben Anweisung Datensätze, deren Fingerabdruck keine aktive Identität mehr benennt. Der Eintrag ist auf den Fingerabdruck geschlüsselt, sodass ein neuer Schlüssel wieder angehängt wird. Ein Gegenüber, das verschlüsselt, ohne zu signieren, erhält die Datei weiterhin, was keinen Schaden anrichtet.
Dies läuft vor jeder Schranke für das Lernen von Schlüsseln: Es hält etwas über unseren eigenen Schlüssel fest, nicht über ihren, sodass weder LEARN_KEYS noch die Spam-Einschätzung etwas dazu zu sagen haben. Wie alles andere hier lässt es die Nachricht nie fehlschlagen.
85.1.26.1.9. Konfiguration¶
Die Optionen liegen im eigenen [stage-<name>]-Abschnitt der Stage (PROGRAM = pepsi-stage-autocrypt-learn): LEARN_KEYS, LEARN_GOSSIP, LEARN_FROM_SPAM, ACCEPT_ROTATION (newest, der Standardwert, oder expired), das optionale RESPONSE_STAGE für Benachrichtigungen über Schlüsseländerungen, die gemeinsamen Lokalitätsoptionen LOCAL_DOMAINS, TARGETS und RECIPIENT_DELIMITER (geparst, aber nur LOCAL_DOMAINS wird herangezogen) und ein verpflichtendes NEXT_STAGE. Die Stage parst außerdem [pepsi-keydiscovery], dessen NEGATIVE_TTL sie an den gemeinsamen Speichern-und-Freigeben-Pfad weiterreicht. Sie sind in pepsi.conf(5) dokumentiert.
Die Stage ist unprivilegiert: Sie schreibt nur öffentliches Schlüsselmaterial (und die Tatsache, dass ein Korrespondent unseren öffentlichen Schlüssel besitzt), läuft daher unter dem gewöhnlichen Dienstkonto pepsi und ist in das Multi-Call-Binärprogramm pepsi eingefaltet. Sie trägt kein setuid- oder setgid-Bit.
85.1.26.1.10. State¶
Eingaben: state.spam (die Einschätzung, die vorgelagerte Stages festhalten); state.crypto.in.encrypted, state.crypto.in.decrypted und state.crypto.in.outer_gossip, geschrieben von pepsi-stage-decrypt(1), die zusammen entscheiden, ob dem Gossip dieser Nachricht geglaubt werden darf. Der Absender wird der Spalte from_header entnommen, ersatzweise dem Umschlagabsender.
Ausgaben: keine an der Nachricht — ihr state bleibt unangetastet. Die Seiteneffekte sind pepsi.peer_key-Datensätze, pepsi.peer_has_own_key-Datensätze, key.peer.rotate/key.peer.rotate.held/key.peer.promote-Datensätze in pepsi.event_log und die bei RESPONSE_STAGE eingespeisten Benachrichtigungen über Schlüsseländerungen (Token <token>-key-rotation-<n>). Der Nachweis liest zusätzlich state.crypto.in.decrypted_with, state.crypto.in.for_client und state.crypto.in.signature. Das State-Layout wird in pepsi.state(7) beschrieben.
Übergänge: schaltet immer zu NEXT_STAGE weiter. Es gibt keine Verzweigung; die Stage pausiert nie, schlägt nie fehl, leitet nie um und schließt nie ab. Jeder Fehler beim Lernen wird protokolliert und verschluckt: Eine Nachricht wird gerade zugestellt, und nichts am Schlüsselmaterial eines Fremden darf dem im Weg stehen. Schlüsselmaterial, das sich nicht parsen lässt, ist Sache des Absenders und wird auf Stufe debug protokolliert; Material, das geparst wurde und nicht gespeichert werden konnte (ein Datenbankfehler), ist Sache dieses Hosts und wird auf Stufe warn protokolliert, damit ein Betreiber einen Speicher bemerkt, der aufgehört hat zu lernen. Die Konfiguration ist die Ausnahme: Der Abschnitt der Stage und [pepsi-keydiscovery] werden beim Start des Workers geprüft (ein kaputter lässt ihn den Start verweigern, Exit 78, und der Dispatcher hält die Warteschlange zurück), und ein Abschnitt, der sich unter einem laufenden Worker nicht mehr parsen lässt, wird erneut versucht statt stillschweigend übersprungen.
85.1.26.1.11. Befehle¶
- worker
Läuft als persistenter pepsi-dispatch(1)-Worker, der Nachrichten-IDs von der Standardeingabe liest.
85.1.26.1.12. Globale Optionen¶
- -c FILE, –config FILE
Liest die Konfiguration aus FILE, statt die Standardorte zu durchsuchen.
- -L LOGLEVEL, –log LOGLEVEL
Setzt die Log-Ausführlichkeit (Standardwert
info).- -v, –verbose
Zeigt Log-Meldungen aus allen Quellen.
- -h, –help; -V, –version
Gibt eine Verwendungsübersicht / die Version aus und beendet sich.
85.1.26.1.13. Exit-Status¶
- 0
Die Nachricht wurde verarbeitet (was immer sie gelehrt hat, oder nichts) und weitergeschaltet.
- 1
Ein Fehler ist aufgetreten (Nachricht nicht gefunden oder nicht
running, eine fehlkonfigurierte Stage — z. B. ein fehlendes NEXT_STAGE — oder ein Datenbankfehler). Der Grund wird in das Journal geschrieben.- 78
Der Worker hat den Start verweigert: Sein Abschnitt oder
[pepsi-keydiscovery]lässt sich nicht parsen. Der Dispatcher reiht erneut ein, was er übergeben hatte, und versucht die Stage später wieder.
85.1.26.1.14. Beispiele¶
Aus Nachricht 42 lernen (sie muss running sein):
echo 42 | pepsi-stage-autocrypt-learn -c /etc/pepsi/pepsi.conf worker
Eine eingehende Pipeline, die sie nach den Spam-Prüfungen und vor der Zustellung platziert:
[stage-check-whitelist]
PROGRAM = pepsi-stage-check-whitelist
NEXT_STAGE = autocrypt-learn
WHITELIST_NAME = correspondents
[stage-autocrypt-learn]
PROGRAM = pepsi-stage-autocrypt-learn
NEXT_STAGE = local
Empfänger benachrichtigen, wenn sich der Schlüssel eines Korrespondenten ändert, und eine Änderung erst annehmen, wenn der alte Schlüssel tot ist:
[stage-autocrypt-learn]
PROGRAM = pepsi-stage-autocrypt-learn
NEXT_STAGE = local
RESPONSE_STAGE = dkim-sign
ACCEPT_ROTATION = expired
Opportunistische Verschlüsselung beibehalten, aber Einführungen Dritter ablehnen:
[stage-autocrypt-learn]
PROGRAM = pepsi-stage-autocrypt-learn
NEXT_STAGE = local
LEARN_GOSSIP = no
85.1.26.1.15. Siehe auch¶
pepsi-stage-decrypt(1), pepsi-stage-encrypt(1), pepsi-keydisc(1), pepsi-keys(1), pepsi-stage-check-whitelist(1), pepsi-dispatch(1), pepsi-status(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)
85.1.26.1.16. Fehler¶
Melden Sie Fehler an den Pepsi-Issue-Tracker.