Repository navigation
Conversation
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
There was a problem hiding this comment.
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.
| 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()) |
There was a problem hiding this comment.
Authenticators may support biometric authentication even if bioEnroll and userVerificationMgmtPreview are absent (such as enrolling fingerprints with an on-device UI).
Motivation
Native applications can use
hmac-secretto 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
local-biometricfeature with an optional zeroize dependency.internal_uv_onlyregister/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.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 = trueand 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, andcrypto_dummy, both with and withoutlocal-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-biometricCoverage 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.