Explicit policy for draft-ietf-webbotauth-httpsig-protocol-00.
new/1 validates every choice without invoking trust, clock, or storage.
Content and replay use the generic RequestSeal.Policy contracts; HMAC
algorithms are forbidden. The :agents trust function selects
caller-configured trust, never an arbitrary fetch URL. Attribution requires
this trusted association. Held-key verification attributes only the
thumbprint, never an unresolved agent URL. Test keys default to rejection
under Section 6.8.
Within the caller's chosen replay namespace, commitments should hash each
signature's nonce, keyid, and agent identifier only (identifier, keyid, and
agent.identifier in the supplied facts; held keys have no agent identifier).
Replay facts retain the agent's stable kind, identifier, type, origin,
and thumbprint fields. They exclude provenance and cache-refresh fields such as
fetched_at and revision, so hashing the supplied facts is stable across directory
refreshes. Full provenance remains available in the verification result.
Replay scope remains caller-owned,
as described in RFC 9421 Section 7.2.2.
Inspection omits callback environments and source configuration.
Summary
Functions
Construct an explicit policy without invoking trust, clock, or storage.
Types
@type agents() :: (map() -> {:ok, RequestSeal.Discovery.Source.t() | RequestSeal.Discovery.KeySet.t()} | :error)
@type signer() :: RequestSeal.Policy.signer()
@type t() :: %RequestSeal.WebBotAuth.Policy{ agents: agents(), algorithms: list(), cache: pid() | nil, components: binary(), content: term(), field_schemas: map(), freshness: map(), max_lifetime: pos_integer(), max_signatures: pos_integer(), replay: term(), test_keys: :reject | :allow, unresolved: term(), untagged: :ignore | :reject }
Functions
@spec new(map()) :: {:ok, t()} | {:error, RequestSeal.Error.t()}
Construct an explicit policy without invoking trust, clock, or storage.
Parameters
attrs- a plain map (not a struct) with the required keys below and any of the optional keys. Unknown keys reject.
Required keys:
:algorithms- nonempty unique list ofRequestSeal.CryptoHTTP tokens or{:jws, name}selections, as inRequestSeal.Policy;"hmac-sha256"and{:jws, "HS256"}reject.:agents- arity-one trust function receiving%{identifier: id, location: url, type: type}, wheretypeis:directory,:jwks_uri, or:cimd,locationis the received member URL, andidentifieris the directory URL (origin/.well-known/http-message-signatures-directory) or the normalized location. It returns{:ok, %RequestSeal.Discovery.Source{}},{:ok, %RequestSeal.Discovery.KeySet{}}, or:error. A Source requires a caller-started:cache. A KeySet must be fresh and associated with the same URL and type. Sources must allow no redirects.:cache- aRequestSeal.Discovery.CachePID, or nil.:freshness- map with:clock(arity zero, integer Unix seconds),:skew(integer 0 to 86,400 seconds), and:max_age(nil or integer 1 to 253,402,300,799 seconds). An optional:require_expireskey is accepted, but expiration is always required.:content-:not_requiredor aRequestSeal.Policycontent map.:replay-:not_requiredor aRequestSeal.Policyreplay map.
Options
:components- serialized Inner List of extra required component identifiers, without Inner List parameters. Default"()".:max_lifetime- integer seconds, 1 to 604,800. Default 86,400.:unresolved-:reject(default) or{:held_keys, key_resolver}. The arity-one resolver receives%{label: label, keyid: keyid, tag: tag}and returns{:ok, %{algorithm: algorithm, key: %RequestSeal.PublicKey{}}}or:error; the algorithm must be in:algorithmsand the key's thumbprint must equalkeyid. It applies when no trusted association resolves, except for revoked keys, source mismatches, and non-origin directory locations. It waives the draft'sSignature-Agentpresence rule only when the field is absent.:test_keys-:reject(default) or:allow.:untagged-:ignore(default; listed inignored) or:reject.:max_signatures- integer 1 to 64. Default 16.:field_schemas- Structured Fields schemas, as inRequestSeal.Policy. Default%{}.
Returns
{:ok, %RequestSeal.WebBotAuth.Policy{}}.{:error, %RequestSeal.Error{}}- always reason:invalid_policy, layer:input. Meanings:RequestSeal.Error.
Examples
iex> attrs = %{algorithms: ["ed25519"], agents: fn _ -> :error end, cache: nil, freshness: %{clock: fn -> 1_760_000_000 end, skew: 5, max_age: 60}, content: :not_required, replay: :not_required}
iex> {:ok, policy} = RequestSeal.WebBotAuth.Policy.new(attrs)
iex> {policy.max_lifetime, policy.unresolved, policy.test_keys, policy.untagged}
{86400, :reject, :reject, :ignore}
iex> {:error, error} = RequestSeal.WebBotAuth.Policy.new(%{attrs | algorithms: ["hmac-sha256"]})
iex> error.reason
:invalid_policy
iex> {:error, error} = RequestSeal.WebBotAuth.Policy.new(Map.put(attrs, :max_lifetime, 604_801))
iex> error.reason
:invalid_policy