diff --git a/CHANGELOG.md b/CHANGELOG.md index 58c6bde..08b1130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add the `Config::new` method to create an instance with the default values. - Add support for multiple credential ID versions and add the `credential_id_version` field to `Config`. - Add `CredentialIdVersion::V2` using AES-256-GCM. +- Make firmware version configurable depending on the current credential ID format. ## [v0.4.0-rc.1](https://github.com/trussed-dev/fido-authenticator/releases/tag/v0.4.0-rc.1) (2026-05-29) diff --git a/fuzz/fuzz_targets/ctap.rs b/fuzz/fuzz_targets/ctap.rs index 158ad9d..127fc83 100644 --- a/fuzz/fuzz_targets/ctap.rs +++ b/fuzz/fuzz_targets/ctap.rs @@ -19,7 +19,7 @@ fuzz_target!(|requests: Vec>| { large_blobs: None, nfc_transport: false, ccid_transport: false, - firmware_version: Some(0), + firmware_version: Some(0.into()), credential_id_version: None, }, ); diff --git a/src/ctap2.rs b/src/ctap2.rs index d67189f..4bfb452 100644 --- a/src/ctap2.rs +++ b/src/ctap2.rs @@ -149,7 +149,10 @@ impl Authenticator for crate::Authenti response.max_creds_in_list = Some(ctap_types::sizes::MAX_CREDENTIAL_COUNT_IN_LIST); response.max_cred_id_length = Some(ctap_types::sizes::MAX_CREDENTIAL_ID_LENGTH); response.algorithms = Some(algorithms); - response.firmware_version = self.config.firmware_version; + response.firmware_version = self + .config + .firmware_version + .map(|version| version.value(self.state.persistent.credential_id_version())); response.remaining_discoverable_credentials = remaining_discoverable_credentials.map(|count| count as usize); response.max_cred_blob_length = Some(MAX_CRED_BLOB_LENGTH); diff --git a/src/lib.rs b/src/lib.rs index f16be97..65ad612 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,7 +133,7 @@ pub struct Config { /// Firmware version reported by `authenticatorGetInfo` (CTAP 2.1 ยง6.4 0x0E). /// /// The runner is expected to plumb its own version constant in here. - pub firmware_version: Option, + pub firmware_version: Option, /// The credential ID format to use for new credentials. /// /// To avoid invalidating existing credentials, this value is only used if the state is clean, @@ -160,6 +160,42 @@ impl Config { } } +/// This struct makes it possible to define the firmware version based on the credential ID format +/// that is currently used by the authenticator. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct FirmwareVersion { + pub default: usize, + pub credential_id_v1: Option, + #[cfg(feature = "credential-id-format-v2")] + pub credential_id_v2: Option, +} + +impl FirmwareVersion { + pub fn new(default: usize) -> Self { + Self { + default, + credential_id_v1: None, + #[cfg(feature = "credential-id-format-v2")] + credential_id_v2: None, + } + } + + pub fn value(&self, credential_id_version: credential::CredentialIdVersion) -> usize { + let value = match credential_id_version { + credential::CredentialIdVersion::V1 => self.credential_id_v1, + #[cfg(feature = "credential-id-format-v2")] + credential::CredentialIdVersion::V2 => self.credential_id_v2, + }; + value.unwrap_or(self.default) + } +} + +impl From for FirmwareVersion { + fn from(default: usize) -> Self { + Self::new(default) + } +} + // impl Default for Config { // fn default() -> Self { // Self { diff --git a/tests/virt/mod.rs b/tests/virt/mod.rs index 0dc6841..48468ea 100644 --- a/tests/virt/mod.rs +++ b/tests/virt/mod.rs @@ -75,7 +75,7 @@ where large_blobs: None, nfc_transport: options.nfc_transport, ccid_transport: options.ccid_transport, - firmware_version: Some(0), + firmware_version: Some(0.into()), credential_id_version: None, }, );