Files
codex/codex-rs/user-verification/src/lib.rs
T
riley-oai e7637306bc Add macOS user verification with Secure Enclave signing (#43624)
## Why

The user-verification API previously returned an unsupported provider on macOS. Enable native verification using biometric-protected credentials.

## What changed

- Implement credential status, creation, reuse, deletion, and challenge signing with P-256 Secure Enclave keys in the Data Protection Keychain.
- Require biometric authentication through the key's access-control policy and use a fresh `LAContext` for each signature.
- Report Touch ID hardware support independently of enrollment and current readiness, and map native failures to structured verification errors.
- Serialize credential operations across processes with cancellable file-lock waits. Invalidate pending authentication on cancellation and wait for the signer to exit before releasing the lock.

## Testing

Add unit tests for lock contention and cancellation, authentication teardown and late-result rejection, native error classification, and validation of Secure Enclave key attributes.

GitOrigin-RevId: 93268962cd824b2befc1a0c54b99dcb77a0f1044
2026-09-08 00:13:28 +00:00

92 lines
3.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Device credentials and signing, independent of RPC routing, UI, and backend registration.
mod credential;
mod error;
mod guard;
mod key_namespace;
#[cfg(any(target_os = "macos", test))]
mod lifecycle_lock;
#[cfg(any(target_os = "macos", test))]
mod native_operation;
#[cfg(any(target_os = "macos", test))]
mod platform_macos;
#[cfg(not(target_os = "macos"))]
mod unsupported;
pub use credential::UserVerificationKeyCreation;
pub use credential::UserVerificationKeyDeletion;
pub use credential::UserVerificationKeyInfo;
pub use credential::UserVerificationProof;
pub use credential::UserVerificationRequest;
pub use credential::UserVerificationStatus;
pub use error::UserVerificationCancellationReason;
pub use error::UserVerificationError;
pub use error::UserVerificationFailureReason;
pub use error::UserVerificationUnavailableReason;
pub use guard::UserVerificationRequestGuard;
pub use key_namespace::UserVerificationKeyNamespace;
use std::sync::Arc;
/// Performs local credential operations for one captured account-user identity.
/// Implementations never perform network registration. Blocking implementations must run off
/// the async executor and check the guard after waiting, before effects, and before returning.
pub trait UserVerificationProvider: Send + Sync {
/// Reads local readiness without creating credentials or prompting for authentication.
fn status(
&self,
guard: &UserVerificationRequestGuard,
) -> Result<UserVerificationStatus, UserVerificationError>;
/// Creates a protected key only if none exists. Success does not mean server enrollment.
fn ensure_key(
&self,
guard: &UserVerificationRequestGuard,
) -> Result<UserVerificationKeyCreation, UserVerificationError>;
/// Removes the local key idempotently. Backend revocation belongs to the caller.
fn delete(
&self,
guard: &UserVerificationRequestGuard,
) -> Result<UserVerificationKeyDeletion, UserVerificationError>;
/// Authenticates and signs 1–4096 challenge bytes without interpreting an elicitation.
/// The caller owns approval UI, request correlation, and the captured identity check.
fn verify(
&self,
request: &UserVerificationRequest,
guard: &UserVerificationRequestGuard,
) -> Result<UserVerificationProof, UserVerificationError>;
}
/// Reports whether this build contains a native provider, independently of local readiness.
pub fn platform_supported() -> bool {
cfg!(target_os = "macos")
}
/// Probes biometric hardware without reading credentials, prompting, or checking enrollment.
/// This performs local OS work; async callers should run it off their executor during setup.
pub fn device_supported() -> bool {
#[cfg(target_os = "macos")]
{
platform_macos::device_supported()
}
#[cfg(not(target_os = "macos"))]
{
false
}
}
pub fn platform_provider(
namespace: UserVerificationKeyNamespace,
) -> Arc<dyn UserVerificationProvider> {
#[cfg(target_os = "macos")]
{
Arc::new(platform_macos::NativeProvider { namespace })
}
#[cfg(not(target_os = "macos"))]
{
let _ = namespace.label;
Arc::new(unsupported::UnsupportedProvider)
}
}