The wire half of a signature scheme, shared by every verifier that reads a
signature out of a request header: Ankusa.Verifier.Hmac and
Ankusa.Verifier.Asymmetric.
A scheme is any struct with the fields signature_header, parse,
sig_prefix, sig_key, version, signed and timestamp (the
Scheme structs of both verifiers carry them). This module knows how to
- pull the candidate signatures, and a signature-borne timestamp, out of
the header (
candidates/2), - read the timestamp and judge it against the replay window
(
timestamp/4), and - compile the
signedtemplate once (compile/1) and fill it per request with{body},{ts}and{header:NAME}(signed_iodata/3).
What is done with those (an HMAC, an Ed25519 or RSA verification) is the
verifier's business. Every failure is a reason from the
Ankusa.Verifier vocabulary (:missing_signature, :malformed_signature,
:timestamp_out_of_tolerance).
Summary
Functions
The candidate signatures in scheme.signature_header, and the timestamp the
header itself carries ({:sig, field} schemes; nil otherwise).
Compile a signed template once: a list of literal binaries, :body, :ts
and {:header, lowercased_name}. signed_iodata/3 fills it per request
without copying the body.
The bytes the provider signed, as iodata: a template compiled by compile/1
with {body}, {ts} and {header:NAME} filled in. The body is the
envelope's own binary, never copied. A header or {ts} the template names
but the request lacks is :missing_signature.
The timestamp a scheme signs, checked against the replay window in opts
(Ankusa.Verifier.check_timestamp/2). {:ok, nil} for a scheme with no
timestamp. sig_ts is what candidates/2 found in the signature header.
signed_iodata/3's result as one binary, for a verifier whose primitive needs
the whole message more than once: a template that is the body alone comes
back as the body itself, any other costs one copy.
Types
Functions
@spec candidates(Ankusa.Envelope.t(), struct()) :: {:ok, [String.t()], String.t() | nil} | {:error, :missing_signature | :malformed_signature}
The candidate signatures in scheme.signature_header, and the timestamp the
header itself carries ({:sig, field} schemes; nil otherwise).
Compile a signed template once: a list of literal binaries, :body, :ts
and {:header, lowercased_name}. signed_iodata/3 fills it per request
without copying the body.
@spec signed_iodata(Ankusa.Envelope.t(), compiled(), String.t() | nil) :: {:ok, iodata()} | {:error, :missing_signature}
The bytes the provider signed, as iodata: a template compiled by compile/1
with {body}, {ts} and {header:NAME} filled in. The body is the
envelope's own binary, never copied. A header or {ts} the template names
but the request lacks is :missing_signature.
@spec timestamp(Ankusa.Envelope.t(), struct(), String.t() | nil, keyword()) :: {:ok, String.t() | nil} | {:error, atom()}
The timestamp a scheme signs, checked against the replay window in opts
(Ankusa.Verifier.check_timestamp/2). {:ok, nil} for a scheme with no
timestamp. sig_ts is what candidates/2 found in the signature header.
signed_iodata/3's result as one binary, for a verifier whose primitive needs
the whole message more than once: a template that is the body alone comes
back as the body itself, any other costs one copy.