Ankusa.Verifier.Asymmetric (ankusa v0.7.0)

Copy Markdown View Source

Public-key signature verifier: the provider signs with a private key only it holds, and Ankusa holds nothing secret, only the provider's public key. A leak of the node's config cannot be used to forge a hook, which is the point over Ankusa.Verifier.Hmac.

opts:

  • :scheme — a preset atom (:standard_webhooks_asym, resolved through Ankusa.Verifier.Schemes.fetch_asymmetric/1) or an inline %Ankusa.Verifier.Asymmetric.Scheme{}. The wire half (which header, how it parses, what is signed, which timestamp) is Ankusa.Verifier.Template, the same engine Hmac runs on.
  • :public_key — the provider's key, or a list of them (current first; every key is tried, so a rotation is public_key: [new, old]). A key is one of
    • whpk_<base64>: the Standard Webhooks form, the 32 raw bytes of an Ed25519 public key;
    • the bare base64 of those 32 bytes;
    • a PEM PUBLIC KEY (SubjectPublicKeyInfo) or, for RSA, RSA PUBLIC KEY (PKCS#1) block;
    • for RSA, the bare base64 of the DER of either. A missing key, an empty list, more than 8 keys, or any element that does not decode to a key of the scheme's algorithm fails every hook with :bad_key, and a source declared in config refuses to boot.
  • :tolerance — the replay window in seconds, as Ankusa.Verifier.Hmac.

Algorithms (Scheme.algorithm): :ed25519 (RFC 8032, the signature is 64 bytes) and :rsa_sha256 (RSASSA-PKCS1-v1_5 over SHA-256; a modulus under 2048 bits or an exponent under 65537 is :bad_key). Signatures are base64 or hex (Scheme.encoding).

The request path stays cheap for a forged flood: a candidate whose decoded length is not the key's signature length is dropped before any public-key operation, and at most 8 candidates are tried.

Summary

Functions

Human name of the scheme for telemetry: the preset name, or "custom".

Check opts the way verify/2 would use them, without a request: the scheme resolves, :tolerance is in range and every public key decodes. :ok, or the error verify/2 would return for every hook.

Functions

scheme_name(opts)

@spec scheme_name(keyword()) :: String.t()

Human name of the scheme for telemetry: the preset name, or "custom".

validate_opts(opts)

@spec validate_opts(keyword()) ::
  :ok | {:error, :bad_scheme | :bad_tolerance | :bad_key}

Check opts the way verify/2 would use them, without a request: the scheme resolves, :tolerance is in range and every public key decodes. :ok, or the error verify/2 would return for every hook.