انتقل إلى المحتوى الرئيسي

Inspect the agent and audit tokens

A local stack keeps its keys on three SoftHSM tokens, one for each deployable that holds keys, so that a service which opens its own token cannot open another's. This page shows how to list the tokens and the keys on each, to check that the keys you expect are there and that none can leave the token.

The commands are for a local stack only. They read a token's user PIN from the stack's local state directory, which exists only on a development machine. A production deployment has a hardware security module, and its PINs are never in a file on an operator's machine.

Run every command from the repository root.

The three tokens​

TokenVolumeSoftHSM configurationUser PIN fileWhat it holds
oktoidoktoid-local_hsm-tokenssofthsm2.confuser-pinThe trust module's federation signing keys, one per hosted entity (federation), and the wrapping key of every person's data key (key-wrap)
oktoid-agentoktoid-local_hsm-tokens-agentsofthsm2-agent.confagent-user-pinIdentifier keys. For each identifier its assertion keys, current and retired, and for a did:webvh identifier the update keys. A spent update key is destroyed once the entry it signed is published
oktoid-auditoktoid-local_hsm-tokens-auditsofthsm2-audit.confaudit-user-pinThe audit trail's checkpoint signing key (audit-checkpoint)

The configuration files are in infra/environments/shared/. The PIN files are in infra/compose/.state/local/secrets/oktoid/hsm/. Each token directory inside a container is /var/lib/softhsm/<directory>, where <directory> is the volume name without oktoid-local_hsm-: tokens, tokens-agent or tokens-audit.

The service images carry neither softhsm2-util nor pkcs11-tool. Use the image of the job that creates the tokens, oktoid/softhsm-init:local, which has both. Every command below runs it with no network, as the user that owns the token directories (uid 1000), and mounts the token's volume read-only, so nothing on this page can change a token.

List the tokens​

Listing the slots needs no PIN. For the agent's token:

docker run --rm --network none --user 1000 --entrypoint softhsm2-util \
-v oktoid-local_hsm-tokens-agent:/var/lib/softhsm/tokens-agent:ro \
-v "$PWD/infra/environments/shared/softhsm2-agent.conf:/etc/softhsm2.conf:ro" \
-e SOFTHSM2_CONF=/etc/softhsm2.conf \
oktoid/softhsm-init:local --show-slots

The token appears in a slot whose number SoftHSM derives from the token, so it is not 0:

Slot 892996715
...
Token info:
...
Initialized: yes
User PIN init.: yes
Label: oktoid-agent

A second slot follows with Initialized: no and no label. That is SoftHSM's free slot, always offered for a new token, and it is expected.

For the other two tokens, change the volume, its directory and the configuration file as the table above gives them.

List the keys on a token​

Listing keys needs the token's user PIN. The PIN must not appear on the command line, where it would be kept in your shell history and could be read from the process list. Mount the PIN file into the container instead, and let the shell inside the container read it into the variable that pkcs11-tool takes the PIN from. For the agent's token:

docker run --rm --network none --user 1000 --entrypoint sh \
-v oktoid-local_hsm-tokens-agent:/var/lib/softhsm/tokens-agent:ro \
-v "$PWD/infra/environments/shared/softhsm2-agent.conf:/etc/softhsm2.conf:ro" \
-v "$PWD/infra/compose/.state/local/secrets/oktoid/hsm/agent-user-pin:/run/pin:ro" \
-e SOFTHSM2_CONF=/etc/softhsm2.conf \
oktoid/softhsm-init:local \
-c 'PIN="$(cat /run/pin)" pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --pin env:PIN --list-objects --type privkey'

Keep the single quotes around the last line: they stop your own shell from expanding $(cat /run/pin), so the PIN is read inside the container and is never on your machine's command line or in its history. --pin env:PIN tells pkcs11-tool to read the PIN from the variable rather than from an argument.

--type privkey lists private keys only. Use --type secrkey for secret keys such as the wrapping key, or leave --type out to list every object, public keys included.

For the oktoid token, mount oktoid-local_hsm-tokens at /var/lib/softhsm/tokens, softhsm2.conf and user-pin. For the audit token, oktoid-local_hsm-tokens-audit at /var/lib/softhsm/tokens-audit, softhsm2-audit.conf and audit-user-pin.

What to look for​

Each key is printed with its label, its use and its access attributes. On the audit token:

Private Key Object; EC
label: audit-checkpoint
ID: 594e86c7091680c793cc511870600c97
Usage: sign
Access: sensitive, always sensitive, never extractable, local

Every private key and every secret key must read sensitive, always sensitive, never extractable, local. never extractable means the key cannot be exported from the token in any form; local means it was generated on the token, not imported. A private or secret key without those attributes is a fault to report. Public keys are listed with Access: local only, which is expected: a public key is not secret.

What each token should hold depends on how far the stack has gone:

TokenOn a stack whose setup has completed
oktoidOne key-wrap secret key (AES, 32 bytes), and a federation private key for the anchor and for each organization whose statements were prepared
oktoid-agentThe anchor's identifier keys, and each further identifier's. After an identifier's key has been rotated, its retired assertion keys are still there, and its spent update keys are not
oktoid-auditOne audit-checkpoint private key

On a stack whose setup is still under way, the oktoid token may hold only the key-wrap key and the agent's token no private key at all: identifier keys are made when the setup run creates the anchor's identifier.

When a command fails​

SymptomCause
--show-slots lists only a slot with Initialized: no and no labelThe volume name is wrong, or the configuration file names another token's directory. Docker creates a named volume that does not exist, empty, so a mistyped name is not an error: remove the stray volume with docker volume rm <name>. docker volume ls lists the stack's real volumes
C_Login failed: rv = CKR_PIN_INCORRECTThe PIN file belongs to another token. Take the volume, the configuration file and the PIN file from the same row of the table