Add test_helpers (#474)

* Add set_enterprise_attestation in TestEnv

* Add test_helpers for Test Unification

* Used it in structured fuzzer and enterprise attestation unittests

* Restructure test_helpers

* Rename setup_enterprise_attestation to enable_
This commit is contained in:
hcyang
2022-05-10 18:50:18 +08:00
committed by GitHub
parent 8979af6ca4
commit 3a39c4dff1
8 changed files with 153 additions and 56 deletions

View File

@@ -489,7 +489,7 @@ impl TryFrom<cbor::Value> for AuthenticatorConfigParameters {
}
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthenticatorAttestationMaterial {
pub certificate: Vec<u8>,
pub private_key: [u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH],

View File

@@ -1053,6 +1053,7 @@ impl From<SetMinPinLengthParams> for cbor::Value {
/// The level of enterprise attestation allowed in MakeCredential.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
pub enum EnterpriseAttestationMode {
/// Enterprise attestation is restricted to a list of RP IDs. Add your
/// enterprises domain, e.g. "example.com", to the list below.

View File

@@ -22,7 +22,7 @@ mod crypto_wrapper;
mod ctap1;
pub mod data_formats;
pub mod hid;
mod key_material;
pub mod key_material;
mod large_blobs;
pub mod main_hid;
mod pin_protocol;
@@ -1436,7 +1436,9 @@ mod test {
};
use super::pin_protocol::{authenticate_pin_uv_auth_token, PinProtocol};
use super::*;
use crate::api::customization;
use crate::env::test::TestEnv;
use crate::test_helpers;
use cbor::{cbor_array, cbor_array_vec, cbor_map};
// The keep-alive logic in the processing of some commands needs a channel ID to send
@@ -2062,17 +2064,13 @@ mod test {
#[test]
fn test_process_make_credential_with_enterprise_attestation_vendor_facilitated() {
let mut env = TestEnv::new();
env.customization_mut().enterprise_attestation_mode =
Some(EnterpriseAttestationMode::VendorFacilitated);
env.customization_mut().enterprise_rp_id_list = vec!["example.com".to_string()];
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
env.customization_mut().setup_enterprise_attestation(
Some(EnterpriseAttestationMode::VendorFacilitated),
Some(vec!["example.com".to_string()]),
);
let mut key_bytes = [0; 32];
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
private_key.to_bytes(array_mut_ref!(key_bytes, 0, 32));
storage::set_attestation_certificate(&mut env, &[0xCC]).unwrap();
storage::set_attestation_private_key(&mut env, &key_bytes).unwrap();
storage::enable_enterprise_attestation(&mut env).unwrap();
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
test_helpers::enable_enterprise_attestation(&mut ctap_state, &mut env).unwrap();
let mut make_credential_params = create_minimal_make_credential_parameters();
make_credential_params.enterprise_attestation = Some(1);
@@ -2112,17 +2110,14 @@ mod test {
#[test]
fn test_process_make_credential_with_enterprise_attestation_platform_managed() {
let mut env = TestEnv::new();
env.customization_mut().enterprise_attestation_mode =
Some(EnterpriseAttestationMode::PlatformManaged);
env.customization_mut().enterprise_rp_id_list = vec!["example.com".to_string()];
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
env.customization_mut().setup_enterprise_attestation(
Some(EnterpriseAttestationMode::PlatformManaged),
Some(vec!["example.com".to_string()]),
);
assert!(customization::is_valid(env.customization()));
let mut key_bytes = [0; 32];
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
private_key.to_bytes(array_mut_ref!(key_bytes, 0, 32));
storage::set_attestation_certificate(&mut env, &[0xCC]).unwrap();
storage::set_attestation_private_key(&mut env, &key_bytes).unwrap();
storage::enable_enterprise_attestation(&mut env).unwrap();
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
test_helpers::enable_enterprise_attestation(&mut ctap_state, &mut env).unwrap();
let mut make_credential_params = create_minimal_make_credential_parameters();
make_credential_params.enterprise_attestation = Some(1);
@@ -2151,8 +2146,9 @@ mod test {
#[test]
fn test_process_make_credential_with_enterprise_attestation_invalid() {
let mut env = TestEnv::new();
env.customization_mut().enterprise_attestation_mode =
Some(EnterpriseAttestationMode::PlatformManaged);
env.customization_mut()
.setup_enterprise_attestation(Some(EnterpriseAttestationMode::PlatformManaged), None);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let mut make_credential_params = create_minimal_make_credential_parameters();
@@ -2164,12 +2160,7 @@ mod test {
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
);
let mut key_bytes = [0; 32];
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
private_key.to_bytes(array_mut_ref!(key_bytes, 0, 32));
storage::set_attestation_certificate(&mut env, &[0xCC]).unwrap();
storage::set_attestation_private_key(&mut env, &key_bytes).unwrap();
storage::enable_enterprise_attestation(&mut env).unwrap();
test_helpers::enable_enterprise_attestation(&mut ctap_state, &mut env).unwrap();
let mut make_credential_params = create_minimal_make_credential_parameters();
make_credential_params.enterprise_attestation = Some(3);

View File

@@ -4,21 +4,34 @@ use alloc::string::String;
use alloc::vec::Vec;
pub struct TestCustomization {
pub default_cred_protect: Option<CredentialProtectionPolicy>,
pub default_min_pin_length: u8,
pub default_min_pin_length_rp_ids: Vec<String>,
pub enforce_always_uv: bool,
pub enterprise_attestation_mode: Option<EnterpriseAttestationMode>,
pub enterprise_rp_id_list: Vec<String>,
pub max_msg_size: usize,
pub max_pin_retries: u8,
pub use_batch_attestation: bool,
pub use_signature_counter: bool,
pub max_cred_blob_length: usize,
pub max_credential_count_in_list: Option<usize>,
pub max_large_blob_array_size: usize,
pub max_rp_ids_length: usize,
pub max_supported_resident_keys: usize,
default_cred_protect: Option<CredentialProtectionPolicy>,
default_min_pin_length: u8,
default_min_pin_length_rp_ids: Vec<String>,
enforce_always_uv: bool,
enterprise_attestation_mode: Option<EnterpriseAttestationMode>,
enterprise_rp_id_list: Vec<String>,
max_msg_size: usize,
max_pin_retries: u8,
use_batch_attestation: bool,
use_signature_counter: bool,
max_cred_blob_length: usize,
max_credential_count_in_list: Option<usize>,
max_large_blob_array_size: usize,
max_rp_ids_length: usize,
max_supported_resident_keys: usize,
}
impl TestCustomization {
pub fn setup_enterprise_attestation(
&mut self,
mode: Option<EnterpriseAttestationMode>,
rp_id_list: Option<Vec<String>>,
) {
self.enterprise_attestation_mode = mode;
if let Some(rp_id_list) = rp_id_list {
self.enterprise_rp_id_list = rp_id_list;
}
}
}
impl Customization for TestCustomization {

4
src/env/test/mod.rs vendored
View File

@@ -10,7 +10,7 @@ use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use rng256::Rng256;
mod customization;
pub mod customization;
mod upgrade_storage;
pub struct TestEnv {
@@ -26,7 +26,7 @@ pub struct TestRng256 {
}
impl TestRng256 {
pub fn seed_rng_from_u64(&mut self, state: u64) {
pub fn seed_from_u64(&mut self, state: u64) {
self.rng = StdRng::seed_from_u64(state);
}
}

View File

@@ -52,6 +52,8 @@ pub mod ctap;
#[cfg(not(feature = "std"))]
mod ctap;
pub mod env;
#[cfg(feature = "std")]
pub mod test_helpers;
/// CTAP implementation parameterized by its environment.
pub struct Ctap<E: Env> {

48
src/test_helpers/mod.rs Normal file
View File

@@ -0,0 +1,48 @@
use crate::clock::CtapInstant;
use crate::ctap::command::{
AuthenticatorAttestationMaterial, AuthenticatorConfigParameters,
AuthenticatorVendorConfigureParameters, Command,
};
use crate::ctap::data_formats::ConfigSubCommand;
use crate::ctap::status_code::Ctap2StatusCode;
use crate::ctap::{key_material, Channel, CtapState};
use crate::env::Env;
// In tests where we define a dummy user-presence check that immediately returns, the channel
// ID is irrelevant, so we pass this (dummy but valid) value.
const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]);
#[cfg(feature = "vendor_hid")]
const VENDOR_CHANNEL: Channel = Channel::VendorHid([0x12, 0x34, 0x56, 0x78]);
pub fn enable_enterprise_attestation(
state: &mut CtapState,
env: &mut impl Env,
) -> Result<AuthenticatorAttestationMaterial, Ctap2StatusCode> {
let dummy_key = [0x41; key_material::ATTESTATION_PRIVATE_KEY_LENGTH];
let dummy_cert = vec![0xdd; 20];
let attestation_material = AuthenticatorAttestationMaterial {
certificate: dummy_cert,
private_key: dummy_key,
};
let configure_params = AuthenticatorVendorConfigureParameters {
lockdown: false,
attestation_material: Some(attestation_material.clone()),
};
#[cfg(feature = "vendor_hid")]
let vendor_channel = VENDOR_CHANNEL;
#[cfg(not(feature = "vendor_hid"))]
let vendor_channel = DUMMY_CHANNEL;
let vendor_command = Command::AuthenticatorVendorConfigure(configure_params);
state.process_parsed_command(env, vendor_command, vendor_channel, CtapInstant::new(0))?;
let config_params = AuthenticatorConfigParameters {
sub_command: ConfigSubCommand::EnableEnterpriseAttestation,
sub_command_params: None,
pin_uv_auth_param: None,
pin_uv_auth_protocol: None,
};
let config_command = Command::AuthenticatorConfig(config_params);
state.process_parsed_command(env, config_command, DUMMY_CHANNEL, CtapInstant::new(0))?;
Ok(attestation_material)
}