Skip to content

Commit fc6d317

Browse files
authored
Update passkey-rs (#606)
## 🎟️ Tracking [PM-17241](https://bitwarden.atlassian.net/browse/PM-17241) ## πŸ“” Objective This updates the SDK to point to a new version of our passkey-rs fork that has been synced with upstream. (The remaining differences between upstream and our fork are documented in the README of our fork.) If approved, we should update `passkey-rs`'s `main` branch to point to the version referenced in this PR (bitwarden/passkey-rs@2e5c0ba). ## 🚨 Breaking Changes - `is_user_verification_enabled()` is no longer asynchronous. Clients should implement any dynamic checks for UV availability in the `check_user()` implementation. - `user_handle has been added to the `find_credential()` method as an optional parameter. If the incoming request contains the user handle, then clients should pass it on. Otherwise, pass a `null` value, and the previous behavior. iOS PR: bitwarden/ios#2190 [PM-17241]: https://bitwarden.atlassian.net/browse/PM-17241?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent 4e0ec8d commit fc6d317

File tree

10 files changed

+72
-89
lines changed

10 files changed

+72
-89
lines changed

β€ŽCargo.lockβ€Ž

Lines changed: 19 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€ŽCargo.tomlβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ version = "2.0.0"
1010
authors = ["Bitwarden Inc"]
1111
edition = "2024"
1212
# Important: Changing rust-version should be considered a breaking change
13-
rust-version = "1.85"
13+
rust-version = "1.85.1"
1414
homepage = "https://bitwarden.com"
1515
repository = "https://github.com/bitwarden/sdk-internal"
1616
license-file = "LICENSE"

β€Žcrates/bitwarden-fido/Cargo.tomlβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ chrono = { workspace = true }
2727
coset = ">=0.3.7, <0.4"
2828
itertools = ">=0.13.0, <0.15"
2929
p256 = ">=0.13.2, <0.14"
30-
passkey = { git = "https://github.com/bitwarden/passkey-rs", rev = "3b764633ebc6576c07bdd12ee14d8e5c87b494ed" }
31-
passkey-client = { git = "https://github.com/bitwarden/passkey-rs", rev = "3b764633ebc6576c07bdd12ee14d8e5c87b494ed", features = [
30+
passkey = { git = "https://github.com/bitwarden/passkey-rs", rev = "357cc9672340f6ff1f22a0b210a74de64799fa73" }
31+
passkey-client = { git = "https://github.com/bitwarden/passkey-rs", rev = "357cc9672340f6ff1f22a0b210a74de64799fa73", features = [
3232
"android-asset-validation",
3333
] }
3434
reqwest = { workspace = true }

β€Žcrates/bitwarden-fido/src/authenticator.rsβ€Ž

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bitwarden_crypto::CryptoError;
55
use bitwarden_vault::{CipherError, CipherView, EncryptionContext};
66
use itertools::Itertools;
77
use passkey::{
8-
authenticator::{Authenticator, DiscoverabilitySupport, StoreInfo, UIHint, UserCheck},
8+
authenticator::{Authenticator, DiscoverabilitySupport, StoreInfo, UiHint, UserCheck},
99
types::{
1010
Passkey,
1111
ctap2::{self, Ctap2Error, StatusCode, VendorError},
@@ -163,7 +163,7 @@ impl<'a> Fido2Authenticator<'a> {
163163
options: passkey::types::ctap2::make_credential::Options {
164164
rk: request.options.rk,
165165
up: true,
166-
uv: self.convert_requested_uv(request.options.uv).await,
166+
uv: self.convert_requested_uv(request.options.uv),
167167
},
168168
pin_auth: None,
169169
pin_protocol: None,
@@ -175,7 +175,7 @@ impl<'a> Fido2Authenticator<'a> {
175175
Err(e) => return Err(MakeCredentialError::Other(format!("{e:?}"))),
176176
};
177177

178-
let attestation_object = response.as_bytes().to_vec();
178+
let attestation_object = response.as_webauthn_bytes().to_vec();
179179
let authenticator_data = response.auth_data.to_vec();
180180
let attested_credential_data = response
181181
.auth_data
@@ -222,7 +222,7 @@ impl<'a> Fido2Authenticator<'a> {
222222
options: passkey::types::ctap2::make_credential::Options {
223223
rk: request.options.rk,
224224
up: true,
225-
uv: self.convert_requested_uv(request.options.uv).await,
225+
uv: self.convert_requested_uv(request.options.uv),
226226
},
227227
pin_auth: None,
228228
pin_protocol: None,
@@ -255,9 +255,13 @@ impl<'a> Fido2Authenticator<'a> {
255255
pub async fn silently_discover_credentials(
256256
&mut self,
257257
rp_id: String,
258+
user_handle: Option<Vec<u8>>,
258259
) -> Result<Vec<Fido2CredentialAutofillView>, SilentlyDiscoverCredentialsError> {
259260
let key_store = self.client.internal.get_key_store();
260-
let result = self.credential_store.find_credentials(None, rp_id).await?;
261+
let result = self
262+
.credential_store
263+
.find_credentials(None, rp_id, user_handle)
264+
.await?;
261265

262266
let mut ctx = key_store.context();
263267
result
@@ -305,8 +309,8 @@ impl<'a> Fido2Authenticator<'a> {
305309
)
306310
}
307311

308-
async fn convert_requested_uv(&self, uv: UV) -> bool {
309-
let verification_enabled = self.user_interface.is_verification_enabled().await;
312+
fn convert_requested_uv(&self, uv: UV) -> bool {
313+
let verification_enabled = self.user_interface.is_verification_enabled();
310314
match (uv, verification_enabled) {
311315
(UV::Preferred, true) => true,
312316
(UV::Preferred, false) => false,
@@ -353,6 +357,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
353357
&self,
354358
ids: Option<&[passkey::types::webauthn::PublicKeyCredentialDescriptor]>,
355359
rp_id: &str,
360+
user_handle: Option<&[u8]>,
356361
) -> Result<Vec<Self::PasskeyItem>, StatusCode> {
357362
#[derive(Debug, Error)]
358363
enum InnerError {
@@ -369,14 +374,15 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
369374
this: &CredentialStoreImpl<'_>,
370375
ids: Option<&[passkey::types::webauthn::PublicKeyCredentialDescriptor]>,
371376
rp_id: &str,
377+
user_handle: Option<&[u8]>,
372378
) -> Result<Vec<CipherViewContainer>, InnerError> {
373379
let ids: Option<Vec<Vec<u8>>> =
374380
ids.map(|ids| ids.iter().map(|id| id.id.clone().into()).collect());
375381

376382
let ciphers = this
377383
.authenticator
378384
.credential_store
379-
.find_credentials(ids, rp_id.to_string())
385+
.find_credentials(ids, rp_id.to_string(), user_handle.map(|h| h.to_vec()))
380386
.await?;
381387

382388
// Remove any that don't have Fido2 credentials
@@ -419,7 +425,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
419425
}
420426
}
421427

422-
inner(self, ids, rp_id).await.map_err(|error| {
428+
inner(self, ids, rp_id, user_handle).await.map_err(|error| {
423429
error!(%error, "Error finding credentials.");
424430
VendorError::try_from(0xF0)
425431
.expect("Valid vendor error code")
@@ -600,7 +606,7 @@ impl passkey::authenticator::UserValidationMethod for UserValidationMethodImpl<'
600606

601607
async fn check_user<'a>(
602608
&self,
603-
hint: UIHint<'a, Self::PasskeyItem>,
609+
hint: UiHint<'a, Self::PasskeyItem>,
604610
presence: bool,
605611
_verification: bool,
606612
) -> Result<UserCheck, Ctap2Error> {
@@ -617,7 +623,7 @@ impl passkey::authenticator::UserValidationMethod for UserValidationMethodImpl<'
617623
};
618624

619625
let result = match hint {
620-
UIHint::RequestNewCredential(user, rp) => {
626+
UiHint::RequestNewCredential(user, rp) => {
621627
let new_credential = try_from_credential_new_view(user, rp)
622628
.map_err(|_| Ctap2Error::InvalidCredential)?;
623629

@@ -655,22 +661,17 @@ impl passkey::authenticator::UserValidationMethod for UserValidationMethodImpl<'
655661
})
656662
}
657663

658-
async fn is_presence_enabled(&self) -> bool {
664+
fn is_presence_enabled(&self) -> bool {
659665
true
660666
}
661667

662-
async fn is_verification_enabled(&self) -> Option<bool> {
663-
Some(
664-
self.authenticator
665-
.user_interface
666-
.is_verification_enabled()
667-
.await,
668-
)
668+
fn is_verification_enabled(&self) -> Option<bool> {
669+
Some(self.authenticator.user_interface.is_verification_enabled())
669670
}
670671
}
671672

672-
fn map_ui_hint(hint: UIHint<'_, CipherViewContainer>) -> UIHint<'_, CipherView> {
673-
use UIHint::*;
673+
fn map_ui_hint(hint: UiHint<'_, CipherViewContainer>) -> UiHint<'_, CipherView> {
674+
use UiHint::*;
674675
match hint {
675676
InformExcludedCredentialFound(c) => InformExcludedCredentialFound(&c.cipher),
676677
InformNoCredentialsFound => InformNoCredentialsFound,

β€Žcrates/bitwarden-fido/src/client.rsβ€Ž

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,7 @@ impl Fido2Client<'_> {
130130
cred_props: result
131131
.client_extension_results
132132
.cred_props
133-
.map(|c| CredPropsResult {
134-
rk: c.discoverable,
135-
authenticator_display_name: c.authenticator_display_name,
136-
}),
133+
.map(|c| CredPropsResult { rk: c.discoverable }),
137134
},
138135
response: AuthenticatorAssertionResponse {
139136
client_data_json: result.response.client_data_json.into(),

β€Žcrates/bitwarden-fido/src/lib.rsβ€Ž

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bitwarden_vault::{
77
CipherError, CipherView, Fido2CredentialFullView, Fido2CredentialNewView, Fido2CredentialView,
88
};
99
use crypto::{CoseKeyToPkcs8Error, PrivateKeyFromSecretKeyError};
10-
use passkey::types::{Passkey, ctap2::Aaguid};
10+
use passkey::types::{CredentialExtensions, Passkey, ctap2::Aaguid};
1111

1212
#[cfg(feature = "uniffi")]
1313
uniffi::setup_scaffolding!();
@@ -26,7 +26,7 @@ pub use authenticator::{
2626
};
2727
pub use client::{Fido2Client, Fido2ClientError};
2828
pub use client_fido::{ClientFido2, ClientFido2Ext, DecryptFido2AutofillCredentialsError};
29-
pub use passkey::authenticator::UIHint;
29+
pub use passkey::authenticator::UiHint;
3030
use thiserror::Error;
3131
pub use traits::{
3232
CheckUserOptions, CheckUserResult, Fido2CallbackError, Fido2CredentialStore,
@@ -126,6 +126,7 @@ fn try_from_credential_full_view(value: Fido2CredentialFullView) -> Result<Passk
126126
rp_id: value.rp_id.clone(),
127127
user_handle: user_handle.map(|u| u.into_bytes().into()),
128128
counter,
129+
extensions: CredentialExtensions { hmac_secret: None },
129130
})
130131
}
131132

β€Žcrates/bitwarden-fido/src/traits.rsβ€Ž

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bitwarden_vault::{CipherListView, CipherView, EncryptionContext, Fido2CredentialNewView};
2-
use passkey::authenticator::UIHint;
2+
use passkey::authenticator::UiHint;
33
use thiserror::Error;
44

55
#[allow(missing_docs)]
@@ -21,7 +21,7 @@ pub trait Fido2UserInterface: Send + Sync {
2121
async fn check_user<'a>(
2222
&self,
2323
options: CheckUserOptions,
24-
hint: UIHint<'a, CipherView>,
24+
hint: UiHint<'a, CipherView>,
2525
) -> Result<CheckUserResult, Fido2CallbackError>;
2626
async fn pick_credential_for_authentication(
2727
&self,
@@ -32,7 +32,7 @@ pub trait Fido2UserInterface: Send + Sync {
3232
options: CheckUserOptions,
3333
new_credential: Fido2CredentialNewView,
3434
) -> Result<(CipherView, CheckUserResult), Fido2CallbackError>;
35-
async fn is_verification_enabled(&self) -> bool;
35+
fn is_verification_enabled(&self) -> bool;
3636
}
3737

3838
#[allow(missing_docs)]
@@ -42,6 +42,7 @@ pub trait Fido2CredentialStore: Send + Sync {
4242
&self,
4343
ids: Option<Vec<Vec<u8>>>,
4444
rip_id: String,
45+
user_handle: Option<Vec<u8>>,
4546
) -> Result<Vec<CipherView>, Fido2CallbackError>;
4647

4748
async fn all_credentials(&self) -> Result<Vec<CipherListView>, Fido2CallbackError>;

0 commit comments

Comments
Β (0)