Attesto.KeyAttestation (Attesto v1.14.0)

Copy Markdown View Source

OID4VCI Key Attestation in JWT format (OpenID4VCI 1.0 draft 15/ID2, "Key Attestation in JWT format" §D.1, #keyattestation-jwt).

A key attestation is a statement - issued by a Wallet's key storage component or its Wallet Provider - that a set of cryptographic public keys are held in a specific class of secure storage and (optionally) gated behind a specific class of user authentication. A Wallet MAY attach one to a Credential Request, either:

  • in the key_attestation JOSE header of a jwt proof (alongside a proof of possession of one of the attested keys), or
  • as the sole element of an attestation proof type (no proof of possession of any attested key - one attestation can vouch for many).

verify/2 validates the attestation JWT and returns its attested_keys plus any assurance claims (key_storage, user_authentication, certification). Trust in the signer (the key storage component / Wallet Provider) is host-supplied, exactly as Attesto.ClientAssertion and Attesto.WalletAttestation take trusted keys from the caller. Conn-free and fail-closed.

JWT shape (typ=key-attestation+jwt)

  • alg - REQUIRED header; MUST NOT be none or a MAC algorithm.
  • typ - REQUIRED header; MUST be key-attestation+jwt.
  • iat - REQUIRED.
  • exp - OPTIONAL per the spec text, but "MUST be present if the attestation is used with the jwt proof type". Since this module cannot see the surrounding proof type, it defaults to requiring exp (fail-closed); pass require_exp: false for a deployment that only ever uses the attestation proof type and intentionally issues attestations with no expiry.
  • attested_keys - REQUIRED, a non-empty array of public JWKs.
  • key_storage, user_authentication - OPTIONAL non-empty arrays of attack-potential-resistance strings (iso_18045_* or an ecosystem-defined value).
  • certification - OPTIONAL, a URL.
  • nonce - OPTIONAL; MUST echo the Issuer's c_nonce when one was provided. Checked against :nonce when supplied.

As of this draft, the key attestation JWT carries no formal iss/aud claim (unlike the Client/Wallet Attestation JWT) - the spec's own example includes iss, but the normative claim list does not. verify/2 still lets a caller pin :issuer for deployments that populate and rely on it by convention; it is not checked unless supplied.

Summary

Functions

Returns true iff jwk (a public JWK map) is among attested_keys, compared by RFC 7638 thumbprint rather than raw map equality so key members in a different order, or an added alg/use/kid, do not cause a false negative.

Verify a key attestation JWT.

Types

verified()

@type verified() :: %{
  attested_keys: [map()],
  key_storage: [String.t()] | nil,
  user_authentication: [String.t()] | nil,
  certification: String.t() | nil,
  claims: map()
}

verify_error()

@type verify_error() ::
  :invalid_attestation
  | :invalid_typ
  | :invalid_alg
  | :unsupported_critical_header
  | :invalid_signature
  | :missing_iat
  | :invalid_iat
  | :missing_exp
  | :expired
  | :not_yet_valid
  | :missing_attested_keys
  | :invalid_attested_keys
  | :invalid_issuer
  | :invalid_nonce

verify_opts()

@type verify_opts() :: [
  trusted_jwks: map() | [map()],
  issuer: String.t(),
  nonce: String.t(),
  now: DateTime.t() | non_neg_integer(),
  require_exp: boolean(),
  accepted_algs: [Attesto.SigningAlg.alg()],
  enforce_fapi_alg_policy: boolean()
]

Functions

covers_key?(attested_keys, jwk)

@spec covers_key?([map()], map()) :: boolean()

Returns true iff jwk (a public JWK map) is among attested_keys, compared by RFC 7638 thumbprint rather than raw map equality so key members in a different order, or an added alg/use/kid, do not cause a false negative.

Used to cross-check a credential-request proof's holder key against a key attestation's attested_keys (see Attesto.CredentialProof's :key_attestation opt).

verify(attestation, opts \\ [])

@spec verify(String.t(), verify_opts()) ::
  {:ok, verified()} | {:error, verify_error()}

Verify a key attestation JWT.

Required opts

  • :trusted_jwks - an RFC 7517 JWK Set, a single public JWK map, or a list of public JWK maps the attestation's signature is checked against. Establishing which key-storage components / Wallet Providers to trust is the host's responsibility.

Optional opts

  • :issuer - when set, the attestation's iss (if present) MUST equal it. Not required to be present unless the caller relies on it - see the module doc.
  • :nonce - the expected c_nonce; when set, the attestation's nonce claim MUST match it exactly.
  • :now - clock reference (DateTime or unix seconds).
  • :require_exp - whether exp must be present. Defaults to true.
  • :accepted_algs - JWS algorithms accepted. Defaults to Attesto.SigningAlg.fapi_algs/0.
  • :enforce_fapi_alg_policy - additionally enforce the FAPI RSA modulus and Edwards-curve restrictions on the attestation signer's key (parity with Attesto.ClientAssertion and Attesto.WalletAttestation). Defaults to true when :accepted_algs is omitted and false when the caller supplies its own :accepted_algs.

Returns {:ok, %{attested_keys:, key_storage:, user_authentication:, certification:, claims:}}, where attested_keys is the list of public JWK maps this attestation vouches for.