Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get_info: Introduce get-info-full feature and update for CTAP 2.1 #48

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []

Expand Down
147 changes: 136 additions & 11 deletions src/ctap2/get_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,66 @@ pub struct Response {
// FIDO_2_1
#[serde(skip_serializing_if = "Option::is_none")]
pub max_serialized_large_blob_array: Option<usize>,

// 0x0C
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub force_pin_change: Option<bool>,

// 0x0D
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub min_pin_length: Option<usize>,

// 0x0E
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub firmware_version: Option<usize>,

// 0x0F
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_cred_blob_length: Option<usize>,

// 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<usize>,

// 0x11
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_platform_uv_attempts: Option<usize>,

// 0x12
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub uv_modality: Option<usize>,

// 0x13
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub certifications: Option<Certifications>,

// 0x14
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub remaining_discoverable_credentials: Option<usize>,

// 0x15
// FIDO_2_1
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub vendor_prototype_config_commands: Option<usize>,
}

impl Default for Response {
Expand All @@ -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
}
}

Expand All @@ -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,
}
}
}
Expand All @@ -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<bool>, // default false
pub rk: bool,
Expand All @@ -119,58 +194,108 @@ pub struct CtapOptions {
pub uv: Option<bool>, // default not capable
#[serde(skip_serializing_if = "Option::is_none")]
pub plat: Option<bool>, // default false
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub uv_acfg: Option<bool>, // default false
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub always_uv: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cred_mgmt: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub authnr_cfg: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub bio_enroll: Option<bool>, // default false
#[serde(skip_serializing_if = "Option::is_none")]
pub client_pin: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub large_blobs: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub uv_bio_enroll: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(rename = "setMinPINLength", skip_serializing_if = "Option::is_none")]
pub set_min_pin_length: Option<bool>, // default false
#[serde(skip_serializing_if = "Option::is_none")]
pub pin_uv_auth_token: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub make_cred_uv_not_rqd: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub credential_mgmt_preview: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub user_verification_mgmt_preview: Option<bool>,
#[cfg(feature = "get-info-full")]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_mc_ga_permissions_with_client_pin: Option<bool>,
}

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<u8>,

#[serde(rename = "FIPS-CMVP-3")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fips_cmpv3: Option<u8>,

#[serde(rename = "FIPS-CMVP-2-PHY")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fips_cmpv2_phy: Option<u8>,

#[serde(rename = "FIPS-CMVP-3-PHY")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fips_cmpv3_phy: Option<u8>,

#[serde(rename = "CC-EAL")]
#[serde(skip_serializing_if = "Option::is_none")]
pub cc_eal: Option<u8>,

#[serde(rename = "FIDO")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fido: Option<u8>,
}
Loading