# `Attesto.KeyAttestation`
[🔗](https://github.com/XukuLLC/attesto/blob/v2.1.0/lib/attesto/key_attestation.ex#L1)

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.

# `verified`

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

# `verify_error`

```elixir
@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`

```elixir
@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()
]
```

# `covers_key?`

```elixir
@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`

```elixir
@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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
