Skip to content

JWKS decoding fails the whole set on an unknown kty (RFC 7517 §5) #246

Description

@RalphBragg

Summary

JWKS is Decodable, and the key-type enum has no unknown case, so decoding a key set that contains a key with an unrecognised kty throws DecodingError.dataCorrupted and the whole set fails to decode. Per RFC 7517 section 5 an unrecognised key should be ignored, not fatal, so one post-quantum key in a published JWKS takes down the classical keys with it.

Reproduction

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

let jwks = try JSONDecoder().decode(JWKS.self, from: mixedJWKS)
// DecodingError.dataCorrupted: Path keys[2].kty,
// "Cannot initialize Backing from invalid String value AKP"

Measured against jwt-kit 5.6.0. The set decodes 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." ML-DSA (FIPS 204 / RFC 9964, kty: "AKP") key publication is beginning across the ecosystem. When an issuer adds an ML-DSA key to a JWKS that a jwt-kit consumer reads, the whole JWKS fails to decode, so the consumer stops verifying every signature from that issuer, including classical RS256/ES256, on a spec-compliant key publication it does not control. For Vapor services fetching a remote JWKS (OIDC, open banking) that is an externally triggered outage.

Suggested fix

Make JWKS decode leniently: decode keys element by element and skip entries that fail to decode into a JWK (optionally record them), rather than failing the container. Alternatively add an unknown case to the key-type enum so an unrecognised key decodes into an inert JWK that is never selected by kid. Either implements the RFC section 5 SHOULD.

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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions