Ankusa.Verifier.Template (ankusa v0.7.0)

Copy Markdown View Source

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 signed template 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

Types

A signed template compiled by compile/1.

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

compiled()

@type compiled() :: [binary() | :body | :ts | {:header, String.t()}]

A signed template compiled by compile/1.

Functions

candidates(env, scheme)

@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(template)

@spec compile(String.t()) :: compiled()

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.

signed_iodata(env, parts, ts)

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

timestamp(env, map, sig_ts, opts)

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

to_binary(iodata)

@spec to_binary(iodata()) :: binary()

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.