diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index 8105b840244..ee6bfbf4366 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -5193,6 +5193,7 @@ dependencies = [ "uuid", "webauthn-rs-core", "webauthn-rs-proto", + "windows 0.41.0", ] [[package]] diff --git a/apps/desktop/desktop_native/fido2_client/Cargo.toml b/apps/desktop/desktop_native/fido2_client/Cargo.toml index fdf2c0e2799..2d1a3d4d784 100644 --- a/apps/desktop/desktop_native/fido2_client/Cargo.toml +++ b/apps/desktop/desktop_native/fido2_client/Cargo.toml @@ -14,7 +14,7 @@ serde = { workspace = true, features = ["derive"] } serde_json.workspace = true secrecy = "0.8.0" hex.workspace = true -webauthn-authenticator-rs = { version = "0.5.3", features = ["ctap2", "cable", "usb"] } +webauthn-authenticator-rs = { version = "0.5.3", features = ["ctap2", "cable", "usb", "win10"] } tokio.workspace = true futures-util = "0.3.31" webauthn-rs-proto = "0.5.3" diff --git a/apps/desktop/desktop_native/fido2_client/src/ctap_hid_fido2.rs b/apps/desktop/desktop_native/fido2_client/src/ctap_hid_fido2.rs index c409535b8a1..c2385ab4867 100644 --- a/apps/desktop/desktop_native/fido2_client/src/ctap_hid_fido2.rs +++ b/apps/desktop/desktop_native/fido2_client/src/ctap_hid_fido2.rs @@ -1,7 +1,6 @@ use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine}; use ctap_hid_fido2::{ - fidokey::{AssertionExtension, GetAssertionArgsBuilder}, - Cfg, FidoKeyHidFactory, + Cfg, FidoKeyHid, FidoKeyHidFactory, fidokey::{AssertionExtension, GetAssertionArgsBuilder, get_assertion::get_assertion_params::GetAssertionArgs} }; use pinentry::PassphraseInput; use secrecy::ExposeSecret; @@ -28,6 +27,24 @@ pub fn available() -> bool { true } +fn make_assertion(options: AssertionOptions, client_data_json: String, credential: Option<&[u8]>, pin: Option) -> Result { + let mut get_assertion_args = + GetAssertionArgsBuilder::new(options.rpid.as_str(), client_data_json.as_bytes()) + .extensions(&[AssertionExtension::HmacSecret(Some(prf_to_hmac( + &options.prf_eval_first, + )))]); + + if pin.is_some() { + get_assertion_args = get_assertion_args.pin(pin.as_ref().unwrap()); + } + + if let Some(cred) = credential { + get_assertion_args = get_assertion_args.credential_id(cred); + } + + Ok(get_assertion_args.build()) +} + pub fn get(options: AssertionOptions) -> Result { let device = FidoKeyHidFactory::create(&Cfg::init()).map_err(|_| Fido2ClientError::NoDevice)?; @@ -37,24 +54,32 @@ pub fn get(options: AssertionOptions) -> Result = None; + let pin: Option; if options.user_verification == crate::UserVerification::Required || options.user_verification == crate::UserVerification::Preferred { pin = Some(get_pin().ok_or(Fido2ClientError::WrongPin)?); - get_assertion_args = get_assertion_args.pin(pin.as_ref().unwrap()); } + let assertions = device .get_assertion_with_args(&get_assertion_args.build()) - .map_err(|_e| Fido2ClientError::AssertionError)?; - let assertion = assertions.get(0).ok_or(Fido2ClientError::AssertionError)?; + .map_err(|_e| { + Fido2ClientError::AssertionError + })?; + + let assertion = if assertions.len() > 1 { + let first_assertion = &assertions[0]; + let mut get_assertion_args = get_assertion_args.credential_id(&first_assertion.credential_id); + let assertions = device + .get_assertion_with_args(&get_assertion_args.build()) + .map_err(|_e| { + Fido2ClientError::AssertionError + })?; + assertions.get(0).ok_or(Fido2ClientError::AssertionError)? + } else { + assertions.get(0).ok_or(Fido2ClientError::AssertionError)? + }; let prf_extension = assertion .extensions @@ -93,7 +118,7 @@ mod tests { get(AssertionOptions { challenge: vec![], timeout: 0, - rpid: "example.com".to_string(), + rpid: "vault.usdev.bitwarden.pw".to_string(), user_verification: crate::UserVerification::Required, allow_credentials: vec![], prf_eval_first: [0u8; 32], diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 0d1e9eb653c..98a70e91eac 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -129,6 +129,7 @@ import { UserVerificationApiService } from "@bitwarden/common/auth/services/user import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service"; import { WebAuthnLoginApiService } from "@bitwarden/common/auth/services/webauthn-login/webauthn-login-api.service"; import { WebAuthnLoginPrfKeyService } from "@bitwarden/common/auth/services/webauthn-login/webauthn-login-prf-key.service"; +import { DefaultTwoFactorApiService, TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; import { AutofillSettingsService, AutofillSettingsServiceAbstraction,