diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b850ddc..d69e649 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,7 @@ jobs: - name: Check library run: | cargo check + cargo check --features get-info-full cargo check --features large-blobs cargo check --all-features diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c2e338..dc575b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Mark `get_assertion::{ExtensionsInput, ExtensionsOutput}` and `make_credential::Extensions` as non-exhaustive and implement `Default` - Mark CTAP2 request and response types as non-exhaustive where possible - Use references where possible +- Put uncommon fields in `get_info` behind `get-info-full` feature flag and add fields for CTAP 2.1 [#8]: https://github.com/trussed-dev/ctap-types/pull/8 [#9]: https://github.com/solokeys/ctap-types/issues/9 diff --git a/Cargo.toml b/Cargo.toml index 87e09e0..c5054ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ serde_bytes = { version = "0.11.12", default-features = false } serde_repr = "0.1" [features] +# enables all fields for ctap2::get_info +get-info-full = [] # enables support for implementing the large-blobs extension, see src/sizes.rs large-blobs = [] diff --git a/src/ctap2/get_info.rs b/src/ctap2/get_info.rs index 056e33c..2b999f4 100644 --- a/src/ctap2/get_info.rs +++ b/src/ctap2/get_info.rs @@ -55,6 +55,66 @@ pub struct Response { // FIDO_2_1 #[serde(skip_serializing_if = "Option::is_none")] pub max_serialized_large_blob_array: Option, + + // 0x0C + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub force_pin_change: Option, + + // 0x0D + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub min_pin_length: Option, + + // 0x0E + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub firmware_version: Option, + + // 0x0F + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub max_cred_blob_length: Option, + + // 0x10 + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub max_rpids_for_set_min_pin_length: Option, + + // 0x11 + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub preferred_platform_uv_attempts: Option, + + // 0x12 + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub uv_modality: Option, + + // 0x13 + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub certifications: Option, + + // 0x14 + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub remaining_discoverable_credentials: Option, + + // 0x15 + // FIDO_2_1 + #[cfg(feature = "get-info-full")] + #[serde(skip_serializing_if = "Option::is_none")] + pub vendor_prototype_config_commands: Option, } impl Default for Response { @@ -63,19 +123,13 @@ impl Default for Response { zero_aaguid.resize_default(16).unwrap(); let aaguid = Bytes::<16>::from(zero_aaguid); - Self { - versions: Vec::new(), - extensions: None, + let mut response = ResponseBuilder { aaguid, - options: Some(CtapOptions::default()), - max_msg_size: None, //Some(MESSAGE_SIZE), - pin_protocols: None, - max_creds_in_list: None, - max_cred_id_length: None, - transports: None, - algorithms: None, - max_serialized_large_blob_array: None, + versions: Vec::new(), } + .build(); + response.options = Some(CtapOptions::default()); + response } } @@ -100,6 +154,26 @@ impl ResponseBuilder { transports: None, algorithms: None, max_serialized_large_blob_array: None, + #[cfg(feature = "get-info-full")] + force_pin_change: None, + #[cfg(feature = "get-info-full")] + min_pin_length: None, + #[cfg(feature = "get-info-full")] + firmware_version: None, + #[cfg(feature = "get-info-full")] + max_cred_blob_length: None, + #[cfg(feature = "get-info-full")] + max_rpids_for_set_min_pin_length: None, + #[cfg(feature = "get-info-full")] + preferred_platform_uv_attempts: None, + #[cfg(feature = "get-info-full")] + uv_modality: None, + #[cfg(feature = "get-info-full")] + certifications: None, + #[cfg(feature = "get-info-full")] + remaining_discoverable_credentials: None, + #[cfg(feature = "get-info-full")] + vendor_prototype_config_commands: None, } } } @@ -108,6 +182,7 @@ impl ResponseBuilder { #[non_exhaustive] #[serde(rename_all = "camelCase")] pub struct CtapOptions { + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub ep: Option, // default false pub rk: bool, @@ -119,32 +194,42 @@ pub struct CtapOptions { pub uv: Option, // default not capable #[serde(skip_serializing_if = "Option::is_none")] pub plat: Option, // default false + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub uv_acfg: Option, // default false + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub always_uv: Option, #[serde(skip_serializing_if = "Option::is_none")] pub cred_mgmt: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub authnr_cfg: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub bio_enroll: Option, // default false #[serde(skip_serializing_if = "Option::is_none")] pub client_pin: Option, #[serde(skip_serializing_if = "Option::is_none")] pub large_blobs: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub uv_bio_enroll: Option, + #[cfg(feature = "get-info-full")] #[serde(rename = "setMinPINLength", skip_serializing_if = "Option::is_none")] pub set_min_pin_length: Option, // default false #[serde(skip_serializing_if = "Option::is_none")] pub pin_uv_auth_token: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub make_cred_uv_not_rqd: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub credential_mgmt_preview: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub user_verification_mgmt_preview: Option, + #[cfg(feature = "get-info-full")] #[serde(skip_serializing_if = "Option::is_none")] pub no_mc_ga_permissions_with_client_pin: Option, } @@ -152,25 +237,65 @@ pub struct CtapOptions { impl Default for CtapOptions { fn default() -> Self { Self { + #[cfg(feature = "get-info-full")] ep: None, rk: false, up: true, uv: None, plat: None, + #[cfg(feature = "get-info-full")] uv_acfg: None, + #[cfg(feature = "get-info-full")] always_uv: None, cred_mgmt: None, + #[cfg(feature = "get-info-full")] authnr_cfg: None, + #[cfg(feature = "get-info-full")] bio_enroll: None, client_pin: None, large_blobs: None, + #[cfg(feature = "get-info-full")] uv_bio_enroll: None, pin_uv_auth_token: None, + #[cfg(feature = "get-info-full")] set_min_pin_length: None, + #[cfg(feature = "get-info-full")] make_cred_uv_not_rqd: None, + #[cfg(feature = "get-info-full")] credential_mgmt_preview: None, + #[cfg(feature = "get-info-full")] user_verification_mgmt_preview: None, + #[cfg(feature = "get-info-full")] no_mc_ga_permissions_with_client_pin: None, } } } + +#[cfg(feature = "get-info-full")] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Certifications { + #[serde(rename = "FIPS-CMVP-2")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fips_cmpv2: Option, + + #[serde(rename = "FIPS-CMVP-3")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fips_cmpv3: Option, + + #[serde(rename = "FIPS-CMVP-2-PHY")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fips_cmpv2_phy: Option, + + #[serde(rename = "FIPS-CMVP-3-PHY")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fips_cmpv3_phy: Option, + + #[serde(rename = "CC-EAL")] + #[serde(skip_serializing_if = "Option::is_none")] + pub cc_eal: Option, + + #[serde(rename = "FIDO")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fido: Option, +}