Attesto.SdJwtVc (Attesto v2.6.1)

Copy Markdown View Source

SD-JWT-based Verifiable Credentials (SD-JWT VC), draft-ietf-oauth-sd-jwt-vc.

The IETF profile of Attesto.SdJwt used by the EUDI wallet stack (and its High-Assurance Interoperability Profile, HAIP): an SD-JWT whose Issuer-signed JWT carries a credential type (vct), an issuer (iss), an optional holder key binding (cnf), an optional Token Status List reference (status), and the usual temporal claims, typed vc+sd-jwt or dc+sd-jwt in the JOSE typ header.

This module adds the VC-specific claim rules on top of the base SD-JWT mechanism; the selective-disclosure machinery, recursive verification, and Key Binding JWT handling all come from Attesto.SdJwt.

  • issue/2 โ€” assemble and sign an SD-JWT VC: sets iss/vct/iat (and optional exp/nbf/cnf/status/sub), makes the chosen credential claims selectively disclosable, and stamps the JOSE typ from the optional :typ (vc+sd-jwt or dc+sd-jwt; defaults to vc+sd-jwt).
  • verify/3 โ€” verify the issuer signature (typed vc+sd-jwt), reconstruct the disclosed claims, and enforce the VC claim rules: iss and vct non-empty by default, exp (if present) not passed, nbf (if present) reached. Holder binding is a separate step - pass the returned cnf key to Attesto.SdJwt.verify_key_binding/3 with the presentation's nonce/audience. Explicit certificate identity mode permits an omitted iss after the caller establishes certificate trust.

Conn-free and fail-closed, like the rest of attesto core.

Summary

Functions

Issue an SD-JWT VC.

Verify an SD-JWT VC presentation and reconstruct the disclosed claims.

Types

verified()

@type verified() :: %{
  claims: map(),
  vct: String.t(),
  iss: String.t() | nil,
  cnf: map() | nil,
  key_binding_jwt: String.t() | nil,
  issuer_jwt: String.t(),
  disclosures: [String.t()]
}

verify_error()

@type verify_error() ::
  Attesto.SdJwt.verify_error()
  | :missing_iss
  | :invalid_issuer_identity
  | :disclosed_registered_claim
  | :missing_vct
  | :expired
  | :not_yet_valid

Functions

issue(required, opts \\ [])

@spec issue(keyword(), keyword()) :: String.t()

Issue an SD-JWT VC.

Required options:

  • :iss - the issuer identifier (its .well-known/jwt-vc-issuer or DID).
  • :vct - the verifiable credential type (a collision-resistant string/URI).
  • :pem - the issuer signing key (PEM).

Optional:

  • :claims - the credential subject claims (a map). Defaults to %{}.
  • :disclosable - which of those claim names to make selectively disclosable. Defaults to all of :claims. Registered claims (iss/vct/cnf/status/iat/exp/nbf/sub) are never made disclosable even if listed here - they always remain visible, so a holder cannot strip holder-binding (cnf) or a status reference.
  • :cnf - the holder key-binding confirmation (RFC 7800), e.g. %{"jwk" => holder_public_jwk}. Included for later Key Binding.
  • :status - a Token Status List reference map, typically built with Attesto.StatusList.reference/2. Always visible when present.
  • :iat / :exp / :nbf / :sub - standard claims (unix seconds / string).
  • :now - clock reference for a defaulted :iat.
  • :kid - JOSE kid header. :sd_alg - SD hashing algorithm.
  • :typ - the SD-JWT VC media type stamped in the JOSE typ header, "vc+sd-jwt" or "dc+sd-jwt" (the credential configuration's format). Defaults to "vc+sd-jwt".
  • :x5c - the issuer X.509 certificate chain (RFC 7515 ยง4.1.6): a non-empty list of base64 DER certificate strings, stamped in the JOSE x5c header so a verifier can bind the credential to a trusted issuer certificate (HAIP). Omitted when nil.

Returns the SD-JWT VC Issuance string (no Key Binding JWT).

verify(combined, jwks, opts \\ [])

@spec verify(String.t(), map() | [map()] | list(), keyword()) ::
  {:ok, verified()} | {:error, verify_error()}

Verify an SD-JWT VC presentation and reconstruct the disclosed claims.

jwks is the issuer's JWK Set. Options are passed through to Attesto.SdJwt.verify/3 (e.g. :accepted_algs), plus:

  • :now / :max_age_seconds - clock reference for the temporal checks.
  • :issuer_identity - defaults to :claim, requiring a nonempty iss. Set :certificate only after validating the issuer's certificate chain and supplying its verified leaf public key as jwks. This mode permits an omitted iss when the signed header contains x5c, as in the SD-JWT VC profile referenced by HAIP. A present malformed iss still fails. This module does not establish certificate trust; an x5c header alone is never a trust decision.

Returns {:ok, %{claims:, vct:, iss:, cnf:, key_binding_jwt:, ...}}. Holder binding is NOT checked here - if cnf is present and the presentation carries a Key Binding JWT, pass both to Attesto.SdJwt.verify_key_binding/3 with the verifier's expected nonce/audience.

A presentation is rejected if a supplied disclosure reconstructs one of the registered claims that must have remained visible. A digest does not reveal the name of an omitted disclosure, so a nonconforming issuer-hidden optional claim that the holder omits is indistinguishable from an absent optional claim. Verifiers must therefore trust the issuer to follow the profile's registered-claim visibility rule.