Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libwebauthn/examples/webauthn_cable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use tokio::time::sleep;
use tracing_subscriber::{self, EnvFilter};

use libwebauthn::ops::webauthn::{
GetAssertionRequest, MakeCredentialRequest, UserVerificationRequirement,
GetAssertionRequest, MakeCredentialRequest, ResidentKeyRequirement, UserVerificationRequirement,
};
use libwebauthn::proto::ctap2::{
Ctap2CredentialType, Ctap2PublicKeyCredentialDescriptor, Ctap2PublicKeyCredentialRpEntity,
Expand Down Expand Up @@ -112,7 +112,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
hash: Vec::from(challenge),
relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"),
user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"),
require_resident_key: false,
resident_key: Some(ResidentKeyRequirement::Discouraged),
user_verification: UserVerificationRequirement::Preferred,
algorithms: vec![Ctap2CredentialType::default()],
exclude: None,
Expand Down
4 changes: 2 additions & 2 deletions libwebauthn/examples/webauthn_extensions_hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use libwebauthn::ops::webauthn::{
CredentialProtectionExtension, CredentialProtectionPolicy, GetAssertionHmacOrPrfInput,
GetAssertionRequest, GetAssertionRequestExtensions, HMACGetSecretInput,
MakeCredentialHmacOrPrfInput, MakeCredentialLargeBlobExtension, MakeCredentialRequest,
MakeCredentialsRequestExtensions, UserVerificationRequirement,
MakeCredentialsRequestExtensions, ResidentKeyRequirement, UserVerificationRequirement,
};
use libwebauthn::pin::PinRequestReason;
use libwebauthn::proto::ctap2::{
Expand Down Expand Up @@ -108,7 +108,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
hash: Vec::from(challenge),
relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"),
user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"),
require_resident_key: true,
resident_key: Some(ResidentKeyRequirement::Required),
user_verification: UserVerificationRequirement::Preferred,
algorithms: vec![Ctap2CredentialType::default()],
exclude: None,
Expand Down
4 changes: 2 additions & 2 deletions libwebauthn/examples/webauthn_hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tokio::sync::mpsc::Receiver;
use tracing_subscriber::{self, EnvFilter};

use libwebauthn::ops::webauthn::{
GetAssertionRequest, MakeCredentialRequest, UserVerificationRequirement,
GetAssertionRequest, MakeCredentialRequest, ResidentKeyRequirement, UserVerificationRequirement,
};
use libwebauthn::pin::PinRequestReason;
use libwebauthn::proto::ctap2::{
Expand Down Expand Up @@ -91,7 +91,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
hash: Vec::from(challenge),
relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"),
user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"),
require_resident_key: false,
resident_key: Some(ResidentKeyRequirement::Discouraged),
user_verification: UserVerificationRequirement::Preferred,
algorithms: vec![Ctap2CredentialType::default()],
exclude: None,
Expand Down
5 changes: 3 additions & 2 deletions libwebauthn/examples/webauthn_preflight_hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use tokio::sync::mpsc::Receiver;
use tracing_subscriber::{self, EnvFilter};

use libwebauthn::ops::webauthn::{
GetAssertionRequest, GetAssertionResponse, MakeCredentialRequest, UserVerificationRequirement,
GetAssertionRequest, GetAssertionResponse, MakeCredentialRequest, ResidentKeyRequirement,
UserVerificationRequirement,
};
use libwebauthn::pin::PinRequestReason;
use libwebauthn::proto::ctap2::{
Expand Down Expand Up @@ -164,7 +165,7 @@ async fn make_credential_call(
hash: Vec::from(challenge),
relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"),
user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"),
require_resident_key: false,
resident_key: Some(ResidentKeyRequirement::Discouraged),
user_verification: UserVerificationRequirement::Preferred,
algorithms: vec![Ctap2CredentialType::default()],
exclude: exclude_list,
Expand Down
4 changes: 2 additions & 2 deletions libwebauthn/examples/webauthn_prf_hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use tracing_subscriber::{self, EnvFilter};
use libwebauthn::ops::webauthn::{
GetAssertionHmacOrPrfInput, GetAssertionRequest, GetAssertionRequestExtensions,
MakeCredentialHmacOrPrfInput, MakeCredentialRequest, MakeCredentialsRequestExtensions,
PRFValue, UserVerificationRequirement,
PRFValue, ResidentKeyRequirement, UserVerificationRequirement,
};
use libwebauthn::pin::PinRequestReason;
use libwebauthn::proto::ctap2::{
Expand Down Expand Up @@ -102,7 +102,7 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
hash: Vec::from(challenge),
relying_party: Ctap2PublicKeyCredentialRpEntity::new("example.org", "example.org"),
user: Ctap2PublicKeyCredentialUserEntity::new(&user_id, "mario.rossi", "Mario Rossi"),
require_resident_key: true,
resident_key: Some(ResidentKeyRequirement::Required),
user_verification: UserVerificationRequirement::Preferred,
algorithms: vec![Ctap2CredentialType::default()],
exclude: None,
Expand Down
7 changes: 4 additions & 3 deletions libwebauthn/src/ops/webauthn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub use make_credential::{
MakeCredentialHmacOrPrfInput, MakeCredentialLargeBlobExtension,
MakeCredentialLargeBlobExtensionOutput, MakeCredentialPrfOutput, MakeCredentialRequest,
MakeCredentialResponse, MakeCredentialsRequestExtensions, MakeCredentialsResponseExtensions,
MakeCredentialsResponseUnsignedExtensions,
MakeCredentialsResponseUnsignedExtensions, ResidentKeyRequirement,
};

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -50,6 +50,7 @@ pub trait DowngradableRequest<T> {

#[cfg(test)]
mod tests {
use crate::ops::webauthn::make_credential::ResidentKeyRequirement;
use crate::ops::webauthn::{
DowngradableRequest, MakeCredentialRequest, UserVerificationRequirement,
};
Expand All @@ -61,15 +62,15 @@ mod tests {
fn ctap2_make_credential_downgradable() {
let mut request = MakeCredentialRequest::dummy();
request.algorithms = vec![Ctap2CredentialType::default()];
request.require_resident_key = false;
request.resident_key = Some(ResidentKeyRequirement::Discouraged);
assert!(request.is_downgradable());
}

#[test]
fn ctap2_make_credential_downgradable_unsupported_rk() {
let mut request = MakeCredentialRequest::dummy();
request.algorithms = vec![Ctap2CredentialType::default()];
request.require_resident_key = true;
request.resident_key = Some(ResidentKeyRequirement::Required);
assert!(!request.is_downgradable());
}

Expand Down
36 changes: 30 additions & 6 deletions libwebauthn/src/ops/webauthn/make_credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,23 @@ impl MakeCredentialsResponseUnsignedExtensions {
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#op-makecred-step-rk
// if the "rk" option is false: the authenticator MUST create a non-discoverable credential.
// Note: This step is a change from CTAP2.0 where if the "rk" option is false the authenticator could optionally create a discoverable credential.
Some(CredentialPropsExtension {
rk: Some(request.require_resident_key),
})
match request.resident_key {
Some(ResidentKeyRequirement::Discouraged) | None => {
Some(CredentialPropsExtension { rk: Some(false) })
}
Some(ResidentKeyRequirement::Preferred) => {
if info.map(|i| i.option_enabled("rk")).unwrap_or_default() {
Some(CredentialPropsExtension { rk: Some(true) })
} else {
// Default value in case "rk" is missing (which it is in this constellation) is "false"
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#makecred-rk
Some(CredentialPropsExtension { rk: Some(false) })
}
}
Some(ResidentKeyRequirement::Required) => {
Some(CredentialPropsExtension { rk: Some(true) })
}
}
} else {
Some(CredentialPropsExtension {
// For CTAP 2.0, we can't say if "rk" is true or not.
Expand Down Expand Up @@ -135,6 +149,13 @@ impl MakeCredentialsResponseUnsignedExtensions {
}
}

#[derive(Debug, Clone, Copy)]
pub enum ResidentKeyRequirement {
Required,
Preferred,
Discouraged,
}

#[derive(Debug, Clone)]
pub struct MakeCredentialRequest {
pub hash: Vec<u8>,
Expand All @@ -143,7 +164,7 @@ pub struct MakeCredentialRequest {
pub relying_party: Ctap2PublicKeyCredentialRpEntity,
/// userEntity
pub user: Ctap2PublicKeyCredentialUserEntity,
pub require_resident_key: bool,
pub resident_key: Option<ResidentKeyRequirement>,
pub user_verification: UserVerificationRequirement,
/// credTypesAndPubKeyAlgs
pub algorithms: Vec<Ctap2CredentialType>,
Expand Down Expand Up @@ -270,7 +291,7 @@ impl MakeCredentialRequest {
exclude: None,
extensions: None,
origin: "example.org".to_owned(),
require_resident_key: false,
resident_key: None,
user_verification: UserVerificationRequirement::Discouraged,
timeout: Duration::from_secs(10),
}
Expand All @@ -294,7 +315,10 @@ impl DowngradableRequest<RegisterRequest> for MakeCredentialRequest {
}

// Options must not include "rk" set to true.
if self.require_resident_key {
if matches!(
self.resident_key,
Some(ResidentKeyRequirement::Required)
) {
debug!("Not downgradable: request requires resident key");
return false;
}
Expand Down
Loading
Loading