@ -36,7 +36,7 @@ pub mod enterprise;
/// > of registered `WebAuthn` Extensions is maintained in the IANA "WebAuthn
/// > of registered `WebAuthn` Extensions is maintained in the IANA "WebAuthn
/// > Attestation Statement Format Identifiers" registry
/// > Attestation Statement Format Identifiers" registry
/// > [IANA-WebAuthn-Registries] established by [RFC8809].
/// > [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)) ]
#[ cfg_attr(feature = " serde " , derive(Serialize, Deserialize)) ]
pub enum FormatIdentifier {
pub enum FormatIdentifier {
/// > The "packed" attestation statement format is a WebAuthn-optimized
/// > 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
/// > Attested credential data is a variable-length byte array added to the
/// > authenticator data when generating an attestation object for a given
/// > authenticator data when generating an attestation object for a given
/// > credential.
/// > credential.
#[ derive(Debug) ]
pub struct CredentialData {
pub struct CredentialData {
/// > The AAGUID of the authenticator.
/// > The AAGUID of the authenticator.
pub aaguid : [ u8 ; 16 ] ,
pub aaguid : [ u8 ; 16 ] ,
@ -82,3 +83,57 @@ pub struct CredentialData {
/// The public key of the credential.
/// The public key of the credential.
pub public_key : coset ::CoseKey ,
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 < Self , Self ::Error > {
// 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 < D > ( deserializer : D ) -> Result < Self , D ::Error >
where
D : serde ::Deserializer < ' de > {
let data = Vec ::< u8 > ::deserialize ( deserializer ) ? ;
// TODO: Improve error handling
CredentialData ::try_from ( data . as_slice ( ) ) . map_err ( serde ::de ::Error ::custom )
}
}