Directory response self-signature

The directory response should carry its own HTTP Message Signatures, one per key, covering the request authority and the Content-Digest of the body, so verifiers can ignore mirrored or misattributed key sets. Advisory.

What this check verifies

The protocol draft recommends that the directory response itself is signed: one HTTP Message Signature per key in the set, made with that key, attached to the response as Signature and Signature-Input headers. A directory that signs must cover two components:

  1. "@authority";req: the authority of the request that fetched the directory. The req flag marks a request component on a response signature.
  2. content-digest: the RFC 9530 digest of the response body, sent as a Content-Digest header.

Each signature also carries created, expires, a keyid that is the key’s RFC 7638 JWK thumbprint, and the tag http-message-signatures-directory.

This check reads those response headers, rebuilds the signature base from every covered component, verifies the signatures against the keys in the directory body, and checks the Content-Digest against the body it received:

  • No Signature/Signature-Input on the response: advisory warning, because signing is RECOMMENDED, not required.
  • A signature verifies and covers "@authority";req and content-digest, and the digest matches the body: pass.
  • A signature verifies but does not cover content-digest: warning. The draft requires both components once a directory signs.
  • A signature verifies but its digest cannot be checked: warning. This happens when the body exceeds 256 KiB, or when a content-encoded (for example gzip) response does not match after decoding, since RFC 9530 digests the encoded bytes.
  • A signature verifies, but the digest does not match the body, the Content-Digest is malformed or uses no algorithm the checker supports (sha-256, sha-512), the keyid is a kid label instead of the thumbprint, or @authority lacks the req flag: fail, with the reason in the message.
  • The signature covers a field the response does not carry, such as content-digest without a Content-Digest field: fail.
  • A signature covers components the checker cannot rebuild for a response (for example a request component like "@method";req), or uses a non-Ed25519 key: warning that names the limitation.
  • Signatures present but none verify, or all are expired: fail, because a broken self-signature is worse than none.

It never caps the grade and never changes the verdict.

Why it matters

The self-signature proves possession: whoever serves the directory also holds the private keys it advertises. Without it, anyone can mirror your key set at their own well-known path and pose as the operator of those keys; the keys are public, after all. A verifier that validates the response signature can ignore keys that arrive without proof of possession, which shuts down mirrored and misattributed directories.

Because the signature covers the request’s authority, a captured response cannot be replayed for a different host. Because it covers content-digest, it also binds the exact key set in the body: a signature lifted onto a different body no longer matches.

How to fix it

  1. At serve time, compute the SHA-256 digest of the exact response body and send it as Content-Digest: sha-256=:<base64>:.
  2. Sign the response with each key in the set, covering ("@authority";req "content-digest"), with created, expires, the thumbprint as keyid, and the tag http-message-signatures-directory. Keep the window short; the headers are computed per response, so a few minutes is plenty.
  3. The directoryResponseHeaders helper in the 0.1.x web-bot-auth package covers "@authority";req only, so its output earns the warning above. The signature base is three lines ("@authority";req: <host>, "content-digest": <field value>, "@signature-params": <inner list and parameters>), so building it by hand and signing it with the key is straightforward.
  4. A static file host cannot set per-request signatures. Serve the well-known path from a small handler (a Worker or equivalent) when you want this pass; until then the check stays an advisory warning.

This site’s own directory does this; check webbotauth.net and compare the response headers.

References

  • The Web Bot Auth protocol draft (draft-ietf-webbotauth-httpsig-protocol-00, Appendix B.1) defines the response signing mechanism, covered components, tag, and validation rules; Appendix E.2.3 has a test vector. It replaces the earlier directory draft.
  • RFC 9421 defines response signatures and the req component flag.
  • RFC 9530 defines the Content-Digest field.
  • How grading works explains how advisory checks affect the score.

How the checker scores this

Tier
JWKS directory
Role
Advisory. Failing this never caps the grade or changes the verdict.
Point deduction
A failure deducts 25 points; a warning deducts 6.