Skip to content

Commit e0f88c4

Browse files
authored
Allow for shared secret to be created even if no PIN is set on the device (#146)
This is to support HMAC/PRF on such devices, which currently only worked for devices with PIN or UV set (i.e. devices that could negotiate a `pinUvAuthToken`). Things of note: - The requests now have a `needs_shared_secret()` function that is only returning true for GetAssertion at the moment. I have not checked all the other commands in detail, if they could potentially also require this. If so, it would be easy to fill in (e.g. for Ctap2.2 where MakeCredential could also do HMAC). - In the `AuthTokenData`-store, `pinUvAuthToken` (and associated permissions) are now optional. Luckily all this is hidden from the rest of the library, as we already had an accessor-function for this that returned an Option. - The `user_verification_helper()` function is getting a bit more complex, sadly. But I hope with all my comments, it's not too bad. Making the naming of `Ctap2UserVerificationOperation`-variations more explicit should also help.
1 parent 94ee46d commit e0f88c4

File tree

10 files changed

+540
-75
lines changed

10 files changed

+540
-75
lines changed

libwebauthn/src/management/authenticator_config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,8 @@ impl Ctap2UserVerifiableRequest for Ctap2AuthenticatorConfigRequest {
199199
fn handle_legacy_preview(&mut self, _info: &Ctap2GetInfoResponse) {
200200
// No-op
201201
}
202+
203+
fn needs_shared_secret(&self, _get_info_response: &Ctap2GetInfoResponse) -> bool {
204+
false
205+
}
202206
}

libwebauthn/src/management/bio_enrollment.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,4 +335,8 @@ impl Ctap2UserVerifiableRequest for Ctap2BioEnrollmentRequest {
335335
}
336336
}
337337
}
338+
339+
fn needs_shared_secret(&self, _get_info_response: &Ctap2GetInfoResponse) -> bool {
340+
false
341+
}
338342
}

libwebauthn/src/management/credential_management.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,8 @@ impl Ctap2UserVerifiableRequest for Ctap2CredentialManagementRequest {
318318
}
319319
}
320320
}
321+
322+
fn needs_shared_secret(&self, _get_info_response: &Ctap2GetInfoResponse) -> bool {
323+
false
324+
}
321325
}

libwebauthn/src/ops/webauthn/make_credential.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ pub enum MakeCredentialHmacOrPrfInput {
193193
// },
194194
}
195195

196-
#[derive(Debug, Default, Clone, Serialize)]
196+
#[derive(Debug, Default, Clone, Serialize, PartialEq)]
197197
pub struct MakeCredentialPrfOutput {
198198
#[serde(skip_serializing_if = "Option::is_none")]
199199
pub enabled: Option<bool>,
@@ -315,10 +315,7 @@ impl DowngradableRequest<RegisterRequest> for MakeCredentialRequest {
315315
}
316316

317317
// Options must not include "rk" set to true.
318-
if matches!(
319-
self.resident_key,
320-
Some(ResidentKeyRequirement::Required)
321-
) {
318+
if matches!(self.resident_key, Some(ResidentKeyRequirement::Required)) {
322319
debug!("Not downgradable: request requires resident key");
323320
return false;
324321
}

libwebauthn/src/proto/ctap2/model.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,17 @@ pub trait Ctap2UserVerifiableRequest {
209209
fn permissions_rpid(&self) -> Option<&str>;
210210
fn can_use_uv(&self, info: &Ctap2GetInfoResponse) -> bool;
211211
fn handle_legacy_preview(&mut self, info: &Ctap2GetInfoResponse);
212+
/// We need to establish a shared secret, even if no PIN or UV is set on the device
213+
fn needs_shared_secret(&self, info: &Ctap2GetInfoResponse) -> bool;
212214
}
213215

214216
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215217
pub enum Ctap2UserVerificationOperation {
216218
GetPinUvAuthTokenUsingUvWithPermissions,
217219
GetPinUvAuthTokenUsingPinWithPermissions,
218220
GetPinToken,
219-
None,
221+
ClientPinOnlyForSharedSecret,
222+
LegacyUv,
220223
}
221224

222225
#[cfg(test)]

libwebauthn/src/proto/ctap2/model/get_assertion.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,20 @@ impl Ctap2UserVerifiableRequest for Ctap2GetAssertionRequest {
441441
fn handle_legacy_preview(&mut self, _info: &Ctap2GetInfoResponse) {
442442
// No-op
443443
}
444+
445+
fn needs_shared_secret(&self, get_info_response: &Ctap2GetInfoResponse) -> bool {
446+
let hmac_supported = get_info_response
447+
.extensions
448+
.as_ref()
449+
.map(|e| e.contains(&String::from("hmac-secret")))
450+
.unwrap_or_default();
451+
let hmac_requested = self
452+
.extensions
453+
.as_ref()
454+
.map(|e| !matches!(e.hmac_or_prf, GetAssertionHmacOrPrfInput::None))
455+
.unwrap_or_default();
456+
hmac_requested && hmac_supported
457+
}
444458
}
445459

446460
impl Ctap2GetAssertionResponse {

0 commit comments

Comments
 (0)