Attesto.Key (Attesto v1.11.0)

Copy Markdown View Source

Pure helpers for working with signing material as PEM strings.

An RSA private key already contains its public half, so there is never a separately stored public PEM to drift out of sync. public_pem/1 derives the public key from a private PEM, giving exactly one source of truth: the verification key always matches the signing key. This closes a real failure mode where a tracked public PEM and a regenerated private key silently mismatch and every verification fails.

kid/1 is the RFC 7638 JWK thumbprint of a key's public half. It is stable for a given key and changes iff the key changes, so rotating to a new key yields a distinct kid automatically - no separate identifier to assign or track.

Summary

Functions

Parse a PEM (private or public) into a JOSE.JWK.

The RFC 7638 SHA-256 JWK thumbprint (kid) of the public half of the key in pem. Accepts a private or public PEM; both yield the same thumbprint because it is computed over the public members only.

Derive the public key, in conventional SPKI (-----BEGIN PUBLIC KEY-----) PEM form, from a private RSA key PEM.

Parse a private PEM into a JOSE.JWK whose public half can sign and derive a kid.

Validate and parse an untrusted JWK for signature verification.

Types

verification_jwk_error()

@type verification_jwk_error() ::
  :private_material
  | :invalid_use
  | :alg_mismatch
  | :incompatible_key
  | :weak_key
  | :oversized_key
  | :malformed_jwk

Functions

jwk(pem)

@spec jwk(String.t()) :: JOSE.JWK.t()

Parse a PEM (private or public) into a JOSE.JWK.

Raises ArgumentError if pem does not contain exactly one parseable key. JOSE.JWK.from_pem/1 returns [] for input with no key entry and a list for a multi-key PEM; left unguarded, thumbprint/1 of those returns [] rather than a string, which would silently poison kid/1 and verification-key selection. Failing loudly here surfaces a malformed keystore PEM as a configuration error instead of a request-time mystery.

Also raises if the key type/curve is not supported by Attesto's asymmetric signing algorithms. Algorithms are derived from trusted key metadata, not from a presented token header.

kid(pem)

@spec kid(String.t()) :: String.t()

The RFC 7638 SHA-256 JWK thumbprint (kid) of the public half of the key in pem. Accepts a private or public PEM; both yield the same thumbprint because it is computed over the public members only.

public_pem(pem)

@spec public_pem(String.t()) :: String.t()

Derive the public key, in conventional SPKI (-----BEGIN PUBLIC KEY-----) PEM form, from a private RSA key PEM.

Accepts the PKCS#1 (RSA PRIVATE KEY) and PKCS#8 (PRIVATE KEY) forms. Raises ArgumentError - signing material is operator-provided, so a misconfiguration is a deploy-time failure that should be loud rather than silently verifying against garbage - if pem contains no key entry, contains more than one, contains a non-RSA key, or is public-only. EC/OKP deployments should publish JWKS instead.

signing_jwk(pem)

@spec signing_jwk(String.t()) :: JOSE.JWK.t()

Parse a private PEM into a JOSE.JWK whose public half can sign and derive a kid.

Unlike jwk/1, this rejects public-only PEMs: they are valid verification material, but cannot sign tokens.

verification_jwk(jwk_map, opts)

@spec verification_jwk(
  map(),
  keyword()
) :: {:ok, JOSE.JWK.t()} | {:error, verification_jwk_error()}

Validate and parse an untrusted JWK for signature verification.

The raw map is checked before parsing so private members and contradictory RFC 7517 metadata cannot be normalized away by the JOSE library. By default, private material is rejected and RSA verification keys must be at least 2048 bits.

:alg is required and is compared with a JWK's optional alg member. :require_public? defaults to true, and :minimum_rsa_bits defaults to 2048.

To retain DPoP's error semantics, explicit Edwards identifiers are checked against the key curve here, while other key-type/algorithm mismatches remain the signature verifier's responsibility.