Attesto.SdJwtVc (Attesto v1.9.0)

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 REQUIRED and non-empty, 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.

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(),
  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
  | :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.
  • :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.

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.