From 90f75b88d86692ddbd2e5b52aa02b1e8215538d4 Mon Sep 17 00:00:00 2001 From: Nick Zana Date: Tue, 16 May 2023 16:05:57 -0400 Subject: [PATCH] fido-common: Implement Deserialize for attestation::CredentialData Relies on ciborium as a dependency because coset requires one of ciborium's error types. It should be possible to remove this type's dependence on ciborium. --- crates/fido-common/Cargo.toml | 3 +- crates/fido-common/src/attestation.rs | 57 ++++++++++++++++++++++++++- crates/fido-common/src/lib.rs | 2 + 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/crates/fido-common/Cargo.toml b/crates/fido-common/Cargo.toml index aa96bd1..9981f22 100644 --- a/crates/fido-common/Cargo.toml +++ b/crates/fido-common/Cargo.toml @@ -6,8 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ciborium = { version = "0.2.1", default-features = false, optional = true } coset = { version = "0.3.4", default-features = false } serde = { version = "1", features = ["derive"], optional = true } [features] -serde = ["dep:serde"] +serde = ["dep:serde", "dep:ciborium"] diff --git a/crates/fido-common/src/attestation.rs b/crates/fido-common/src/attestation.rs index 58d3d15..5b76fe6 100644 --- a/crates/fido-common/src/attestation.rs +++ b/crates/fido-common/src/attestation.rs @@ -36,7 +36,7 @@ pub mod enterprise; /// > of registered `WebAuthn` Extensions is maintained in the IANA "WebAuthn /// > Attestation Statement Format Identifiers" registry /// > [IANA-WebAuthn-Registries] established by [RFC8809]. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum FormatIdentifier { /// > The "packed" attestation statement format is a WebAuthn-optimized @@ -74,6 +74,7 @@ pub enum FormatIdentifier { /// > Attested credential data is a variable-length byte array added to the /// > authenticator data when generating an attestation object for a given /// > credential. +#[derive(Debug)] pub struct CredentialData { /// > The AAGUID of the authenticator. pub aaguid: [u8; 16], @@ -82,3 +83,57 @@ pub struct CredentialData { /// The public key of the credential. pub public_key: coset::CoseKey, } + +#[cfg(feature = "serde")] +impl TryFrom<&[u8]> for CredentialData { + // TODO: Custom error type? + type Error = coset::CoseError; + + fn try_from(data: &[u8]) -> Result { + // aaguid: 16 Bytes + // SAFETY: Validate that data.len >= 16 for aaguid bytes + if data.len() < 16 { + return Err(coset::CoseError::DecodeFailed(ciborium::de::Error::Io( + coset::EndOfFile, + ))); + } + let (&aaguid, data) = data.split_array_ref::<16>(); + + // credentialIdLengh: 2 Bytes + // > Byte length L of credentialId, 16-bit unsigned big-endian integer. Value + // > MUST be ≤ 1023. + // SAFETY: Validate that there are 2 bytes for u16 + if data.len() < 2 { + return Err(coset::CoseError::DecodeFailed(ciborium::de::Error::Io( + coset::EndOfFile, + ))); + } + let (&credential_id_length, mut data) = data.split_array_ref::<2>(); + let credential_id_length = u16::from_be_bytes(credential_id_length); + if credential_id_length > 1023 { + return Err(coset::CoseError::UnexpectedItem( + "a credentialIdLength (L) of greater than 1023", + "a 16-bit unsigned big-endian integer less than or equal to 1023", + )); + } + + // credentialId: L (credential_id_length) Bytes + let credential_id: &[u8] = data.take(..credential_id_length as usize) + .ok_or(coset::CoseError::DecodeFailed(ciborium::de::Error::Io( + coset::EndOfFile, + )))?; + + Ok(Self { aaguid, id: credential_id.to_vec(), public_key: Default::default() }) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for CredentialData { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> { + let data = Vec::::deserialize(deserializer)?; + // TODO: Improve error handling + CredentialData::try_from(data.as_slice()).map_err(serde::de::Error::custom) + } +} diff --git a/crates/fido-common/src/lib.rs b/crates/fido-common/src/lib.rs index 316066e..2bcce8d 100644 --- a/crates/fido-common/src/lib.rs +++ b/crates/fido-common/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(split_array, slice_take)] + pub mod attestation; pub mod authenticator; pub mod credential;