# Linux Hello **Secure facial authentication for Linux using IR cameras and TPM2** A Windows Hello-equivalent biometric authentication system for Linux, designed with security-first principles: TPM-backed credential storage, anti-spoofing detection, and proper PAM integration. --- ## Table of Contents 1. [Project Overview](#project-overview) 2. [Architecture](#architecture) 3. [Security Model](#security-model) 4. [Components](#components) 5. [Technical Specifications](#technical-specifications) 6. [Development Phases](#development-phases) 7. [Build Instructions](#build-instructions) 8. [Testing Strategy](#testing-strategy) 9. [Threat Model](#threat-model) 10. [Contributing](#contributing) --- ## Project Overview ### Problem Statement Current Linux facial authentication solutions (primarily Howdy) have significant security limitations: - Face templates stored unencrypted on disk - No TPM integration for secure credential storage - Basic or no anti-spoofing capabilities - Vulnerable to photo and video replay attacks - No secure enclave processing ### Goals 1. **Security parity with Windows Hello** — TPM2-backed storage, anti-spoofing ML models, secure template handling 2. **Privacy by design** — all biometric data stays local, encrypted at rest, never leaves the device 3. **Seamless UX** — sub-second authentication, works with login managers, sudo, lock screens 4. **Broad compatibility** — support major distros, common IR camera hardware, multiple desktop environments ### Non-Goals - RGB-only camera support (IR is required for security) - Cloud-based authentication - Multi-device sync of biometric data - Fingerprint or other biometric modalities (future scope) --- ## Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Desktop Environment │ │ (GNOME, KDE, SDDM, GDM, etc.) │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ PAM Module │ │ (pam_linux_hello.so) │ │ - Authentication entry point │ │ - Communicates with daemon via Unix socket │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ D-Bus Service Daemon │ │ (linux-hello-daemon) │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │ │ │ Camera │ │ Face │ │ Anti- │ │ TPM2 │ │ │ │ Interface │ │ Detection │ │ Spoofing │ │ Storage │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ IR Camera│ │ TPM2 │ │ ONNX │ │ /dev/vid │ │ Device │ │ Runtime │ └──────────┘ └──────────┘ └──────────┘ ``` ### Component Communication | From | To | Protocol | Purpose | |------|----|----------|---------| | PAM Module | Daemon | Unix Socket (abstract) | Auth requests/responses | | Desktop Env | Daemon | D-Bus (system bus) | Enrollment, settings, status | | Daemon | Camera | V4L2 | Frame capture, IR emitter control | | Daemon | TPM2 | tss-esapi / tpm2-tss | Secure key/template storage | --- ## Security Model ### Biometric Template Protection 1. **Enrollment**: Face embeddings are generated and immediately encrypted using a TPM2-bound key 2. **Storage**: Encrypted templates stored in `/var/lib/linux-hello/templates//` 3. **Decryption**: Only possible on this specific TPM, with user authentication 4. **Deletion**: Secure wipe on unenrollment, templates never backed up ### Anti-Spoofing Layers | Layer | Technique | Defeats | |-------|-----------|---------| | 1 | IR-only capture | Printed photos, most screens | | 2 | Depth estimation from structured light | 2D images, flat screens | | 3 | Liveness CNN | Photos, static masks | | 4 | Temporal micro-movement analysis | Static 3D prints | | 5 | (Optional) Challenge-response | All static attacks | ### Authentication Flow ``` 1. PAM requests authentication for 2. Daemon activates IR emitter + camera 3. Capture N frames (configurable, default 5) 4. For each frame: a. Run anti-spoofing checks (must pass threshold) b. Extract face embedding 5. Compare embeddings against TPM-decrypted templates 6. Return success/failure to PAM 7. Zero-out all frame buffers and embeddings from memory ``` ### Threat Model Summary | Threat | Mitigation | |--------|------------| | Stolen laptop (off) | TPM-bound keys, no access without hardware | | Stolen laptop (suspended) | Memory encryption (separate concern), short auth timeout | | Photo attack | IR camera, depth detection | | Video replay on screen | IR doesn't capture screens properly | | 3D printed mask | Temporal liveness detection | | Evil maid (template extraction) | TPM binding, encrypted at rest | | Shoulder surfing | N/A (face auth inherently resistant) | | Similar-looking attacker | Embedding distance threshold tuning | --- ## Components ### 1. PAM Module (`pam_linux_hello.so`) **Language**: C (for maximum PAM compatibility) **Responsibilities**: - Integrate with PAM authentication stack - Communicate with daemon via Unix socket - Handle timeouts and fallback to password - Provide configuration via `/etc/pam.d/` and `/etc/linux-hello/pam.conf` **Key Functions**: ```c PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv); PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv); ``` **Configuration Options**: - `timeout=` — max time to attempt face auth (default: 5) - `fallback=password` — allow password if face fails - `debug` — verbose logging to syslog --- ### 2. Daemon (`linux-hello-daemon`) **Language**: Rust **Crates**: - `tss-esapi` — TPM2 integration - `v4l` — Video4Linux camera control - `zbus` — D-Bus service - `ort` — ONNX Runtime bindings for ML inference - `opencv` — Image processing (via rust bindings or FFI) - `tokio` — Async runtime - `secrecy` — Secure memory handling **Responsibilities**: - Manage camera lifecycle (open, configure, capture, close) - Control IR emitter via UVC extension units - Run face detection and embedding models - Run anti-spoofing models - Interface with TPM2 for key management and encryption - Expose D-Bus API for enrollment and management - Handle concurrent authentication requests **D-Bus Interface** (`org.linux-hello.Manager`): ```xml ``` --- ### 3. IR Camera Interface **Driver Layer**: V4L2 (Video4Linux2) **Key Challenges**: - IR emitter control varies by hardware (UVC extension units) - Need to identify IR camera vs RGB camera - Handle camera already in use by other applications **IR Emitter Control**: Most IR cameras use USB Video Class (UVC) extension units. We'll need to: 1. Enumerate UVC extension units 2. Find the IR emitter control (vendor-specific) 3. Send enable/disable commands Reference implementation: [linux-enable-ir-emitter](https://github.com/EmixamPP/linux-enable-ir-emitter) **Camera Detection Heuristic**: ``` 1. Enumerate /dev/video* devices 2. Query V4L2 capabilities 3. Look for IR-specific formats (Y8, GREY, etc.) 4. Check for multiple cameras (typically IR is second device) 5. Attempt IR emitter activation as confirmation ``` --- ### 4. Face Detection & Embedding **Model Options**: | Model | Size | Speed | Accuracy | License | |-------|------|-------|----------|---------| | RetinaFace | ~100MB | ~50ms | High | MIT | | MTCNN | ~2MB | ~100ms | Medium | MIT | | BlazeFace | ~500KB | ~10ms | Medium | Apache 2.0 | **Embedding Model**: | Model | Embedding Size | Accuracy (LFW) | License | |-------|----------------|----------------|---------| | ArcFace | 512 | 99.8% | MIT | | FaceNet | 128/512 | 99.6% | Apache 2.0 | | MobileFaceNet | 128 | 99.4% | MIT | **Recommendation**: - Detection: BlazeFace (speed) or RetinaFace (accuracy) - Embedding: MobileFaceNet (good balance for on-device) **Inference Runtime**: ONNX Runtime with CPU execution provider (GPU optional) --- ### 5. Anti-Spoofing Module **Multi-Stage Pipeline**: ``` Frame → IR Validation → Depth Check → Liveness CNN → Temporal Analysis → Decision │ │ │ │ ▼ ▼ ▼ ▼ Reject if Reject if Score 0-1 Micro-movement not IR-like depth < thresh threshold detection ``` **Stage 1: IR Validation** - Verify frame characteristics match IR capture (histogram analysis) - Reject frames that appear to be visible light **Stage 2: Depth Estimation** - Use structured light patterns from IR emitter - Estimate depth map, reject if too flat - Reference: [3DDFA_V2](https://github.com/cleardusk/3DDFA_V2) **Stage 3: Liveness CNN** - Binary classifier: real face vs spoof - Training data: CelebA-Spoof, CASIA-FASD, Replay-Attack datasets - Architecture: MobileNetV3-Small backbone **Stage 4: Temporal Analysis** - Capture sequence of frames (not just one) - Detect micro-movements (eye blinks, slight head motion) - Use optical flow or landmark tracking **Confidence Scoring**: ``` final_score = w1 * depth_score + w2 * liveness_score + w3 * temporal_score if final_score < threshold: reject("Spoof detected") ``` Default weights: `w1=0.3, w2=0.5, w3=0.2` Default threshold: `0.7` --- ### 6. TPM2 Storage Module **Key Hierarchy**: ``` TPM Storage Root Key (SRK) └── Linux Hello Primary Key (sealed to PCRs) └── User Template Encryption Key (per-user) └── Encrypted face template ``` **Operations**: | Operation | TPM2 Command | Purpose | |-----------|--------------|---------| | Create primary key | `TPM2_CreatePrimary` | One-time setup | | Create user key | `TPM2_Create` | Per-user enrollment | | Encrypt template | `TPM2_EncryptDecrypt` | Secure storage | | Decrypt template | `TPM2_EncryptDecrypt` | Authentication | | Seal to PCRs | `TPM2_PolicyPCR` | Bind to boot state (optional) | **PCR Binding (Optional)**: - PCR 7: Secure Boot state - PCR 11: BitLocker-like (unified kernel image) - Effect: Templates inaccessible if boot chain modified **Key Storage**: - Primary key handle persisted at `0x81000001` - User keys stored as TPM2 context blobs in `/var/lib/linux-hello/keys/` --- ### 7. CLI Tool (`linux-hello`) **Commands**: ```bash # Enrollment linux-hello enroll [--label ] # Add face model linux-hello enroll --glasses # Add variant # Management linux-hello list # Show enrolled models linux-hello remove