Intel T2 Touch ID for Linux
Experimental, fail-closed Touch ID authentication for Intel Macs with an Apple
T2 chip. It talks to bridgeOS BiometricKit over BridgeXPC and exposes a minimal
fprintd-compatible D-Bus service for PAM clients.
This is research software, not an upstream libfprint driver. The complete
research workflow has been proven on one machine, while the boot and
authentication path has been reproduced on a second model. macOS remains the
recovery environment.
Read Before you start before installing anything.
Contents
- Status
- Normal operation after setup
- Proven configuration
- Prerequisites
- Before you start
- Concepts
- Installation
- Linux bring-up troubleshooting
- Verification
- Recovery and uninstall
- Diagnostics
- Enrollment (experimental)
- Identity management (experimental)
- Single-identity deletion (experimental)
- Cross-OS reconciliation
- Security properties
- Limitations
- Reporting compatibility
- Repository layout
- Development status
- Background and provenance
- Tests
- License
Status
"Exposed" means a user can invoke it on an installed system. "Hardware-tested" means it has been proven on the proven configuration below, and nowhere else.
| Feature | Exposed? | Hardware-tested? |
|---|---|---|
Fingerprint verification through fprintd and PAM |
Yes, installed and enabled | Yes, including negative controls and password fallback |
| Keybag unlock (manual, PAM hook, or encrypted credential) | Yes, installed | Yes, including cold boot |
| Persistent BridgeOS network and boot ordering | Yes, installed and enabled through service dependencies | Yes, including reboot and recovery from the observed SEP timeout race |
| Diagnostics and identity inventory | Yes, installed | Yes |
Enrollment from Linux (t2-touchid-enroll) |
Yes, separate root-only CLI | Yes, one identity enrolled and re-proven after Linux reboot; a later macOS boot removed it |
Label rename (t2-touchid-manage rename-fprint) |
Yes, separate root-only CLI | Yes |
| Adaptive Catacomb persistence | Yes, opt-in (T2_TOUCHID_AUTO_SYNC_ADAPTIVE=1) |
Partly; the journaled path is installed but has no dedicated live control |
Single-identity deletion (t2-touchid-manage delete) |
Yes, behind explicit acknowledgements | No; the first live hardware test has not been performed |
Native fprintd-enroll / fprintd-delete |
No; default-off flags and an uninstalled drop-in | No |
| Multi-user / mapped Linux accounts | No; t2-touchid-user-map only writes forced-disabled records |
Read-only AKS gates only; no live multi-user operation |
| Endpoint-10 / ACM transport | Opt-in research only (T2_TOUCHID_ENABLE_ACM_RESEARCH=1) |
Preflight and one transient-context lifecycle test only |
| Suspend/resume | Yes, installer selects s2idle |
Yes; live match and all health controls passed after resume. deep remains broken |
The fprintd service never exposes enrollment or deletion. The experimental
mutation commands are separate root-only, journaled brokers.
Normal operation after setup
The default setup does not store either password and does not display a boot password prompt. Each Linux boot follows this sequence:
t2-bridge-network.servicedetaches the configured T2cdc_ncminterface from NetworkManager, brings up its link-local IPv6 path, and verifies the configured BridgeOS peer.- The biometric BridgeXPC port is refreshed before
t2-sep-transport.servicenegotiates with SEP. This ordering avoids the capability timeout observed when discovery and transport startup overlapped. t2-keybag-load.serviceloads the exported macOS keybag and records its boot-specific handles under/run/t2-touchid. The handles are still locked, and fingerprint PAM is deliberately skipped.- The first sudo authentication asks for the Linux password normally. Only after that succeeds, a separate hidden prompt asks for the macOS login password. The passwords are never assumed to match.
- The macOS password is used once from locked process memory to unlock both SEP handles. A root-only readiness marker is published for that boot and fprintd is refreshed.
- Later sudo requests and the Omarchy lock screen can use Touch ID. Rebooting clears the runtime handles and readiness marker, so the first-sudo sequence repeats.
Cancelling or entering the wrong macOS password does not turn a valid sudo
password into an authentication failure. Sudo succeeds, Touch ID remains
unavailable, and the separate macOS prompt is offered after the next successful
password-authenticated sudo. sudo t2-keybag-unlock remains the manual recovery
path. t2-interactive-unlock.service is installed but disabled by default; it
is only for systems with a working systemd password agent during boot.
Proven configuration
The complete verification, enrollment, rename, reconciliation, and mutation
research described below was developed on an Intel MacBookPro16,2, bridgeOS
build 23P1072, BridgeXPC 39, and Omarchy/Arch Linux.
Persistent BridgeOS networking, ordered port/transport startup, keybag loading,
the separate Linux/macOS first-sudo prompts, sudo Touch ID, and Omarchy lock
screen Touch ID were additionally verified on an Intel MacBookPro15,2 with
bridgeOS build 23P350. This does not imply that enrollment, deletion, or every
research command has been validated on that second model.
A positive right-index control and a negative unenrolled-finger control were
both verified at the raw bridge, fprintd, and sudo/PAM layers. After the
first Linux enrollment and a reboot, the macOS-enrolled right index and the
Linux-enrolled right thumb were reconciled and assigned the canonical
right-index-finger and right-thumb labels. Both independently return
verify-match through an explicit fprintd-verify -f any "$USER" request,
while an unenrolled finger returns verify-no-match; named requests also
select only their corresponding identity.
That Linux-only thumb did not appear in macOS Touch ID settings. After macOS booted, the next Linux boot found one stable SEP identity but two records in the Linux-local Catacomb. fprintd correctly failed closed. This cross-OS boundary and its host-only recovery are documented below.
Prerequisites
Hardware and firmware
- An Intel Mac with an Apple T2 chip. Full research coverage is limited to
MacBookPro16,2on bridgeOS23P1072; the authentication path is also verified onMacBookPro15,2on bridgeOS23P350. - macOS still installed on the same machine, with at least one enrolled finger. macOS is both the source of the exported keybags and the recovery environment.
Kernel and T2 support
- A Linux kernel with the T2 support stack (
t2bce/apple-bce), providing the T2 USB-network (cdc_ncm) interface used to reach BridgeXPC. Development used the t2linux patched kernels. - Kernel build headers for the running kernel
(
/lib/modules/$(uname -r)/build), a C compiler, andmake. The installer buildst2_sep_transportand two small helper binaries. dkmsis optional but strongly recommended; without it, the installer must be rerun by hand after every kernel upgrade.
Userspace
systemd, includingsystemd-credsand libsystemd, plus D-Bus andpolkit.fprintd1.94.5 and its PAM modulepam_fprintd.so. The documented client behaviour, including thePAM_SILENTworkaround described under Installation, is specific to that version.- Python 3.12 or newer, with
venvandpip, plusgit. CI covers Python 3.12 and 3.14. The installer creates/opt/t2-touchid/.venvand installsdbus-nextpluspymobiledevice3from a pinned git revision, so it needs network access on first run. sudo, and root access to the machine.
Optional desktop feedback
libnotify(notify-send) andlibcanberra(canberra-gtk-play) for the audible and visual cues described under Desktop feedback. Everything works without them.
Before you start
Two things are far more likely to ruin your day than anything else in this document. Read these first:
- Keep macOS available, and keep password authentication working. macOS is the only recovery environment for the fingerprint state in SEP. Never remove password authentication from PAM.
- PAM changes can lock you out. Install the PAM templates only after both
the positive and negative fingerprint controls pass, keep a root shell open
while you test, and remember that
sudo tools/rollback-pam.shrestores the unchanged project-managed stacks and removes the project hook fromsystem-authwithout discarding unrelated later edits. Backups are kept in/var/lib/t2-touchid/pam-backups. - Use
s2idle, notdeep. The installer selects the live-proven mode with a systemd sleep drop-in. Deep-S3 resume still breaks T2 communication until reboot on the proven machine; see Suspend/resume. - The kernel module is pinned after DMA registration. Never unload it; reboot before replacing it.
- Deletion is irreversible in SEP and has never been tested on hardware.
The full recovery and removal commands are collected under Recovery and uninstall.
Concepts
These terms recur throughout the document and the commands.
Operation lock. A single machine-wide lock serialising every biometric operation. Inventory, enrollment, rename, deletion, and the adaptive Catacomb sync all take it, so two of them can never touch SEP at once.
Mutation journal. Every mutating broker writes durable intent before it
dispatches a command to SEP, and records the reconciled outcome afterwards. An
interrupted or ambiguous operation therefore leaves a journal that must be
reconciled with a recover* subcommand. Never blindly replay a mutation:
inspect status first and follow only the recovery path it identifies.
Post-reboot proof. A completed enrollment, rename, or deletion stays
blocking — it is the only mutation allowed — until the resulting
identity and Catacomb state have been proved again from a different Linux
boot and a different Bridge connection. t2-touchid-post-reboot.service
performs that read-only proof automatically before fprintd starts; the
manual verify-post-reboot commands remain diagnostic fallbacks.
Compatibility alias. While any reconciled label is not a unique canonical
fprint finger name, fprintd-list and fprintd-verify deliberately expose one
configured logical finger slot (for example right-index-finger). That slot
means "authenticate against any built-in identity owned by the configured Apple
user". It is not an enrollment count. Use sep_identity_count from
t2-touchid-inventory, or t2-touchid-enroll list, for the truthful hardware
identity count. Once every label is uniquely canonical, the service
automatically lists every finger, restricts a named verification to only that
identity, and reports the exact canonical identity selected by a successful
any match.
Management slot. t2-touchid-identities prints numbered slots for the
reconciled identities. A slot number is valid only for that one reconciled
invocation and is the selector used by the identity-management commands.
Acknowledgement flags. --acknowledge-* options are statements that you
have already performed a control or accepted a consequence. They never run a
control and never, by themselves, authorize anything else.
Generation pinning. Live operations pin one Bridge connection generation, one Linux boot, and one Linux account generation. If any of them changes mid-operation, the operation fails closed rather than continuing against different state.
Installation
-
Keep macOS available and enroll exactly the finger you intend to use.
-
Run the export helpers in
tools/macos/from macOS and transfer the outputs privately. Never commit or publish them. -
On Linux, identify the T2 USB-network interface and BridgeOS link-local IPv6 peer, then run
sudo ./install.sh. Edit/etc/t2-touchid.confwhen prompted, including the interface, peer, numeric macOS user ID, and corresponding special bag. Once configured,t2-bridge-network.serviceprepares this path automatically and keeps NetworkManager from racing it. -
Start
t2-sep-transport.servicefor initial bring-up. The installer builds the module for the running kernel and enables ordered startup for later boots. PCI autoload remains observation-only; the service loader requestsregister_ool=1andprobe_capabilities=1only after BridgeOS port discovery completes. Neither option is configured for early modalias autoload because early capability negotiation caused a persistent-110timeout before BridgeOS was ready. The loader accepts an already operational module and can safely replace an early observation-only instance; it never unloads an instance that registered SEP DMA. After/dev/t2-aksexists, do not unload the module: reboot before rebuilding or replacing it. Re-run the installer after a kernel upgrade. -
Place the extracted keybag at
/var/lib/t2-touchid/user.kb, owned by root and mode0600. Provision the validated, root-private local Catacomb from the macOS export, then startt2-keybag-load.service:sudo t2-touchid-provision-catacomb /private/path/t2-touchid-catacomb.tar.gzThe command rejects symlinks and non-private archives, independently validates all three components, atomically creates the local store, and is idempotent only when an existing store is byte-equal. It does not retain a second raw archive copy. This local baseline is required because fprintd fails closed rather than listing identities from unreconciled SEP state.
-
Unlock the loaded normal handle and the special user bag with the macOS password.
t2-keybag-load.servicerecords the boot-specific values in/run/t2-touchid/keybag.env(mode0700directory, root-only):sudo cat /run/t2-touchid/keybag.envT2_KEYBAG_HANDLEis the handle SEP returned for the loaded keybag; it changes on every boot.T2_KEYBAG_SPECIALis the special bag fromT2_TOUCHID_SPECIAL_BAGin/etc/t2-touchid.conf(-501for macOS user501). Unlock both with the boot-scoped helper:sudo t2-keybag-unlockThe helper validates the root-only runtime values, asks once through
systemd-ask-password, and uses that in-memory secret for both unlocks. Its C helper disables dumps, locks the password buffer in RAM, and explicitly wipes it after both requests; the password is never placed in argv, the environment, or persistent storage. A root-only boot-scoped readiness marker is recorded only when both unlocks succeed. The helper also restarts fprintd when the daemon is already active, so no separate service restart is normally needed. Before that marker exists, the supplied sudo PAM stack skips fingerprint immediately and asks for the password instead of waiting for a biometric timeout.After PAM is installed, manual unlocking is no longer the normal boot workflow. See Unlocking keybags from password authentication for the default first-sudo path, or Unattended boot unlock for its higher-risk stored-credential alternative.
-
Start
fprintd.serviceand run the controls under Verification. -
Only after those controls pass, install the relevant files from
pam/into/etc/pam.d/withsudo tools/install-pam.sh. Keep password authentication as a fallback and keep a root shell open while you test;sudo tools/rollback-pam.shrestores the originals.The sudo template displays a generic pre-capture sensor message through a fixed-text helper that writes to the controlling terminal or sudo's terminal-output channel. This is intentional: sudo sets
PAM_SILENT, which hides conversation-basedpam_echomessages, while fprintd 1.94.5's PAM client suppresses the ABI-validVerifyFingerSelected("any")prompt when multiple identities are available. The message never names one finger because either enrolled identity is valid, and warns not to type until the hidden-input password prompt appears: terminal input can otherwise echo while pam_fprintd owns the sequential PAM transaction. The clamshell guard skips both the message and the fingerprint module when the laptop is closed.
The installer is safe to rerun and replaces only project-managed files. When DKMS is available it registers the transport for kernel upgrades; otherwise it warns that the installer must be rerun after an upgrade.
If the desktop user's systemd user manager is already running, installation
reloads it through that user's /run/user/<uid>/bus. If no user bus exists,
the reload is skipped quietly and the units are discovered at the next login;
the root environment is never mistaken for a desktop user session. Uninstall
uses the same bounded user-bus rule after removing the feedback units.
Unlocking keybags from password authentication
Linux and macOS passwords are treated as separate credentials. On the first
sudo after boot, PAM validates the Linux password normally and then the helper
asks separately for the macOS password used to unlock both T2 keybags. The
macOS password is kept only in locked process memory and is not placed in argv,
the environment, logs, or persistent storage. The helper reads the boot-specific
handle recorded under /run by t2-keybag-load.service and always exits
successfully, so a T2 failure cannot block password authentication.
The PAM installer validates the known Arch system-auth ordering, then places
a sudo-only gate and unlock hook after pam_faillock.so authsucc. It refuses to
patch unfamiliar or administrator-modified stacks and preserves rollback state:
auth [success=ignore default=1] pam_succeed_if.so quiet service = sudo
auth optional pam_exec.so quiet seteuid /usr/local/sbin/t2-pam-unlock
Omarchy uses SDDM autologin followed by separate unprivileged lock-screen PAM
services, so the initial desktop password does not traverse system-auth and
cannot execute the root-only keybag helper. Do not add this hook to
omarchy-lock-password; use manual keybag unlock or the encrypted system
credential described below. The supplied Omarchy password template preserves
the stock password stack, while omarchy-lock-fingerprint provides the
separate fingerprint path after the keybags are unlocked.
Only sudo reaches the helper. It unlocks the bags after the first successful
Linux password authentication and separate macOS password prompt after boot.
It cannot touch SEP after an incorrect Linux password. The helper also checks
PAM_SERVICE=sudo and restricts itself to T2_TOUCHID_USER from
/etc/t2-touchid.conf.
Unattended boot unlock
For unattended keybag availability after SDDM autologin, provision an encrypted systemd credential:
sudo tools/provision-credential.sh
sudo systemctl enable t2-credential-unlock.service
The provisioning prompt is local and hidden. The plaintext password is piped directly into
