# `Pkcs11ex.Slot.Server`
[🔗](https://github.com/utaladriz/pkcs11ex/blob/v0.1.0/lib/pkcs11ex/slot/server.ex#L1)

GenServer that owns a single slot's PKCS#11 module + persistent session.

One process per configured slot. State machine:

    :uninitialized ──open──▶ :open ──login──▶ :logged_in
                              │                  │
                              │                  ├─ logout ─▶ :open
                              │                  └─ timeout ─▶ :open (with reauthentication policy)
                              └─ shutdown ─▶ (terminate)

Sessions persist for the lifetime of the GenServer (Phase 1's per-call
open/close model is replaced here). For PIN-protected token slots this
matches the spec's single-session-pinned model: all sign/verify calls to
this slot serialize through this GenServer's mailbox AND through the
session's internal mutex, so concurrent token access is impossible by
construction.

## Phase 2 status

This step ships the lifecycle plumbing. The `pin_callback` lifecycle from
`api.md` §4.2 lands in step 2 (PIN reauth, `:reauthentication :prompt`/`:fail`,
session timeouts). For now, the PIN is supplied at sign/verify call time.

# `slot_state`

```elixir
@type slot_state() :: :uninitialized | :open | :logged_in
```

State machine state of the slot.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `get_config`

```elixir
@spec get_config(atom()) :: {:ok, keyword()} | {:error, :slot_not_found}
```

Returns the slot's configured `slot_config` keyword list.

Used by signer-ref resolution (`Pkcs11ex.sign_bytes(..., signer: {slot, key})`)
to look up the actual `key_label` for a logical `key_ref` without needing
to read `Application.config()` directly. The Slot.Server is the single
source of truth for whichever slot it serves — wherever it was started
from (the application supervisor or a test) the same lookup works.

# `import_keypair`

```elixir
@spec import_keypair(atom(), keyword(), keyword()) :: :ok | {:error, term()}
```

Provisioning: import an RSA keypair + cert into the slot's token.

Used by `mix pkcs11ex.import_p12`. **Not** a runtime API — calling this
from a request path violates the "no software signing" non-goal because
it implies the caller has the private-key components in software memory.

`args` keyword list:
  * `:components` — `Pkcs11ex.Native.RsaPrivateComponents` struct
  * `:cert_der` — full DER-encoded leaf cert
  * `:subject_der` — DER-encoded subject DN (extracted from cert)
  * `:key_label` — `CKA_LABEL` for the imported private key
  * `:cert_label` — `CKA_LABEL` for the imported cert (often == `:key_label`)
  * `:id` — `CKA_ID` byte string. Empty string means "no id".

Login follows the standard PIN priority chain (`opts[:pin]` →
configured `:pin_callback`).

# `login`

```elixir
@spec login(atom(), binary()) :: :ok | {:error, term()}
```

Explicit one-shot login. The PIN is consumed and dropped — not stored on
the GenServer state.

Always lands on worker 1: `session_pool_size > 1` is forbidden for
`:token` slots (the only slot type where login state is observable),
so worker 1 is the only worker that has login state worth setting.

# `logout`

```elixir
@spec logout(atom()) :: :ok | {:error, term()}
```

Explicit logout. The session stays open; subsequent sign calls will need a
PIN again. Targets worker 1 — see `login/2`.

# `sign`

```elixir
@spec sign(atom(), String.t(), atom(), iodata(), keyword()) ::
  {:ok, binary()} | {:error, term()}
```

Sign `data` with `key_label` on the slot. PIN is supplied per call.

Routes through `Pkcs11ex.Slot.Pool.next_worker_index/1`: for non-pool
slots (`session_pool_size: 1` or unconfigured) always lands on worker
1; for pool slots round-robins across the workers.

Emits `[:pkcs11ex, :slot, :sign]` telemetry with metadata
`%{slot_ref:, worker_index:, mechanism:}` after the call returns.

# `start_link`

Start a slot server. Options:

  * `:slot_ref` — atom from `Pkcs11ex.Config.t().slots`. Required.
  * `:worker_index` — integer ≥ 1, identifying this worker within the
    slot's pool. Defaults to `1`. The supervisor passes 1..N for pool
    slots; tests and single-worker production paths use the default.
  * `:slot_config` — the keyword list for that slot. Required.
  * `:driver_pins` — the global `:driver_pins` map. Defaults to `%{}`.
  * `:name` — registered name. Defaults to the via-tuple in
    `Pkcs11ex.Slot.Registry` keyed by `{slot_ref, worker_index}`.

# `status`

```elixir
@spec status(atom()) :: slot_state()
```

Returns the slot's current state machine state (worker 1).

# `verify`

```elixir
@spec verify(atom(), String.t(), atom(), iodata(), binary(), keyword()) ::
  :ok | {:error, term()}
```

Verify a signature on the slot. Routes through pool round-robin like
`sign/5`. Emits `[:pkcs11ex, :slot, :verify]` telemetry on the same
shape.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
