AlgoVoi Live verifier

What are RFC 9421's canonicalization rules?

The canonicalization rules for RFC 9421 HTTP message signatures ensure that covered components are serialized in a deterministic, byte-for-byte identical format before signing or verification. This process includes structured-field canonicalization for HTTP fields, strict ordering of @signature-params, and exact byte representation of the signature base. Without canonicalization, signatures cannot be verified reliably, as even minor formatting differences (e.g., whitespace, header ordering) would break verification.


Why canonicalization matters

HTTP message signatures (RFC 9421) bind cryptographic proofs to HTTP requests or responses. For verification to succeed, the signature base, the exact byte string signed by the sender, must be reconstructed identically by the verifier. Canonicalization eliminates ambiguity by defining how components like headers, query parameters, and metadata are formatted before hashing. If the verifier's reconstruction differs by even a single byte, the signature will fail validation.


How RFC 9421 canonicalization works

1. Covered components and deterministic serialization

Every component listed in the covered-components parameter of @signature-params must be serialized in a fixed order. For example: - HTTP headers are lowercased and sorted alphabetically. - Query parameters are sorted by name (and by value if names collide). - The request target (e.g., /path?query) is normalized to exclude redundant slashes or encoding variations.

This ensures that Host: api.algovoi.co.uk and host: api.algovoi.co.uk produce the same byte sequence.

2. @signature-params canonicalization

The @signature-params component is a structured field that lists the signature's metadata (e.g., algorithm, key ID, covered components). Its canonical form requires: - Components to be listed in the order they appear in the covered-components parameter. - No extraneous whitespace or line breaks. - Strict adherence to the Structured Field format (e.g., integers as bare numbers, strings in quotes).

For example:

@signature-params: ("@method" "@path" "content-digest");keyid="test-key-rsa-pss";alg="rsa-pss-sha512"

3. Structured-field canonicalization

HTTP fields that use structured syntax (e.g., Content-Digest, Signature-Input) must be serialized according to RFC 8941. This means: - Dictionaries are sorted by key. - Lists are ordered as declared. - Items are separated by commas, with no trailing delimiters.

Example for Content-Digest:

Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:

4. Byte-exact signature base construction

The final signature base is constructed by concatenating: 1. The serialized @signature-params. 2. A newline (\n). 3. Each covered component in order, serialized as above.

The verifier must reconstruct this byte string exactly to validate the signature. For example:

("@method" "@path" "content-digest");keyid="test-key-rsa-pss";alg="rsa-pss-sha512"
get
/
sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:

Do it with AlgoVoi

The free, open-source AlgoVoi RFC 9421 Verifier (algovoi-rfc9421-verifier, v0.4.4) implements these canonicalization rules with byte-for-byte parity in Python and TypeScript. It supports Ed25519 signatures today, with ECDSA-P256 and RSA-PSS coming soon.


Start with the docs

Ready to implement RFC 9421 signatures? Start with the docs.