implements alwaysUv and makeCredUvNotRqd
This commit is contained in:
@@ -21,6 +21,21 @@ use super::status_code::Ctap2StatusCode;
|
||||
use super::storage::PersistentStore;
|
||||
use alloc::vec;
|
||||
|
||||
/// The specification mandates that authenticators support users disabling
|
||||
/// alwaysUv unless required not to by specific external certifications.
|
||||
const CAN_DISABLE_ALWAYS_UV: bool = true;
|
||||
|
||||
/// Processes the subcommand toggleAlwaysUv for AuthenticatorConfig.
|
||||
fn process_toggle_always_uv(
|
||||
persistent_store: &mut PersistentStore,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
if !CAN_DISABLE_ALWAYS_UV && persistent_store.has_always_uv()? {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_OPERATION_DENIED);
|
||||
}
|
||||
persistent_store.toggle_always_uv()?;
|
||||
Ok(ResponseData::AuthenticatorConfig)
|
||||
}
|
||||
|
||||
/// Processes the subcommand setMinPINLength for AuthenticatorConfig.
|
||||
fn process_set_min_pin_length(
|
||||
persistent_store: &mut PersistentStore,
|
||||
@@ -66,7 +81,11 @@ pub fn process_config(
|
||||
pin_uv_auth_protocol,
|
||||
} = params;
|
||||
|
||||
if persistent_store.pin_hash()?.is_some() {
|
||||
let enforce_uv = match sub_command {
|
||||
ConfigSubCommand::ToggleAlwaysUv => false,
|
||||
_ => true,
|
||||
} && persistent_store.has_always_uv()?;
|
||||
if persistent_store.pin_hash()?.is_some() || enforce_uv {
|
||||
// TODO(kaczmarczyck) The error code is specified inconsistently with other commands.
|
||||
check_pin_uv_auth_protocol(pin_uv_auth_protocol)
|
||||
.map_err(|_| Ctap2StatusCode::CTAP2_ERR_PUAT_REQUIRED)?;
|
||||
@@ -85,6 +104,7 @@ pub fn process_config(
|
||||
}
|
||||
|
||||
match sub_command {
|
||||
ConfigSubCommand::ToggleAlwaysUv => process_toggle_always_uv(persistent_store),
|
||||
ConfigSubCommand::SetMinPinLength => {
|
||||
if let Some(ConfigSubCommandParams::SetMinPinLength(params)) = sub_command_params {
|
||||
process_set_min_pin_length(persistent_store, params)
|
||||
@@ -101,6 +121,89 @@ mod test {
|
||||
use super::*;
|
||||
use crypto::rng256::ThreadRng256;
|
||||
|
||||
#[test]
|
||||
fn test_process_toggle_always_uv() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut pin_protocol_v1 = PinProtocolV1::new_test(key_agreement_key, pin_uv_auth_token);
|
||||
|
||||
let config_params = AuthenticatorConfigParameters {
|
||||
sub_command: ConfigSubCommand::ToggleAlwaysUv,
|
||||
sub_command_params: None,
|
||||
pin_uv_auth_param: None,
|
||||
pin_uv_auth_protocol: None,
|
||||
};
|
||||
let config_response =
|
||||
process_config(&mut persistent_store, &mut pin_protocol_v1, config_params);
|
||||
assert_eq!(config_response, Ok(ResponseData::AuthenticatorConfig));
|
||||
assert!(persistent_store.has_always_uv().unwrap());
|
||||
|
||||
let config_params = AuthenticatorConfigParameters {
|
||||
sub_command: ConfigSubCommand::ToggleAlwaysUv,
|
||||
sub_command_params: None,
|
||||
pin_uv_auth_param: None,
|
||||
pin_uv_auth_protocol: None,
|
||||
};
|
||||
let config_response =
|
||||
process_config(&mut persistent_store, &mut pin_protocol_v1, config_params);
|
||||
if CAN_DISABLE_ALWAYS_UV {
|
||||
assert_eq!(config_response, Ok(ResponseData::AuthenticatorConfig));
|
||||
assert!(!persistent_store.has_always_uv().unwrap());
|
||||
} else {
|
||||
assert_eq!(
|
||||
config_response,
|
||||
Err(Ctap2StatusCode::CTAP2_ERR_OPERATION_DENIED)
|
||||
);
|
||||
assert!(persistent_store.has_always_uv().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_toggle_always_uv_with_pin() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut pin_protocol_v1 = PinProtocolV1::new_test(key_agreement_key, pin_uv_auth_token);
|
||||
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
||||
|
||||
let pin_uv_auth_param = Some(vec![
|
||||
0x99, 0xBA, 0x0A, 0x57, 0x9D, 0x95, 0x5A, 0x44, 0xE3, 0x77, 0xCF, 0x95, 0x51, 0x3F,
|
||||
0xFD, 0xBE,
|
||||
]);
|
||||
let config_params = AuthenticatorConfigParameters {
|
||||
sub_command: ConfigSubCommand::ToggleAlwaysUv,
|
||||
sub_command_params: None,
|
||||
pin_uv_auth_param: pin_uv_auth_param.clone(),
|
||||
pin_uv_auth_protocol: Some(1),
|
||||
};
|
||||
let config_response =
|
||||
process_config(&mut persistent_store, &mut pin_protocol_v1, config_params);
|
||||
assert_eq!(config_response, Ok(ResponseData::AuthenticatorConfig));
|
||||
assert!(persistent_store.has_always_uv().unwrap());
|
||||
|
||||
let config_params = AuthenticatorConfigParameters {
|
||||
sub_command: ConfigSubCommand::ToggleAlwaysUv,
|
||||
sub_command_params: None,
|
||||
pin_uv_auth_param,
|
||||
pin_uv_auth_protocol: Some(1),
|
||||
};
|
||||
let config_response =
|
||||
process_config(&mut persistent_store, &mut pin_protocol_v1, config_params);
|
||||
if CAN_DISABLE_ALWAYS_UV {
|
||||
assert_eq!(config_response, Ok(ResponseData::AuthenticatorConfig));
|
||||
assert!(!persistent_store.has_always_uv().unwrap());
|
||||
} else {
|
||||
assert_eq!(
|
||||
config_response,
|
||||
Err(Ctap2StatusCode::CTAP2_ERR_OPERATION_DENIED)
|
||||
);
|
||||
assert!(persistent_store.has_always_uv().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
fn create_min_pin_config_params(
|
||||
min_pin_length: u8,
|
||||
min_pin_length_rp_ids: Option<Vec<String>>,
|
||||
|
||||
Reference in New Issue
Block a user