diff --git a/Cargo.toml b/Cargo.toml index 4c2d16c..295abe4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ crypto = { path = "libraries/crypto" } byteorder = { version = "1", default-features = false } arrayref = "0.3.6" subtle = { version = "2.2", default-features = false, features = ["nightly"] } +enum-iterator = "0.6.0" [features] debug_allocations = ["libtock/debug_allocations"] diff --git a/src/ctap/data_formats.rs b/src/ctap/data_formats.rs index b07cdf0..fc3d183 100644 --- a/src/ctap/data_formats.rs +++ b/src/ctap/data_formats.rs @@ -18,6 +18,8 @@ use alloc::string::String; use alloc::vec::Vec; use core::convert::TryFrom; use crypto::{ecdh, ecdsa}; +#[cfg(test)] +use enum_iterator::IntoEnumIterator; // https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrpentity #[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug, PartialEq))] @@ -167,6 +169,7 @@ impl From for cbor::Value { // https://www.w3.org/TR/webauthn/#enumdef-authenticatortransport #[cfg_attr(any(test, feature = "debug_ctap"), derive(Clone, Debug, PartialEq))] +#[cfg_attr(test, derive(IntoEnumIterator))] pub enum AuthenticatorTransport { Usb, Nfc, @@ -455,6 +458,7 @@ impl TryFrom for SignatureAlgorithm { #[derive(Clone, Copy, PartialEq, PartialOrd)] #[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug))] +#[cfg_attr(test, derive(IntoEnumIterator))] pub enum CredentialProtectionPolicy { UserVerificationOptional = 0x01, UserVerificationOptionalWithCredentialIdList = 0x02, @@ -684,7 +688,8 @@ impl TryFrom 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 { GetPinRetries = 0x01, GetKeyAgreement = 0x02, @@ -1167,11 +1172,10 @@ mod test { let expected_error = Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE); assert_eq!(policy_error, expected_error); - for policy_literal in 1..=3 { - let cbor_policy: cbor::Value = cbor_int!(policy_literal); - let policy = CredentialProtectionPolicy::try_from(cbor_policy.clone()); - let created_cbor: cbor::Value = policy.unwrap().into(); - assert_eq!(created_cbor, cbor_policy); + for policy in CredentialProtectionPolicy::into_enum_iter() { + let created_cbor: cbor::Value = policy.into(); + let reconstructed = CredentialProtectionPolicy::try_from(created_cbor).unwrap(); + assert_eq!(policy, reconstructed); } } @@ -1188,13 +1192,10 @@ mod test { let created_cbor: cbor::Value = authenticator_transport.unwrap().into(); assert_eq!(created_cbor, cbor_authenticator_transport); - let transports = ["usb", "nfc", "ble", "internal"]; - for transport in transports.iter() { - let cbor_authenticator_transport: cbor::Value = cbor_text!(*transport); - let authenticator_transport = - AuthenticatorTransport::try_from(cbor_authenticator_transport.clone()); - let created_cbor: cbor::Value = authenticator_transport.unwrap().into(); - assert_eq!(created_cbor, cbor_authenticator_transport); + for transport in AuthenticatorTransport::into_enum_iter() { + let created_cbor: cbor::Value = transport.clone().into(); + let reconstructed = AuthenticatorTransport::try_from(created_cbor).unwrap(); + assert_eq!(transport, reconstructed); } } @@ -1339,15 +1340,10 @@ mod test { let created_cbor: cbor::Value = sub_command.unwrap().into(); assert_eq!(created_cbor, cbor_sub_command); - #[cfg(not(feature = "with_ctap2_1"))] - let last_literal = 0x05; - #[cfg(feature = "with_ctap2_1")] - let last_literal = 0x09; - 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); + for command in ClientPinSubCommand::into_enum_iter() { + let created_cbor: cbor::Value = command.clone().into(); + let reconstructed = ClientPinSubCommand::try_from(created_cbor).unwrap(); + assert_eq!(command, reconstructed); } } diff --git a/src/ctap/pin_protocol_v1.rs b/src/ctap/pin_protocol_v1.rs index 32ca180..8523daf 100644 --- a/src/ctap/pin_protocol_v1.rs +++ b/src/ctap/pin_protocol_v1.rs @@ -26,6 +26,8 @@ use crypto::hmac::{hmac_256, verify_hmac_256_first_128bits}; use crypto::rng256::Rng256; use crypto::sha256::Sha256; use crypto::Hash256; +#[cfg(all(test, feature = "with_ctap2_1"))] +use enum_iterator::IntoEnumIterator; use subtle::ConstantTimeEq; // 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_attr(test, derive(IntoEnumIterator))] // TODO remove when all variants are used #[allow(dead_code)] pub enum PinPermission { @@ -1102,55 +1105,16 @@ mod test { let mut rng = ThreadRng256 {}; let mut pin_protocol_v1 = PinProtocolV1::new(&mut rng); pin_protocol_v1.permissions = 0x7F; - assert_eq!( - pin_protocol_v1.has_permission(PinPermission::MakeCredential), - 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(()) - ); + for permission in PinPermission::into_enum_iter() { + assert_eq!(pin_protocol_v1.has_permission(permission), Ok(())); + } pin_protocol_v1.permissions = 0x00; - assert_eq!( - pin_protocol_v1.has_permission(PinPermission::MakeCredential), - 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) - ); + for permission in PinPermission::into_enum_iter() { + assert_eq!( + pin_protocol_v1.has_permission(permission), + Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID) + ); + } } #[cfg(feature = "with_ctap2_1")]