From a8a9eeb817c9fb8afbcc0c770aa05eee4d49ddc1 Mon Sep 17 00:00:00 2001 From: Nick Zana Date: Sun, 11 Jun 2023 16:26:17 -0400 Subject: [PATCH] ctap2-proto: Move authenticator::client_pin::AuthProtocolVersion to own module In preparation for adding traits for the PIN/UV Auth Protocol, this splits the AuthProtocolVersion type into its own module and renames it to auth_protocol::Version. --- .../src/authenticator/assertion/get.rs | 4 +- .../authenticator/client_pin/auth_protocol.rs | 31 ++++++++ .../src/authenticator/client_pin/mod.rs | 79 +++++++------------ .../ctap2-proto/src/authenticator/config.rs | 10 +-- .../src/authenticator/credential/make.rs | 2 +- .../authenticator/credential/management.rs | 10 +-- .../ctap2-proto/src/authenticator/device.rs | 4 +- 7 files changed, 76 insertions(+), 64 deletions(-) create mode 100644 crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs diff --git a/crates/ctap2-proto/src/authenticator/assertion/get.rs b/crates/ctap2-proto/src/authenticator/assertion/get.rs index 00b8e86..52f8324 100644 --- a/crates/ctap2-proto/src/authenticator/assertion/get.rs +++ b/crates/ctap2-proto/src/authenticator/assertion/get.rs @@ -1,5 +1,5 @@ use crate::Sha256Hash; -use crate::{authenticator::client_pin::AuthProtocolVersion, extensions}; +use crate::{authenticator::client_pin::auth_protocol, extensions}; use fido_common::credential::public_key; use std::{collections::BTreeMap, usize}; @@ -69,7 +69,7 @@ pub struct Request<'a> { pub pin_uv_auth_param: Option<&'a [u8]>, /// > PIN/UV protocol version selected by platform. #[cfg_attr(feature = "serde", serde(rename = 0x07))] - pub pin_uv_auth_protocol_version: Option, + pub pin_uv_auth_protocol_version: Option, } /// Response structure for [`Ctap2Device::get_assertion`] operation. diff --git a/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs b/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs new file mode 100644 index 0000000..627b044 --- /dev/null +++ b/crates/ctap2-proto/src/authenticator/client_pin/auth_protocol.rs @@ -0,0 +1,31 @@ +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(into = "u8", try_from = "u8") +)] +pub enum Version { + One = 1, + Two = 2, +} + +impl From for u8 { + fn from(value: Version) -> Self { + value as u8 + } +} + +impl TryFrom for Version { + type Error = super::Error; + + fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Version::One), + 2 => Ok(Version::Two), + _ => Err(super::Error::InvalidParameter), + } + } +} diff --git a/crates/ctap2-proto/src/authenticator/client_pin/mod.rs b/crates/ctap2-proto/src/authenticator/client_pin/mod.rs index b7f9a30..e2f8266 100644 --- a/crates/ctap2-proto/src/authenticator/client_pin/mod.rs +++ b/crates/ctap2-proto/src/authenticator/client_pin/mod.rs @@ -4,55 +4,15 @@ use std::collections::BTreeSet; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(into = "u8", try_from = "u8") -)] -pub enum AuthProtocolVersion { - One = 1, - Two = 2, -} - -impl From for u8 { - fn from(value: AuthProtocolVersion) -> Self { - value as u8 - } -} - -impl TryFrom for AuthProtocolVersion { - type Error = Error; - - fn try_from(value: u8) -> Result { - match value { - 1 => Ok(AuthProtocolVersion::One), - 2 => Ok(AuthProtocolVersion::Two), - _ => Err(Error::InvalidParameter), - } - } -} - where - D: serde::Deserializer<'de>, - { - use serde::de; +pub mod auth_protocol; - match u8::deserialize(deserializer)? { - 1 => Ok(Self::One), - 2 => Ok(Self::Two), - i => Err(de::Error::invalid_value( - de::Unexpected::Unsigned(i.into()), - &"1 or 2", - )), - } - } -} +pub type PinUvAuthParam = [u8; 16]; -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum Request<'a> { GetPinRetries, GetKeyAgreement { - version: AuthProtocolVersion, + version: auth_protocol::Version, }, SetPin { key_agreement: &'a coset::CoseKey, @@ -60,25 +20,25 @@ pub enum Request<'a> { pin_uv_auth_param: &'a [u8], }, ChangePin { - version: AuthProtocolVersion, + version: auth_protocol::Version, pin_hash_encrypted: &'a [u8], new_pin_encrypted: &'a [u8], pin_uv_auth_param: &'a [u8], }, GetPinToken { - version: AuthProtocolVersion, - key_agreement: &'a coset::CoseKey, + version: auth_protocol::Version, + key_agreement: cosey::PublicKey, pin_hash_encrypted: &'a [u8], }, GetPinUvAuthTokenUsingUvWithPermissions { - version: AuthProtocolVersion, + version: auth_protocol::Version, key_agreement: &'a coset::CoseKey, permissions: &'a BTreeSet, // TODO: Enforce non-empty set? relying_party_id: Option, }, GetUvRetries, GetPinUvAuthTokenUsingPinWithPermissions { - version: AuthProtocolVersion, + version: auth_protocol::Version, key_agreement: &'a coset::CoseKey, pin_hash_encrypted: usize, permissions: &'a BTreeSet, // TODO: Enforce non-empty set? @@ -126,6 +86,7 @@ pub enum Response { }, } +#[derive(Debug, Clone, Copy)] pub enum Error { MissingParameter, InvalidParameter, @@ -142,6 +103,26 @@ pub enum Error { UserVerificationInvalid, } +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::MissingParameter => write!(f, "Missing parameter"), + Error::InvalidParameter => write!(f, "Invalid parameter"), + Error::PinAuthInvalid => write!(f, "PIN auth invalid"), + Error::PinPolicyViolation => write!(f, "PIN policy violation"), + Error::PinBlocked => write!(f, "PIN blocked"), + Error::PinAuthBlocked => write!(f, "PIN auth blocked"), + Error::PinInvalid => write!(f, "PIN invalid"), + Error::OperationDenied => write!(f, "Operation denied"), + Error::UnauthorizedPermission => write!(f, "Unauthorized permission"), + Error::NotAllowed => write!(f, "Not allowed"), + Error::UserVerificationBlocked => write!(f, "User verification blocked"), + Error::UserActionTimeout => write!(f, "User action timeout"), + Error::UserVerificationInvalid => write!(f, "User verification invalid"), + } + } +} + /// > When obtaining a `pinUvAuthToken`, the platform requests permissions /// > appropriate for the operations it intends to perform. Consequently, the /// > `pinUvAuthToken` can only be used for those operations. diff --git a/crates/ctap2-proto/src/authenticator/config.rs b/crates/ctap2-proto/src/authenticator/config.rs index 4a6e00b..0ebeeff 100644 --- a/crates/ctap2-proto/src/authenticator/config.rs +++ b/crates/ctap2-proto/src/authenticator/config.rs @@ -1,19 +1,19 @@ use std::collections::BTreeMap; -use super::client_pin::AuthProtocolVersion; +use super::client_pin::auth_protocol; #[derive(Clone, Copy)] pub enum Request<'a> { /// > This `enableEnterpriseAttestation` subcommand is only implemented if /// > the enterprise attestation feature is supported. EnableEnterpriseAttestation { - pin_uv_auth_protocol: AuthProtocolVersion, + pin_uv_auth_protocol: auth_protocol::Version, pin_uv_auth_param: &'a [u8], // TODO: Is using a more specific type possible? }, /// > This `toggleAlwaysUv` subcommand is only implemented if the Always /// > Require User Verification feature is supported. ToggleAlwaysUserVerification { - pin_uv_auth_protocol: AuthProtocolVersion, + pin_uv_auth_protocol: auth_protocol::Version, pin_uv_auth_param: &'a [u8], // TODO: Is using a more specific type possible? }, /// > This `setMinPINLength` subcommand is only implemented if the @@ -22,7 +22,7 @@ pub enum Request<'a> { /// > This command sets the minimum PIN length in Unicode code points to be /// > enforced by the authenticator while changing/setting up a ClientPIN. SetMinPinLength { - pin_uv_auth_protocol: AuthProtocolVersion, + pin_uv_auth_protocol: auth_protocol::Version, pin_uv_auth_param: &'a [u8], // TODO: Is using a more specific type possible? }, /// > This subCommand allows vendors to test authenticator configuration @@ -39,7 +39,7 @@ pub enum Request<'a> { vendor_command_id: usize, params: &'a BTreeMap, Vec>, /* TODO: Is the character space of keys * restricted to UTF-8? */ - pin_uv_auth_protocol: AuthProtocolVersion, + pin_uv_auth_protocol: auth_protocol::Version, pin_uv_auth_param: &'a [u8], // TODO: Is using a more specific type possible? }, } diff --git a/crates/ctap2-proto/src/authenticator/credential/make.rs b/crates/ctap2-proto/src/authenticator/credential/make.rs index 9d147ff..e3589ea 100644 --- a/crates/ctap2-proto/src/authenticator/credential/make.rs +++ b/crates/ctap2-proto/src/authenticator/credential/make.rs @@ -99,7 +99,7 @@ pub struct Request<'a> { /// > PIN/UV protocol version selected by platform. #[builder(default, setter(strip_option))] #[cfg_attr(feature = "serde", serde(rename = 0x09))] - pub pin_uv_auth_protocol_version: Option, + pub pin_uv_auth_protocol_version: Option, /// > An authenticator supporting this enterprise attestation feature is /// > enterprise attestation capable and signals its support via the `ep` /// > Option ID in the `authenticatorGetInfo` command response. diff --git a/crates/ctap2-proto/src/authenticator/credential/management.rs b/crates/ctap2-proto/src/authenticator/credential/management.rs index cfdb4f2..8ef9428 100644 --- a/crates/ctap2-proto/src/authenticator/credential/management.rs +++ b/crates/ctap2-proto/src/authenticator/credential/management.rs @@ -7,13 +7,13 @@ pub type PinUvAuthParam = [u8; 16]; pub enum Request<'a> { GetCredentialsMetadata { /// > PIN/UV protocol version chosen by the platform. - pin_uv_auth_protocol: client_pin::AuthProtocolVersion, + pin_uv_auth_protocol: client_pin::auth_protocol::Version, /// > First 16 bytes of HMAC-SHA-256 of contents using `pinUvAuthToken`. pin_uv_auth_param: &'a PinUvAuthParam, }, EnumerateRPsBegin { /// > PIN/UV protocol version chosen by the platform. - pin_uv_auth_protocol: client_pin::AuthProtocolVersion, + pin_uv_auth_protocol: client_pin::auth_protocol::Version, /// > First 16 bytes of HMAC-SHA-256 of contents using `pinUvAuthToken`. pin_uv_auth_param: &'a PinUvAuthParam, }, @@ -22,7 +22,7 @@ pub enum Request<'a> { /// The ID of the relying party to enumerate credentials for. relying_party_id_hash: &'a Sha256Hash, /// > PIN/UV protocol version chosen by the platform. - pin_uv_auth_protocol: client_pin::AuthProtocolVersion, + pin_uv_auth_protocol: client_pin::auth_protocol::Version, /// > First 16 bytes of HMAC-SHA-256 of contents using `pinUvAuthToken`. pin_uv_auth_param: &'a PinUvAuthParam, }, @@ -31,7 +31,7 @@ pub enum Request<'a> { /// The ID of the credential to delete. credential_id: &'a public_key::Descriptor, /// > PIN/UV protocol version chosen by the platform. - pin_uv_auth_protocol: client_pin::AuthProtocolVersion, + pin_uv_auth_protocol: client_pin::auth_protocol::Version, /// > First 16 bytes of HMAC-SHA-256 of contents using `pinUvAuthToken`. pin_uv_auth_param: &'a PinUvAuthParam, }, @@ -41,7 +41,7 @@ pub enum Request<'a> { /// The updated user information. user: &'a public_key::UserEntity, /// > PIN/UV protocol version chosen by the platform. - pin_uv_auth_protocol: client_pin::AuthProtocolVersion, + pin_uv_auth_protocol: client_pin::auth_protocol::Version, /// > First 16 bytes of HMAC-SHA-256 of contents using `pinUvAuthToken`. pin_uv_auth_param: &'a PinUvAuthParam, }, diff --git a/crates/ctap2-proto/src/authenticator/device.rs b/crates/ctap2-proto/src/authenticator/device.rs index 260cb0f..ea2c041 100644 --- a/crates/ctap2-proto/src/authenticator/device.rs +++ b/crates/ctap2-proto/src/authenticator/device.rs @@ -1,4 +1,4 @@ -use crate::authenticator::client_pin::AuthProtocolVersion; +use crate::authenticator::client_pin::auth_protocol; use crate::authenticator::Transport; use crate::extensions; use fido_common::credential::public_key; @@ -247,7 +247,7 @@ pub struct Info { /// > authenticator preference. MUST NOT contain duplicate values... // Cannot be empty if present #[cfg_attr(feature = "serde", serde(rename = 0x06))] - pub pin_uv_auth_protocols: Option>, + pub pin_uv_auth_protocols: Option>, /// > Maximum number of credentials supported in credentialID list at a time /// > by the authenticator. #[cfg_attr(feature = "serde", serde(rename = 0x07))]