new client pin subcommands
This commit is contained in:
@@ -278,6 +278,14 @@ pub struct AuthenticatorClientPinParameters {
|
||||
pub pin_auth: Option<Vec<u8>>,
|
||||
pub new_pin_enc: Option<Vec<u8>>,
|
||||
pub pin_hash_enc: Option<Vec<u8>>,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
pub min_pin_length: Option<u64>,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
pub min_pin_length_rp_ids: Option<Vec<String>>,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
pub permissions: Option<u8>,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
pub permissions_rp_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
|
||||
@@ -305,6 +313,39 @@ impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
|
||||
let new_pin_enc = new_pin_enc.map(extract_byte_string).transpose()?;
|
||||
let pin_hash_enc = pin_hash_enc.map(extract_byte_string).transpose()?;
|
||||
|
||||
// TODO(kaczmarczyck) merge with new map destructuring (and use hex!)
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
let min_pin_length = param_map
|
||||
.remove(&cbor_unsigned!(7))
|
||||
.map(extract_unsigned)
|
||||
.transpose()?;
|
||||
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
let min_pin_length_rp_ids = match param_map.remove(&cbor_unsigned!(8)) {
|
||||
Some(entry) => Some(
|
||||
extract_array(entry)?
|
||||
.into_iter()
|
||||
.map(extract_text_string)
|
||||
.collect::<Result<Vec<String>, Ctap2StatusCode>>()?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
// We expect a bit field of 8 bits, and drop everything else.
|
||||
// This means we ignore extensions in future versions.
|
||||
let permissions = param_map
|
||||
.remove(&cbor_unsigned!(9))
|
||||
.map(extract_unsigned)
|
||||
.transpose()?
|
||||
.map(|p| p as u8);
|
||||
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
let permissions_rp_id = param_map
|
||||
.remove(&cbor_unsigned!(10))
|
||||
.map(extract_text_string)
|
||||
.transpose()?;
|
||||
|
||||
Ok(AuthenticatorClientPinParameters {
|
||||
pin_protocol,
|
||||
sub_command,
|
||||
@@ -312,6 +353,14 @@ impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
|
||||
pin_auth,
|
||||
new_pin_enc,
|
||||
pin_hash_enc,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
min_pin_length,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
min_pin_length_rp_ids,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
permissions,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
permissions_rp_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -434,6 +483,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_from_cbor_client_pin_parameters() {
|
||||
// TODO(kaczmarczyck) inline the #cfg when the ICE is resolved:
|
||||
// https://github.com/rust-lang/rust/issues/73663
|
||||
#[cfg(not(feature = "with_ctap2_1"))]
|
||||
let cbor_value = cbor_map! {
|
||||
1 => 1,
|
||||
2 => ClientPinSubCommand::GetPinRetries,
|
||||
@@ -442,6 +494,19 @@ mod test {
|
||||
5 => vec! [0xCC],
|
||||
6 => vec! [0xDD],
|
||||
};
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
let cbor_value = cbor_map! {
|
||||
1 => 1,
|
||||
2 => ClientPinSubCommand::GetPinRetries,
|
||||
3 => cbor_map!{},
|
||||
4 => vec! [0xBB],
|
||||
5 => vec! [0xCC],
|
||||
6 => vec! [0xDD],
|
||||
7 => 4,
|
||||
8 => cbor_array!["example.com"],
|
||||
9 => 0x03,
|
||||
10 => "example.com",
|
||||
};
|
||||
let returned_pin_protocol_parameters =
|
||||
AuthenticatorClientPinParameters::try_from(cbor_value).unwrap();
|
||||
|
||||
@@ -452,6 +517,14 @@ mod test {
|
||||
pin_auth: Some(vec![0xBB]),
|
||||
new_pin_enc: Some(vec![0xCC]),
|
||||
pin_hash_enc: Some(vec![0xDD]),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
min_pin_length: Some(4),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
min_pin_length_rp_ids: Some(vec!["example.com".to_string()]),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
permissions: Some(0x03),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
permissions_rp_id: Some("example.com".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -690,9 +690,15 @@ pub enum ClientPinSubCommand {
|
||||
GetKeyAgreement = 0x02,
|
||||
SetPin = 0x03,
|
||||
ChangePin = 0x04,
|
||||
GetPinUvAuthTokenUsingPin = 0x05,
|
||||
GetPinUvAuthTokenUsingUv = 0x06,
|
||||
GetPinToken = 0x05,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
GetPinUvAuthTokenUsingUvWithPermissions = 0x06,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
GetUvRetries = 0x07,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
SetMinPinLength = 0x08,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
GetPinUvAuthTokenUsingPinWithPermissions = 0x09,
|
||||
}
|
||||
|
||||
impl From<ClientPinSubCommand> for cbor::Value {
|
||||
@@ -712,10 +718,16 @@ impl TryFrom<cbor::Value> for ClientPinSubCommand {
|
||||
0x02 => Ok(GetKeyAgreement),
|
||||
0x03 => Ok(SetPin),
|
||||
0x04 => Ok(ChangePin),
|
||||
0x05 => Ok(GetPinUvAuthTokenUsingPin),
|
||||
0x06 => Ok(GetPinUvAuthTokenUsingUv),
|
||||
0x05 => Ok(GetPinToken),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
0x06 => Ok(GetPinUvAuthTokenUsingUvWithPermissions),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
0x07 => Ok(GetUvRetries),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
0x08 => Ok(SetMinPinLength),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
0x09 => Ok(GetPinUvAuthTokenUsingPinWithPermissions),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND),
|
||||
#[cfg(not(feature = "with_ctap2_1"))]
|
||||
_ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
|
||||
|
||||
@@ -849,6 +849,7 @@ where
|
||||
}
|
||||
}
|
||||
if pin.len() < 4 || pin.len() == PIN_PADDED_LENGTH {
|
||||
// TODO(kaczmarczyck) check 4 code point minimum instead
|
||||
return false;
|
||||
}
|
||||
let mut pin_hash = [0; 16];
|
||||
@@ -973,7 +974,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_get_pin_uv_auth_token_using_pin(
|
||||
fn process_get_pin_token(
|
||||
&mut self,
|
||||
key_agreement: CoseKey,
|
||||
pin_hash_enc: Vec<u8>,
|
||||
@@ -1007,7 +1008,8 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn process_get_pin_uv_auth_token_using_uv(
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
fn process_get_pin_uv_auth_token_using_uv_with_permissions(
|
||||
&self,
|
||||
_: CoseKey,
|
||||
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
@@ -1019,6 +1021,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
fn process_get_uv_retries(&self) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
// User verifications is only supported through PIN currently.
|
||||
Ok(AuthenticatorClientPinResponse {
|
||||
@@ -1028,6 +1031,37 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
fn process_set_min_pin_length(
|
||||
&mut self,
|
||||
_min_pin_length: u64,
|
||||
_min_pin_length_rp_ids: Vec<String>,
|
||||
_pin_auth: Vec<u8>,
|
||||
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
// TODO
|
||||
Ok(AuthenticatorClientPinResponse {
|
||||
key_agreement: None,
|
||||
pin_token: None,
|
||||
retries: Some(0),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
fn process_get_pin_uv_auth_token_using_pin_with_permissions(
|
||||
&mut self,
|
||||
_key_agreement: CoseKey,
|
||||
_pin_hash_enc: Vec<u8>,
|
||||
_permissions: u8,
|
||||
_permissions_rp_id: String,
|
||||
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
// TODO
|
||||
Ok(AuthenticatorClientPinResponse {
|
||||
key_agreement: None,
|
||||
pin_token: None,
|
||||
retries: Some(0),
|
||||
})
|
||||
}
|
||||
|
||||
fn process_client_pin(
|
||||
&mut self,
|
||||
client_pin_params: AuthenticatorClientPinParameters,
|
||||
@@ -1039,6 +1073,14 @@ where
|
||||
pin_auth,
|
||||
new_pin_enc,
|
||||
pin_hash_enc,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
min_pin_length,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
min_pin_length_rp_ids,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
permissions,
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
permissions_rp_id,
|
||||
} = client_pin_params;
|
||||
|
||||
if pin_protocol != 1 {
|
||||
@@ -1065,18 +1107,37 @@ where
|
||||
)?;
|
||||
None
|
||||
}
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingPin => {
|
||||
Some(self.process_get_pin_uv_auth_token_using_pin(
|
||||
ClientPinSubCommand::GetPinToken => Some(self.process_get_pin_token(
|
||||
key_agreement.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
pin_hash_enc.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
)?),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions => Some(
|
||||
self.process_get_pin_uv_auth_token_using_uv_with_permissions(
|
||||
key_agreement.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
)?,
|
||||
),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
ClientPinSubCommand::GetUvRetries => Some(self.process_get_uv_retries()?),
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
ClientPinSubCommand::SetMinPinLength => {
|
||||
self.process_set_min_pin_length(
|
||||
min_pin_length.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
min_pin_length_rp_ids.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
pin_auth.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
)?;
|
||||
None
|
||||
}
|
||||
#[cfg(feature = "with_ctap2_1")]
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions => {
|
||||
self.process_get_pin_uv_auth_token_using_pin_with_permissions(
|
||||
key_agreement.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
pin_hash_enc.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
)?)
|
||||
permissions.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
permissions_rp_id.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
)?;
|
||||
None
|
||||
}
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingUv => {
|
||||
Some(self.process_get_pin_uv_auth_token_using_uv(
|
||||
key_agreement.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||
)?)
|
||||
}
|
||||
ClientPinSubCommand::GetUvRetries => Some(self.process_get_uv_retries()?),
|
||||
};
|
||||
Ok(ResponseData::AuthenticatorClientPin(response))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user