diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
commit | d8bbc7858622b6d9c278469aab701ca0b609cddf (patch) | |
tree | eff41dc61d9f714852212739e6b3738b82a2af87 /dom/webauthn/authrs_bridge/src | |
parent | Releasing progress-linux version 125.0.3-1~progress7.99u1. (diff) | |
download | firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/webauthn/authrs_bridge/src')
-rw-r--r-- | dom/webauthn/authrs_bridge/src/about_webauthn_controller.rs | 4 | ||||
-rw-r--r-- | dom/webauthn/authrs_bridge/src/lib.rs | 125 |
2 files changed, 58 insertions, 71 deletions
diff --git a/dom/webauthn/authrs_bridge/src/about_webauthn_controller.rs b/dom/webauthn/authrs_bridge/src/about_webauthn_controller.rs index 8d77a62df4..5c160b9333 100644 --- a/dom/webauthn/authrs_bridge/src/about_webauthn_controller.rs +++ b/dom/webauthn/authrs_bridge/src/about_webauthn_controller.rs @@ -4,9 +4,9 @@ use super::*; use authenticator::{ - ctap2::commands::{PinUvAuthResult, StatusCode}, + ctap2::commands::StatusCode, errors::{CommandError, HIDError}, - BioEnrollmentCmd, CredManagementCmd, InteractiveRequest, InteractiveUpdate, PinError, + BioEnrollmentCmd, CredManagementCmd, InteractiveUpdate, PinError, }; use serde::{Deserialize, Serialize}; diff --git a/dom/webauthn/authrs_bridge/src/lib.rs b/dom/webauthn/authrs_bridge/src/lib.rs index 353e1e89a4..b6d54a30b9 100644 --- a/dom/webauthn/authrs_bridge/src/lib.rs +++ b/dom/webauthn/authrs_bridge/src/lib.rs @@ -10,7 +10,7 @@ extern crate xpcom; use authenticator::{ authenticatorservice::{RegisterArgs, SignArgs}, - ctap2::attestation::AttestationObject, + ctap2::attestation::{AAGuid, AttestationObject, AttestationStatement}, ctap2::commands::{get_info::AuthenticatorVersion, PinUvAuthResult}, ctap2::server::{ AuthenticationExtensionsClientInputs, AuthenticatorAttachment, @@ -33,8 +33,8 @@ use nserror::{ }; use nsstring::{nsACString, nsAString, nsCString, nsString}; use serde::Serialize; -use serde_cbor; use serde_json::json; +use std::cell::RefCell; use std::fmt::Write; use std::sync::mpsc::{channel, Receiver, RecvError, Sender}; use std::sync::{Arc, Mutex, MutexGuard}; @@ -87,7 +87,6 @@ enum BrowserPromptType<'a> { }, PinIsTooLong, PinIsTooShort, - RegisterDirect, UvInvalid { retries: Option<u8>, }, @@ -167,7 +166,8 @@ fn cancel_prompts(tid: u64) -> Result<(), nsresult> { #[xpcom(implement(nsIWebAuthnRegisterResult), atomic)] pub struct WebAuthnRegisterResult { - result: RegisterResult, + // result is only borrowed mutably in `Anonymize`. + result: RefCell<RegisterResult>, } impl WebAuthnRegisterResult { @@ -179,13 +179,13 @@ impl WebAuthnRegisterResult { xpcom_method!(get_attestation_object => GetAttestationObject() -> ThinVec<u8>); fn get_attestation_object(&self) -> Result<ThinVec<u8>, nsresult> { let mut out = ThinVec::new(); - serde_cbor::to_writer(&mut out, &self.result.att_obj).or(Err(NS_ERROR_FAILURE))?; + serde_cbor::to_writer(&mut out, &self.result.borrow().att_obj).or(Err(NS_ERROR_FAILURE))?; Ok(out) } xpcom_method!(get_credential_id => GetCredentialId() -> ThinVec<u8>); fn get_credential_id(&self) -> Result<ThinVec<u8>, nsresult> { - let Some(credential_data) = &self.result.att_obj.auth_data.credential_data else { + let Some(credential_data) = &self.result.borrow().att_obj.auth_data.credential_data else { return Err(NS_ERROR_FAILURE); }; Ok(credential_data.credential_id.as_slice().into()) @@ -198,7 +198,7 @@ impl WebAuthnRegisterResult { // In tests, the result is not very important, but we can at least return "internal" if // we're simulating platform attachment. if static_prefs::pref!("security.webauth.webauthn_enable_softtoken") - && self.result.attachment == AuthenticatorAttachment::Platform + && self.result.borrow().attachment == AuthenticatorAttachment::Platform { Ok(thin_vec![nsString::from("internal")]) } else { @@ -208,7 +208,7 @@ impl WebAuthnRegisterResult { xpcom_method!(get_hmac_create_secret => GetHmacCreateSecret() -> bool); fn get_hmac_create_secret(&self) -> Result<bool, nsresult> { - let Some(hmac_create_secret) = self.result.extensions.hmac_create_secret else { + let Some(hmac_create_secret) = self.result.borrow().extensions.hmac_create_secret else { return Err(NS_ERROR_NOT_AVAILABLE); }; Ok(hmac_create_secret) @@ -216,7 +216,7 @@ impl WebAuthnRegisterResult { xpcom_method!(get_cred_props_rk => GetCredPropsRk() -> bool); fn get_cred_props_rk(&self) -> Result<bool, nsresult> { - let Some(cred_props) = &self.result.extensions.cred_props else { + let Some(cred_props) = &self.result.borrow().extensions.cred_props else { return Err(NS_ERROR_NOT_AVAILABLE); }; Ok(cred_props.rk) @@ -229,12 +229,29 @@ impl WebAuthnRegisterResult { xpcom_method!(get_authenticator_attachment => GetAuthenticatorAttachment() -> nsAString); fn get_authenticator_attachment(&self) -> Result<nsString, nsresult> { - match self.result.attachment { + match self.result.borrow().attachment { AuthenticatorAttachment::CrossPlatform => Ok(nsString::from("cross-platform")), AuthenticatorAttachment::Platform => Ok(nsString::from("platform")), AuthenticatorAttachment::Unknown => Err(NS_ERROR_NOT_AVAILABLE), } } + + xpcom_method!(has_identifying_attestation => HasIdentifyingAttestation() -> bool); + fn has_identifying_attestation(&self) -> Result<bool, nsresult> { + if self.result.borrow().att_obj.att_stmt != AttestationStatement::None { + return Ok(true); + } + if let Some(data) = &self.result.borrow().att_obj.auth_data.credential_data { + return Ok(data.aaguid != AAGuid::default()); + } + Ok(false) + } + + xpcom_method!(anonymize => Anonymize()); + fn anonymize(&self) -> Result<nsresult, nsresult> { + self.result.borrow_mut().att_obj.anonymize(); + Ok(NS_OK) + } } #[xpcom(implement(nsIWebAuthnAttObj), atomic)] @@ -276,6 +293,17 @@ impl WebAuthnAttObj { // safe to cast to i32 by inspection of defined values Ok(credential_data.credential_public_key.alg as i32) } + + xpcom_method!(is_identifying => IsIdentifying() -> bool); + fn is_identifying(&self) -> Result<bool, nsresult> { + if self.att_obj.att_stmt != AttestationStatement::None { + return Ok(true); + } + if let Some(data) = &self.att_obj.auth_data.credential_data { + return Ok(data.aaguid != AAGuid::default()); + } + Ok(false) + } } #[xpcom(implement(nsIWebAuthnSignResult), atomic)] @@ -491,10 +519,11 @@ impl RegisterPromise { fn resolve_or_reject(&self, result: Result<RegisterResult, nsresult>) -> Result<(), nsresult> { match result { Ok(result) => { - let wrapped_result = - WebAuthnRegisterResult::allocate(InitWebAuthnRegisterResult { result }) - .query_interface::<nsIWebAuthnRegisterResult>() - .ok_or(NS_ERROR_FAILURE)?; + let wrapped_result = WebAuthnRegisterResult::allocate(InitWebAuthnRegisterResult { + result: RefCell::new(result), + }) + .query_interface::<nsIWebAuthnRegisterResult>() + .ok_or(NS_ERROR_FAILURE)?; unsafe { self.0.Resolve(wrapped_result.coerce()) }; } Err(result) => { @@ -544,7 +573,6 @@ impl TransactionPromise { } enum TransactionArgs { - Register(/* timeout */ u64, RegisterArgs), Sign(/* timeout */ u64, SignArgs), } @@ -714,13 +742,6 @@ impl AuthrsService { } } - let mut attestation_conveyance_preference = nsString::new(); - unsafe { args.GetAttestationConveyancePreference(&mut *attestation_conveyance_preference) } - .to_result()?; - let none_attestation = !(attestation_conveyance_preference.eq("indirect") - || attestation_conveyance_preference.eq("direct") - || attestation_conveyance_preference.eq("enterprise")); - let mut cred_props = false; unsafe { args.GetCredProps(&mut cred_props) }.to_result()?; @@ -761,51 +782,19 @@ impl AuthrsService { use_ctap1_fallback: !static_prefs::pref!("security.webauthn.ctap2"), }; - *self.transaction.lock().unwrap() = Some(TransactionState { + let mut guard = self.transaction.lock().unwrap(); + *guard = Some(TransactionState { tid, browsing_context_id, - pending_args: Some(TransactionArgs::Register(timeout_ms as u64, info)), + pending_args: None, promise: TransactionPromise::Register(promise), pin_receiver: None, selection_receiver: None, interactive_receiver: None, puat_cache: None, }); - - if none_attestation - || static_prefs::pref!("security.webauth.webauthn_testing_allow_direct_attestation") - { - self.resume_make_credential(tid, none_attestation) - } else { - send_prompt( - BrowserPromptType::RegisterDirect, - tid, - Some(&origin), - Some(browsing_context_id), - ) - } - } - - xpcom_method!(resume_make_credential => ResumeMakeCredential(aTid: u64, aForceNoneAttestation: bool)); - fn resume_make_credential( - &self, - tid: u64, - force_none_attestation: bool, - ) -> Result<(), nsresult> { - let mut guard = self.transaction.lock().unwrap(); - let Some(state) = guard.as_mut() else { - return Err(NS_ERROR_FAILURE); - }; - if state.tid != tid { - return Err(NS_ERROR_FAILURE); - }; - let browsing_context_id = state.browsing_context_id; - let Some(TransactionArgs::Register(timeout_ms, info)) = state.pending_args.take() else { - return Err(NS_ERROR_FAILURE); - }; - // We have to drop the guard here, as there _may_ still be another operation - // ongoing and `register()` below will try to cancel it. This will call the state - // callback of that operation, which in turn may try to access `transaction`, deadlocking. + // drop the guard here to ensure we don't deadlock if the call to `register()` below + // hairpins the state callback. drop(guard); let (status_tx, status_rx) = channel::<StatusUpdate>(); @@ -826,7 +815,7 @@ impl AuthrsService { let callback_transaction = self.transaction.clone(); let callback_origin = info.origin.clone(); let state_callback = StateCallback::<Result<RegisterResult, AuthenticatorError>>::new( - Box::new(move |mut result| { + Box::new(move |result| { let mut guard = callback_transaction.lock().unwrap(); let Some(state) = guard.as_mut() else { return; @@ -837,13 +826,6 @@ impl AuthrsService { let TransactionPromise::Register(ref promise) = state.promise else { return; }; - if let Ok(inner) = result.as_mut() { - // Tokens always provide attestation, but the user may have asked we not - // include the attestation statement in the response. - if force_none_attestation { - inner.att_obj.anonymize(); - } - } if let Err(AuthenticatorError::CredentialExcluded) = result { let _ = send_prompt( BrowserPromptType::AlreadyRegistered, @@ -875,14 +857,14 @@ impl AuthrsService { Some(browsing_context_id), )?; self.usb_token_manager.lock().unwrap().register( - timeout_ms, + timeout_ms.into(), info, status_tx, state_callback, ); } else if static_prefs::pref!("security.webauth.webauthn_enable_softtoken") { self.test_token_manager - .register(timeout_ms, info, status_tx, state_callback); + .register(timeout_ms.into(), info, status_tx, state_callback); } else { return Err(NS_ERROR_FAILURE); } @@ -890,6 +872,11 @@ impl AuthrsService { Ok(()) } + xpcom_method!(set_has_attestation_consent => SetHasAttestationConsent(aTid: u64, aHasConsent: bool)); + fn set_has_attestation_consent(&self, _tid: u64, _has_consent: bool) -> Result<(), nsresult> { + Err(NS_ERROR_NOT_IMPLEMENTED) + } + xpcom_method!(get_assertion => GetAssertion(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsIWebAuthnSignArgs, aPromise: *const nsIWebAuthnSignPromise)); fn get_assertion( &self, |