SignCore.Policy.PinnedRegistry (sign_core v0.1.0)

Copy Markdown View Source

Default SignCore.Policy implementation: SPKI pinning.

Trust is rooted in an explicit allowlist mapping SHA-256(SubjectPublicKeyInfo) (hex, lowercase) → an application-defined subject_id. Onboarding a counterparty is put/2; off-boarding is delete/1. There is no chain validation, no CA, no revocation protocol — the registry IS the source of truth, and removing an entry is the revocation primitive.

SPKI pin (vs. whole-cert pin) survives routine certificate re-issuance with the same key; rotations of the key require an explicit re-pin.

Configuration

config :pkcs11ex, SignCore.Policy.PinnedRegistry,
  pins: [
    {"a3f1...d29c", :acme_corp},
    {"7e2b...4810", :beta_inc}
  ]

Initial pins are loaded once at supervisor start. Runtime updates go through put/2 and delete/1, which serialize through the registry's GenServer to keep the ETS table single-writer.

Reads (resolve/2, validate/3, list/0, lookup/1) hit the ETS table directly with no GenServer round-trip — they're hot path.

Summary

Functions

Returns a specification to start this module under a supervisor.

Removes a pin. Returns :ok whether or not the entry existed.

Returns the full list of {spki_hex, subject_id} entries.

Looks up a single pin without going through the policy interface.

Adds or updates a pin. subject_id is whatever the application uses to identify the counterparty downstream — typically an atom or a struct.

Types

spki_hex()

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

subject_id()

@type subject_id() :: term()

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

delete(spki_hex)

@spec delete(spki_hex()) :: :ok | {:error, :invalid_spki_hex}

Removes a pin. Returns :ok whether or not the entry existed.

list()

@spec list() :: [{spki_hex(), subject_id()}]

Returns the full list of {spki_hex, subject_id} entries.

lookup(spki_hex)

@spec lookup(spki_hex()) :: {:ok, subject_id()} | :error

Looks up a single pin without going through the policy interface.

Returns {:ok, subject_id} or :error. Hex digest is matched case-insensitively (callers usually pass lowercase, but uppercase from e.g. Base.encode16/1 works).

put(spki_hex, subject_id)

@spec put(spki_hex(), subject_id()) :: :ok | {:error, :invalid_spki_hex}

Adds or updates a pin. subject_id is whatever the application uses to identify the counterparty downstream — typically an atom or a struct.

Hex digest is normalized to lowercase before storage.