Skip to content

JwkSet deserialization fails the whole set on an unknown kty (RFC 7517 §5) #529

Description

@RalphBragg

Summary

JwkSet derives Deserialize, and AlgorithmParameters is an untagged enum with no fallback variant. A key whose kty (or alg) is not one of the known variants therefore fails deserialization of the entire JwkSet, not just that key. Per RFC 7517 section 5 an unrecognised key should be ignored, so one post-quantum key in a published JWKS breaks parsing of the classical keys alongside it.

Reproduction

A JWKS with a classical key and one post-quantum ML-DSA key (kty: "AKP", RFC 9964):

let set: jsonwebtoken::jwk::JwkSet = serde_json::from_str(mixed_jwks)?;
// Err: data did not match any variant of untagged enum AlgorithmParameters

Measured against 10.4.0 (fails on the unknown kty) and 9.3.1 (fails on the unknown alg). The set deserializes fine once the AKP key is removed. Fixture and probe available on request.

Why this matters

RFC 7517 section 5: "Implementations SHOULD ignore JWKs within a JWK Set that use kty values that are not understood by them." As post-quantum migration begins (ML-DSA in Node today, Go stdlib in 1.27, RFC 9964 defines the AKP JWK form), issuers will publish AKP keys into key sets that jsonwebtoken consumers read. Because the whole JwkSet fails to deserialize, those consumers stop verifying every signature from that issuer, including classical RS256/ES256, on a key publication they do not control.

Suggested fix

Two options, either works:

  • Add a catch-all variant to AlgorithmParameters (for example an Other/Unknown arm, or #[serde(other)] where applicable) so an unknown key deserializes into an inert variant and JwkSet::find(kid) simply never selects it; or
  • Deserialize keys as a Vec of raw values and skip members that fail to parse into a Jwk, keeping the recognised keys.

Either implements the RFC section 5 SHOULD without changing behaviour for recognised keys.

Offer

Happy to share the reproduction harness (mixed classical + AKP JWKS plus a control) and to open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions