use the enum-iterator crate for better testing of enums

This commit is contained in:
Fabian Kaczmarczyck
2020-07-08 17:59:20 +02:00
parent 04278d91d8
commit 131f876cdd
3 changed files with 31 additions and 70 deletions

View File

@@ -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"]

View File

@@ -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);
} }
} }

View File

@@ -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")]