aitp-transport-http — hardening register

Status tracker for the aitp-transport-http subsystems. CLAUDE.md's architecture notes point here ("each one corresponds to a hardening item in docs/transport-hardening.md").

aitp-transport-http is the only async crate in the workspace (reqwest/axum/tokio); the protocol crates stay sync. Features split: client, server, client-spki-pinning (the facade re-exposes them as http-client / http-server / all).

Status legend: scaffolded (compiles, thin) · tested (unit/integration coverage) · documented (rustdoc + usage notes) · done (tested + documented, shipping in 0.2.0).

Subsystems

ModulePurposeRFCStatusRemaining / acceptance
client.rsManifest fetch (HTTPS-only, cache validators, retry)0003 / 0007doneHonors published_at/expires_at; HTTPS enforced.
client_config.rsConnection-pool + TLS knobs per fetcherdoneDocument max-pool-size + any per-route override if one is added.
key_resolution.rsKeyResolutionPolicy: cache → pinned store → /.well-known/aitp-keys → OIDC JWKS, with fail modes0007doneRequires a multi-thread tokio context in the calling thread; pure-sync deployments MUST use the pinned-issuer store. SoftFail fails closed on resolve(); degraded state only via resolve_outcome().
dpop.rsDPoP (RFC 9449) proof generation + verification, replay cacheRFC 9449testedOpen: wire DpopProof into the token_exchange.rs flow end-to-end; add a conformance-style test for the bound-token path.
retry.rsExponential backoff + jitter for idempotent outbound readsdoneJitter strategy + max-attempts are configurable; keep retries to idempotent GETs only.
revocation.rsRevocationCache + RevocationProvider, per-issuer cache, fail modes0008doneOpen (nice-to-have): add a no_op provider type for tests; keep RevocationFailMode default = fail-closed.
server.rsManifestServer + HandshakeServer (hello/commit), RevocationListProducer0003 / 0004doneProducer trait lets a control plane supply signed lists; never mint a fresh empty list on backing-store failure.
server_limits.rsRequest body-size cap (axum-level) + header recommendations0009doneDocument how the cap composes with axum::DefaultBodyLimit.
tls_pinning.rsSHA-256 SPKI pinning for outbound HTTPSRFC 7469doneBehind client-spki-pinning (off by default — avoids pulling a CryptoProvider). Document feature activation + a reqwest integration example.
token_exchange.rsOAuth 2.0 Token Exchange (RFC 8693): bootstrap OIDC identity from mTLS/SAML/JWTRFC 8693testedOpen: add a JWT → AID mapping test; confirm composition with KeyResolutionPolicy for the resulting identity.
session_bundle_server.rsSession Trust Bundle HTTP transport0010 (draft)testedGated by experimental-session-bundle; draft, no wire-stability promise.

Cross-cutting acceptance criteria

  • Async stays contained. No async leaks into aitp-core / aitp-tct / aitp-handshake. New blocking-bridge points must document the tokio-context requirement (as key_resolution.rs does).
  • Fail-closed defaults. Revocation and key-resolution soft-fail modes must fail closed on the plain accessor; degraded state is opt-in via the *_outcome() variants.
  • Feature minimalism. Pinning stays behind client-spki-pinning so a default http-client build doesn't pull in a rustls CryptoProvider.

Open items (rolled up)

  1. dpop.rstoken_exchange.rs: end-to-end DPoP-bound token-exchange flow + test.
  2. token_exchange.rs: JWT → AID mapping test.
  3. revocation.rs: no_op provider type for tests.
  4. Usage examples in rustdoc for tls_pinning (reqwest) and client_config pool sizing.