Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Spec couche 2 — air-mail (SMTP + POP3 + IMAP4, patron sans-IO)

Spécification technique — Version 0.1 (proposition). Couche 2 « Frameworks système ».

Cadrage. air-mail = client de messagerie : SMTP (soumission, RFC 5321/ 6409), POP3 (RFC 1939), IMAP4rev2 (RFC 9051) — trois modules internes d’un crate unique (comme air-http fédère h1/h2/h3 : codec-ligne, SASL et TLS partagés). Maison, pur Rust, zéro-C, zéro unsafe. Serveur mail hors périmètre (client only). Compose air-tls + air-network.

Position et méthode

Trois protocoles filaires texte, ligne par ligne (CRLF) qui partagent : framing de ligne (+ littéraux IMAP {n}), STARTTLS / TLS implicite, SASL AUTH. Un crate, trois modules, un codec-ligne + SASL + TLS communs.

Décision — crate unique, modules internes. SMTP (envoi) et POP3/IMAP (réception) diffèrent par le rôle mais partagent framing/TLS/SASL → factorisés une fois (anti-duplication, règle 80 %). Surface publique par protocole ; cœur partagé.

Périmètre de sécurité — moderne, TLS d’abord

ProtocoleRetenuPorts
SMTPsoumission RFC 6409, SMTPUTF8, DSN, PIPELINING ; TLS implicite (465) préféré, STARTTLS (587) sinon465/587
POP3RFC 1939 + STARTTLS ; TLS implicite (995) préféré995/110
IMAP4rev2RFC 9051 + STARTTLS ; TLS implicite (993) préféré ; IDLE, extensions993/143
SASLSCRAM-SHA-256(-PLUS), PLAIN/LOGIN uniquement sous TLS, OAUTHBEARER/XOAUTH2
  • TLS obligatoire pour l’AUTH : jamais d’AUTH en clair ; anti STARTTLS-stripping (préférer le port TLS implicite ; rejeter le downgrade). Certif. vérifié (air-tls).
  • Omis : AUTH en clair sans TLS ; POP3 APOP (MD5) ; IMAP legacy LOGIN sans TLS ; SMTP relay ouvert (client only).

Anatomie : les 9 composants (par module, cœur partagé)

#ComposantSMTPPOP3IMAP
1FramerLineFramer (CRLF) — partagé ; IMAP ajoute littéraux {n}
2CodecSmtpCodecPop3CodecImapCodec (commandes taguées, réponses)
3StateMachinegreeting→EHLO→STARTTLS→AUTH→MAIL/RCPT/DATAgreeting→STLS→AUTH→TRANS→UPDATEgreeting→STARTTLS→AUTH→SELECT→…
4HandshakerSTARTTLS/TLS via air-tls + SASL (partagé)
5Flow Controller// NO// NO// NO
6Multiplexer// NO// NOtags de commande (léger : réponses corrélées)
7Timer ManagertimeoutstimeoutsIDLE (push), timeouts
8Session Contextcapabilities (EHLO)état TRANScapabilities + état de mailbox (SELECT)
9Extension hooksSMTPUTF8/DSN/SIZEextensions IMAP (CONDSTORE, MOVE…)

Inventaire — ~20 objets

Surface (~12) : SmtpClient, Pop3Client, ImapClient, MailAddress (validé), OutgoingMessage/Envelope, Mailbox/MessageSummary (IMAP), SaslCredential (SCRAM/PLAIN/OAuth), Capabilities, FetchItem (IMAP), MailError, MailAuth, ConnectionSecurity (implicit-tls/starttls/plain-refused). Cœur partagé (~5) : LineFramer, SaslCodec (SCRAM/PLAIN/OAUTHBEARER), HeaderCodec (RFC 5322 en-têtes), ImecCodec (encodages MIME/UTF-8), TlsUpgrade (STARTTLS). Cœurs par module (~3) : SmtpStateMachine, Pop3StateMachine, ImapStateMachine.

#![allow(unused)]
fn main() {
impl ImapClient {
    pub async fn connect(endpoint: AirEndpoint, security: ConnectionSecurity,
        tls: Arc<TlsClientConfig>) -> Result<Self, MailError>;
    pub async fn authenticate(&mut self, cred: SaslCredential) -> Result<(), MailError>;
    pub async fn select(&mut self, mailbox: &str) -> Result<Mailbox, MailError>;
    pub async fn fetch(&mut self, set: SequenceSet, items: &[FetchItem]) -> Result<Vec<MessageSummary>, MailError>;
    pub async fn idle(&mut self) -> Result<IdleHandle, MailError>;      // push (RFC 2177)
}
}

Dépendances

air-network (L2, connexion), air-tls (L2, STARTTLS/implicite), air-crypto (L1 — HMAC/SHA-256 pour SCRAM ; PBKDF2 = additif ci-dessous), air-runtime/air-base-core (L1). Zéro-C, zéro tierce.

Additif air-crypto — INSTRUIT (ADR-082). SCRAM-SHA-256 dérive via PBKDF2-HMAC-SHA256 → additif pbkdf2 (RustCrypto), pur Rust zéro-C, KAT RFC 6070. Requis si SCRAM ; sinon OAUTHBEARER/XOAUTH2 (token, sans PBKDF2) couvre les fournisseurs modernes.

Sécurité & tests

  • TLS avant AUTH non négociable ; anti STARTTLS-stripping ; SASL moderne ; adresses/ en-têtes RFC 5322 parsés bornés (anti-injection d’en-têtes / CRLF injection).
  • Tests : LineFramer/codecs fuzzés (littéraux IMAP, réponses hostiles) ; StateMachine property (phases + refus AUTH-avant-TLS) ; interop Postfix/Dovecot en loopback TLS.

Travail à reprendre

  • Additif air-crypto PBKDF2instruit (ADR-082) (si SCRAM) ; MIME complet (parsing/multipart) ; IDLE/push ; envoi (composition MIME) ; ABI C différée.

Licence : MPL 2.0. Statut : spec air-mail (L2) v0.1 — SMTP/POP3/IMAP4 client, crate unique modules internes, sans-IO ; TLS d’abord, SASL moderne.