PIN protocol V2 in ClientPin (#293)

* PIN protocol V2 in ClientPin

* the test ClientPin has a random second private key
This commit is contained in:
kaczmarczyck
2021-03-15 13:36:28 +01:00
committed by GitHub
parent eb0a0770dd
commit e5313057f9
8 changed files with 815 additions and 525 deletions

View File

@@ -356,6 +356,7 @@ pub struct GetAssertionHmacSecretInput {
pub key_agreement: CoseKey,
pub salt_enc: Vec<u8>,
pub salt_auth: Vec<u8>,
pub pin_uv_auth_protocol: PinUvAuthProtocol,
}
impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
@@ -367,16 +368,20 @@ impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
1 => key_agreement,
2 => salt_enc,
3 => salt_auth,
4 => pin_uv_auth_protocol,
} = extract_map(cbor_value)?;
}
let key_agreement = CoseKey::try_from(ok_or_missing(key_agreement)?)?;
let salt_enc = extract_byte_string(ok_or_missing(salt_enc)?)?;
let salt_auth = extract_byte_string(ok_or_missing(salt_auth)?)?;
let pin_uv_auth_protocol =
pin_uv_auth_protocol.map_or(Ok(PinUvAuthProtocol::V1), PinUvAuthProtocol::try_from)?;
Ok(Self {
key_agreement,
salt_enc,
salt_auth,
pin_uv_auth_protocol,
})
}
}
@@ -638,7 +643,7 @@ impl TryFrom<cbor::Value> for PublicKeyCredentialSource {
let cred_protect_policy = cred_protect_policy
.map(CredentialProtectionPolicy::try_from)
.transpose()?;
let creation_order = creation_order.map(extract_unsigned).unwrap_or(Ok(0))?;
let creation_order = creation_order.map_or(Ok(0), extract_unsigned)?;
let user_name = user_name.map(extract_text_string).transpose()?;
let user_icon = user_icon.map(extract_text_string).transpose()?;
let cred_blob = cred_blob.map(extract_byte_string).transpose()?;
@@ -809,6 +814,24 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PinUvAuthProtocol {
V1,
V2,
}
impl TryFrom<cbor::Value> for PinUvAuthProtocol {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
match extract_unsigned(cbor_value)? {
1 => Ok(PinUvAuthProtocol::V1),
2 => Ok(PinUvAuthProtocol::V2),
_ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(test, derive(IntoEnumIterator))]
pub enum ClientPinSubCommand {
@@ -1569,7 +1592,7 @@ mod test {
}
#[test]
fn test_from_get_assertion_extensions() {
fn test_from_get_assertion_extensions_default_protocol() {
let mut rng = ThreadRng256 {};
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
let pk = sk.genpk();
@@ -1588,6 +1611,7 @@ mod test {
key_agreement: cose_key,
salt_enc: vec![0x02; 32],
salt_auth: vec![0x03; 16],
pin_uv_auth_protocol: PinUvAuthProtocol::V1,
};
let expected_extensions = GetAssertionExtensions {
hmac_secret: Some(expected_input),
@@ -1597,6 +1621,38 @@ mod test {
assert_eq!(extensions, Ok(expected_extensions));
}
#[test]
fn test_from_get_assertion_extensions_with_protocol() {
let mut rng = ThreadRng256 {};
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
let pk = sk.genpk();
let cose_key = CoseKey::from(pk);
let cbor_extensions = cbor_map! {
"hmac-secret" => cbor_map! {
1 => cbor::Value::from(cose_key.clone()),
2 => vec![0x02; 32],
3 => vec![0x03; 16],
4 => 2,
},
"credBlob" => true,
"largeBlobKey" => true,
};
let extensions = GetAssertionExtensions::try_from(cbor_extensions);
let expected_input = GetAssertionHmacSecretInput {
key_agreement: cose_key,
salt_enc: vec![0x02; 32],
salt_auth: vec![0x03; 16],
pin_uv_auth_protocol: PinUvAuthProtocol::V2,
};
let expected_extensions = GetAssertionExtensions {
hmac_secret: Some(expected_input),
cred_blob: true,
large_blob_key: Some(true),
};
assert_eq!(extensions, Ok(expected_extensions));
// TODO more tests, check default
}
#[test]
fn test_from_make_credential_options() {
let cbor_make_options = cbor_map! {
@@ -1759,6 +1815,25 @@ mod test {
assert_eq!(cose_key.algorithm, ES256_ALGORITHM);
}
#[test]
fn test_from_pin_uv_auth_protocol() {
let cbor_protocol: cbor::Value = cbor_int!(0x01);
assert_eq!(
PinUvAuthProtocol::try_from(cbor_protocol),
Ok(PinUvAuthProtocol::V1)
);
let cbor_protocol: cbor::Value = cbor_int!(0x02);
assert_eq!(
PinUvAuthProtocol::try_from(cbor_protocol),
Ok(PinUvAuthProtocol::V2)
);
let cbor_protocol: cbor::Value = cbor_int!(0x03);
assert_eq!(
PinUvAuthProtocol::try_from(cbor_protocol),
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
);
}
#[test]
fn test_from_into_client_pin_sub_command() {
let cbor_sub_command: cbor::Value = cbor_int!(0x01);