Attesto.SigningAlg (Attesto v1.4.1)

Copy Markdown View Source

Key-derived JOSE signing algorithm helpers.

Attesto treats the algorithm as metadata of the trusted key selected by kid, never as policy learned from the presented token. RSA keys infer RS256 (RSASSA-PKCS1-v1_5) as the JWA default for the RSA key type, while EC/OKP keys infer their JOSE algorithm from the public JWK curve. For wire compatibility, Ed25519 and Ed448 inference retains the legacy EdDSA identifier; trusted keystore metadata can opt into RFC 9864's explicit Ed25519 or Ed448 identifiers. RSA deployments that intentionally use PS256 can likewise label the key through keystore metadata. Ed448 requires a JOSE backend with Curve448 and SHAKE256 support.

Summary

Functions

Algorithms Attesto can sign/verify when backed by a matching key.

Default set of algorithms accepted for signatures a client presents (client assertions and request objects).

Signing algorithms permitted for FAPI 2 client authentication and, when a signed Request Object is processed, its signature: PS256, ES256, legacy EdDSA over Ed25519, and RFC 9864 Ed25519.

Whether alg and its trusted key satisfy Attesto's default FAPI policy.

Resolve the algorithm for a key in keystore.

hash_alg(alg) deprecated

Return the fixed digest associated with an ID Token signing algorithm.

Return half the fixed digest length for an ID Token signing algorithm.

Infer the default algorithm from a parsed JWK's public members.

The unique signing algorithms across a keystore's verification keys.

Calculate an OIDC at_hash / c_hash value for a key-bound algorithm.

Return the OIDC hash profile bound to alg and a trusted key.

Whether an RSA JWK's unsigned modulus is at least minimum_bits long.

Validate that alg is one of Attesto's supported asymmetric JOSE algorithms.

Validate an algorithm and bind it to a compatible trusted key.

Types

alg()

@type alg() :: String.t()

oidc_hash_profile()

@type oidc_hash_profile() ::
  {:fixed, :sha256 | :sha384 | :sha512, pos_integer()}
  | {:xof, :shake256, pos_integer(), pos_integer()}

Functions

allowed()

@spec allowed() :: [alg()]

Algorithms Attesto can sign/verify when backed by a matching key.

default_client_algs()

@spec default_client_algs() :: [alg()]

Default set of algorithms accepted for signatures a client presents (client assertions and request objects).

Equal to fapi_algs/0: PS256, ES256, legacy EdDSA over Ed25519, and explicit Ed25519. A host with a non-FAPI profile can pass an explicit :accepted_algs option to the relevant verifier. A composed FAPI profile that narrows this list also passes enforce_fapi_alg_policy: true to retain the FAPI 2 key-strength and curve gates.

fapi_algs()

@spec fapi_algs() :: [alg()]

Signing algorithms permitted for FAPI 2 client authentication and, when a signed Request Object is processed, its signature: PS256, ES256, legacy EdDSA over Ed25519, and RFC 9864 Ed25519.

The algorithm list alone cannot express legacy EdDSA's curve. Verifiers using this policy also call fapi_compatible?/2, which requires an RSA modulus of at least 2048 bits and rejects an Ed448 key even when its trusted metadata uses the legacy EdDSA identifier.

RS256 (RSASSA-PKCS1-v1_5) is deliberately excluded - FAPI 2 mandates PS256 for RSA keys. This is the policy gate for verifying a signature a client presents; it is narrower than allowed/0, which still admits RS256 for the provider's own token signing.

fapi_compatible?(alg, jwk)

@spec fapi_compatible?(term(), JOSE.JWK.t()) :: boolean()

Whether alg and its trusted key satisfy Attesto's default FAPI policy.

RSA keys require a modulus of at least 2048 bits. The legacy EdDSA identifier is accepted only over an Ed25519 key. Ed448 and weaker RSA keys remain available to callers that explicitly select a non-FAPI algorithm policy.

for_key(keystore, pem, opts \\ [])

@spec for_key(module(), String.t(), keyword()) :: alg()

Resolve the algorithm for a key in keystore.

Resolution order:

  • per-key metadata from key_algs/0, keyed by RFC 7638 kid
  • signing_alg/0 for the current signing key only
  • inference from the JWK type/curve

hash_alg(alg)

This function is deprecated. EdDSA is curve-dependent; use oidc_hash_profile/2 or oidc_hash/3.
@spec hash_alg(alg()) :: :sha256 | :sha384 | :sha512

Return the fixed digest associated with an ID Token signing algorithm.

Deprecated because EdDSA's digest is curve-dependent. Its keyless EdDSA result corresponds to Ed25519; use oidc_hash_profile/2 or oidc_hash/3 for key-aware calculation.

hash_half_bytes(alg)

This function is deprecated. EdDSA is curve-dependent; use oidc_hash_profile/2 or oidc_hash/3.
@spec hash_half_bytes(alg()) :: pos_integer()

Return half the fixed digest length for an ID Token signing algorithm.

Deprecated because EdDSA's digest length is curve-dependent. Its keyless EdDSA result corresponds to Ed25519; use oidc_hash_profile/2 or oidc_hash/3 for key-aware calculation.

infer(jwk)

@spec infer(JOSE.JWK.t()) :: alg()

Infer the default algorithm from a parsed JWK's public members.

keystore_algs(keystore)

@spec keystore_algs(module()) :: [alg()]

The unique signing algorithms across a keystore's verification keys.

Used to advertise the algorithms the server itself signs with (the id_token_signing_alg_values_supported and the JARM authorization_signing_alg_values_supported, which share the same keys). Returns [] when the keystore exposes no verification keys (or resolution fails), leaving the caller to apply any default.

oidc_hash(value, alg, jwk)

@spec oidc_hash(binary(), alg(), JOSE.JWK.t()) :: String.t()

Calculate an OIDC at_hash / c_hash value for a key-bound algorithm.

Applying OIDC's generic "hash associated with the signing algorithm" rule to RFC 8032, legacy EdDSA selects from the trusted key curve: SHA-512 (left 32 bytes) for Ed25519, or SHAKE256 with 114 bytes of output (left 57 bytes) for Ed448. SHAKE256 is invoked through JOSE's configured SHA3 module, preserving the application's chosen pure-Erlang, NIF, or driver backend.

oidc_hash_profile(alg, jwk)

@spec oidc_hash_profile(alg(), JOSE.JWK.t()) :: oidc_hash_profile()

Return the OIDC hash profile bound to alg and a trusted key.

Fixed-output hashes return {:fixed, digest, half_bytes}. Ed448 returns {:xof, :shake256, output_bytes, half_bytes}, making both SHAKE256 lengths explicit and avoiding the ambiguity of the keyless legacy helpers.

rsa_modulus_at_least?(jwk, minimum_bits)

@spec rsa_modulus_at_least?(JOSE.JWK.t(), pos_integer()) :: boolean()

Whether an RSA JWK's unsigned modulus is at least minimum_bits long.

Returns false for a non-RSA key or malformed modulus. This keeps protocol policy checks independent from JOSE's backend-specific key representation.

validate!(alg)

@spec validate!(term()) :: alg()

Validate that alg is one of Attesto's supported asymmetric JOSE algorithms.

validate_for_key!(alg, jwk)

@spec validate_for_key!(term(), JOSE.JWK.t()) :: alg()

Validate an algorithm and bind it to a compatible trusted key.

RFC 9864's explicit Ed25519 and Ed448 identifiers require the matching OKP curve. Legacy EdDSA remains compatible with either curve. RSA and EC algorithms are likewise checked against their key type and curve so trusted metadata cannot relabel a key with an incompatible algorithm.