DPoP-SK normative-statement companion
Extracted with AI assistance (Claude Fable 5, Anthropic) from the pinned spec source; awaiting review by the human editor, like the spec itself.
Verification steps 1-4 and 7-8 of #attestation-verification are normative only by the lead-in ('Verification, in order, all fail-closed:') and carry no BCP 14 keyword; errata candidate: give the lead-in a MUST.
The tls-exporter key-derivation formula (#kd-exporter, 'Both ends compute...') is definitional prose with no BCP 14 keyword; conformance to it hangs on the conformance section's 'implements' list. Errata candidate.
'The flavour REQUIRES TLS 1.3.' (#kd-exporter) uses the non-BCP14 form REQUIRES; the requirement is captured here via DPOPSK-EST-6's MUST. Errata candidate: rephrase with a BCP 14 keyword.
'Neither party may log or persist it' (#establishment-response) uses lowercase 'may' with mandatory intent (RFC 8174 reserves only UPPERCASE forms); the enforced form is DPOPSK-SEC-KH-1's MUST NOT. Errata candidate.
'It MUST use the https scheme and SHOULD be same-origin with resource.' (#discovery) mixes two requirement levels in one sentence; split here into DPOPSK-DISC-1 and DPOPSK-DISC-2.
The conformance section (#impl-status) enumerates what each conformance class 'implements' without BCP 14 force; the per-statement inventory here is the checkable form.
DPoP-SK: Negotiated Symmetric Session Keys for DPoP-Bound Requests
DPoP-SK resource server
DPoP-SK client
No conformance vectors exist yet for this profile: the spec is design-first, implementation-pending (see the spec's Conformance and implementation status section — 'There are no implementations of this profile as of this draft.'). Vectors are planned alongside the solid-server-rs Tier-2 reference implementation, homed as a dpop-sk suite in jeswr/agentic-solid-conformance; the spec's execution-verified tools/compute-examples.mjs (key derivation, confirm value, signature base, HMAC tag) is the seed fixture set.
Not testable as specified: exhausting the 64-bit counter space (2^64 - 1 values) is unreachable in any practical test run, and the spec itself calls the bound theoretical. The statement is retained for completeness; a unit-level test could only exercise an artificially lowered bound, which the spec does not define.
A resource server implementing DPoP-SK MUST continue to accept ordinary per-request DPoP exactly as before.
A client MUST NOT use DPoP-SK against a server that has not advertised it
An access token MUST NOT ever be accepted bare (bearer-style).
'It' = the pop_session endpoint member (the session establishment endpoint URL).
Subject of the fragment: the pop_session endpoint member. Split from the same sentence as DPOPSK-DISC-1 (two levels in one sentence; see the companion's extraction notes).
A server MUST NOT advertise tls-exporter on any deployment where it does not terminate TLS in the same process that evaluates requests
Deployment-topology property: where TLS terminates is not observable black-box; checkable only by deployment audit.
Clients MUST ignore a pop_session member whose profile they do not recognise.
A server MAY additionally direct clients to the metadata document from any 401 challenge using the resource_metadata parameter of WWW-Authenticate
A client MUST NOT attempt establishment unless the metadata offers an algorithm and a channel binding flavour it supports.
The request MUST be authenticated as an ordinary DPoP request: the server MUST perform the complete RFC9449 Section 4.3 validation of the proof
A session MUST NOT be created if any check fails.
If the server cannot satisfy it exactly it MUST refuse with 400
'It' = the requested channel binding flavour (the establishment body's cb member, which is a demand, not a menu).
Continuation of the DPOPSK-EST-3 sentence: on an unsatisfiable cb demand the server refuses; it never answers with a different flavour.
the server MUST additionally verify that the request arrived on a TLS 1.3 connection terminated by the server process itself
Condition: cb=tls-exporter establishment only. Self-termination is deployment topology (audit-only); the TLS-version half is black-box testable via DPOPSK-EST-6.
MUST reject establishment over TLS < 1.3
Condition: cb=tls-exporter establishment only. Captures the #kd-exporter 'The flavour REQUIRES TLS 1.3.' requirement in BCP 14 form (see extraction notes).
The server SHOULD rate-limit this endpoint at least as strictly as any authenticated write
Rate limiting is observable under load but the threshold is deployment policy; audit-checked.
MUST contain at least 128 bits of CSPRNG output, encoded base64url without padding
Subject of the fragment: the session_id response member. Length and encoding are black-box observable, but the CSPRNG-source claim is only auditable — hence A-exist.
'One' = a session_id value.
'It' = the response cb member.
a client MUST abort (discard the session, use plain DPoP) if it differs
'It' = the response cb member vs the requested flavour.
key (REQUIRED when cb=none; MUST be absent otherwise)
confirm (REQUIRED when cb=tls-exporter; MUST be absent otherwise)
A client MUST verify it and MUST discard the session on mismatch.
'It' = the confirm key-confirmation value; the derivation and expected value are execution-verified by the spec's tools/compute-examples.mjs.
The response MUST carry Cache-Control: no-store.
Browser clients SHOULD import it as a non-extractable WebCrypto HMAC key and discard the raw bytes immediately.
Implementations MUST use the exporter_master_secret
Condition: cb=tls-exporter derivation. The derivation pipeline (HKDF salt/info construction) is deterministic and vectorable from a fixed EKM — the spec's tools/compute-examples.mjs reproduces it; using the wrong exporter secret manifests as a key-confirmation mismatch.
Capacity bounds and eviction policy are implementation state, auditable but not deterministically black-box testable.
Inside an established session the client MUST NOT send a DPoP proof header field with attested requests
The covered components MUST include, at minimum and in this order: ("@method" "@target-uri" "authorization")
servers MUST verify whatever set was declared.
'Set' = the declared covered-component set of the attestation signature.
created (REQUIRED, Integer), keyid (REQUIRED, the session identifier)
The REQUIRED signature parameters; the source sentence continues with nonce (REQUIRED, the counter) — the counter discipline itself is DPOPSK-AR-1..5.
if present it MUST equal the session's algorithm
Condition: the OPTIONAL alg signature parameter is present. Server-side enforcement is DPOPSK-DG-5.
the server MUST process it under this profile exclusively
Condition: the request bears a signature whose tag is dpop-sk.
it MUST NOT fall back to evaluating a DPoP header also present on the same request
MUST NOT treat the access token as bearer under any outcome
servers SHOULD apply the same window they apply to DPoP iat
The freshness acceptance window for the created signature parameter.
This step MUST complete successfully before any session-state mutation.
'This step' = signature verification (step 6). Black-box testable via the forged-traffic window-burn probe (adversarial-review entry A7).
Any failure of steps 1–7 MUST yield 401 with the server's standard WWW-Authenticate: DPoP challenge
A DPoP-SK client receiving a 401 on an attested request MUST treat the session as dead and either re-establish or fall back to per-request DPoP
servers MUST NOT emit, and clients MUST NOT require, any DPoP-SK-specific error code
the client MUST start at 1 and assign strictly increasing values — never reusing one
The nonce parameter's per-session counter discipline.
Continuation of DPOPSK-AR-1's sentence (gaps are tolerated but waste window space).
Values MUST fit in an unsigned 64-bit integer
a client that could exhaust the space MUST re-establish first
Servers MUST reject non-numeric, zero, or >64-bit values at parse time.
W = the receive-window width.
Continuation of DPOPSK-AR-6's sentence: the recommended window width.
the window MUST NOT be consulted-and-mutated, advanced, or shifted for any request whose HMAC has not verified
The signature-verify + window check-and-mark pair for one session MUST be atomic with respect to concurrent requests
Concurrency atomicity is exercisable only by nondeterministic race probing; deterministic vectors cannot pin it. A formal model (sc:formalModel seam) is the stronger future check.
expires_in MUST NOT exceed the remaining lifetime of the bound access token
Continuation of DPOPSK-LT-1's sentence: the recommended ceiling on expires_in.
Servers MUST enforce both the session expiry and the token expiry on every request.
Clients MAY re-establish before expiry and overlap the old and new sessions.
The server MAY invalidate any session at any time
Clients MUST tolerate this at any moment (it is indistinguishable from expiry).
'This' = a server-forced session invalidation.
A client SHOULD terminate a session it will not use again
The server MUST verify the attestation like any other request before deleting, and respond 204
Implementations MUST NOT persist K to durable storage.
Negative internal property; audit/code-review only.
a request carrying a valid DPoP proof and no dpop-sk-tagged signature MUST be processed as plain DPoP, always, on every server
the server MUST NOT create a session under a different flavour than requested (400 instead)
the client MUST discard a session whose response cb differs from its request
The server MUST verify with the session's algorithm only, regardless of any alg parameter on the request
Servers MUST NOT advertise, and clients MUST NOT use, tls-exporter across any TLS-terminating intermediary
establishment requests and attested requests MUST be rejected (with the standard challenge) if received as early data
Deterministically testable with a TLS 1.3 test client offering 0-RTT early data.
the early exporter MUST NOT be used in key derivation
Internal KDF-input choice; a wrong choice surfaces indirectly as key-confirmation mismatch but the prohibition itself is audit-checked.
Deployments where the target URI must be reconstructed (e.g. behind a trusted reverse proxy, cb=none only) MUST derive it from configuration or authenticated forwarding information, never from unauthenticated client-controlled headers.
Deployment configuration property; spot-checkable by probing with spoofed forwarding headers but conformance is a topology/config audit.
they MUST NOT be logged, MUST NOT appear in URLs, MUST NOT be persisted durably
'They' = K and the key response member (credentials).
SHOULD be held non-extractable where the platform allows (WebCrypto)
Timing discipline; checkable by code audit or statistical timing analysis, not a deterministic vector.
session_id MAY appear in logs (it is an identifier, not a secret)