Add optional face-verified WebAuthn/passkey platform authenticator (experimental)#1125
Open
qilsklo wants to merge 231 commits into
Open
Add optional face-verified WebAuthn/passkey platform authenticator (experimental)#1125qilsklo wants to merge 231 commits into
qilsklo wants to merge 231 commits into
Conversation
Signed-off-by: MusiKid <musikid@outlook.com>
Signed-off-by: MusiKid <musikid@outlook.com>
Signed-off-by: MusiKid <musikid@outlook.com>
Signed-off-by: MusiKid <musikid@outlook.com>
Signed-off-by: MusiKid <musikid@outlook.com>
Add python-opencv as a dependency for ArchLinux
Fix some bugs on GUI
inverted error message
Update datetime since datetime.utcnow() was deprecated since Python 3.12.
…lation Since pam_python depends on python2 and python2 cannot be installed through fedoras repositories the installation will fail. The beta of Howdy has fixed this issue. This problem is also explained in the copr repo. But it requires some searching.
Fix datetime.datetime.utcnow()
Remove use of Environment Python
fix(pam): use environ variable when getenv doesn't work
Fix unwanted unlocks when auth client subprocesses exit with 0
Fix polkit policy
Fix things regarding translations
Connect to signals of the shown window
Update README.md for Fedora 41 users
The current EDITOR handling is a bit lacking. Improvements: - check that the editor exists before trying to spawn a subprocess - add vi as nano alternative - if everything else fails, perhaps the user is using sudo. Suggest using 'sudo -E howdy [...]', as otherwise the command would run in a non-interactive shell (i.e. without sourcing the initialization files), and no environment variable is carried over (including EDITOR) unless explicitly preserved
…ndling feat(config): better EDITOR handling
Update compare.py from boltgolt#968
Release 3.0.0
Research and architecture for an optional WebAuthn/FIDO2 platform-style authenticator gated on Howdy facial verification. Chosen architecture: transport-agnostic CTAP2 core (python-fido2) + virtual UHID CTAP2 HID transport, keystore abstraction with TPM2 and development software backends, credentialsd D-Bus portal as documented future path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
verification.py exposes verify_face(user) / FaceVerifier by wrapping the compare.py subprocess exit-code contract already used by the PAM module, leaving all existing authentication paths untouched. Includes pytest scaffolding and unit tests driven by a stub compare script. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Credential records (RP id, user handle, COSE public key, sign counter, resident flag) persisted atomically as root-only JSON with flock guarded read-modify-write. KeyStore abstraction with an AES-256-GCM software development backend and an optional TPM 2.0 backend (tpm2_pytss): keys created and used inside the TPM, only wrapped blobs on disk. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Transport-agnostic CTAP 2.1 command handling (MakeCredential, GetAssertion, GetNextAssertion, GetInfo, Reset, Selection) built on python-fido2 structures, with a mandatory fresh face verification in front of every credential operation and packed self-attestation. New 'howdy webauthn' CLI: init, status, list, remove, plus local register/authenticate end-to-end tests against a fake RP. Existing commands and PAM behaviour unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire the CTAP2 authenticator core to a virtual FIDO2 HID device so unmodified browsers can talk to it: - webauthn/ctaphid.py: CTAPHID framing/reassembly, channel allocation, keepalives (UPNEEDED during face verification), CBOR dispatch, cancel - webauthn/uhid.py: /dev/uhid virtual HID device with a FIDO usage-page report descriptor - webauthn/service.py + webauthn_daemon.py: root daemon that resolves its target user from config and pumps host reports into the authenticator. Separate entry point so it never trips the CLI's "no root" guard - howdy-webauthn.service / 70-howdy-webauthn.rules: systemd unit (hardened, refuses to start unless enabled in config) and udev uaccess rule - meson: install the above behind -Dwith_webauthn (off by default), so the normal PAM/login/sudo path is completely unaffected Tests: CTAPHID unit tests and an in-memory end-to-end test driving the stack with python-fido2's independent CTAP2 client (registration, self-attestation + assertion signature verification, counter increments). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User-facing guide covering installation (-Dwith_webauthn), keystore setup, browser usage (Firefox/Chromium), full config/CLI reference, the security model and its convenience-grade classification, limitations, troubleshooting, developer architecture and roadmap. Installed to the datadir path the systemd unit's Documentation= references when built with -Dwith_webauthn. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Log each CTAP2 operation, its RP id/counts, the face-verification result and any CTAP error or unexpected exception via a "howdy.webauthn" logger, routed to the journal by the daemon. Never logs keys, credential IDs, assertions, client-data hashes or biometric data. - Make UHidDevice.close() capture-and-null the fd and never raise, so the SIGTERM handler interrupting the read loop can't double-close (previously crashed with TypeError: 'NoneType' ... on shutdown). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Browsers drive a built-in-UV, no-PIN authenticator with two messages our handlers rejected outright, which aborted every registration and sign-in: - Zero-length pinUvAuthParam (the CTAP2.1 PIN/UV state probe): we returned PIN_AUTH_INVALID. Now answer PIN_NOT_SET so the platform retries the ceremony using built-in user verification. A non-empty pinUvAuthParam (a token we never issue) is ignored; the face check remains the UV gate. - getAssertion with up=false (silent credential-discovery pre-flight): we returned UNSUPPORTED_OPTION. Now return a no-UP/no-UV assertion without a face check and without advancing the counter. An RP rejects an up=0 assertion as a login, so this is not a verification bypass. Updates the unit tests to the corrected behavior and adds coverage for the probe and the silent pre-flight. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Overlapping ceremonies (e.g. clicking "sign in with a passkey" twice) could crash the browser: keepalive, worker-response and feed-thread frames were written to the HID device from several threads with no serialization, so a foreign frame could be spliced into the middle of a fragmented CBOR response and corrupt the host's reassembler. - Guard all outbound framing with a send lock so each message reaches the host as one contiguous run of frames. - On CTAPHID_INIT re-sync of a channel, cancel any in-flight operation (and its face verification / keepalives) instead of leaving it running. Adds tests for non-interleaved concurrent sends and re-INIT cancellation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A cancelled operation dropped its response frame entirely. Per the CTAP HID spec, after CTAPHID_CANCEL the pending makeCredential/getAssertion must still complete and return CTAP2_ERR_KEEPALIVE_CANCEL to the host; dropping it left the browser waiting for a reply that never came and could crash it. Now send the response on CTAPHID_CANCEL, and only suppress it for a CTAPHID_INIT re-sync (where the channel was reset and the INIT frame is the reply). Tests updated accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This adds an optional, off-by-default software platform authenticator that
lets browsers create and use WebAuthn/passkeys unlocked by Howdy face
recognition. It presents a virtual FIDO2 HID device via the kernel's
uhidinterface, so unmodified Firefox (≥114) and Chromium talk to it as if it
were a plugged-in security key — no browser extension, patch, or
native-messaging host required.
Flow:
browser → CTAPHID over /dev/uhid → CTAP2 core → face verification (the same compare.py path PAM uses) → per-RP key signs the challenge.None of this touches the existing PAM / login / sudo path. The feature is
not built or installed unless you configure Meson with
-Dwith_webauthn=true,and the daemon refuses to start unless explicitly enabled in
config.ini.What's included
verification.py) wrappingcompare.pywith a clean
verify_face()/FaceVerifierinterface. PAM is unchanged.webauthn/authenticator.py) —make_credential,get_assertion,get_info, etc., built onpython-fido2(no home-growncrypto or protocol). ES256, per-RP keys, persisted signing counter.
flock-guarded writes.via
tpm2-pytss) and an AES-256-GCM software backend clearly labelleddevelopment-grade.
uaccessrule (all installedonly behind
-Dwith_webauthn).howdy webauthn {init,status,list,remove,register,authenticate,run}.docs/webauthn-design.md(architecture + threat model) anddocs/webauthn.md(operator guide).howdy testcrashing on NumPy 2.x (cv2.calcHistindexing).Security posture (deliberately honest)
This is convenience-grade, not a certified FIDO authenticator, and not
equivalent to Windows Hello or a hardware security key:
software keystore is filesystem-permission protected and marked as such).
credential operation — no caching.
or secrets.
systems; this is documented.
Limitations
sites requiring
authenticatorAttachment: "platform"may not offer it.on the roadmap in the design doc.
Testing
83 unit + integration tests (
python -m pytest tests/). The integration testdrives the full stack with python-fido2's own CTAP2 client over an in-memory
loopback (no root/uhid needed), verifying registration, self-attestation and
assertion signatures, and counter increments against an independent
implementation.
Try it