use the enum-iterator crate for better testing of enums
This commit is contained in:
@@ -16,6 +16,7 @@ crypto = { path = "libraries/crypto" }
|
|||||||
byteorder = { version = "1", default-features = false }
|
byteorder = { version = "1", default-features = false }
|
||||||
arrayref = "0.3.6"
|
arrayref = "0.3.6"
|
||||||
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
|
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
|
||||||
|
enum-iterator = "0.6.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug_allocations = ["libtock/debug_allocations"]
|
debug_allocations = ["libtock/debug_allocations"]
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ use alloc::string::String;
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use crypto::{ecdh, ecdsa};
|
use crypto::{ecdh, ecdsa};
|
||||||
|
#[cfg(test)]
|
||||||
|
use enum_iterator::IntoEnumIterator;
|
||||||
|
|
||||||
// https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrpentity
|
// https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrpentity
|
||||||
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))]
|
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))]
|
||||||
@@ -167,6 +169,7 @@ impl From<PublicKeyCredentialParameter> for cbor::Value {
|
|||||||
|
|
||||||
// https://www.w3.org/TR/webauthn/#enumdef-authenticatortransport
|
// https://www.w3.org/TR/webauthn/#enumdef-authenticatortransport
|
||||||
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Clone, Debug, PartialEq))]
|
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Clone, Debug, PartialEq))]
|
||||||
|
#[cfg_attr(test, derive(IntoEnumIterator))]
|
||||||
pub enum AuthenticatorTransport {
|
pub enum AuthenticatorTransport {
|
||||||
Usb,
|
Usb,
|
||||||
Nfc,
|
Nfc,
|
||||||
@@ -455,6 +458,7 @@ impl TryFrom<cbor::Value> for SignatureAlgorithm {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug))]
|
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug))]
|
||||||
|
#[cfg_attr(test, derive(IntoEnumIterator))]
|
||||||
pub enum CredentialProtectionPolicy {
|
pub enum CredentialProtectionPolicy {
|
||||||
UserVerificationOptional = 0x01,
|
UserVerificationOptional = 0x01,
|
||||||
UserVerificationOptionalWithCredentialIdList = 0x02,
|
UserVerificationOptionalWithCredentialIdList = 0x02,
|
||||||
@@ -684,7 +688,8 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))]
|
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Clone, Debug, PartialEq))]
|
||||||
|
#[cfg_attr(test, derive(IntoEnumIterator))]
|
||||||
pub enum ClientPinSubCommand {
|
pub enum ClientPinSubCommand {
|
||||||
GetPinRetries = 0x01,
|
GetPinRetries = 0x01,
|
||||||
GetKeyAgreement = 0x02,
|
GetKeyAgreement = 0x02,
|
||||||
@@ -1167,11 +1172,10 @@ mod test {
|
|||||||
let expected_error = Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
|
let expected_error = Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
|
||||||
assert_eq!(policy_error, expected_error);
|
assert_eq!(policy_error, expected_error);
|
||||||
|
|
||||||
for policy_literal in 1..=3 {
|
for policy in CredentialProtectionPolicy::into_enum_iter() {
|
||||||
let cbor_policy: cbor::Value = cbor_int!(policy_literal);
|
let created_cbor: cbor::Value = policy.into();
|
||||||
let policy = CredentialProtectionPolicy::try_from(cbor_policy.clone());
|
let reconstructed = CredentialProtectionPolicy::try_from(created_cbor).unwrap();
|
||||||
let created_cbor: cbor::Value = policy.unwrap().into();
|
assert_eq!(policy, reconstructed);
|
||||||
assert_eq!(created_cbor, cbor_policy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1188,13 +1192,10 @@ mod test {
|
|||||||
let created_cbor: cbor::Value = authenticator_transport.unwrap().into();
|
let created_cbor: cbor::Value = authenticator_transport.unwrap().into();
|
||||||
assert_eq!(created_cbor, cbor_authenticator_transport);
|
assert_eq!(created_cbor, cbor_authenticator_transport);
|
||||||
|
|
||||||
let transports = ["usb", "nfc", "ble", "internal"];
|
for transport in AuthenticatorTransport::into_enum_iter() {
|
||||||
for transport in transports.iter() {
|
let created_cbor: cbor::Value = transport.clone().into();
|
||||||
let cbor_authenticator_transport: cbor::Value = cbor_text!(*transport);
|
let reconstructed = AuthenticatorTransport::try_from(created_cbor).unwrap();
|
||||||
let authenticator_transport =
|
assert_eq!(transport, reconstructed);
|
||||||
AuthenticatorTransport::try_from(cbor_authenticator_transport.clone());
|
|
||||||
let created_cbor: cbor::Value = authenticator_transport.unwrap().into();
|
|
||||||
assert_eq!(created_cbor, cbor_authenticator_transport);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1339,15 +1340,10 @@ mod test {
|
|||||||
let created_cbor: cbor::Value = sub_command.unwrap().into();
|
let created_cbor: cbor::Value = sub_command.unwrap().into();
|
||||||
assert_eq!(created_cbor, cbor_sub_command);
|
assert_eq!(created_cbor, cbor_sub_command);
|
||||||
|
|
||||||
#[cfg(not(feature = "with_ctap2_1"))]
|
for command in ClientPinSubCommand::into_enum_iter() {
|
||||||
let last_literal = 0x05;
|
let created_cbor: cbor::Value = command.clone().into();
|
||||||
#[cfg(feature = "with_ctap2_1")]
|
let reconstructed = ClientPinSubCommand::try_from(created_cbor).unwrap();
|
||||||
let last_literal = 0x09;
|
assert_eq!(command, reconstructed);
|
||||||
for command_literal in 1..=last_literal {
|
|
||||||
let cbor_sub_command: cbor::Value = cbor_int!(command_literal);
|
|
||||||
let sub_command = ClientPinSubCommand::try_from(cbor_sub_command.clone());
|
|
||||||
let created_cbor: cbor::Value = sub_command.unwrap().into();
|
|
||||||
assert_eq!(created_cbor, cbor_sub_command);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ use crypto::hmac::{hmac_256, verify_hmac_256_first_128bits};
|
|||||||
use crypto::rng256::Rng256;
|
use crypto::rng256::Rng256;
|
||||||
use crypto::sha256::Sha256;
|
use crypto::sha256::Sha256;
|
||||||
use crypto::Hash256;
|
use crypto::Hash256;
|
||||||
|
#[cfg(all(test, feature = "with_ctap2_1"))]
|
||||||
|
use enum_iterator::IntoEnumIterator;
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
// Those constants have to be multiples of 16, the AES block size.
|
// Those constants have to be multiples of 16, the AES block size.
|
||||||
@@ -143,6 +145,7 @@ fn check_and_store_new_pin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "with_ctap2_1")]
|
#[cfg(feature = "with_ctap2_1")]
|
||||||
|
#[cfg_attr(test, derive(IntoEnumIterator))]
|
||||||
// TODO remove when all variants are used
|
// TODO remove when all variants are used
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum PinPermission {
|
pub enum PinPermission {
|
||||||
@@ -1102,55 +1105,16 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let mut pin_protocol_v1 = PinProtocolV1::new(&mut rng);
|
let mut pin_protocol_v1 = PinProtocolV1::new(&mut rng);
|
||||||
pin_protocol_v1.permissions = 0x7F;
|
pin_protocol_v1.permissions = 0x7F;
|
||||||
assert_eq!(
|
for permission in PinPermission::into_enum_iter() {
|
||||||
pin_protocol_v1.has_permission(PinPermission::MakeCredential),
|
assert_eq!(pin_protocol_v1.has_permission(permission), Ok(()));
|
||||||
Ok(())
|
}
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::GetAssertion),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::CredentialManagement),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::BioEnrollment),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::PlatformConfiguration),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::AuthenticatorConfiguration),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
pin_protocol_v1.permissions = 0x00;
|
pin_protocol_v1.permissions = 0x00;
|
||||||
assert_eq!(
|
for permission in PinPermission::into_enum_iter() {
|
||||||
pin_protocol_v1.has_permission(PinPermission::MakeCredential),
|
assert_eq!(
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
pin_protocol_v1.has_permission(permission),
|
||||||
);
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
assert_eq!(
|
);
|
||||||
pin_protocol_v1.has_permission(PinPermission::GetAssertion),
|
}
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::CredentialManagement),
|
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::BioEnrollment),
|
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::PlatformConfiguration),
|
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
pin_protocol_v1.has_permission(PinPermission::AuthenticatorConfiguration),
|
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "with_ctap2_1")]
|
#[cfg(feature = "with_ctap2_1")]
|
||||||
|
|||||||
Reference in New Issue
Block a user