Security model¶
This page states what the library protects against, what it assumes about the host and where the host must add its own controls. It is written for the person deciding whether the library fits a CA's security requirements.
Trust boundaries¶
flowchart LR
subgraph Untrusted
Client[ACME client]
Target[Validation target]
TA[Token Authority]
end
subgraph Library
Handler[Handler and worker]
Validators[Validators]
end
subgraph Host
Store[(Store)]
CA[CA]
Policy[Policy hooks]
end
Client -->|signed requests| Handler
Validators -->|bounded fetches| Target
TA -.->|tokens via client| Handler
Handler --> Store
Handler --> CA
Handler --> Policy
Clients, validation targets and Token Authorities are untrusted. The store, the CA and the policy hooks are trusted host code. The library sits between them and applies the protocol.
What the library enforces¶
Request authentication. Every POST is a JWS verified against the embedded key or the stored
account key. The protected url must equal the request URL built from the base URL, so a request
captured for one server cannot be replayed against another path or host. The nonce is consumed
before the payload is read and a nonce is valid exactly once. newAccount requires an embedded
key and every other resource requires a kid, as RFC 8555 section 6.2 demands.
Key policy. Account keys must be ES256, ES384, ES512, RS256 or EdDSA keys and CSR keys must be RSA 2048 to 4096 bits, P-256, P-384, P-521, Ed25519, ML-DSA-44, ML-DSA-65, ML-DSA-87, any SLH-DSA parameter set or composite ML-DSA. The CSR key must differ from the account key. Issuer signatures in the returned chain may be composite ML-DSA or SLH-DSA. The server verifies both halves of a composite signature and checks SLH-DSA CSR and chain signatures in pure mode only.
Authorization before issuance. A certificate is issued only for an order whose every authorization is valid, whose CSR requests exactly the order's identifiers and whose CA basic constraint matches what the authorizations granted. The decision is stored before the CA is called. The deadline stored with it stops late signing.
Validation egress. The bundled validators resolve names through configured resolvers only, refuse special-purpose and private destinations unless allowed, recheck every redirect, ignore proxy environment variables, bound every read and never include fetched content in error details. The rules are in Challenge validators.
Bounded parsing. JSON is limited in size, nesting depth and duplicate members. Member names are exact, so a name that matches a known member only when case is ignored is refused. JWS, JWK, DNS responses, TLS handshakes and TLS-ALPN proofs are parsed with explicit limits. Those parsers have fuzz targets that CI runs, as do the CSR and chain signature checks.
Publication checks. A chain from the CA is served only if the leaf key, identifiers, validity, CA constraint and chain signatures match what was authorized. Anything else is retained for the host and never served.
Revocation authority. Only the issuing account, the certificate key or an account that proved every identity the certificate asserts may revoke. The operation is recorded before the CA call and survives a client disconnect.
Idempotent host calls. The issuer and the revoker receive a durable operation ID on every attempt, so a retry after a lost response cannot produce a second certificate or a second revocation if the host deduplicates as the contract requires.
What the host must provide¶
| Concern | Host responsibility |
|---|---|
| Transport security | HTTPS at the origin Config.BaseURL names. The library never sees the connection |
| Durable, atomic storage | A Store that passes storetest and keeps its uniqueness and revision guarantees under concurrency |
| CA controls | Key protection, serial uniqueness, certificate policy and CRL or OCSP publication behind Issuer and Revoker |
| Deduplication | Issuer and Revoker must deduplicate by OperationID |
| Who may register and order | Policy, external account binding keys and terms of service |
| Rate limits and abuse controls | A Limiter for nonces, new accounts, new orders, challenge responses and renewal information lookups, plus Policy and IssuancePolicy. The only built-in limit is MaxPendingValidations per account |
| CAA and name policy | IssuancePolicy or the CA. The library does not check CAA |
| Token Authority trust | challenge.TokenAuthorities for tkauth-01 |
| Network function certificate contents | The Issuer builds the subject, nfTypes extension and key usages of an NfInstanceId order from the granted names and NF type |
| Unpublished result reconciliation | Query orders with UnpublishedResult and act in the CA |
| Nonce coordination | A shared NonceManager when several replicas serve one origin |
| Retention and audit | Reading and pruning the store |
Threats and treatment¶
| Threat | Treatment |
|---|---|
| Request replay | Single-use nonces, URL binding of every signature |
| Account takeover through key rollover | The inner JWS must be signed by the new key over the old key and the account URL, and the new key must not own another account |
| Issuance for a name the client does not control | Fresh authorizations per order, validators that fetch proof from the resolved destination only, CSR identifiers compared with the order |
| SSRF through validation | Egress policy on every resolved address and every redirect, no proxy use, no destination ports other than 80 and 443 |
| Resource exhaustion through requests | Body size, JSON depth, identifier count, contact count, external account key identifier length and DNS or TLS read limits. Rate limits come from the host's Limiter |
| Nonce flooding through error answers | An error answer to a request that spent no nonce gets one only within the host's newNonce limit, so unauthenticated errors cannot push other clients' nonces out of the manager |
| Worker starvation through validations of unresponsive destinations | A bound on the validations one account may have in progress, a Limiter kind for challenge responses and a Ready that passes while workers hold leases |
| Double issuance after a crash | Dispatch decision stored before the CA call, operation ID reuse, fenced task completion |
| Serving a certificate the CA got wrong | Publication checks, retained unpublished results |
| Forged Authority Tokens | Signature under a certificate the host's trust source returns, claim checks against the challenge identifier and account key, no fetch of x5u |
| Replacing another account's certificate | replaces must name a certificate of the same account that shares an identifier |
Reporting¶
Report suspected vulnerabilities privately as SECURITY.md describes. Only the latest release receives fixes.