use super::utils::{from_slice_stream, read_be_u16, read_be_u32, read_byte};
use crate::crypto::{COSEAlgorithm, CryptoError, SharedSecret};
use crate::ctap2::server::{CredentialProtectionPolicy, HMACGetSecretOutput, RpIdHash};
use crate::ctap2::utils::serde_parse_err;
use crate::{crypto::COSEKey, errors::AuthenticatorError};
use base64::Engine;
use serde::ser::{Error as SerError, SerializeMap, Serializer};
use serde::{
de::{Error as SerdeError, Unexpected, Visitor},
Deserialize, Deserializer, Serialize,
};
use serde_cbor;
use std::convert::TryInto;
use std::fmt;
use std::io::{Cursor, Read};
#[derive(Debug, PartialEq, Eq)]
pub enum HmacSecretResponse {
Confirmed(bool),
Secret(Vec<u8>),
}
impl HmacSecretResponse {
pub fn decrypt_secrets(
&self,
shared_secret: &SharedSecret,
) -> Option<Result<HMACGetSecretOutput, CryptoError>> {
if let HmacSecretResponse::Secret(hmac_outputs) = self {
Some(Self::decrypt_secrets_internal(shared_secret, hmac_outputs))
} else {
None
}
}
fn decrypt_secrets_internal(
shared_secret: &SharedSecret,
hmac_outputs: &[u8],
) -> Result<HMACGetSecretOutput, CryptoError> {
let output_secrets = shared_secret.decrypt(hmac_outputs)?;
match if output_secrets.len() < 32 {
Err(CryptoError::WrongSaltLength)
} else {
let (output1, output2) = output_secrets.split_at(32);
Ok(HMACGetSecretOutput {
output1: output1
.try_into()
.map_err(|_| CryptoError::WrongSaltLength)?,
output2: (!output2.is_empty())
.then(|| output2.try_into().map_err(|_| CryptoError::WrongSaltLength))
.transpose()?,
})
} {
err @ Err(CryptoError::WrongSaltLength) => {
debug!(
"Bad hmac-secret output length: {} bytes (expected exactly 32 or 64)",
output_secrets.len()
);
err
}
other => other,
}
}
}
impl Serialize for HmacSecretResponse {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
HmacSecretResponse::Confirmed(x) => serializer.serialize_bool(*x),
HmacSecretResponse::Secret(x) => serializer.serialize_bytes(x),
}
}
}
impl<'de> Deserialize<'de> for HmacSecretResponse {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct HmacSecretResponseVisitor;
impl<'de> Visitor<'de> for HmacSecretResponseVisitor {
type Value = HmacSecretResponse;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte array or a boolean")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: SerdeError,
{
Ok(HmacSecretResponse::Secret(v.to_vec()))
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: SerdeError,
{
Ok(HmacSecretResponse::Confirmed(v))
}
}
deserializer.deserialize_any(HmacSecretResponseVisitor)
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct Extension {
#[serde(rename = "credProtect", skip_serializing_if = "Option::is_none")]
pub cred_protect: Option<CredentialProtectionPolicy>,
#[serde(rename = "hmac-secret", skip_serializing_if = "Option::is_none")]
pub hmac_secret: Option<HmacSecretResponse>,
#[serde(rename = "minPinLength", skip_serializing_if = "Option::is_none")]
pub min_pin_length: Option<u64>,
}
impl Extension {
pub fn has_some(&self) -> bool {
self.min_pin_length.is_some() || self.hmac_secret.is_some() || self.cred_protect.is_some()
}
}
#[derive(Serialize, PartialEq, Default, Eq, Clone)]
pub struct AAGuid(pub [u8; 16]);
impl AAGuid {
pub fn from(src: &[u8]) -> Result<AAGuid, AuthenticatorError> {
let mut payload = [0u8; 16];
if src.len() != payload.len() {
Err(AuthenticatorError::InternalError(String::from(
"Failed to parse AAGuid",
)))
} else {
payload.copy_from_slice(src);
Ok(AAGuid(payload))
}
}
}
impl fmt::Debug for AAGuid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"AAGuid({:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x})",
self.0[0],
self.0[1],
self.0[2],
self.0[3],
self.0[4],
self.0[5],
self.0[6],
self.0[7],
self.0[8],
self.0[9],
self.0[10],
self.0[11],
self.0[12],
self.0[13],
self.0[14],
self.0[15]
)
}
}
impl<'de> Deserialize<'de> for AAGuid {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct AAGuidVisitor;
impl<'de> Visitor<'de> for AAGuidVisitor {
type Value = AAGuid;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte array")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: SerdeError,
{
let mut buf = [0u8; 16];
if v.len() != buf.len() {
return Err(E::invalid_length(v.len(), &"16"));
}
buf.copy_from_slice(v);
Ok(AAGuid(buf))
}
}
deserializer.deserialize_bytes(AAGuidVisitor)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct AttestedCredentialData {
pub aaguid: AAGuid,
pub credential_id: Vec<u8>,
pub credential_public_key: COSEKey,
}
fn parse_attested_cred_data<R: Read, E: SerdeError>(
data: &mut R,
) -> Result<AttestedCredentialData, E> {
let mut aaguid_raw = [0u8; 16];
data.read_exact(&mut aaguid_raw)
.map_err(|_| serde_parse_err("AAGuid"))?;
let aaguid = AAGuid(aaguid_raw);
let cred_len = read_be_u16(data)?;
let mut credential_id = vec![0u8; cred_len as usize];
data.read_exact(&mut credential_id)
.map_err(|_| serde_parse_err("CredentialId"))?;
let credential_public_key = from_slice_stream(data)?;
Ok(AttestedCredentialData {
aaguid,
credential_id,
credential_public_key,
})
}
bitflags! {
pub struct AuthenticatorDataFlags: u8 {
const USER_PRESENT = 0x01;
const RESERVED_1 = 0x02;
const USER_VERIFIED = 0x04;
const RESERVED_3 = 0x08;
const RESERVED_4 = 0x10;
const RESERVED_5 = 0x20;
const ATTESTED = 0x40;
const EXTENSION_DATA = 0x80;
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct AuthenticatorData {
pub rp_id_hash: RpIdHash,
pub flags: AuthenticatorDataFlags,
pub counter: u32,
pub credential_data: Option<AttestedCredentialData>,
pub extensions: Extension,
}
impl AuthenticatorData {
pub fn to_vec(&self) -> Vec<u8> {
match serde_cbor::value::to_value(self) {
Ok(serde_cbor::value::Value::Bytes(out)) => out,
_ => unreachable!(), }
}
}
impl<'de> Deserialize<'de> for AuthenticatorData {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct AuthenticatorDataVisitor;
impl<'de> Visitor<'de> for AuthenticatorDataVisitor {
type Value = AuthenticatorData;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte array")
}
fn visit_bytes<E>(self, input: &[u8]) -> Result<Self::Value, E>
where
E: SerdeError,
{
let mut cursor = Cursor::new(input);
let mut rp_id_hash_raw = [0u8; 32];
cursor
.read_exact(&mut rp_id_hash_raw)
.map_err(|_| serde_parse_err("32 bytes"))?;
let rp_id_hash = RpIdHash(rp_id_hash_raw);
let flags = AuthenticatorDataFlags::from_bits_truncate(read_byte(&mut cursor)?);
let counter = read_be_u32(&mut cursor)?;
let mut credential_data = None;
if flags.contains(AuthenticatorDataFlags::ATTESTED) {
credential_data = Some(parse_attested_cred_data(&mut cursor)?);
}
let extensions = if flags.contains(AuthenticatorDataFlags::EXTENSION_DATA) {
from_slice_stream(&mut cursor)?
} else {
Default::default()
};
Ok(AuthenticatorData {
rp_id_hash,
flags,
counter,
credential_data,
extensions,
})
}
}
deserializer.deserialize_bytes(AuthenticatorDataVisitor)
}
}
impl Serialize for AuthenticatorData {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut data = Vec::new();
data.extend(self.rp_id_hash.0); data.extend([self.flags.bits()]); data.extend(self.counter.to_be_bytes());
if let Some(cred) = &self.credential_data {
data.extend(cred.aaguid.0); data.extend((cred.credential_id.len() as u16).to_be_bytes()); data.extend(&cred.credential_id); data.extend(
&serde_cbor::to_vec(&cred.credential_public_key)
.map_err(|_| SerError::custom("Failed to serialize auth_data"))?,
);
}
if self.extensions.has_some() || self.flags.contains(AuthenticatorDataFlags::EXTENSION_DATA)
{
data.extend(
&serde_cbor::to_vec(&self.extensions)
.map_err(|_| SerError::custom("Failed to serialize auth_data"))?,
);
}
serializer.serialize_bytes(&data)
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct AttestationCertificate(#[serde(with = "serde_bytes")] pub Vec<u8>);
impl AsRef<[u8]> for AttestationCertificate {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub struct Signature(#[serde(with = "serde_bytes")] pub Vec<u8>);
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let value = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&self.0);
write!(f, "Signature({value})")
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl From<&[u8]> for Signature {
fn from(sig: &[u8]) -> Signature {
Signature(sig.to_vec())
}
}
#[derive(Debug, PartialEq, Eq, Deserialize)]
#[serde(tag = "fmt", content = "attStmt", rename_all = "lowercase")]
pub enum AttestationStatement {
#[serde(deserialize_with = "deserialize_none_att_stmt")]
None,
Packed(AttestationStatementPacked),
#[serde(rename = "fido-u2f")]
FidoU2F(AttestationStatementFidoU2F),
#[serde(rename = "android-key")]
AndroidKey(serde_cbor::Value),
#[serde(rename = "android-safetynet")]
AndroidSafetyNet(serde_cbor::Value),
Apple(serde_cbor::Value),
Tpm(serde_cbor::Value),
}
impl AttestationStatement {
pub fn id(&self) -> &str {
match self {
Self::None => "none",
Self::Packed(..) => "packed",
Self::FidoU2F(..) => "fido-u2f",
Self::AndroidKey(..) => "android-key",
Self::AndroidSafetyNet(..) => "android-safetynet",
Self::Apple(..) => "apple",
Self::Tpm(..) => "tpm",
}
}
}
impl Serialize for AttestationStatement {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::None => serializer.serialize_map(Some(0))?.end(),
Self::Packed(ref v) => serializer.serialize_some(v),
Self::FidoU2F(ref v) => serializer.serialize_some(v),
Self::AndroidKey(ref v) => serializer.serialize_some(v),
Self::AndroidSafetyNet(ref v) => serializer.serialize_some(v),
Self::Apple(ref v) => serializer.serialize_some(v),
Self::Tpm(ref v) => serializer.serialize_some(v),
}
}
}
fn deserialize_none_att_stmt<'de, D>(deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
let map = <std::collections::BTreeMap<(), ()>>::deserialize(deserializer)?;
if !map.is_empty() {
return Err(D::Error::invalid_value(Unexpected::Map, &"the empty map"));
}
Ok(())
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct AttestationStatementFidoU2F {
pub sig: Signature, #[serde(rename = "x5c")]
pub attestation_cert: Vec<AttestationCertificate>, }
impl AttestationStatementFidoU2F {
pub fn new(cert: &[u8], signature: &[u8]) -> Self {
AttestationStatementFidoU2F {
attestation_cert: vec![AttestationCertificate(Vec::from(cert))],
sig: Signature::from(signature),
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct AttestationStatementPacked {
pub alg: COSEAlgorithm, pub sig: Signature, #[serde(rename = "x5c", skip_serializing_if = "Vec::is_empty", default)]
pub attestation_cert: Vec<AttestationCertificate>, }
#[derive(Debug, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AttestationObject {
pub auth_data: AuthenticatorData,
#[serde(flatten)]
pub att_stmt: AttestationStatement,
}
impl AttestationObject {
pub fn anonymize(&mut self) {
self.att_stmt = AttestationStatement::None;
if let Some(credential_data) = self.auth_data.credential_data.as_mut() {
credential_data.aaguid = AAGuid::default();
}
}
}
impl Serialize for AttestationObject {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_map!(
serializer,
&"fmt" => self.att_stmt.id(),
&"attStmt" => &self.att_stmt,
&"authData" => &self.auth_data,
)
}
}
#[cfg(test)]
pub mod test {
use super::super::utils::from_slice_stream;
use super::*;
use crate::crypto::{COSEAlgorithm, COSEEC2Key, COSEKey, COSEKeyType, Curve};
use serde_cbor::{from_slice, to_vec};
const SAMPLE_ATTESTATION_STMT_NONE: [u8; 19] = [
0xa2, 0x63, 0x66, 0x6d, 0x74, 0x64, 0x6e, 0x6f, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x74, 0x53, 0x74, 0x6d, 0x74, 0xa0, ];
const SAMPLE_ATTESTATION_STMT_FIDO_U2F: [u8; 840] = [
0xa2, 0x63, 0x66, 0x6d, 0x74, 0x68, 0x66, 0x69, 0x64, 0x6f, 0x2d, 0x75, 0x32, 0x66, 0x67, 0x61, 0x74, 0x74, 0x53, 0x74, 0x6d, 0x74, 0xa2, 0x63, 0x78, 0x35, 0x63, 0x81, 0x59, 0x02, 0xdd, 0x30, 0x82, 0x02, 0xd9, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09,
0x00, 0xdf, 0x92, 0xd9, 0xc4, 0xe2, 0xed, 0x66, 0x0a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a,
0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55,
0x32, 0x46, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20, 0x17,
0x0d, 0x31, 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18,
0x0f, 0x32, 0x30, 0x35, 0x30, 0x30, 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x5a, 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53,
0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x59, 0x75, 0x62,
0x69, 0x63, 0x6f, 0x20, 0x41, 0x42, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72,
0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x28, 0x30,
0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20,
0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x31,
0x31, 0x35, 0x35, 0x31, 0x30, 0x39, 0x35, 0x39, 0x39, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x0a, 0x18, 0x6c, 0x6e, 0x4d, 0x0a, 0x6a, 0x52, 0x8a,
0x44, 0x90, 0x9a, 0x7a, 0x24, 0x23, 0x68, 0x70, 0x28, 0xd4, 0xc5, 0x7e, 0xcc, 0xb7, 0x17,
0xba, 0x12, 0x80, 0xb8, 0x5c, 0x2f, 0xc1, 0xe4, 0xe0, 0x61, 0x66, 0x8c, 0x3c, 0x20, 0xae,
0xf3, 0x33, 0x50, 0xd1, 0x96, 0x45, 0x23, 0x8a, 0x2c, 0x39, 0x0b, 0xf5, 0xdf, 0xfa, 0x34,
0xff, 0x25, 0x50, 0x2f, 0x47, 0x0f, 0x3d, 0x40, 0xb8, 0x88, 0xa3, 0x81, 0x81, 0x30, 0x7f,
0x30, 0x13, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x0d, 0x01, 0x04,
0x05, 0x04, 0x03, 0x05, 0x04, 0x03, 0x30, 0x22, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01,
0x82, 0xc4, 0x0a, 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34,
0x2e, 0x31, 0x2e, 0x34, 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x37, 0x30, 0x13, 0x06,
0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03,
0x02, 0x04, 0x30, 0x30, 0x21, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c,
0x01, 0x01, 0x04, 0x04, 0x12, 0x04, 0x10, 0x2f, 0xc0, 0x57, 0x9f, 0x81, 0x13, 0x47, 0xea,
0xb1, 0x16, 0xbb, 0x5a, 0x8d, 0xb9, 0x20, 0x2a, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x82, 0xac, 0xaf,
0x11, 0x30, 0xa9, 0x9b, 0xd1, 0x43, 0x27, 0xd2, 0xf8, 0xf9, 0xb0, 0x41, 0xa2, 0xa0, 0x4a,
0x66, 0x85, 0x27, 0x24, 0x22, 0xe5, 0x7b, 0x14, 0xb0, 0xb8, 0xf8, 0x3b, 0x6f, 0x15, 0x45,
0x66, 0x4b, 0xbf, 0x55, 0x68, 0x1e, 0xaf, 0x01, 0x58, 0x72, 0x2a, 0xbf, 0xce, 0xd2, 0xe4,
0xac, 0x63, 0x3c, 0xec, 0x09, 0x59, 0x56, 0x45, 0x24, 0xb0, 0xf2, 0xe5, 0x17, 0xdd, 0x97,
0x10, 0x98, 0xb9, 0x89, 0x15, 0x17, 0xec, 0xd0, 0xc5, 0x53, 0xa2, 0xe4, 0x73, 0x9f, 0x9d,
0xe1, 0x3d, 0xaf, 0xd0, 0xd5, 0xd7, 0xb8, 0xac, 0x4a, 0x37, 0xf4, 0xf2, 0xcc, 0x30, 0xef,
0x25, 0xcb, 0x00, 0x65, 0x2d, 0x19, 0xdb, 0x69, 0xd7, 0xda, 0x57, 0xbd, 0x1a, 0x9c, 0x1d,
0x8e, 0xd8, 0x7d, 0x46, 0xd8, 0x0d, 0x2b, 0x3b, 0xdf, 0xd1, 0xd9, 0xef, 0x9d, 0x2b, 0x68,
0x32, 0xd4, 0xad, 0x5b, 0xcd, 0x74, 0x21, 0x4c, 0xe6, 0xa6, 0x14, 0x1d, 0x16, 0xb2, 0xe9,
0x3a, 0xcb, 0x2c, 0x88, 0xf6, 0x0a, 0x3e, 0xb6, 0xd5, 0xf6, 0x14, 0x71, 0x97, 0x59, 0x09,
0x37, 0x3b, 0xc6, 0x77, 0x90, 0x23, 0x24, 0x57, 0x1a, 0x57, 0x3f, 0x60, 0xf0, 0x7b, 0xbe,
0xd1, 0x7b, 0x92, 0xc8, 0xb5, 0x9f, 0xa2, 0x82, 0x10, 0xbf, 0xa8, 0xc6, 0x01, 0x22, 0x93,
0x00, 0x1b, 0x39, 0xef, 0xe5, 0x7b, 0xf9, 0xcb, 0x1e, 0x3a, 0xca, 0x8a, 0x41, 0x30, 0xf8,
0x3a, 0xf8, 0x66, 0x8f, 0x73, 0xde, 0xf2, 0x71, 0x1b, 0x20, 0xdc, 0x99, 0xe8, 0xa8, 0x04,
0xee, 0xa3, 0xf7, 0x42, 0x71, 0x97, 0xb6, 0xb4, 0x51, 0xb3, 0x73, 0x5c, 0x23, 0xbc, 0x9b,
0x1b, 0xe2, 0x74, 0xc2, 0x6d, 0x3b, 0xf9, 0x19, 0x6f, 0x8c, 0x4a, 0x4b, 0x71, 0x5f, 0x4b,
0x95, 0xc4, 0xdb, 0x7b, 0x97, 0xe7, 0x59, 0x4e, 0xb4, 0x65, 0x64, 0x8c, 0x1c, 0x63, 0x73,
0x69, 0x67, 0x58, 0x46, 0x30, 0x44, 0x02, 0x20, 0x48, 0x5a, 0x72, 0x40, 0xdf, 0x2c, 0x1e, 0x31, 0xa5, 0xb3, 0x0b,
0x3b, 0x2c, 0xd1, 0xad, 0xd0, 0x8d, 0xae, 0x8d, 0x7a, 0x25, 0x3e, 0xf5, 0xa6, 0x25, 0xdb,
0x2e, 0x22, 0x1b, 0x71, 0xe5, 0x78, 0x02, 0x20, 0x45, 0xbd, 0xdc, 0x30, 0xde, 0xf4, 0x05,
0x97, 0x5c, 0xac, 0x72, 0x58, 0x96, 0xa6, 0x00, 0x94, 0x57, 0x3a, 0xa5, 0xe8, 0x1e, 0xf4,
0xfd, 0x30, 0xd3, 0x88, 0x11, 0x8b, 0x49, 0x97, 0xdf, 0x34,
];
const SAMPLE_ATTESTATION_OBJ_PACKED: [u8; 677] = [
0xa3, 0x63, 0x66, 0x6D, 0x74, 0x66, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x67, 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74, 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x58, 0x47, 0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c, 0xc1, 0x5c,
0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4, 0x62, 0xd5, 0xf0, 0x56, 0x12,
0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89, 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f, 0xf9, 0x10,
0xcc, 0xb5, 0x6a, 0xc5, 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2,
0xb7, 0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29, 0x63, 0x78, 0x35, 0x63, 0x81, 0x59, 0x01, 0x97, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b,
0x4c, 0x29, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63,
0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72,
0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x1e, 0x17,
0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17,
0x0d, 0x32, 0x36, 0x31, 0x32, 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30,
0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63,
0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72,
0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59, 0x30,
0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52,
0xe5, 0x3a, 0xd5, 0xdf, 0xed, 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf,
0x8f, 0x22, 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04, 0xff,
0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c, 0xb4, 0x84, 0x99, 0x79,
0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60, 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d,
0x30, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a,
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46,
0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25, 0xf7, 0x37, 0x3e, 0x10,
0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94, 0xd0, 0xc0, 0x3f, 0x3f, 0xda, 0x1f, 0xd2,
0x2d, 0xb3, 0xd0, 0x30, 0xe7, 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec, 0x34, 0x45, 0xa8, 0x20,
0xcf, 0x43, 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9, 0xc5,
0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3, 0x68, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x58, 0x94, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84,
0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a,
0x87, 0x05, 0x1d, 0x41, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c,
0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1,
0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97,
0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20,
0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c,
0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e,
0xa6, 0x1c,
];
const SAMPLE_CERT_CHAIN: [u8; 709] = [
0x81, 0x59, 0x2, 0xc1, 0x30, 0x82, 0x2, 0xbd, 0x30, 0x82, 0x1, 0xa5, 0xa0, 0x3, 0x2, 0x1,
0x2, 0x2, 0x4, 0x18, 0xac, 0x46, 0xc0, 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0xd, 0x1, 0x1, 0xb, 0x5, 0x0, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x6, 0x3, 0x55, 0x4, 0x3,
0x13, 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x52, 0x6f,
0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x34, 0x35,
0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0xd, 0x31, 0x34, 0x30, 0x38,
0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0xf, 0x32, 0x30, 0x35, 0x30,
0x30, 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6e, 0x31, 0xb,
0x30, 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13, 0x2, 0x53, 0x45, 0x31, 0x12, 0x30, 0x10, 0x6,
0x3, 0x55, 0x4, 0xa, 0xc, 0x9, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x41, 0x42, 0x31,
0x22, 0x30, 0x20, 0x6, 0x3, 0x55, 0x4, 0xb, 0xc, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x31, 0x27, 0x30, 0x25, 0x6, 0x3, 0x55, 0x4, 0x3, 0xc, 0x1e, 0x59,
0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x20, 0x34, 0x31, 0x33, 0x39, 0x34, 0x33, 0x34, 0x38, 0x38, 0x30,
0x59, 0x30, 0x13, 0x6, 0x7, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x2, 0x1, 0x6, 0x8, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0x3, 0x42, 0x0, 0x4, 0x79, 0xea, 0x3b, 0x2c, 0x7c, 0x49,
0x70, 0x10, 0x62, 0x23, 0xc, 0xd2, 0x3f, 0xeb, 0x60, 0xe5, 0x29, 0x31, 0x71, 0xd4, 0x83,
0xf1, 0x0, 0xbe, 0x85, 0x9d, 0x6b, 0xf, 0x83, 0x97, 0x3, 0x1, 0xb5, 0x46, 0xcd, 0xd4, 0x6e,
0xcf, 0xca, 0xe3, 0xe3, 0xf3, 0xf, 0x81, 0xe9, 0xed, 0x62, 0xbd, 0x26, 0x8d, 0x4c, 0x1e,
0xbd, 0x37, 0xb3, 0xbc, 0xbe, 0x92, 0xa8, 0xc2, 0xae, 0xeb, 0x4e, 0x3a, 0xa3, 0x6c, 0x30,
0x6a, 0x30, 0x22, 0x6, 0x9, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0xc4, 0xa, 0x2, 0x4, 0x15,
0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x31, 0x34,
0x38, 0x32, 0x2e, 0x31, 0x2e, 0x37, 0x30, 0x13, 0x6, 0xb, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82,
0xe5, 0x1c, 0x2, 0x1, 0x1, 0x4, 0x4, 0x3, 0x2, 0x5, 0x20, 0x30, 0x21, 0x6, 0xb, 0x2b, 0x6,
0x1, 0x4, 0x1, 0x82, 0xe5, 0x1c, 0x1, 0x1, 0x4, 0x4, 0x12, 0x4, 0x10, 0xcb, 0x69, 0x48,
0x1e, 0x8f, 0xf7, 0x40, 0x39, 0x93, 0xec, 0xa, 0x27, 0x29, 0xa1, 0x54, 0xa8, 0x30, 0xc,
0x6, 0x3, 0x55, 0x1d, 0x13, 0x1, 0x1, 0xff, 0x4, 0x2, 0x30, 0x0, 0x30, 0xd, 0x6, 0x9, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0xb, 0x5, 0x0, 0x3, 0x82, 0x1, 0x1, 0x0, 0x97, 0x9d,
0x3, 0x97, 0xd8, 0x60, 0xf8, 0x2e, 0xe1, 0x5d, 0x31, 0x1c, 0x79, 0x6e, 0xba, 0xfb, 0x22,
0xfa, 0xa7, 0xe0, 0x84, 0xd9, 0xba, 0xb4, 0xc6, 0x1b, 0xbb, 0x57, 0xf3, 0xe6, 0xb4, 0xc1,
0x8a, 0x48, 0x37, 0xb8, 0x5c, 0x3c, 0x4e, 0xdb, 0xe4, 0x83, 0x43, 0xf4, 0xd6, 0xa5, 0xd9,
0xb1, 0xce, 0xda, 0x8a, 0xe1, 0xfe, 0xd4, 0x91, 0x29, 0x21, 0x73, 0x5, 0x8e, 0x5e, 0xe1,
0xcb, 0xdd, 0x6b, 0xda, 0xc0, 0x75, 0x57, 0xc6, 0xa0, 0xe8, 0xd3, 0x68, 0x25, 0xba, 0x15,
0x9e, 0x7f, 0xb5, 0xad, 0x8c, 0xda, 0xf8, 0x4, 0x86, 0x8c, 0xf9, 0xe, 0x8f, 0x1f, 0x8a,
0xea, 0x17, 0xc0, 0x16, 0xb5, 0x5c, 0x2a, 0x7a, 0xd4, 0x97, 0xc8, 0x94, 0xfb, 0x71, 0xd7,
0x53, 0xd7, 0x9b, 0x9a, 0x48, 0x4b, 0x6c, 0x37, 0x6d, 0x72, 0x3b, 0x99, 0x8d, 0x2e, 0x1d,
0x43, 0x6, 0xbf, 0x10, 0x33, 0xb5, 0xae, 0xf8, 0xcc, 0xa5, 0xcb, 0xb2, 0x56, 0x8b, 0x69,
0x24, 0x22, 0x6d, 0x22, 0xa3, 0x58, 0xab, 0x7d, 0x87, 0xe4, 0xac, 0x5f, 0x2e, 0x9, 0x1a,
0xa7, 0x15, 0x79, 0xf3, 0xa5, 0x69, 0x9, 0x49, 0x7d, 0x72, 0xf5, 0x4e, 0x6, 0xba, 0xc1,
0xc3, 0xb4, 0x41, 0x3b, 0xba, 0x5e, 0xaf, 0x94, 0xc3, 0xb6, 0x4f, 0x34, 0xf9, 0xeb, 0xa4,
0x1a, 0xcb, 0x6a, 0xe2, 0x83, 0x77, 0x6d, 0x36, 0x46, 0x53, 0x78, 0x48, 0xfe, 0xe8, 0x84,
0xbd, 0xdd, 0xf5, 0xb1, 0xba, 0x57, 0x98, 0x54, 0xcf, 0xfd, 0xce, 0xba, 0xc3, 0x44, 0x5,
0x95, 0x27, 0xe5, 0x6d, 0xd5, 0x98, 0xf8, 0xf5, 0x66, 0x71, 0x5a, 0xbe, 0x43, 0x1, 0xdd,
0x19, 0x11, 0x30, 0xe6, 0xb9, 0xf0, 0xc6, 0x40, 0x39, 0x12, 0x53, 0xe2, 0x29, 0x80, 0x3f,
0x3a, 0xef, 0x27, 0x4b, 0xed, 0xbf, 0xde, 0x3f, 0xcb, 0xbd, 0x42, 0xea, 0xd6, 0x79,
];
const SAMPLE_AUTH_DATA_MAKE_CREDENTIAL: [u8; 164] = [
0x58, 0xA2, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84,
0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a,
0x87, 0x05, 0x1d, 0xC1, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c,
0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1,
0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97,
0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20,
0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c,
0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e,
0xa6, 0x1c, 0xA1, 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xF5, ];
const SAMPLE_AUTH_DATA_GET_ASSERTION: [u8; 229] = [
0x58, 0xE3, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84,
0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a,
0x87, 0x05, 0x1d, 0xC1, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c,
0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1,
0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97,
0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20,
0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c,
0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e,
0xa6, 0x1c, 0xA1, 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x58, 0x40, 0x1F, 0x91, 0x52, 0x6C, 0xAE, 0x45, 0x6E, 0x4C, 0xBB, 0x71, 0xC4, 0xDD, 0xE7, 0xBB, 0x87,
0x71, 0x57, 0xE6, 0xE5, 0x4D, 0xFE, 0xD3, 0x01, 0x5D, 0x7D, 0x4D, 0xBB, 0x22, 0x69, 0xAF,
0xCD, 0xE6, 0xA9, 0x1B, 0x8D, 0x26, 0x7E, 0xBB, 0xF8, 0x48, 0xEB, 0x95, 0xA6, 0x8E, 0x79,
0xC7, 0xAC, 0x70, 0x5E, 0x35, 0x1D, 0x54, 0x3D, 0xB0, 0x16, 0x58, 0x87, 0xD6, 0x29, 0x0F,
0xD4, 0x7A, 0x40, 0xC4,
];
pub fn create_attestation_obj() -> AttestationObject {
AttestationObject {
auth_data: AuthenticatorData {
rp_id_hash: RpIdHash::from(&[
0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d,
0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65,
0xbe, 0x59, 0x7a, 0x87, 0x5, 0x1d,
])
.unwrap(),
flags: AuthenticatorDataFlags::USER_PRESENT | AuthenticatorDataFlags::ATTESTED,
counter: 11,
credential_data: Some(AttestedCredentialData {
aaguid: AAGuid::from(&[
0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11,
0x1f, 0x9e, 0xdc, 0x7d,
])
.unwrap(),
credential_id: vec![
0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6,
0xd9, 0x43, 0x5c, 0x6f,
],
credential_public_key: COSEKey {
alg: COSEAlgorithm::ES256,
key: COSEKeyType::EC2(COSEEC2Key {
curve: Curve::SECP256R1,
x: vec![
0xA5, 0xFD, 0x5C, 0xE1, 0xB1, 0xC4, 0x58, 0xC5, 0x30, 0xA5, 0x4F,
0xA6, 0x1B, 0x31, 0xBF, 0x6B, 0x04, 0xBE, 0x8B, 0x97, 0xAF, 0xDE,
0x54, 0xDD, 0x8C, 0xBB, 0x69, 0x27, 0x5A, 0x8A, 0x1B, 0xE1,
],
y: vec![
0xFA, 0x3A, 0x32, 0x31, 0xDD, 0x9D, 0xEE, 0xD9, 0xD1, 0x89, 0x7B,
0xE5, 0xA6, 0x22, 0x8C, 0x59, 0x50, 0x1E, 0x4B, 0xCD, 0x12, 0x97,
0x5D, 0x3D, 0xFF, 0x73, 0x0F, 0x01, 0x27, 0x8E, 0xA6, 0x1C,
],
}),
},
}),
extensions: Default::default(),
},
att_stmt: AttestationStatement::Packed(AttestationStatementPacked {
alg: COSEAlgorithm::ES256,
sig: Signature(vec![
0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c, 0xc1,
0x5c, 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4, 0x62, 0xd5,
0xf0, 0x56, 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89, 0x02, 0x21, 0x00,
0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5, 0xb5, 0x96, 0x51, 0x19,
0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7, 0x99, 0x59, 0x94, 0x80, 0x78,
0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29,
]),
attestation_cert: vec![AttestationCertificate(vec![
0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02,
0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29, 0x30, 0x0a,
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x47, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62,
0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06,
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x32,
0x30, 0x34, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x36,
0x31, 0x32, 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30, 0x47,
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75,
0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20,
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52,
0xe5, 0x3a, 0xd5, 0xdf, 0xed, 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4,
0xe1, 0xaf, 0x8f, 0x22, 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13,
0xc3, 0xd5, 0x04, 0xff, 0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96,
0xc4, 0x4c, 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8,
0x60, 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02,
0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25, 0xf7, 0x37, 0x3e,
0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94, 0xd0, 0xc0, 0x3f, 0x3f,
0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7, 0x02, 0x21, 0x00, 0xc4, 0xfa,
0xec, 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43, 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe,
0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9, 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d,
0xa2, 0x37, 0x23, 0xf3,
])],
}),
}
}
#[test]
fn parse_cert_chain() {
let cert: AttestationCertificate = from_slice(&SAMPLE_CERT_CHAIN[1..]).unwrap();
assert_eq!(&cert.0, &SAMPLE_CERT_CHAIN[4..]);
let _cert: Vec<AttestationCertificate> = from_slice(&SAMPLE_CERT_CHAIN).unwrap();
}
#[test]
fn parse_attestation_statement() {
let actual: AttestationStatement = from_slice(&SAMPLE_ATTESTATION_STMT_NONE).unwrap();
let expected = AttestationStatement::None;
assert_eq!(expected, actual);
let actual: AttestationStatement = from_slice(&SAMPLE_ATTESTATION_STMT_FIDO_U2F).unwrap();
let expected = AttestationStatement::FidoU2F(AttestationStatementFidoU2F {
attestation_cert: vec![AttestationCertificate(vec![
0x30, 0x82, 0x02, 0xd9, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
0x09, 0x00, 0xdf, 0x92, 0xd9, 0xc4, 0xe2, 0xed, 0x66, 0x0a, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, 0x31,
0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x23, 0x59, 0x75, 0x62, 0x69,
0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30,
0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x38, 0x30, 0x31, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x35, 0x30, 0x30, 0x39,
0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6f, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53, 0x45, 0x31, 0x12, 0x30, 0x10,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20,
0x41, 0x42, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41,
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x28, 0x30, 0x26,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20,
0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20,
0x31, 0x31, 0x35, 0x35, 0x31, 0x30, 0x39, 0x35, 0x39, 0x39, 0x30, 0x59, 0x30, 0x13,
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x0a, 0x18, 0x6c, 0x6e, 0x4d,
0x0a, 0x6a, 0x52, 0x8a, 0x44, 0x90, 0x9a, 0x7a, 0x24, 0x23, 0x68, 0x70, 0x28, 0xd4,
0xc5, 0x7e, 0xcc, 0xb7, 0x17, 0xba, 0x12, 0x80, 0xb8, 0x5c, 0x2f, 0xc1, 0xe4, 0xe0,
0x61, 0x66, 0x8c, 0x3c, 0x20, 0xae, 0xf3, 0x33, 0x50, 0xd1, 0x96, 0x45, 0x23, 0x8a,
0x2c, 0x39, 0x0b, 0xf5, 0xdf, 0xfa, 0x34, 0xff, 0x25, 0x50, 0x2f, 0x47, 0x0f, 0x3d,
0x40, 0xb8, 0x88, 0xa3, 0x81, 0x81, 0x30, 0x7f, 0x30, 0x13, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x0d, 0x01, 0x04, 0x05, 0x04, 0x03, 0x05, 0x04,
0x03, 0x30, 0x22, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x02,
0x04, 0x15, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e,
0x34, 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x37, 0x30, 0x13, 0x06, 0x0b, 0x2b,
0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02,
0x04, 0x30, 0x30, 0x21, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c,
0x01, 0x01, 0x04, 0x04, 0x12, 0x04, 0x10, 0x2f, 0xc0, 0x57, 0x9f, 0x81, 0x13, 0x47,
0xea, 0xb1, 0x16, 0xbb, 0x5a, 0x8d, 0xb9, 0x20, 0x2a, 0x30, 0x0c, 0x06, 0x03, 0x55,
0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
0x00, 0x82, 0xac, 0xaf, 0x11, 0x30, 0xa9, 0x9b, 0xd1, 0x43, 0x27, 0xd2, 0xf8, 0xf9,
0xb0, 0x41, 0xa2, 0xa0, 0x4a, 0x66, 0x85, 0x27, 0x24, 0x22, 0xe5, 0x7b, 0x14, 0xb0,
0xb8, 0xf8, 0x3b, 0x6f, 0x15, 0x45, 0x66, 0x4b, 0xbf, 0x55, 0x68, 0x1e, 0xaf, 0x01,
0x58, 0x72, 0x2a, 0xbf, 0xce, 0xd2, 0xe4, 0xac, 0x63, 0x3c, 0xec, 0x09, 0x59, 0x56,
0x45, 0x24, 0xb0, 0xf2, 0xe5, 0x17, 0xdd, 0x97, 0x10, 0x98, 0xb9, 0x89, 0x15, 0x17,
0xec, 0xd0, 0xc5, 0x53, 0xa2, 0xe4, 0x73, 0x9f, 0x9d, 0xe1, 0x3d, 0xaf, 0xd0, 0xd5,
0xd7, 0xb8, 0xac, 0x4a, 0x37, 0xf4, 0xf2, 0xcc, 0x30, 0xef, 0x25, 0xcb, 0x00, 0x65,
0x2d, 0x19, 0xdb, 0x69, 0xd7, 0xda, 0x57, 0xbd, 0x1a, 0x9c, 0x1d, 0x8e, 0xd8, 0x7d,
0x46, 0xd8, 0x0d, 0x2b, 0x3b, 0xdf, 0xd1, 0xd9, 0xef, 0x9d, 0x2b, 0x68, 0x32, 0xd4,
0xad, 0x5b, 0xcd, 0x74, 0x21, 0x4c, 0xe6, 0xa6, 0x14, 0x1d, 0x16, 0xb2, 0xe9, 0x3a,
0xcb, 0x2c, 0x88, 0xf6, 0x0a, 0x3e, 0xb6, 0xd5, 0xf6, 0x14, 0x71, 0x97, 0x59, 0x09,
0x37, 0x3b, 0xc6, 0x77, 0x90, 0x23, 0x24, 0x57, 0x1a, 0x57, 0x3f, 0x60, 0xf0, 0x7b,
0xbe, 0xd1, 0x7b, 0x92, 0xc8, 0xb5, 0x9f, 0xa2, 0x82, 0x10, 0xbf, 0xa8, 0xc6, 0x01,
0x22, 0x93, 0x00, 0x1b, 0x39, 0xef, 0xe5, 0x7b, 0xf9, 0xcb, 0x1e, 0x3a, 0xca, 0x8a,
0x41, 0x30, 0xf8, 0x3a, 0xf8, 0x66, 0x8f, 0x73, 0xde, 0xf2, 0x71, 0x1b, 0x20, 0xdc,
0x99, 0xe8, 0xa8, 0x04, 0xee, 0xa3, 0xf7, 0x42, 0x71, 0x97, 0xb6, 0xb4, 0x51, 0xb3,
0x73, 0x5c, 0x23, 0xbc, 0x9b, 0x1b, 0xe2, 0x74, 0xc2, 0x6d, 0x3b, 0xf9, 0x19, 0x6f,
0x8c, 0x4a, 0x4b, 0x71, 0x5f, 0x4b, 0x95, 0xc4, 0xdb, 0x7b, 0x97, 0xe7, 0x59, 0x4e,
0xb4, 0x65, 0x64, 0x8c, 0x1c,
])],
sig: Signature(vec![
0x30, 0x44, 0x02, 0x20, 0x48, 0x5a, 0x72, 0x40, 0xdf, 0x2c, 0x1e, 0x31, 0xa5, 0xb3,
0x0b, 0x3b, 0x2c, 0xd1, 0xad, 0xd0, 0x8d, 0xae, 0x8d, 0x7a, 0x25, 0x3e, 0xf5, 0xa6,
0x25, 0xdb, 0x2e, 0x22, 0x1b, 0x71, 0xe5, 0x78, 0x02, 0x20, 0x45, 0xbd, 0xdc, 0x30,
0xde, 0xf4, 0x05, 0x97, 0x5c, 0xac, 0x72, 0x58, 0x96, 0xa6, 0x00, 0x94, 0x57, 0x3a,
0xa5, 0xe8, 0x1e, 0xf4, 0xfd, 0x30, 0xd3, 0x88, 0x11, 0x8b, 0x49, 0x97, 0xdf, 0x34,
]),
});
assert_eq!(expected, actual);
}
#[test]
fn parse_attestation_object() {
let actual: AttestationObject = from_slice(&SAMPLE_ATTESTATION_OBJ_PACKED).unwrap();
let expected = create_attestation_obj();
assert_eq!(expected, actual);
}
#[test]
fn test_anonymize_att_obj() {
let mut att_obj = create_attestation_obj();
assert_ne!(att_obj.att_stmt, AttestationStatement::None);
assert_ne!(
att_obj
.auth_data
.credential_data
.as_ref()
.expect("credential_data should be Some")
.aaguid,
AAGuid::default()
);
att_obj.anonymize();
let encoded_att_obj = to_vec(&att_obj).expect("could not serialize anonymized att_obj");
let att_obj: AttestationObject =
from_slice(&encoded_att_obj).expect("could not deserialize anonymized att_obj");
assert_eq!(att_obj.att_stmt, AttestationStatement::None);
assert_eq!(
att_obj
.auth_data
.credential_data
.as_ref()
.expect("credential_data should be Some")
.aaguid,
AAGuid::default()
);
}
#[test]
fn parse_reader() {
let v: Vec<u8> = vec![
0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72,
];
let mut data = Cursor::new(v);
let value: String = from_slice_stream::<_, _, serde_cbor::Error>(&mut data).unwrap();
assert_eq!(value, "foobar");
let mut remaining = Vec::new();
data.read_to_end(&mut remaining).unwrap();
assert_eq!(
remaining.as_slice(),
&[0x66, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]
);
let mut data = Cursor::new(remaining);
let value: String = from_slice_stream::<_, _, serde_cbor::Error>(&mut data).unwrap();
assert_eq!(value, "foobar");
let mut remaining = Vec::new();
data.read_to_end(&mut remaining).unwrap();
assert!(remaining.is_empty());
}
#[test]
fn parse_extensions() {
let auth_make: AuthenticatorData = from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL).unwrap();
assert_eq!(
auth_make.extensions.hmac_secret,
Some(HmacSecretResponse::Confirmed(true))
);
let auth_get: AuthenticatorData = from_slice(&SAMPLE_AUTH_DATA_GET_ASSERTION).unwrap();
assert_eq!(
auth_get.extensions.hmac_secret,
Some(HmacSecretResponse::Secret(vec![
0x1F, 0x91, 0x52, 0x6C, 0xAE, 0x45, 0x6E, 0x4C, 0xBB, 0x71, 0xC4, 0xDD, 0xE7, 0xBB,
0x87, 0x71, 0x57, 0xE6, 0xE5, 0x4D, 0xFE, 0xD3, 0x01, 0x5D, 0x7D, 0x4D, 0xBB, 0x22,
0x69, 0xAF, 0xCD, 0xE6, 0xA9, 0x1B, 0x8D, 0x26, 0x7E, 0xBB, 0xF8, 0x48, 0xEB, 0x95,
0xA6, 0x8E, 0x79, 0xC7, 0xAC, 0x70, 0x5E, 0x35, 0x1D, 0x54, 0x3D, 0xB0, 0x16, 0x58,
0x87, 0xD6, 0x29, 0x0F, 0xD4, 0x7A, 0x40, 0xC4,
]))
);
}
#[test]
fn test_empty_extension_data() {
let mut parsed_auth_data: AuthenticatorData =
from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL).unwrap();
assert!(parsed_auth_data
.flags
.contains(AuthenticatorDataFlags::EXTENSION_DATA));
parsed_auth_data.extensions = Default::default();
let with_flag = to_vec(&parsed_auth_data).expect("could not serialize auth data");
assert_eq!(with_flag[with_flag.len() - 1], 0xA0);
parsed_auth_data
.flags
.remove(AuthenticatorDataFlags::EXTENSION_DATA);
let without_flag = to_vec(&parsed_auth_data).expect("could not serialize auth data");
assert!(with_flag.len() == without_flag.len() + 1);
}
#[test]
fn test_aaguid_output() {
let input = [
0xcb, 0x69, 0x48, 0x1e, 0x8f, 0xf0, 0x00, 0x39, 0x93, 0xec, 0x0a, 0x27, 0x29, 0xa1,
0x54, 0xa8,
];
let expected = "AAGuid(cb69481e-8ff0-0039-93ec-0a2729a154a8)";
let result = AAGuid::from(&input).expect("Failed to parse AAGuid");
let res_str = format!("{result:?}");
assert_eq!(expected, &res_str);
}
#[test]
fn test_ad_flags_from_bits() {
for x in 0..=u8::MAX {
assert_eq!(
AuthenticatorDataFlags::from_bits(x),
Some(AuthenticatorDataFlags::from_bits_truncate(x))
);
}
}
#[test]
fn serialize_att_obj_none() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::None;
assert_eq!(serde_cbor::ser::to_vec(&att_stmt)?, [0xa0]);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x64, 0x6e, 0x6f, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x74,
0x53, 0x74, 0x6d, 0x74, 0xa0, 0x68, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
0x58, 0xa2, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65,
0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11,
0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00,
0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9,
0x43, 0x5c, 0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5,
0xfd, 0x5c, 0xe1, 0xb1, 0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf,
0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a,
0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20, 0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9,
0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c, 0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97,
0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e, 0xa6, 0x1c, 0xa1, 0x6b, 0x68, 0x6d,
0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xf5
]
);
Ok(())
}
#[test]
fn serialize_att_obj_packed() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::Packed(AttestationStatementPacked {
alg: COSEAlgorithm::ES256,
sig: Signature(vec![1, 2, 3, 4]),
attestation_cert: vec![
AttestationCertificate(vec![5, 6, 7, 8]),
AttestationCertificate(vec![9, 10, 11, 12]),
],
});
assert_eq!(
serde_cbor::ser::to_vec(&att_stmt)?,
[
0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x44, 0x01, 0x02, 0x03,
0x04, 0x63, 0x78, 0x35, 0x63, 0x82, 0x44, 0x05, 0x06, 0x07, 0x08, 0x44, 0x09, 0x0a,
0x0b, 0x0c
]
);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x66, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x67, 0x61,
0x74, 0x74, 0x53, 0x74, 0x6d, 0x74, 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73,
0x69, 0x67, 0x44, 0x01, 0x02, 0x03, 0x04, 0x63, 0x78, 0x35, 0x63, 0x82, 0x44, 0x05,
0x06, 0x07, 0x08, 0x44, 0x09, 0x0a, 0x0b, 0x0c, 0x68, 0x61, 0x75, 0x74, 0x68, 0x44,
0x61, 0x74, 0x61, 0x58, 0xa2, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34,
0x6a, 0xb4, 0xe4, 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25,
0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0xc1, 0x00, 0x00, 0x00, 0x0b,
0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e,
0xdc, 0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a,
0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1, 0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6,
0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb,
0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20, 0xfa, 0x3a, 0x32, 0x31, 0xdd,
0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c, 0x59, 0x50, 0x1e, 0x4b,
0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e, 0xa6, 0x1c, 0xa1,
0x6b, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xf5
]
);
Ok(())
}
#[test]
fn serialize_att_obj_fido_u2f() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::FidoU2F(AttestationStatementFidoU2F {
sig: Signature(vec![1, 2, 3, 4]),
attestation_cert: vec![
AttestationCertificate(vec![5, 6, 7, 8]),
AttestationCertificate(vec![9, 10, 11, 12]),
],
});
assert_eq!(
serde_cbor::ser::to_vec(&att_stmt)?,
[
0xa2, 0x63, 0x73, 0x69, 0x67, 0x44, 0x01, 0x02, 0x03, 0x04, 0x63, 0x78, 0x35, 0x63,
0x82, 0x44, 0x05, 0x06, 0x07, 0x08, 0x44, 0x09, 0x0a, 0x0b, 0x0c
]
);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x68, 0x66, 0x69, 0x64, 0x6f, 0x2d, 0x75, 0x32, 0x66,
0x67, 0x61, 0x74, 0x74, 0x53, 0x74, 0x6d, 0x74, 0xa2, 0x63, 0x73, 0x69, 0x67, 0x44,
0x01, 0x02, 0x03, 0x04, 0x63, 0x78, 0x35, 0x63, 0x82, 0x44, 0x05, 0x06, 0x07, 0x08,
0x44, 0x09, 0x0a, 0x0b, 0x0c, 0x68, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
0x58, 0xa2, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65,
0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11,
0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00,
0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9,
0x43, 0x5c, 0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5,
0xfd, 0x5c, 0xe1, 0xb1, 0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf,
0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a,
0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20, 0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9,
0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c, 0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97,
0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e, 0xa6, 0x1c, 0xa1, 0x6b, 0x68, 0x6d,
0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xf5
]
);
Ok(())
}
#[test]
fn serialize_att_obj_android_key() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::AndroidKey(serde_cbor::Value::Map(
vec![
("alg".to_string().into(), serde_cbor::Value::Integer(-7)),
(
"sig".to_string().into(),
serde_cbor::Value::Bytes(vec![1, 2, 3, 4]),
),
(
"x5c".to_string().into(),
serde_cbor::Value::Array(vec![
serde_cbor::Value::Bytes(vec![5, 6, 7, 8]),
serde_cbor::Value::Bytes(vec![9, 10, 11, 12]),
]),
),
]
.into_iter()
.collect(),
));
assert_eq!(
serde_cbor::ser::to_vec(&att_stmt)?,
[
0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x44, 0x01, 0x02, 0x03,
0x04, 0x63, 0x78, 0x35, 0x63, 0x82, 0x44, 0x05, 0x06, 0x07, 0x08, 0x44, 0x09, 0x0a,
0x0b, 0x0c
]
);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x6b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2d,
0x6b, 0x65, 0x79, 0x67, 0x61, 0x74, 0x74, 0x53, 0x74, 0x6d, 0x74, 0xa3, 0x63, 0x61,
0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x44, 0x01, 0x02, 0x03, 0x04, 0x63, 0x78,
0x35, 0x63, 0x82, 0x44, 0x05, 0x06, 0x07, 0x08, 0x44, 0x09, 0x0a, 0x0b, 0x0c, 0x68,
0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x58, 0xa2, 0xc2, 0x89, 0xc5, 0xca,
0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d,
0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d,
0xc1, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80,
0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b,
0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f, 0xa5, 0x01, 0x02,
0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1, 0xc4, 0x58,
0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf,
0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20,
0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22,
0x8c, 0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01,
0x27, 0x8e, 0xa6, 0x1c, 0xa1, 0x6b, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63,
0x72, 0x65, 0x74, 0xf5
]
);
Ok(())
}
#[test]
fn serialize_att_obj_android_safetynet() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::AndroidSafetyNet(serde_cbor::Value::Map(
vec![
(
"ver".to_string().into(),
"Kom ihåg att du aldrig får snyta dig i mattan!"
.to_string()
.into(),
),
(
"response".to_string().into(),
serde_cbor::Value::Bytes(vec![1, 2, 3, 4]),
),
]
.into_iter()
.collect(),
));
assert_eq!(
serde_cbor::ser::to_vec(&att_stmt)?,
[
0xa2, 0x63, 0x76, 0x65, 0x72, 0x78, 0x30, 0x4b, 0x6f, 0x6d, 0x20, 0x69, 0x68, 0xc3,
0xa5, 0x67, 0x20, 0x61, 0x74, 0x74, 0x20, 0x64, 0x75, 0x20, 0x61, 0x6c, 0x64, 0x72,
0x69, 0x67, 0x20, 0x66, 0xc3, 0xa5, 0x72, 0x20, 0x73, 0x6e, 0x79, 0x74, 0x61, 0x20,
0x64, 0x69, 0x67, 0x20, 0x69, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x61, 0x6e, 0x21, 0x68,
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x01, 0x02, 0x03, 0x04
]
);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x71, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2d,
0x73, 0x61, 0x66, 0x65, 0x74, 0x79, 0x6e, 0x65, 0x74, 0x67, 0x61, 0x74, 0x74, 0x53,
0x74, 0x6d, 0x74, 0xa2, 0x63, 0x76, 0x65, 0x72, 0x78, 0x30, 0x4b, 0x6f, 0x6d, 0x20,
0x69, 0x68, 0xc3, 0xa5, 0x67, 0x20, 0x61, 0x74, 0x74, 0x20, 0x64, 0x75, 0x20, 0x61,
0x6c, 0x64, 0x72, 0x69, 0x67, 0x20, 0x66, 0xc3, 0xa5, 0x72, 0x20, 0x73, 0x6e, 0x79,
0x74, 0x61, 0x20, 0x64, 0x69, 0x67, 0x20, 0x69, 0x20, 0x6d, 0x61, 0x74, 0x74, 0x61,
0x6e, 0x21, 0x68, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x01, 0x02,
0x03, 0x04, 0x68, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x58, 0xa2, 0xc2,
0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84, 0x27,
0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a,
0x87, 0x05, 0x1d, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a,
0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x10, 0x89, 0x59,
0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f,
0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1,
0xb1, 0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe,
0x8b, 0x97, 0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1,
0x22, 0x58, 0x20, 0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b,
0xe5, 0xa6, 0x22, 0x8c, 0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff,
0x73, 0x0f, 0x01, 0x27, 0x8e, 0xa6, 0x1c, 0xa1, 0x6b, 0x68, 0x6d, 0x61, 0x63, 0x2d,
0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xf5
]
);
Ok(())
}
#[test]
fn serialize_att_obj_apple() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::Apple(serde_cbor::Value::Map(
vec![(
"x5c".to_string().into(),
serde_cbor::Value::Array(vec![
serde_cbor::Value::Bytes(vec![1, 2, 3, 4]),
serde_cbor::Value::Bytes(vec![5, 6, 7, 8]),
]),
)]
.into_iter()
.collect(),
));
assert_eq!(
serde_cbor::ser::to_vec(&att_stmt)?,
[
0xa1, 0x63, 0x78, 0x35, 0x63, 0x82, 0x44, 0x01, 0x02, 0x03, 0x04, 0x44, 0x05, 0x06,
0x07, 0x08
]
);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x65, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x67, 0x61, 0x74,
0x74, 0x53, 0x74, 0x6d, 0x74, 0xa1, 0x63, 0x78, 0x35, 0x63, 0x82, 0x44, 0x01, 0x02,
0x03, 0x04, 0x44, 0x05, 0x06, 0x07, 0x08, 0x68, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61,
0x74, 0x61, 0x58, 0xa2, 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a,
0xb4, 0xe4, 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0xf8,
0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc,
0xd6, 0xd9, 0x43, 0x5c, 0x6f, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1, 0xc4, 0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b,
0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf, 0xde, 0x54, 0xdd, 0x8c, 0xbb, 0x69,
0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20, 0xfa, 0x3a, 0x32, 0x31, 0xdd, 0x9d,
0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c, 0x59, 0x50, 0x1e, 0x4b, 0xcd,
0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e, 0xa6, 0x1c, 0xa1, 0x6b,
0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xf5
]
);
Ok(())
}
#[test]
fn serialize_att_obj_tpm() -> Result<(), serde_cbor::Error> {
let att_stmt = AttestationStatement::Tpm(serde_cbor::Value::Map(
vec![
("ver".to_string().into(), "2.0".to_string().into()),
("alg".to_string().into(), (-7).into()),
(
"x5c".to_string().into(),
serde_cbor::Value::Array(vec![
serde_cbor::Value::Bytes(vec![1, 2, 3, 4]),
serde_cbor::Value::Bytes(vec![5, 6, 7, 8]),
]),
),
(
"sig".to_string().into(),
serde_cbor::Value::Bytes(vec![9, 10, 11, 12]),
),
(
"certInfo".to_string().into(),
serde_cbor::Value::Bytes(vec![13, 14, 15, 16]),
),
(
"pubArea".to_string().into(),
serde_cbor::Value::Bytes(vec![17, 18, 19, 20]),
),
]
.into_iter()
.collect(),
));
assert_eq!(
serde_cbor::ser::to_vec(&att_stmt)?,
[
0xa6, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x44, 0x09, 0x0a, 0x0b,
0x0c, 0x63, 0x76, 0x65, 0x72, 0x63, 0x32, 0x2e, 0x30, 0x63, 0x78, 0x35, 0x63, 0x82,
0x44, 0x01, 0x02, 0x03, 0x04, 0x44, 0x05, 0x06, 0x07, 0x08, 0x67, 0x70, 0x75, 0x62,
0x41, 0x72, 0x65, 0x61, 0x44, 0x11, 0x12, 0x13, 0x14, 0x68, 0x63, 0x65, 0x72, 0x74,
0x49, 0x6e, 0x66, 0x6f, 0x44, 0x0d, 0x0e, 0x0f, 0x10
]
);
let att_obj = AttestationObject {
auth_data: serde_cbor::de::from_slice(&SAMPLE_AUTH_DATA_MAKE_CREDENTIAL)?,
att_stmt,
};
assert_eq!(
serde_cbor::ser::to_vec(&att_obj)?,
[
0xa3, 0x63, 0x66, 0x6d, 0x74, 0x63, 0x74, 0x70, 0x6d, 0x67, 0x61, 0x74, 0x74, 0x53,
0x74, 0x6d, 0x74, 0xa6, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x44,
0x09, 0x0a, 0x0b, 0x0c, 0x63, 0x76, 0x65, 0x72, 0x63, 0x32, 0x2e, 0x30, 0x63, 0x78,
0x35, 0x63, 0x82, 0x44, 0x01, 0x02, 0x03, 0x04, 0x44, 0x05, 0x06, 0x07, 0x08, 0x67,
0x70, 0x75, 0x62, 0x41, 0x72, 0x65, 0x61, 0x44, 0x11, 0x12, 0x13, 0x14, 0x68, 0x63,
0x65, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x44, 0x0d, 0x0e, 0x0f, 0x10, 0x68, 0x61,
0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x58, 0xa2, 0xc2, 0x89, 0xc5, 0xca, 0x9b,
0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31,
0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0xc1,
0x00, 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06,
0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c,
0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f, 0xa5, 0x01, 0x02, 0x03,
0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1, 0xc4, 0x58, 0xc5,
0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf, 0xde,
0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20, 0xfa,
0x3a, 0x32, 0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c,
0x59, 0x50, 0x1e, 0x4b, 0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27,
0x8e, 0xa6, 0x1c, 0xa1, 0x6b, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72,
0x65, 0x74, 0xf5
]
);
Ok(())
}
mod hmac_secret {
use std::convert::TryFrom;
use crate::{
crypto::{
COSEAlgorithm, COSEEC2Key, COSEKey, COSEKeyType, Curve, PinUvAuthProtocol,
SharedSecret,
},
ctap2::{attestation::HmacSecretResponse, commands::CommandError},
AuthenticatorInfo,
};
fn make_test_secret(pin_protocol: u64) -> Result<SharedSecret, CommandError> {
let fake_unused_key = COSEKey {
alg: COSEAlgorithm::ECDH_ES_HKDF256,
key: COSEKeyType::EC2(COSEEC2Key {
curve: Curve::SECP256R1,
x: vec![],
y: vec![],
}),
};
let pin_protocol = PinUvAuthProtocol::try_from(&AuthenticatorInfo {
pin_protocols: Some(vec![pin_protocol]),
..Default::default()
})?;
let key = {
let aes_key = 0..32;
let hmac_key = 32..64;
match pin_protocol.id() {
1 => aes_key.collect(),
2 => hmac_key.chain(aes_key).collect(),
_ => unimplemented!(),
}
};
Ok(SharedSecret::new_test(
pin_protocol,
key,
fake_unused_key.clone(),
fake_unused_key,
))
}
#[test]
fn decrypt_confirmed_returns_none() -> Result<(), CommandError> {
let shared_secret = make_test_secret(2)?;
for flag in [true, false] {
let resp = HmacSecretResponse::Confirmed(flag);
let hmac_output = resp.decrypt_secrets(&shared_secret);
assert_eq!(hmac_output, None, "Failed for confirmed flag: {:?}", flag);
}
Ok(())
}
#[cfg(not(feature = "crypto_dummy"))]
mod requires_crypto {
use super::*;
use crate::{
crypto::CryptoError,
ctap2::{attestation::HmacSecretResponse, commands::CommandError},
};
const PIN_PROTOCOL_2_IV: [u8; 16] = [0; 16];
const EXPECTED_OUTPUT1: [u8; 32] = [
145, 61, 188, 229, 73, 58, 253, 192, 87, 114, 133, 138, 173, 74, 68, 50, 105, 3,
44, 7, 205, 92, 54, 139, 137, 207, 7, 105, 89, 85, 211, 130,
];
const EXPECTED_OUTPUT2: Option<[u8; 32]> = Some([
155, 19, 88, 255, 192, 226, 50, 42, 243, 22, 42, 12, 146, 77, 108, 29, 71, 72, 149,
153, 183, 65, 182, 149, 71, 202, 57, 123, 239, 79, 94, 230,
]);
#[test]
fn decrypt_one_secret_pin_protocol_1() -> Result<(), CommandError> {
const CT_LEN: u8 = 32;
let shared_secret = make_test_secret(1)?;
let resp = HmacSecretResponse::Secret((0..CT_LEN).collect());
let hmac_output = resp.decrypt_secrets(&shared_secret).unwrap()?;
assert_eq!(hmac_output.output1, EXPECTED_OUTPUT1, "Incorrect output1");
assert_eq!(hmac_output.output2, None, "Incorrect output2");
Ok(())
}
#[test]
fn decrypt_two_secrets_pin_protocol_1() -> Result<(), CommandError> {
const CT_LEN: u8 = 32 * 2;
let shared_secret = make_test_secret(1)?;
let resp = HmacSecretResponse::Secret((0..CT_LEN).collect());
let hmac_output = resp.decrypt_secrets(&shared_secret).unwrap()?;
assert_eq!(hmac_output.output1, EXPECTED_OUTPUT1, "Incorrect output1");
assert_eq!(hmac_output.output2, EXPECTED_OUTPUT2, "Incorrect output2");
Ok(())
}
#[test]
fn decrypt_one_secret_pin_protocol_2() -> Result<(), CommandError> {
const CT_LEN: u8 = 32;
let shared_secret = make_test_secret(2)?;
let resp = HmacSecretResponse::Secret(
PIN_PROTOCOL_2_IV.iter().copied().chain(0..CT_LEN).collect(),
);
let hmac_output = resp.decrypt_secrets(&shared_secret).unwrap()?;
assert_eq!(hmac_output.output1, EXPECTED_OUTPUT1, "Incorrect output1");
assert_eq!(hmac_output.output2, None, "Incorrect output2");
Ok(())
}
#[test]
fn decrypt_two_secrets_pin_protocol_2() -> Result<(), CommandError> {
const CT_LEN: u8 = 32 * 2;
let shared_secret = make_test_secret(2)?;
let resp = HmacSecretResponse::Secret(
PIN_PROTOCOL_2_IV.iter().copied().chain(0..CT_LEN).collect(),
);
let hmac_output = resp.decrypt_secrets(&shared_secret).unwrap()?;
assert_eq!(hmac_output.output1, EXPECTED_OUTPUT1, "Incorrect output1");
assert_eq!(hmac_output.output2, EXPECTED_OUTPUT2, "Incorrect output2");
Ok(())
}
#[test]
fn decrypt_wrong_length_pin_protocol_2() -> Result<(), CommandError> {
let shared_secret = make_test_secret(2)?;
{
let resp = HmacSecretResponse::Secret(PIN_PROTOCOL_2_IV.to_vec());
let hmac_output = resp.decrypt_secrets(&shared_secret).unwrap();
assert_eq!(hmac_output, Err(CryptoError::WrongSaltLength));
}
{
let resp = HmacSecretResponse::Secret(
PIN_PROTOCOL_2_IV.iter().copied().chain(0..96).collect(),
);
let hmac_output = resp.decrypt_secrets(&shared_secret).unwrap();
assert_eq!(hmac_output, Err(CryptoError::WrongSaltLength));
}
Ok(())
}
}
}
}