Skip to content

How passkey-tpm works

The figures are generated from code in docs/diagrams/src/ with spinagram; run docs/diagrams/render.sh after changing them.

Components

passkey-tpm architecture

Browsers and FIDO2 tools see an ordinary USB security key. passkey-tpm-agent creates it with /dev/uhid in your session and forwards each CTAP request to the broker over the system bus. The broker, passkey-tpm-uvd, runs as its own system user. It checks that you are the user in front of the screen (logind), asks fprintd to match your finger, and is the only process that can make the TPM sign. passkey-tpm-tray shows the status, enrolls fingerprints through fprintd and sets the PIN through the broker. Everything in your session is untrusted: it can relay or drop requests, but it can't sign without your finger or PIN.

Registering with a fingerprint

Register with a fingerprint

The agent shows a "touch the reader" prompt, but the decision is the broker's. Only a verify-match from fprintd, for the calling user and from the fprintd instance the broker claimed, becomes user-verification evidence.

Without a fingerprint: PIN and Allow

No fingerprint: PIN + Allow

Users with no enrolled fingerprint verify with the security-key PIN, which the TPM checks against a DA-limited PIN gate. Presence comes from an Allow click: the broker sends PresenceRequested to the program that made the request and accepts ConfirmPresence only from that same connection. This is weaker than a fingerprint touch; see the threat model and STATE AD-022.

TPM policy

TPM policy model

Each passkey is a TPM key whose policy is PolicySecret on the per-user UV gate, bound to the relying party (H(tag ‖ rpIdHash)). Only the broker knows the UV gate secret, so a compromised session or another user with TPM access can't sign. A PIN is checked against the PIN gate first; the signature still goes through the UV gate. Details: ADR 0003.