Repository navigation
soc: apple: sep: add /dev/sep-key for P-256 keys that stay in the SEP - #1196
Conversation
Add a character device that creates P-256 keys inside the Secure Enclave's key store and signs digests with them. Each key is an enclave ref-key bound to this SEP and to the Linux identity key bag; the private key never leaves the enclave. Userspace gets an opaque handle (a short versioned header plus the enclave's wrapped record) that only this Mac can use, and the public point. ioctls (magic 0xB1, nr 0x20-0x23): SEP_KEY_GET_INFO, SEP_KEY_CREATE, SEP_KEY_SIGN (ECDSA-P256 over a caller-supplied 32-byte digest, DER signature) and SEP_KEY_PUBLIC (point from a handle, no enclave round trip). Each enclave operation loads and unlocks the identity key bag the way a trusted-key unseal does and unloads it afterwards. Version 1 has no access control: every flags field must be zero and is reserved for an enclave-enforced policy. A handle the enclave does not accept (another Mac, another key bag) fails with EKEYREJECTED, so the ref-key sign helper now reports the enclave's refusal separately from a missing or malformed reply. KUnit covers the handle format and the reply bounds. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
|
Hardware results: one-shot test kernel
The provider row covers: enrol Kernel log during the tests: |
Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
Add SEP_KEY_CREATE_BIOMETRY_CURRENT_SET (interface version 2). Such a key's record carries the access-control list macOS gives a Secure Enclave key made with .biometryCurrentSet: signing, key agreement and derivation need a biometric credential for this catacomb and enrolled set; delete and attest are free. The kernel reads the catacomb id and enrolled-set hash with SBIO 0x33 and 0x36 (read only) and puts the list in the create request (`ed`); the enclave keeps it in the record and enforces it on every later operation. Adding or removing a finger changes the hash and makes the key unusable. SEP_KEY_SIGN on such a key waits up to 30 s for a touch. Inside that one call the kernel opens a fresh credential context, evaluates the signing constraint on it (ACM command 0x20, best effort), runs one Touch ID match in it through the normal verify path (ACM match mode, MATCH_CANCEL, the same lockout counting and template persistence as any verify), signs with the context (`acmh`) and deletes the context before returning. No handle to the context ever reaches userspace, so a satisfied context cannot outlive the signature it was opened for: every signature needs its own touch. While it runs, the verify belongs to the ioctl, not to /dev/sep-bio's session; it serialises with that session's work on the catacomb writer lock and never reuses its open prompt. SEP_KEY_SELFTEST (test only: apple_sep.key_selftest=1 and root) signs a biometric key under deliberately unsuitable contexts: none, one with no match, one holding only the key-bag secret (the Linux passcode), a deleted one, and, with one touch, the matched context after it was deleted. It reports the enclave's answer, so the refusal is seen to come from the enclave. The request layouts follow our own trace of macOS 26.6.2 creating and using such keys through public APIs. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
One verify capture already waits up to a minute for a finger, so the 30 s overall budget only ever allowed one capture. Make the budget a minute and say "about a minute" in the UAPI comment and the log. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
|
Stage 1: Touch ID keys the enclave guards (ed3d647, ac6c191).
Hardware, no finger, M1 Pro (13.5 key store): one-shot 7.3.0-aurora-sepkey2, Enforcing, 0 AVC, Touch ID identities restored.
KUnit apple_sep* 188/188. Finger cases (a touch signs, a wrong finger is refused, the matched context is refused after delete) wait for Ryan. |
…icies Add SEP_KEY_CREATE_BIOMETRY_ANY, macOS's .biometryAny: the key's access-control list names the Touch ID catacomb (pbioc) but no enrolled-set hash, so any finger enrolled on this install matches, including fingers enrolled after the key was made. SIGN runs the same touch-gated path as a biometry-current-set key; handle flag 0x02 (with 0x01) picks the matching preflight constraint. The enclave enforces the list in the record either way. Reserve SEP_KEY_CREATE_USER_PRESENCE (.userPresence, Touch ID or the password) and SEP_KEY_CREATE_DEVICE_PASSCODE (.devicePasscode). Both need the enclave to check the user's own password. On Linux the only passcode the enclave knows today is the identity key bag's secret, which root holds, so such a key would be root-satisfiable. CREATE refuses them with EOPNOTSUPP; they are not emulated in software. At most one policy bit may be set. Add self-test mode 6 (key_selftest=1, root, no finger): a throwaway key with the .userPresence list as macOS writes it (cpo "DeviceOwnerAuthentication"), signed with a key-bag-secret context and with an unsatisfied context, to measure what the enclave enforces for that policy on Linux. KUnit: policy parsing, handle flags, the biometry-any and presence lists. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
|
Finger results, M1 Pro,
Two retries along the way, both correct refusals: a touch at the very end of a window that did not match ( |
|
Policy rows on hardware, M1 Pro,
Pending: the biometry-any signature with a finger (one touch, queued for the morning). |
|
Second Mac: the Neo (variant-5 key store), |
…n/linux into sepkey/sep-key-chardev # Conflicts: # include/uapi/linux/apple-sep.h
|
Fleet qualification: test kernel |
Adds
/dev/sep-key: P-256 keys that the Secure Enclave creates and keeps. Userspace never sees the private key; it gets an opaque handle that only this Mac (and this Linux install) can use, plus the public point. Signatures are ECDSA-P256 over a 32-byte digest the caller supplies. Keys can carry an access policy the enclave enforces, the same ones macOS offers throughSecAccessControl.Stages (commits)
SEP_KEY_CREATE_BIOMETRY_CURRENT_SET, Touch ID keys the enclave guards. The kernel opens a fresh credential context insideSEP_KEY_SIGN, runs the Touch ID match in it, signs with it and deletes it before the call returns. One touch, one signature; no context handle reaches userspace.SEP_KEY_CREATE_BIOMETRY_ANY; the password policies reserved (below); self-test mode 6.Access policies (macOS semantics)
SEP_KEY_CREATE_*BIOMETRY_CURRENT_SET0x1.biometryCurrentSetBIOMETRY_ANY0x2.biometryAnyUSER_PRESENCE0x4.userPresence(Touch ID or password)EOPNOTSUPPDEVICE_PASSCODE0x8.devicePasscodeEOPNOTSUPPAt most one policy bit;
flags_supportedlists the ones the kernel accepts (0x3 now). The lists are the ones macOS writes (our own clean trace of public macOS APIs:cbio{pbioc, pbioh}for current-set,cbio{pbioc}for any,cpo "DeviceOwnerAuthentication"for user presence).Why the password policies are reserved. On macOS the enclave checks the password itself, against the user's key bag, so root cannot fake the password path. On Linux the only passcode the enclave knows today is the Linux identity key bag's secret, which root holds. A Touch ID-or-password key built on it would be root-satisfiable, and a password checked in software would be too. Neither ships under the macOS name. They need per-user, password-keyed key bags (design in #921); how macOS binds the password credential is being researched. Self-test mode 6 measures what the enclave does with a
.userPresencelist on Linux today (bag-secret context vs unsatisfied context).Limits, plainly
EACCES). macOS falls back to the password; on Linux there is no password path yet, so users keep a second way in.authorized_keys, as with hardware security keys.SIGNcall.pbioc/pbiohon Linux.ABI (
include/uapi/linux/apple-sep.h, ioctl magic 0xB1, nr 0x20-0x24)SEP_KEY_GET_INFOsep_key_info(16)SEP_KEY_CREATEsep_key_create(2124)SEP_KEY_SIGNsep_key_sign(2164)SEP_KEY_PUBLICsep_key_public(2124)SEP_KEY_SELFTESTsep_key_selftest(2104)apple_sep.key_selftest=1, root): deliberately unsuitable contextsErrors:
EINVAL(malformed request/handle),EOPNOTSUPP(reserved policy),EKEYREJECTED(the enclave refused: another Mac or install, or the ACL is not satisfied),EACCES(no match or lockout),ETIMEDOUT(no finger),ENODEV(key store or Touch ID not up),EIO(other enclave failure).Tests
apple_sep*191/191 on 50ba8b0 (188/188 on ed3d647). W=1 clean on drivers/soc/apple.7.3.0-aurora-sepkey2= stage 1, 11-08):ETIMEDOUT; plain keys still sign; OpenSSH provider hw 13/13.EACCES; one touch signs once, the same (deleted) matched context is then refused by the enclave (status -8).7.3.0-aurora-sepkey3(= 50ba8b0), no finger, on the M1 Pro (13.5 key store) and the Neo (variant 5): stage 1 11/11 and policies 15/15 on both (comments 6720791684, 6722423549).Userspace: OpenSSH security-key provider in aurora-silicon/aurora-sep-userspace#15 (
AURORA_SEP_SK_POLICY=presence|any|current-set|passcode). Lane FIDO builds a CTAP2 authenticator on the same node.Ready for review: rows passed on two Macs. Next: carried by the next fleet kernel (FLEET5), then merged with the merge train after that fleet passes on one Mac.
🤖 Generated with Claude Code