31. pepsi-stage-arc

ARC verification, signing and sealing — the entry stage on the inbound path.

31.1. Role

pepsi-stage-arc implements ARC (RFC 8617). It verifies any existing inbound ARC chain and, when an ARC_DOMAIN and its keys are configured, seals the message as our ADMD so the boundary authentication verdict survives Pepsi’s forwarding hop. Because it applies only to mail we receive and forward, it must never touch our own submissions (state.local_origin) — those are signed as the author domain by pepsi-stage-dkim-sign instead, and the stage skips any such message. On a host that both receives and submits, place it on the inbound branch only, after the state.local_origin split (ahead of SRS); on a receive-only host it is the [stage-init] stage. Reference: pepsi-stage-arc(1).

31.2. Features

  • ARC verification of any inbound chain; the verdict is recorded under state.auth.arc.

  • ARC sealing: prepends a fresh ARC set — ARC-Authentication-Results (AAR), ARC-Message-Signature (AMS) and ARC-Seal (AS) — as the ARC_DOMAIN identity, signed with the single ARC_ALGORITHM (rsa or ed25519; ARC permits one signature per hop).

  • AAR from the boundary verdict: the AAR reuses the Authentication-Results fragment ingress stored under state.origin.ar_results, so SPF/DKIM/DMARC are verified exactly once, at ingress. Only the inbound ARC chain is verified here, to compute the chain-validation (cv=) value and the AAR’s arc= line.

  • Prepend-only: the seal is added at the top, so existing lower signatures and the ingress Received: header are undisturbed; only the headers column is rewritten, never the body.

  • Fail-open: if the origin context, [pepsi] config or keys are missing, or sealing errors, the message is advanced unsealed with a warning (the verdict is still recorded when computable).

31.3. Configuration

[stage-<name>]: PROGRAM = pepsi-stage-arc, NEXT_STAGE (required — the stage always hands the message on, so a missing one fails every message), the DNS settings DNS_SERVERS (empty = system resolver) / DNS_TIMEOUT, and the shared signature parameters HEADER_CANONICALIZATION / BODY_CANONICALIZATION (relaxed by default, or simple), SIGNED_HEADERS (which must include From) and SIGNATURE_EXPIRATION_DAYS (no x= by default) applied to the AMS and the ARC-Seal. The signing identity, keys and algorithm come from the shared [pepsi] section (ARC_DOMAIN, ARC_ALGORITHM, KEY_DIR, DKIM_SELECTOR). See pepsi-stage-arc(1).

31.4. State

  • Inputs: state.local_origin — when true the message is advanced untouched (no ARC on mail we originate); otherwise state.origin — the authserv_id (required to reproduce the AAR identity; without it the stage advances unsealed), ar_results (reused in the AAR), and remote_ip / helo for the ARC verification context.

  • Outputs: overwrites state.auth.arc with the re-evaluated chain verdict and records the chain’s sealer domains under state.auth.arc_sealers (the rest of state, including the other state.auth siblings and state.dsn, is preserved). Note arc_sealers says only who claimed to seal, so any reader must first require state.auth.arc == "pass".

31.5. See also

pepsi-ingress, pepsi-stage-dkim-sign, Supported Features, pepsi-stage-arc(1).