From 9fa9c6d1d9903df93fe682b3df0148bd490946aa Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 2 Jun 2026 23:10:46 +0200 Subject: [PATCH 1/2] Reduce number of generated tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch selects the test cases to run more carefully to reduce the test execution time. Instead of testing all possible combinations in one test case, the patch splits the tests into multiple test cases where each test case covers one field exhaustively. The other fields are either limited to all sensible values (if they seem relevant) or chosen randomly (if they don’t seem relevant). --- tests/basic.rs | 259 ++++++++++++++++++++++++++++++++++++++---- tests/webauthn/mod.rs | 47 +++++++- 2 files changed, 278 insertions(+), 28 deletions(-) diff --git a/tests/basic.rs b/tests/basic.rs index 48b941b..387ccea 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -16,13 +16,51 @@ use rand::RngCore as _; use fs::list_fs; use virt::{Ctap2, Ctap2Error, Options}; use webauthn::{ - exhaustive_struct, AttStmtFormat, AuthenticatorConfig, AuthenticatorConfigParams, ClientPin, - CredentialManagement, CredentialManagementParams, Exhaustive, GetAssertion, + exhaustive_struct, iter_map, AttStmtFormat, AuthenticatorConfig, AuthenticatorConfigParams, + ClientPin, CredentialManagement, CredentialManagementParams, Exhaustive, GetAssertion, GetAssertionExtensionsInput, GetAssertionOptions, GetInfo, GetNextAssertion, HmacSecretInput, KeyAgreementKey, MakeCredential, MakeCredentialExtensionsInput, MakeCredentialOptions, PinToken, PubKeyCredDescriptor, PubKeyCredParam, PublicKey, Rp, SharedSecret, Test, User, }; +macro_rules! run_tests { + ($test:ident { + $(exhaustive = [ + $($exh_field:ident: $exh_type:ty,)* + ],)? + $(iter = [ + $($iter_field:ident: $iter:expr,)* + ],)? + $(random = [ + $($random_field:ident: $random_type:ty,)* + ],)? + $(fixed = [ + $($fixed_field:ident: $fixed_value:expr,)* + ],)? + }) => {{ + $( + let mut rng = rand::thread_rng(); + $( + let $random_field: Vec<$random_type> = <$random_type as Exhaustive>::iter_exhaustive().collect(); + )* + )? + let tests = iter_map! { + [ + $($($exh_field: <$exh_type as Exhaustive>::iter_exhaustive(),)*)? + $($($iter_field: $iter,)*)? + ] => $test { + $($($exh_field,)*)? + $($($iter_field,)*)? + $($($fixed_field: $fixed_value,)*)? + $($($random_field: *::rand::seq::SliceRandom::choose($random_field.as_slice(), &mut rng).unwrap(),)*)? + } + }; + for test in tests { + test.run(); + } + }} +} + #[test] fn test_ping() { virt::run_ctaphid(|device| { @@ -551,6 +589,18 @@ enum PinAuth { PinToken(RequestPinToken), } +impl PinAuth { + fn iter_valid() -> impl Iterator + Clone { + [ + Self::NoPin, + Self::PinNoToken, + Self::PinToken(RequestPinToken::ValidRpId), + Self::PinToken(RequestPinToken::NoRpId), + ] + .into_iter() + } +} + impl Exhaustive for PinAuth { fn iter_exhaustive() -> impl Iterator + Clone { [Self::NoPin, Self::PinNoToken] @@ -707,21 +757,107 @@ impl Test for TestMakeCredential { } } -impl Exhaustive for TestMakeCredential { - fn iter_exhaustive() -> impl Iterator + Clone { - exhaustive_struct! { - pin_auth: PinAuth, - options: Option, - valid_pub_key_alg: bool, - attestation_formats_preference: Option, - hmac_secret: bool, +#[test] +fn test_make_credential_pub_key_alg() { + run_tests! { + TestMakeCredential { + exhaustive = [ + valid_pub_key_alg: bool, + ], + iter = [ + pin_auth: PinAuth::iter_valid(), + options: MakeCredentialOptions::iter_valid().map(Some), + ], + random = [ + attestation_formats_preference: Option, + hmac_secret: bool, + ], } } } #[test] -fn test_make_credential() { - TestMakeCredential::run_all(); +fn test_make_credential_hmac_secret() { + run_tests! { + TestMakeCredential { + exhaustive = [ + hmac_secret: bool, + ], + iter = [ + pin_auth: PinAuth::iter_valid(), + options: MakeCredentialOptions::iter_valid().map(Some), + ], + random = [ + attestation_formats_preference: Option, + ], + fixed = [ + valid_pub_key_alg: true, + ], + } + } +} + +#[test] +fn test_make_credential_pin_auth() { + run_tests! { + TestMakeCredential { + exhaustive = [ + pin_auth: PinAuth, + ], + iter = [ + options: MakeCredentialOptions::iter_valid().map(Some), + ], + random = [ + attestation_formats_preference: Option, + hmac_secret: bool, + ], + fixed = [ + valid_pub_key_alg: true, + ], + } + } +} + +#[test] +fn test_make_credential_options() { + run_tests! { + TestMakeCredential { + exhaustive = [ + options: Option, + ], + iter = [ + pin_auth: PinAuth::iter_valid(), + ], + random = [ + attestation_formats_preference: Option, + hmac_secret: bool, + ], + fixed = [ + valid_pub_key_alg: true, + ], + } + } +} + +#[test] +fn test_make_credential_attestation_formats_preference() { + run_tests! { + TestMakeCredential { + exhaustive = [ + attestation_formats_preference: Option, + ], + iter = [ + pin_auth: PinAuth::iter_valid(), + options: MakeCredentialOptions::iter_valid().map(Some), + ], + random = [ + hmac_secret: bool, + ], + fixed = [ + valid_pub_key_alg: true, + ], + } + } } #[derive(Clone, Copy, Debug, Default)] @@ -922,8 +1058,85 @@ impl Exhaustive for TestGetAssertion { } #[test] -fn test_get_assertion() { - TestGetAssertion::run_all(); +fn test_get_assertion_options() { + run_tests! { + TestGetAssertion { + exhaustive = [ + rk: bool, + allow_list: bool, + options: Option, + ], + random = [ + mc_extensions: Option, + ga_hmac_secret: bool, + ga_third_party_payment: Option, + ga_cred_blob: bool, + ], + } + } +} + +#[test] +fn test_get_assertion_hmac_secret() { + run_tests! { + TestGetAssertion { + exhaustive = [ + rk: bool, + allow_list: bool, + mc_extensions: Option, + ga_hmac_secret: bool, + ], + iter = [ + options: GetAssertionOptions::iter_valid().map(Some), + ], + random = [ + ga_third_party_payment: Option, + ga_cred_blob: bool, + ], + } + } +} + +#[test] +fn test_get_assertion_third_party_payment() { + run_tests! { + TestGetAssertion { + exhaustive = [ + rk: bool, + allow_list: bool, + mc_extensions: Option, + ga_third_party_payment: Option, + ], + iter = [ + options: GetAssertionOptions::iter_valid().map(Some), + ], + random = [ + ga_hmac_secret: bool, + ga_cred_blob: bool, + ], + } + } +} + +#[test] +fn test_get_assertion_cred_blob() { + run_tests! { + TestGetAssertion { + exhaustive = [ + rk: bool, + allow_list: bool, + mc_extensions: Option, + ga_cred_blob: bool, + ], + iter = [ + options: GetAssertionOptions::iter_valid().map(Some), + ], + random = [ + ga_hmac_secret: bool, + ga_third_party_payment: Option, + ], + } + } } fn run_test_get_next_assertion(device: &Ctap2) { @@ -1155,18 +1368,16 @@ impl Test for TestListCredentials { } } -impl Exhaustive for TestListCredentials { - fn iter_exhaustive() -> impl Iterator + Clone { - exhaustive_struct! { - pin_token_rp_id: bool, - third_party_payment: Option, - } - } -} - #[test] fn test_list_credentials() { - TestListCredentials::run_all(); + run_tests! { + TestListCredentials { + exhaustive = [ + pin_token_rp_id: bool, + third_party_payment: Option, + ], + } + } } // ============================================================================ diff --git a/tests/webauthn/mod.rs b/tests/webauthn/mod.rs index 0666afe..9b3d67c 100644 --- a/tests/webauthn/mod.rs +++ b/tests/webauthn/mod.rs @@ -23,12 +23,24 @@ impl Exhaustive for Option { } } +macro_rules! iter_map { + ([ $($name:ident: $iter:expr,)* ] => $map:expr) => { + ::itertools::iproduct!( + $($iter,)* + ).map(|($($name,)*)| { $map }) + } +} + +#[allow(unused_imports)] +pub(crate) use iter_map; + macro_rules! exhaustive_struct { ($($field:ident: $type:ty,)*) => { - ::itertools::iproduct!( - $(<$type as Exhaustive>::iter_exhaustive(),)* - ) - .map(|($($field,)*)| Self { $($field,)* }) + $crate::webauthn::iter_map! { + [ + $($field: <$type as Exhaustive>::iter_exhaustive(),)* + ] => Self { $($field,)* } + } } } @@ -537,6 +549,21 @@ impl MakeCredentialOptions { } } +impl MakeCredentialOptions { + pub fn iter_valid() -> impl Iterator + Clone { + iter_map! { + [ + rk: [true, false], + uv: [true, false], + ] => Self { + rk: rk.then_some(true), + up: None, + uv: uv.then_some(true), + } + } + } +} + impl From for Value { fn from(options: MakeCredentialOptions) -> Value { let mut map = Map::default(); @@ -777,6 +804,18 @@ impl GetAssertionOptions { self.uv = Some(uv); self } + + pub fn iter_valid() -> impl Iterator + Clone { + iter_map! { + [ + up: [true, false], + uv: [true, false], + ] => Self { + up: Some(up), + uv: uv.then_some(true), + } + } + } } impl From for Value { From 4477192edb1ca821f6668eba4315f7d34e0431ba Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Wed, 3 Jun 2026 09:29:15 +0200 Subject: [PATCH 2/2] Update trussed Fixes: https://github.com/trussed-dev/fido-authenticator/issues/58 --- Cargo.toml | 4 ++-- fuzz/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index de151e1..ede3775 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ rand = "0.8.4" rand_chacha = "0.3" sha2 = "0.10" serde_test = "1.0.176" -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "ad577412599156ac98f29ee969e76537e506f2bc", features = ["virt"] } +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "b2492feada78ee17b936c99c13df480a4fc6d2f5", features = ["virt"] } trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0", features = ["chunked", "hkdf", "virt", "fs-info"] } trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner.git", rev = "017921df0930707c4af68882ccb1f8b3f1bbf7c5", default-features = false, features = ["ctaphid"] } usbd-ctaphid = "0.4" @@ -79,7 +79,7 @@ x509-parser = "0.16" features = ["chunked", "dispatch"] [patch.crates-io] -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "ad577412599156ac98f29ee969e76537e506f2bc" } +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "b2492feada78ee17b936c99c13df480a4fc6d2f5" } [profile.test] opt-level = 2 diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index b7153ab..6cf4efa 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -24,5 +24,5 @@ doc = false bench = false [patch.crates-io] -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "ad577412599156ac98f29ee969e76537e506f2bc" } +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "b2492feada78ee17b936c99c13df480a4fc6d2f5" } trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0" }