From 2f53d730c8c75eb5707bde473e49f71a28547c16 Mon Sep 17 00:00:00 2001 From: Nick Zana Date: Wed, 14 Jun 2023 15:09:50 -0400 Subject: [PATCH] ctap2-proto: Add client_pin::raw::RawRequest for de/serialization of client_pin::Request enum as CBOR --- .../src/authenticator/client_pin/mod.rs | 9 + .../src/authenticator/client_pin/raw/mod.rs | 156 ++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/crates/ctap2-proto/src/authenticator/client_pin/mod.rs b/crates/ctap2-proto/src/authenticator/client_pin/mod.rs index 1dd30a5..5cf7006 100644 --- a/crates/ctap2-proto/src/authenticator/client_pin/mod.rs +++ b/crates/ctap2-proto/src/authenticator/client_pin/mod.rs @@ -10,6 +10,9 @@ pub mod auth_protocol; #[cfg(feature = "serde")] mod raw; +#[cfg(feature = "serde")] +use raw::RawRequest; + pub type PinUvAuthParam = [u8; 16]; @@ -64,6 +67,12 @@ impl SerializeAs for Bytes { } } } +#[derive(Clone, Debug)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(into = "RawRequest", try_from = "RawRequest") +)] pub enum Request<'a> { GetPinRetries, GetKeyAgreement { diff --git a/crates/ctap2-proto/src/authenticator/client_pin/raw/mod.rs b/crates/ctap2-proto/src/authenticator/client_pin/raw/mod.rs index 014f593..2a0f3c8 100644 --- a/crates/ctap2-proto/src/authenticator/client_pin/raw/mod.rs +++ b/crates/ctap2-proto/src/authenticator/client_pin/raw/mod.rs @@ -2,10 +2,17 @@ //! possible in CBOR format while maintaining ergonomic enum variants for public //! API. +use super::auth_protocol; +use super::Error; use super::Permission; +use super::{PinUvAuthParam, PinUvAuthToken}; +use super::{Request, Response}; use flagset::flags; use flagset::FlagSet; use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Bytes}; +use std::borrow::Cow; + mod public_key; #[derive(Clone, Serialize, Deserialize)] @@ -27,6 +34,155 @@ impl From for u8 { } } +#[serde_as] +#[derive(Clone, Serialize, Deserialize)] +pub(crate) struct RawRequest<'a> { + #[serde(rename = 0x01, skip_serializing_if = "Option::is_none")] + pub pin_uv_auth_protocol: Option, + #[serde(rename = 0x02)] + pub sub_command: RawSubcommand, + #[serde( + rename = 0x03, + deserialize_with = "public_key::deserialize", + skip_serializing_if = "Option::is_none" + )] + pub key_agreement: Option, + #[serde_as(as = "Option")] + #[serde(rename = 0x04, skip_serializing_if = "Option::is_none")] + pub pin_uv_auth_param: Option, + #[serde_as(as = "Option")] + #[serde(rename = 0x05, skip_serializing_if = "Option::is_none")] + pub new_pin_enc: Option<[u8; 64]>, + #[serde_as(as = "Option")] + #[serde(rename = 0x06, skip_serializing_if = "Option::is_none")] + pub pin_hash_enc: Option<[u8; 16]>, + #[serde(rename = 0x09, skip_serializing_if = "Option::is_none")] + pub permissions: Option>, // TODO: Deserialize from bitfield + #[serde(rename = 0x0A, skip_serializing_if = "Option::is_none")] + pub rp_id: Option>, +} + +impl<'a> From> for RawRequest<'a> { + fn from(value: Request<'a>) -> Self { + match value { + Request::GetPinRetries => Self { + pin_uv_auth_protocol: None, + sub_command: RawSubcommand::GetPinRetries, + key_agreement: None, + pin_uv_auth_param: None, + new_pin_enc: None, + pin_hash_enc: None, + rp_id: None, + permissions: None, + }, + Request::GetKeyAgreement { version } => Self { + pin_uv_auth_protocol: Some(version), + sub_command: RawSubcommand::GetKeyAgreement, + key_agreement: None, + pin_uv_auth_param: None, + new_pin_enc: None, + pin_hash_enc: None, + rp_id: None, + permissions: None, + }, + Request::SetPin { + key_agreement, + new_pin_encrypted, + pin_uv_auth_param, + version, + } => Self { + pin_uv_auth_protocol: Some(version), + sub_command: RawSubcommand::SetPin, + key_agreement: Some(key_agreement), + pin_uv_auth_param: Some(pin_uv_auth_param), + new_pin_enc: Some(new_pin_encrypted.clone()), + pin_hash_enc: None, + rp_id: None, + permissions: None, + }, + Request::ChangePin { + version, + pin_hash_encrypted, + new_pin_encrypted, + pin_uv_auth_param, + key_agreement, + } => Self { + pin_uv_auth_protocol: Some(version), + sub_command: RawSubcommand::ChangePin, + key_agreement: Some(key_agreement), + pin_uv_auth_param: Some(pin_uv_auth_param), + new_pin_enc: Some(new_pin_encrypted.clone()), + pin_hash_enc: Some(pin_hash_encrypted.clone()), + rp_id: None, + permissions: None, + }, + Request::GetPinToken { + version, + key_agreement, + pin_hash_encrypted, + } => Self { + pin_uv_auth_protocol: Some(version), + sub_command: RawSubcommand::GetPinToken, + key_agreement: Some(key_agreement), + pin_uv_auth_param: None, + new_pin_enc: None, + pin_hash_enc: Some(pin_hash_encrypted.clone()), + rp_id: None, + permissions: None, + }, + Request::GetPinUvAuthTokenUsingUvWithPermissions { + version, + key_agreement, + permissions, + relying_party_id, + } => Self { + pin_uv_auth_protocol: Some(version), + sub_command: RawSubcommand::GetPinUvAuthTokenUsingUvWithPermissions, + key_agreement: Some(key_agreement), + pin_uv_auth_param: None, + new_pin_enc: None, + pin_hash_enc: None, + rp_id: relying_party_id, + permissions: Some(permissions.iter().map(Clone::clone).collect()), + }, + Request::GetUvRetries => Self { + pin_uv_auth_protocol: None, + sub_command: RawSubcommand::GetUvRetries, + key_agreement: None, + pin_uv_auth_param: None, + new_pin_enc: None, + pin_hash_enc: None, + rp_id: None, + permissions: None, + }, + Request::GetPinUvAuthTokenUsingPinWithPermissions { + version, + key_agreement, + pin_hash_encrypted, + permissions, + relying_party_id, + } => Self { + pin_uv_auth_protocol: Some(version), + sub_command: RawSubcommand::GetPinUvAuthTokenUsingPinWithPermissions, + key_agreement: Some(key_agreement), + pin_uv_auth_param: None, + new_pin_enc: None, + pin_hash_enc: Some(pin_hash_encrypted), + rp_id: relying_party_id, + permissions: Some(permissions.iter().map(Clone::clone).collect()), + }, + } + } +} + +impl<'a> TryFrom> for Request<'a> { + type Error = Error; + + fn try_from(value: RawRequest<'a>) -> Result { + todo!() + } +} + flags! { #[derive(Serialize, Deserialize)]