Skip to content

Add opt-in native biometric authentication - #386

Closed
dmulder wants to merge 2 commits into
mozilla:ctap2-2021from
dmulder:feat/local-biometric-policy
Closed

dmulder wants to merge 2 commits into
mozilla:ctap2-2021from
dmulder:feat/local-biometric-policy

Conversation

@dmulder

@dmulder dmulder commented Oct 16, 2026

Copy link
Copy Markdown

Motivation

Native applications can use hmac-secret to unlock encrypted local credentials. In Himmelblau's Linux Hello integration, the output unlocks a separately encrypted Hello PIN; the application therefore needs to require fresh built-in biometric verification, reject authenticator-PIN substitution, and account for retries consumed inside the library. Ordinary WebAuthn PIN fallback remains useful and should retain its current behavior.

This proposes the reusable dependency changes upstream so native consumers can eventually use a released authenticator crate instead of maintaining a fork. Application-specific PAM, TPM sealing, PIN fallback, and persistent retry state stay outside this crate.

Changes

  • Add a non-default local-biometric feature with an optional zeroize dependency.
  • With that feature, expose an explicit internal_uv_only register/sign policy. It requires CTAP2, required UV, configured built-in verification, hmac-secret and biometric-management capabilities; rejects supplied PINs and PIN fallback; and bounds reported CTAP 2.0/2.1 UV failures by a caller-supplied remaining budget of one to three. Hardware lockout takes precedence.
  • Add feature-gated Linux capability discovery, selected-device management access, and opt-in bounded HID reads. A separate PIN-only management assertion proves selected-token credential ownership without releasing HMAC/PRF output. Existing upstream biometric and PIN-management helpers are reused.
  • With the feature enabled, wipe HMAC/PRF outputs, PINs, shared keys, PIN/UV tokens and temporary key material, redact secret Debug implementations, and wipe OpenSSL error-path buffers. Preserve Clone implementations; each cloned secret wipes its own allocation. Public PIN helper methods keep their Vec return types and internal callers protect those buffers without adding plaintext copies during resizing.
  • Add policy and compatibility tests, usage documentation, and three Linux CI matrix entries for the opt-in feature.

Compatibility

The default feature set is unchanged. Without local-biometric, existing argument struct literals, return types, Clone/Debug implementations, serialization, authentication fallback and HID timeouts retain their behavior, and zeroize is not activated by this feature. Regression tests exercise ordinary PIN prompting and the original argument API.

Enabling the feature makes the native API available; it does not select biometric-only authentication for ordinary register/sign requests. Callers must explicitly set internal_uv_only = true and require UV. The local controls are skipped during serialization. Secret wiping and Debug redaction apply throughout a feature-enabled build; the new Drop implementations mean consumers should borrow or take PRF fields instead of moving them directly. The included examples compile in both configurations.

Verification

Using the repository's pinned Rust 1.90 toolchain, run tests and CI-equivalent Clippy with warnings denied for each of crypto_openssl, crypto_rust, and crypto_dummy, both with and without local-biometric:

RUSTFLAGS=-Dwarnings cargo test --no-default-features --features crypto_openssl,local-biometric
RUSTFLAGS=-Dwarnings cargo clippy --all --no-default-features --features crypto_openssl,local-biometric

Coverage includes CTAP 2.0/2.1 retry limits, UV lockout, rejection of PIN substitution and weaker UV requirements, management/secret-release separation, ordinary PIN prompting, unchanged public PIN helper values/types, output cloning, secret Debug redaction, and omission of local policy fields from serialized inputs. Formatting and diff whitespace checks pass.

No physical authenticator was available for validation. NSS and non-Linux configurations need upstream CI; this does not claim firmware certification or protection from privileged live-memory inspection.

Support biometric-only hmac-secret use in native applications behind a non-default feature while retaining existing authentication defaults. Add bounded verification, selected-device management, secret cleanup, compatibility coverage, and feature-enabled CI checks.

Signed-off-by: David Mulder <[email protected]>
Assisted-by: Codex
Disable the inherited raw PIN-hash trace when native biometric protection is enabled. Preserve the existing trace behavior when the feature is disabled.

Signed-off-by: David Mulder <[email protected]>
Assisted-by: Codex

@micolous micolous left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With major features like this, we like an issue report first, so we can give feedback about whether it is something we'd accept. :)

The changes to zeroise and redact sensitive buffers is sensible, and something that could be merged as a separate PR. Ideally, such a change would also fix this all crypto backends.

Generally speaking, this library is only concerned with interfacing with actual security-key type devices, not platform APIs (per #170). Linux already allows for user-space virtual HIDs, and there are a plethora of virtual CTAP2 devices intended to extend what sort of authenticators Firefox (and this library) can support. Any device which looks and works sufficiently similar to a real CTAP2 authenticator will already work with no changes needed.

Adding support for TPM authentication specifically is something that would be better fit for a platform service like credentialsd. There's already a bug for Firefox to integrate with that, and a patch in progress. Other apps should look to solutions like that, as it would allow Linux userspace applications to share a TPM-backed authenticator as they can on Windows.

RegisterArgs/SignArgs::internal_uv_only is effectively a new AuthenticatorSelectionCriteria parameter in WebAuthn terms. This is something that should be proposed as a WebAuthn standards change, and is similar to w3c/webauthn#2482 (and comes with the same problems).

The internal_uv_only parameter this change adds has no security effect at all - the hmac-secret is not associated with a particular user verification modality or particular fingerprint template, only a particular authenticator. An RP can already require support for (but not use of) biometrics by verifying authenticator attestation, even when using a TPM.

This PR's proposed additions to AuthenticationExtensionsClientInputs are a security risk, as these inputs come from untrusted sources.

The biometric_failures and uv_attempt_limit are also things that should be part of an authenticator implementation and managed in TEE/SE space, and are not an effective security mechanism as they are implemented here.

There's a proposed uvx extension for CTAP2 which will allow the RP to query the user verification modality and templates, but this won't affect locally-processed hmac-secret outputs.

If an app wants to always use a particular authenticator device, then an app can provide a FidoDevice implementation to crate::ctap2::register or sign, replacing the device selection logic in StateMachine. This doesn't require any changes to authenticator-rs.

It feels like using hmac-secret in this way is misusing WebAuthn, and it's something that should be handled by a TPM interface. I don't see the benefit or need to solve it with WebAuthn for a native application.

Comment thread src/lib.rs
if dev.get_authenticator_info().is_some_and(|info| {
info.supports_hmac_secret()
&& (info.options.bio_enroll.is_some()
|| info.options.user_verification_mgmt_preview.is_some())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Authenticators may support biometric authentication even if bioEnroll and userVerificationMgmtPreview are absent (such as enrolling fingerprints with an on-device UI).

@micolous micolous closed this Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants