Expand description
SD-JWT (Selective Disclosure for JWTs) issuance and verification, per
draft-ietf-oauth-selective-disclosure-jwt.
An SD-JWT lets an issuer mint a single signed token that carries some
claims in the clear and others only as digests (_sd[]), plus a
separate list of Disclosures — [salt, claim_name, claim_value]
triples — that reveal what each digest stands for. A holder decides,
per presentation, which Disclosures to forward alongside the JWT; a
verifier can only recover the claims for the Disclosures it was handed,
and can cryptographically prove every disclosed value was actually
vouched for by the issuer (its digest is in _sd[], which is inside
the signed payload) without the issuer needing to mint one token per
disclosure combination.
§What this module does and does not implement
In scope: issuing and verifying flat, top-level, object-property
Disclosures, serialized in SD-JWT compact form (<jwt>~<d1>~<d2>~).
Deliberately out of scope (spec features this module does not touch):
- Key Binding JWT (KB-JWT) — holder proof-of-possession. This module
verifies the issuer’s signature and the Disclosure digests only; it
has no notion of a holder key or a
~<kb-jwt>suffix. - Array-element and recursive/nested Disclosures — only flat top-level object properties are supported, matching every consumer this crate has today.
- SD-JWT VC (
vc+sd-jwt) — novct/type metadata handling.
None of these are hard to misuse into thinking they’re covered — there is simply no code path for them. A caller needing KB-JWT or nested disclosures needs to build that on top, not assume it’s already here.
§Security properties this module enforces (and why)
_sd_algis never silently defaulted tosha-256when present and unrecognized. A verifier that treats an unknown digest algorithm as “must mean sha-256” is an algorithm-confusion bug: an attacker who controls (or can influence) the claimed_sd_algcould otherwise coax a verifier into hashing Disclosures with a weaker/attacker- favorable function while the verifier’s logic still believes it’s checking sha-256 digests. This module fails closed instead: an absent_sd_algdefaults to sha-256 (per spec, the assumed default), but a present-and-different value is rejected outright.- A presented Disclosure whose digest is not found in
_sd[]fails the whole verification, not just that one claim. Accepting it would let a holder (or a network attacker who can append to the compact form) inject arbitrary claims the issuer never signed for — the entire point of_sd[]living inside the signed JWT payload is that only digests the issuer actually put there are trustworthy. - Duplicate digests in
_sd[]are rejected. They serve no legitimate purpose (each Disclosure is independently salted, so two honestly-generated Disclosures never collide) and are a cheap way to smuggle a second, attacker-chosen Disclosure past the “digest found” check above once one legitimate Disclosure’s digest becomes known. - A disclosed claim can never shadow a registered top-level JWT claim
(
iss,sub,aud,exp,iat,nbf,jti,scope) or an already-presentextraclaim. Selective disclosure is additive by design; letting a Disclosure silently overwriteaudorexpwould let a holder forge the very claims the issuer’s signature is supposed to pin down.
Structs§
- Disclosable
Claim - A claim an issuer wants to make selectively disclosable, instead of stamping it directly onto the JWT payload.
- Issued
SdJwt - The result of issuing an SD-JWT: the signed JWT, the SD-JWT compact serialization ready to hand to a holder, and the raw Disclosure strings (in case the caller wants to persist or selectively re-forward a subset later, e.g. to build a holder-controlled presentation).
- Verified
SdJwt - The result of verifying a presented SD-JWT compact form: the validated
JWT claims (signature,
iss/aud/expalready checked byTokenManager::validate_token) plus whatever claims the presented Disclosures actually proved out.