Verify a signed HTTP request (RFC 9421, with IETF example)

HTTP Message Signatures following RFC 9421 are the basis of Web Bot Auth and the Trusted Agent Protocol. This guide verifies the official example from the standard and shows how tampering is detected.

Key points

  • HTTP signatures following RFC 9421 are the basis of Web Bot Auth and the Trusted Agent Protocol.
  • The official example from Appendix B.2.6 yields indeterminate, level KYA-A1, in KYA.
  • A change to the signed path makes the signature invalid.
  • A valid signature proves origin, not the authority for the action.

Prepare the signed request

A signed request consists of the request line, headers, an empty line and the content. The Signature-Input and Signature headers carry the signature. The example from Appendix B.2.6 of RFC 9421 looks like this:

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Length: 18
Signature-Input: sig-b26=("date" "@method" "@path" "@authority" "content-type" "content-length");created=1618884473;keyid="test-key-ed25519"
Signature: sig-b26=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:

{"hello": "world"}

Signed here are date, method, path, host, content type and content length, using an Ed25519 test key.

Provide the public key as a JWKS

On the verification page, open the advanced section for keys, status lists and timestamp anchors, and paste the public test key from Appendix B.1.4 under “Trusted keys (JWK or JWKS)”:

{"keys":[{"kty":"OKP","crv":"Ed25519","kid":"test-key-ed25519","x":"JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"}]}

The kid must match the keyid in Signature-Input. In practice, the key comes from the operator's published directory.

Verify

Paste the request into the input field and click “Verify”. It is quicker with the example “IETF RFC 9421 (Appendix B.2.6)” under “Examples”, which already contains request and key.

The result is “indeterminate” at level KYA-A1: the signature is valid, the key comes from the verifying party, identity and instruction are proven. The request contains no authority.

Counter-check: change the path

Change only the path in the request line from /foo to /bar and verify again. Because the path is part of the signature base, the signature no longer matches, and the verdict is “invalid”.

This counter-check shows what HTTP signatures achieve: any change to a signed component is detected. Unsigned headers, by contrast, could be changed unnoticed; that is why all relevant parts belong in the signature.

Interpret the result

A valid HTTP signature proves whose agent is asking, not what it may do. For purchases and other actions with consequences, proof of authority is also needed, such as a mandate or a signed purchase intent following Verifiable Intent.

The same verification applies to requests following Web Bot Auth and to the signature level of the Trusted Agent Protocol.

Frequently asked questions

Which algorithms does KYA verify for HTTP signatures?

Ed25519, ECDSA and RSA-PSS. The standard also registers HMAC, which is not suitable for public verification by third parties because it requires a shared key.

Why is the result not valid?

Because a signature only proves the origin of the request. For “valid”, the authority for the action must also be proven, and a plain HTTP signature does not contain it.

Do I have to provide the key myself?

Yes. KYA makes no network requests and does not load key directories automatically. This keeps the trust decision with the verifying party.

Can I create my own signatures with OpenSSL?

Yes. Build the signature base following RFC 9421, sign it with your private key and set the Signature-Input and Signature headers. Appendix B of the standard serves as a template.

Sources

  1. RFC 9421, Anhang B.2.6: https://www.rfc-editor.org/rfc/rfc9421.html#appendix-B.2.6
  2. RFC 9421, Anhang B.1.4 (Testschlüssel): https://www.rfc-editor.org/rfc/rfc9421.html#appendix-B.1.4