michael 22938f657a feat(daemon-fido): Authenticator trait + Mock + Ctap impl + signals (Lane A)
Bundles plan tasks A2 (PamU2fCred encoder), A3 (Authenticator trait), A4
(MockAuthenticator), A5 (CtapAuthenticator wrapping ctap-hid-fido2 3.5.9),
A6 (wire enrollment through AppState::enroll), A7 (DeviceFound /
TouchRequired / EnrollmentSucceeded / EnrollmentFailed D-Bus signals).

- daemon/src/fido/format.rs — PamU2fCred -> 'kh,pk,es256,+presence' with
  hex::encode for the binary blobs and CoseType matching COSE alg -7/-8.
- daemon/src/fido/authenticator.rs — Authenticator trait with discover() and
  make_credential(rp_id, user, pin); AuthnError covers NoDevice / Cancelled /
  PinRequired / Backend.
- daemon/src/fido/mock.rs — MockAuthenticator::with_one_yubikey produces
  deterministic-but-distinct PamU2fCreds (counter-bumped per call).
- daemon/src/fido/ctap.rs — CtapAuthenticator. discover via
  ctap_hid_fido2::get_fidokey_devices(); make_credential via
  FidoKeyHidFactory::create + fk.make_credential. Heuristic error mapping
  to AuthnError variants. Real-hardware path; compile-clean gate only.
- daemon/src/state.rs — AppState::open now takes Arc<dyn Authenticator>.
  New enroll(user, nickname) replaces the Phase 2 add_credential stub: calls
  authn.make_credential, writes pam_u2f line via CredentialsStore::add,
  records enrollment in userdb, returns Credential with hex(keyHandle) as id.
- daemon/src/dbus.rs — enroll_own / enroll_other now emit TouchRequired
  before the call and EnrollmentSucceeded / EnrollmentFailed after. Removed
  the unused stub-credential builder + import baggage.
- daemon/src/main.rs — picks CtapAuthenticator for prod; tests inject Mock.

Test count: 33 daemon tests pass (was 26). Adds 2 fido::format tests, 3
fido::mock tests, 1 state::enroll_writes_real_pam_u2f_line, 1 dbus::
enrollment_succeeded_signal_fires_on_enroll_own. cargo clippy --workspace
--all-targets -D warnings clean. cargo fmt clean.

Plan deviations:
- HidInfo doesn't have a serial_number field in 3.5.9; switched to using
  product_string and HidParam::Path/VidPid for the device path label.
- FidoKeyHidFactory and LibCfg are at the crate root, not under fidokey::.
- fido/mod.rs has #![allow(dead_code)] for now: discover() and DiscoveredDevice
  fields are wired via the trait but only called from tests until Phase 8
  GUI consumes the DeviceFound signal.
2026-04-27 08:29:42 -07:00

authforge

Turnkey U2F / FIDO2 passkey / TOTP MFA for Linux desktops. v1 ships on Ubuntu LTS + GNOME; Debian and KDE Plasma are on the roadmap.

Install (end users)

sudo add-apt-repository ppa:dangerousthings/authforge
sudo apt install authforge

Build from source

See docs/BUILDING.md.

Status

Pre-alpha. Phases 02 code complete (workspace scaffold, D-Bus daemon, storage layer with policy.d / pending / credentials / userdb); Phase 3 (FIDO2 enrollment backend) is next. See docs/plans/ for design, roadmap, and per-phase implementation plans.

Copyright 2026 Dangerous Things, LLC. Licensed under the Apache License, Version 2.0.

Description
mfa support and related user management and policy tools for linux
Readme 398 KiB
Languages
Rust 95.9%
C 3.6%
Jinja 0.3%
Makefile 0.2%