1288 lines
46 KiB
Rust
1288 lines
46 KiB
Rust
#[deny(missing_debug_implementations, unused_results)]
|
|
use failure::_core::marker::PhantomData;
|
|
use num_traits::{FromPrimitive, ToPrimitive};
|
|
use serde::de::{Error, MapAccess, Visitor};
|
|
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant};
|
|
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
|
use serde_cbor::de::IoRead;
|
|
use serde_cbor::ser::IoWrite;
|
|
use std::borrow::Cow;
|
|
use std::collections::{BTreeMap, HashMap};
|
|
use std::fmt;
|
|
use std::fmt::Debug;
|
|
use std::io::{Read, Write};
|
|
|
|
pub trait CborSerializable: Serialize {
|
|
fn serialize_cbor(&self, sink: &mut impl Write) -> Result<(), serde_cbor::error::Error> {
|
|
self.serialize(&mut serde_cbor::Serializer::new(IoWrite::new(sink)).packed_format())
|
|
}
|
|
}
|
|
|
|
impl<T: Serialize> CborSerializable for T {}
|
|
|
|
pub trait CborDeserializable<'a>: Deserialize<'a> {
|
|
fn deserialize_cbor(source: &mut impl Read) -> Result<Self, serde_cbor::error::Error> {
|
|
Self::deserialize(&mut serde_cbor::Deserializer::from_reader(source))
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Deserialize<'a>> CborDeserializable<'a> for T {}
|
|
|
|
#[allow(clippy::large_enum_variant)]
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub enum CborRequest<'a> {
|
|
__Bump,
|
|
// 0x01
|
|
MakeCredential(MakeCredentialRequest<'a>),
|
|
// 0x02
|
|
GetAssertion(GetAssertionRequest<'a>),
|
|
// 0x03
|
|
___Unused,
|
|
// 0x04
|
|
GetInfo(GetInfoRequest),
|
|
// 0x05
|
|
____Unused,
|
|
// 0x06
|
|
ClientPin(GetClientPinRequest<'a>),
|
|
// 0x07
|
|
Reset(Reset),
|
|
// 0x08
|
|
GetNextAssertion,
|
|
// 0x09
|
|
BioEnrolment,
|
|
// 0x0A
|
|
CredentialManagement,
|
|
// 0x0B
|
|
Selection,
|
|
// 0x0C
|
|
Config,
|
|
}
|
|
|
|
macro_rules! map_response {
|
|
($name:ident, $from:ty, $( $request:path, $response_struct:ty => $response:ident),* ) => {
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub enum $name<'a> {
|
|
$(
|
|
$response($response_struct),
|
|
)*
|
|
}
|
|
|
|
impl<'a> $name<'a> {
|
|
|
|
/// Parse the response if one is to be expected
|
|
pub fn parse_response(request: &$from, source: &mut impl Read) -> Option<Result<Self, serde_cbor::error::Error>> {
|
|
match request {
|
|
$(
|
|
$request{..} => Some(<$response_struct>::deserialize_cbor(source).map(Self::$response)),
|
|
)*
|
|
_ => None
|
|
}
|
|
}
|
|
}
|
|
|
|
$(
|
|
impl<'a> std::convert::From<$response_struct> for $name<'a> {
|
|
fn from(resp: $response_struct) -> Self {
|
|
Self::$response(resp)
|
|
}
|
|
}
|
|
)*
|
|
}}
|
|
|
|
map_response! {
|
|
CborResponse,CborRequest<'a>,
|
|
CborRequest::MakeCredential, MakeCredentialResponse<'a> => MakeCredential,
|
|
CborRequest::GetAssertion, GetAssertionResponse<'a> => GetAssertion,
|
|
CborRequest::GetInfo, GetInfoResponse<'a> => GetInfo,
|
|
CborRequest::ClientPin, GetClientPinResponse<'a> => ClientPin
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CborCommand<T: CborCommandValue>(pub T);
|
|
|
|
/*impl<T: CborCommandValue> CborCommand<T> {
|
|
pub fn parse_response<'a, R: Deserialize<'a> + Debug + Sized>(message: &mut dyn Read) -> Result<R, Error> where Self: CborCommandResponse<'a, R> {
|
|
R::deserialize_cbor(message)
|
|
}
|
|
}
|
|
|
|
pub trait CborCommandResponse<'a,R: Deserialize<'a> + Debug> {}*/
|
|
pub trait CborCommandValue: Serialize + Debug {
|
|
fn value() -> u8;
|
|
}
|
|
|
|
impl<T: CborCommandValue + Serialize> Serialize for CborCommand<T> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
serializer.serialize_newtype_variant("", T::value() as u32, "", &self.0)
|
|
}
|
|
}
|
|
|
|
macro_rules! command_value {
|
|
($request_:ty,$lifetime:tt,$x:expr) => {
|
|
impl<$lifetime> CborCommandValue for $request_ {
|
|
fn value() -> u8 {
|
|
$x
|
|
}
|
|
}
|
|
};
|
|
($request_:ty,$x:expr) => {
|
|
impl CborCommandValue for $request_ {
|
|
fn value() -> u8 {
|
|
$x
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
command_value!(MakeCredentialRequest<'a>,'a, 0x01);
|
|
command_value!(GetAssertionRequest<'a>,'a, 0x02);
|
|
command_value!(GetInfoRequest, 0x04);
|
|
command_value!(GetClientPinRequest<'a>, 'a, 0x06);
|
|
command_value!(Reset, 0x07);
|
|
|
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct GetInfoRequest;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub struct GetInfoResponse<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
versions: Cow<'a, [Cow<'a, str>]>,
|
|
// 0x02
|
|
extensions: Cow<'a, [Cow<'a, str>]>,
|
|
// 0x03
|
|
aaguid: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x04
|
|
options: GetInfoOptions,
|
|
// FIDO2.1 from here on therefore optional
|
|
// 0x05
|
|
#[serde(rename = "maxMsgSize", default)]
|
|
max_msg_size: u64,
|
|
// 0x06
|
|
#[serde(rename = "pinUvAuthProtocols")]
|
|
pin_auth_protocols: Cow<'a, [u64]>,
|
|
// 0x07
|
|
#[serde(rename = "maxCredentialCountInList", default)]
|
|
max_credential_count: u64,
|
|
// 0x08
|
|
#[serde(rename = "maxCredentialIdLength", default)]
|
|
max_credential_id_len: u64,
|
|
// 0x09
|
|
#[serde(default)]
|
|
transports: Cow<'a, [Cow<'a, str>]>,
|
|
// 0x0A
|
|
#[serde(default)]
|
|
algorithms: Cow<'a, [Cow<'a, PublicKeyCredentialParameters>]>,
|
|
// 0x0B
|
|
#[serde(rename = "maxAuthenticatorConfigLength", default)]
|
|
max_config_len: u64,
|
|
// 0x0C
|
|
#[serde(rename = "defaultCredProtect", default)]
|
|
default_cred_protect: CredProtect,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub struct GetInfoOptions {
|
|
#[serde(default)]
|
|
plat: bool,
|
|
#[serde(default)]
|
|
rk: bool,
|
|
#[serde(default, rename = "clientPin")]
|
|
client_pin: Option<bool>,
|
|
#[serde(default)]
|
|
up: bool,
|
|
#[serde(default)]
|
|
uv: bool,
|
|
#[serde(default, rename = "uvToken")]
|
|
uv_token: bool,
|
|
#[serde(default)]
|
|
config: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Deserialize, Eq, PartialEq)]
|
|
pub struct PublicKeyCredentialParameters {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
#[serde(default, rename = "type")]
|
|
type_: PublicKeyCredentialType,
|
|
// 0x02
|
|
alg: PublicKeyCredentialAlgorithm,
|
|
}
|
|
|
|
// Ensure keys aren't packed but instead serialized as string
|
|
impl Serialize for PublicKeyCredentialParameters {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut s = serializer.serialize_map(Some(2))?;
|
|
s.serialize_entry("type", &self.type_)?;
|
|
s.serialize_entry("alg", &self.alg)?;
|
|
|
|
s.end()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub enum PublicKeyCredentialType {
|
|
#[serde(rename = "public-key")]
|
|
PublicKey = 0,
|
|
NoTwo = 2,
|
|
#[serde(other)]
|
|
Other,
|
|
}
|
|
|
|
impl Default for PublicKeyCredentialType {
|
|
fn default() -> Self {
|
|
PublicKeyCredentialType::PublicKey
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, FromPrimitive, ToPrimitive, Eq, PartialEq)]
|
|
pub enum PublicKeyCredentialAlgorithm {
|
|
ES256 = -7,
|
|
// Unsupported
|
|
EdDSA = -8,
|
|
// Compatibility reasons
|
|
ECDH_ES_HKDF_256 = -25,
|
|
// Unsupported
|
|
ES384 = -35,
|
|
// Unsupported
|
|
ES512 = -36,
|
|
// Unsupported
|
|
PS256 = -37,
|
|
// Unsupported
|
|
PS384 = -38,
|
|
// Unsupported
|
|
PS512 = -39,
|
|
// Unsupported
|
|
RS256 = -257,
|
|
// Unsupported
|
|
//#[serde(other)]
|
|
Unknown = std::i32::MIN as isize,
|
|
}
|
|
|
|
impl Default for PublicKeyCredentialAlgorithm {
|
|
fn default() -> Self {
|
|
PublicKeyCredentialAlgorithm::Unknown
|
|
}
|
|
}
|
|
|
|
impl Serialize for PublicKeyCredentialAlgorithm {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
serializer.serialize_i32(self.to_i32().unwrap())
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for PublicKeyCredentialAlgorithm {
|
|
fn deserialize<D>(deserializer: D) -> Result<PublicKeyCredentialAlgorithm, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct AlgorithmVisitor;
|
|
impl<'de> Visitor<'de> for AlgorithmVisitor {
|
|
type Value = i32;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("an integer between -2^31 and 2^31")
|
|
}
|
|
|
|
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
Ok(value as i32)
|
|
}
|
|
|
|
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
Ok(value as i32)
|
|
}
|
|
}
|
|
Ok(PublicKeyCredentialAlgorithm::from_i32(dbg!(
|
|
deserializer.deserialize_i32(AlgorithmVisitor)?
|
|
))
|
|
.unwrap_or_default()) //Not ideal
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub enum CredProtect {
|
|
VerificationOptional,
|
|
VerificationOptionalWithCredentialIDList,
|
|
VerificationRequired,
|
|
}
|
|
|
|
impl Default for CredProtect {
|
|
fn default() -> Self {
|
|
CredProtect::VerificationOptional
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub struct GetClientPinRequest<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
#[serde(rename = "pinUvAuthProtocol")]
|
|
pin_auth_protocols: u64,
|
|
// 0x02
|
|
#[serde(rename = "subCommand")]
|
|
sub_command: GetClientPinSubommand,
|
|
// 0x03
|
|
#[serde(rename = "keyAgreement", default)]
|
|
key_agreement: Option<PublicKeyCredentialParameters>,
|
|
// 0x04
|
|
#[serde(rename = "pinUvAuthParam", default)]
|
|
pin_auth_param: Option<Cow<'a, serde_bytes::Bytes>>,
|
|
// 0x05
|
|
#[serde(rename = "newPinEnc", default)]
|
|
new_pin_enc: Option<Cow<'a, serde_bytes::Bytes>>,
|
|
// 0x06
|
|
#[serde(rename = "pinHashEnc", default)]
|
|
pin_hash_enc: Option<Cow<'a, serde_bytes::Bytes>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub enum GetClientPinSubommand {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
__bump,
|
|
// 0x01
|
|
#[serde(rename = "getPINRetries")]
|
|
GetPINRetries,
|
|
// 0x02
|
|
#[serde(rename = "getKeyAgreement")]
|
|
GetKeyAgreement,
|
|
// 0x03
|
|
#[serde(rename = "setPIN")]
|
|
SetPIN,
|
|
// 0x04
|
|
#[serde(rename = "changePIN")]
|
|
ChangePIN,
|
|
// 0x05
|
|
#[serde(rename = "getPinUvAuthTokenUsingPin")]
|
|
GetPinUvAuthTokenUsingPin,
|
|
// 0x06
|
|
#[serde(rename = "getPinUvAuthTokenUsingUv")]
|
|
GetPinUvAuthTokenUsingUv,
|
|
// 0x07
|
|
#[serde(rename = "getUVRetries")]
|
|
GetUVRetries,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
pub struct GetClientPinResponse<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
#[serde(rename = "keyAgreement", default)]
|
|
key_agreement: Option<CoseKey<'a>>,
|
|
// 0x02
|
|
/// Encrypted pinUvAuthToken using sharedSecret used in subsequent authenticatorMakeCredential authenticatorGetAssertion operations
|
|
#[serde(rename = "pinUvAuthToken", default)]
|
|
pin_auth_token: Option<Cow<'a, serde_bytes::Bytes>>,
|
|
// 0x03
|
|
/// Number of PIN attempts remaining before lockout.
|
|
#[serde(rename = "pinRetries", default)]
|
|
pin_retries: u8,
|
|
// 0x04
|
|
/// Present and true if the authenticator requires a power cycle
|
|
/// before any future PIN operation, false if no power cycle
|
|
/// needed. If the field is omitted, no information is given about
|
|
/// whether a power cycle is needed or not.
|
|
#[serde(rename = "powerCycleState", default)]
|
|
requires_power_cycle: bool,
|
|
// 0x05
|
|
/// Number of uv attempts remaining before lockout.
|
|
#[serde(rename = "uvRetries", default)]
|
|
uv_retries: u8,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
pub struct CoseKey<'a> {
|
|
// 0x01
|
|
type_: PublicKeyCredentialType,
|
|
// 0x02
|
|
id: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x03
|
|
alg: PublicKeyCredentialAlgorithm,
|
|
// remainder
|
|
parameters: BTreeMap<i32, serde_cbor::value::Value>,
|
|
}
|
|
|
|
impl<'a> Serialize for CoseKey<'a> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut s = serializer.serialize_map(Some(
|
|
self.parameters.len() + 2 + (!self.id.is_empty()) as usize,
|
|
))?;
|
|
s.serialize_entry(&0x01, &self.type_)?;
|
|
if !self.id.is_empty() {
|
|
s.serialize_entry(&0x02, &self.id)?;
|
|
}
|
|
s.serialize_entry(&0x03, &self.alg)?;
|
|
for (k, v) in &self.parameters {
|
|
s.serialize_entry(k, v)?;
|
|
}
|
|
s.end()
|
|
}
|
|
}
|
|
|
|
impl<'a, 'de> Deserialize<'de> for CoseKey<'a> {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
enum Field {
|
|
Type,
|
|
Alg,
|
|
Id,
|
|
Other(i32),
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Field {
|
|
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct FieldVisitor;
|
|
|
|
impl<'de> Visitor<'de> for FieldVisitor {
|
|
type Value = Field;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("type, alg, id or other")
|
|
}
|
|
|
|
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
match value {
|
|
"alg" => Ok(Field::Alg),
|
|
"type" => Ok(Field::Type),
|
|
"id" => Ok(Field::Id),
|
|
_ => Err(de::Error::unknown_field(value, &["type", "alg", "id"])),
|
|
}
|
|
}
|
|
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
match value {
|
|
b"alg" => Ok(Field::Alg),
|
|
b"type" => Ok(Field::Type),
|
|
b"id" => Ok(Field::Id),
|
|
_ => Err(de::Error::unknown_field(
|
|
&format!("{:?}", value),
|
|
&["type", "alg", "id"],
|
|
)),
|
|
}
|
|
}
|
|
fn visit_i64<E>(self, value: i64) -> Result<Field, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
match value {
|
|
0x01 => Ok(Field::Type),
|
|
0x02 => Ok(Field::Id),
|
|
0x03 => Ok(Field::Alg),
|
|
other => Ok(Field::Other(other as i32)),
|
|
}
|
|
}
|
|
|
|
fn visit_u64<E>(self, value: u64) -> Result<Field, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
let signed: i64 = value as i64;
|
|
self.visit_i64(signed)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_identifier(FieldVisitor)
|
|
}
|
|
}
|
|
|
|
struct CoseKeyVisitor<'a>(PhantomData<&'a ()>);
|
|
|
|
impl<'a, 'de> Visitor<'de> for CoseKeyVisitor<'a> {
|
|
type Value = CoseKey<'a>;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("struct CoseKey")
|
|
}
|
|
|
|
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
|
where
|
|
V: MapAccess<'de>,
|
|
{
|
|
let mut type_: Option<PublicKeyCredentialType> = None;
|
|
let mut alg: Option<PublicKeyCredentialAlgorithm> = None;
|
|
let mut id: Option<Cow<'a, serde_bytes::Bytes>> = None;
|
|
let mut parameters: BTreeMap<i32, serde_cbor::value::Value> = BTreeMap::new();
|
|
while let Some(k) = map.next_key()? {
|
|
match k {
|
|
Field::Type => type_ = Some(map.next_value()?),
|
|
Field::Id => id = Some(map.next_value()?),
|
|
Field::Alg => alg = Some(map.next_value()?),
|
|
Field::Other(i) => {
|
|
parameters.insert(i, map.next_value()?);
|
|
}
|
|
};
|
|
}
|
|
let type_ = type_.ok_or_else(|| serde::de::Error::missing_field("type"))?;
|
|
let id = id.unwrap_or(Cow::Borrowed(serde_bytes::Bytes::new(&[])));
|
|
//let id = id.map(|id| id.into_vec()).unwrap_or_else(|| vec![]);
|
|
let alg = alg.ok_or_else(|| serde::de::Error::missing_field("alg"))?;
|
|
Ok(CoseKey {
|
|
type_,
|
|
id,
|
|
alg,
|
|
parameters,
|
|
})
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_map(CoseKeyVisitor(PhantomData))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct MakeCredentialRequest<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
#[serde(rename = "clientDataHash")]
|
|
client_data_hash: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x02
|
|
rp: PublicKeyCredentialRpEntity<'a>,
|
|
// 0x03
|
|
user: PublicKeyCredentialUserEntity<'a>,
|
|
// 0x04
|
|
#[serde(rename = "pubKeyCredParams")]
|
|
pubkey_cred_params: Cow<'a, [PublicKeyCredentialParameters]>,
|
|
// 0x05
|
|
#[serde(rename = "excludeList", default)]
|
|
exclude_list: Cow<'a, [PublicKeyCredentialDescriptor<'a>]>,
|
|
// 0x06
|
|
#[serde(default)]
|
|
extensions: BTreeMap<Cow<'a, str>, Cow<'a, serde_cbor::value::Value>>,
|
|
#[serde(default)]
|
|
options: Option<AuthenticatorOptions<'a>>,
|
|
#[serde(rename = "pinUvAuthParam", default)]
|
|
pin_auth_param: Option<Cow<'a, serde_bytes::Bytes>>,
|
|
#[serde(rename = "pinUvAuthProtocol", default)]
|
|
pin_auth_protocol: Option<u64>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
|
|
pub struct PublicKeyCredentialRpEntity<'a> {
|
|
id: Cow<'a, str>,
|
|
#[serde(default)]
|
|
name: Option<Cow<'a, str>>,
|
|
#[serde(default)]
|
|
icon: Option<Cow<'a, str>>,
|
|
}
|
|
|
|
// Ensure keys aren't packed but instead serialized as string
|
|
impl<'a> Serialize for PublicKeyCredentialRpEntity<'a> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut s = serializer.serialize_map(Some(
|
|
1 + self.name.is_some() as usize + self.icon.is_some() as usize,
|
|
))?;
|
|
for (k, v) in &[
|
|
("id", Some(&self.id)),
|
|
("name", self.name.as_ref()),
|
|
("icon", self.icon.as_ref()),
|
|
] {
|
|
s.serialize_entry(k, v)?;
|
|
}
|
|
s.end()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
|
|
pub struct PublicKeyCredentialUserEntity<'a> {
|
|
id: Cow<'a, serde_bytes::Bytes>,
|
|
#[serde(default)]
|
|
name: Option<Cow<'a, str>>,
|
|
#[serde(default)]
|
|
icon: Option<Cow<'a, str>>,
|
|
}
|
|
|
|
// Ensure keys aren't packed but instead serialized as string
|
|
impl<'a> Serialize for PublicKeyCredentialUserEntity<'a> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut s = serializer.serialize_map(Some(
|
|
1 + self.name.is_some() as usize + self.icon.is_some() as usize,
|
|
))?;
|
|
s.serialize_entry("id", &self.id)?;
|
|
for (k, v) in &[("name", self.name.as_ref()), ("icon", self.icon.as_ref())] {
|
|
s.serialize_entry(k, v)?;
|
|
}
|
|
s.end()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
|
|
pub struct PublicKeyCredentialDescriptor<'a> {
|
|
#[serde(rename = "type")]
|
|
type_: PublicKeyCredentialType,
|
|
id: Cow<'a, serde_bytes::Bytes>,
|
|
}
|
|
|
|
// Ensure keys aren't packed but instead serialized as string
|
|
impl<'a> Serialize for PublicKeyCredentialDescriptor<'a> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut s = serializer.serialize_map(Some(2))?;
|
|
s.serialize_entry("type", &self.type_)?;
|
|
s.serialize_entry("id", &self.id)?;
|
|
s.end()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct AuthenticatorOptions<'a> {
|
|
options: BTreeMap<Cow<'a, str>, bool>,
|
|
}
|
|
|
|
impl AuthenticatorOptions<'_> {
|
|
pub fn credential(rk: bool, uv: bool) -> Self {
|
|
AuthenticatorOptions {
|
|
options: [("rk", rk), ("uv", uv)]
|
|
.to_vec()
|
|
.into_iter()
|
|
.filter(|(_, val)| *val)
|
|
.map(|(k, v)| (Cow::Borrowed(k), v))
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
pub fn assertion(up: bool, uv: bool) -> Self {
|
|
AuthenticatorOptions {
|
|
options: [("up", up), ("uv", uv)]
|
|
.to_vec()
|
|
.into_iter()
|
|
.filter(|(_, val)| *val)
|
|
.map(|(k, v)| (Cow::Borrowed(k), v))
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
/// Resident key
|
|
pub fn rk(&self) -> bool {
|
|
*self.options.get("rk").unwrap_or(&false)
|
|
}
|
|
|
|
/// User verification
|
|
pub fn uv(&self) -> bool {
|
|
*self.options.get("uv").unwrap_or(&false)
|
|
}
|
|
|
|
/// User presence
|
|
pub fn up(&self) -> bool {
|
|
*self.options.get("up").unwrap_or(&false)
|
|
}
|
|
|
|
pub fn is_silent_auth(&self) -> bool {
|
|
!self.up() && !self.uv()
|
|
}
|
|
|
|
pub fn is_physical_up(&self) -> bool {
|
|
self.up() && self.uv()
|
|
}
|
|
}
|
|
|
|
impl<'a> Serialize for AuthenticatorOptions<'a> {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let mut s =
|
|
serializer.serialize_map(Some(self.options.iter().filter(|(_, val)| **val).count()))?;
|
|
for (k, v) in &self.options {
|
|
if *v {
|
|
s.serialize_entry(k, v)?;
|
|
}
|
|
}
|
|
s.end()
|
|
}
|
|
}
|
|
|
|
impl<'a, 'de> Deserialize<'de> for AuthenticatorOptions<'a> {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
enum Field {
|
|
Other(String),
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Field {
|
|
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct FieldVisitor;
|
|
|
|
impl<'de> Visitor<'de> for FieldVisitor {
|
|
type Value = Field;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("enum AuthenticatorOptions")
|
|
}
|
|
|
|
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
match value {
|
|
other => Ok(Field::Other(other.into())),
|
|
}
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_identifier(FieldVisitor)
|
|
}
|
|
}
|
|
|
|
struct AuthenticatorOptionsVisitor<'a>(PhantomData<&'a ()>);
|
|
|
|
impl<'a, 'de> Visitor<'de> for AuthenticatorOptionsVisitor<'a> {
|
|
type Value = AuthenticatorOptions<'a>;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("struct AuthenticatorOptions")
|
|
}
|
|
|
|
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
|
where
|
|
V: MapAccess<'de>,
|
|
{
|
|
let mut options = BTreeMap::<Cow<'a, str>, bool>::new();
|
|
while let Some(k) = map.next_key()? {
|
|
match k {
|
|
Field::Other(i) => {
|
|
options.insert(Cow::Owned(i), map.next_value()?);
|
|
}
|
|
};
|
|
}
|
|
Ok(AuthenticatorOptions { options })
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_map(AuthenticatorOptionsVisitor::<'a>(PhantomData))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct MakeCredentialResponse<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
fmt: Cow<'a, str>,
|
|
// 0x02
|
|
#[serde(rename = "authData")]
|
|
auth_data: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x03
|
|
#[serde(rename = "attStmt")]
|
|
attestation_statement: BTreeMap<serde_cbor::value::Value, serde_cbor::value::Value>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct GetAssertionRequest<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
#[serde(rename = "rpId")]
|
|
rp_id: Cow<'a, str>,
|
|
// 0x02
|
|
#[serde(rename = "clientDataHash")]
|
|
client_data_hash: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x03
|
|
#[serde(rename = "allowList", default)]
|
|
allow_list: Cow<'a, [PublicKeyCredentialDescriptor<'a>]>,
|
|
// 0x04
|
|
#[serde(default)]
|
|
extensions: BTreeMap<Cow<'a, str>, Cow<'a, serde_cbor::value::Value>>,
|
|
// 0x05
|
|
#[serde(default)]
|
|
options: Option<AuthenticatorOptions<'a>>,
|
|
// 0x06
|
|
#[serde(rename = "pinUvAuthParam", default)]
|
|
pin_auth_param: Option<Cow<'a, serde_bytes::Bytes>>,
|
|
// 0x07
|
|
#[serde(rename = "pinUvAuthProtocol", default)]
|
|
pin_auth_protocol: Option<u64>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct GetAssertionResponse<'a> {
|
|
/// Not used in protocol but required to bump the packed index to 0x01
|
|
// 0x00
|
|
#[serde(default)]
|
|
__bump: (),
|
|
// 0x01
|
|
credential: PublicKeyCredentialDescriptor<'a>,
|
|
// 0x02
|
|
#[serde(rename = "authData")]
|
|
auth_data: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x03
|
|
signature: Cow<'a, serde_bytes::Bytes>,
|
|
// 0x04
|
|
/// User identifiable information (name, DisplayName, icon) MUST not be returned if user verification is not done by the authenticator.
|
|
#[serde(default)]
|
|
user: Option<PublicKeyCredentialUserEntity<'a>>,
|
|
// 0x05
|
|
#[serde(rename = "numberOfCredentials", default)]
|
|
credential_count: Option<u64>,
|
|
#[serde(rename = "userSelected", default)]
|
|
credential_selected: Option<bool>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct Reset;
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
fn assert_ok<O: Debug, E: Debug>(res: Result<O, E>) {
|
|
assert!(dbg!(res).is_ok());
|
|
}
|
|
|
|
fn assert_decodes<'a, T: Debug + Deserialize<'a>>(mut bytes: &[u8]) -> T {
|
|
let mut cbor = bytes;
|
|
match T::deserialize_cbor(&mut bytes) {
|
|
e @ Err(_) => {
|
|
dbg!(serde_cbor::value::Value::deserialize_cbor(&mut cbor));
|
|
dbg!(e).unwrap();
|
|
unreachable!()
|
|
}
|
|
Ok(ok) => return ok,
|
|
}
|
|
}
|
|
|
|
fn encode_round<'a, T: Serialize + Deserialize<'a> + Debug + Eq>(val: T) {
|
|
let mut buf = Vec::new();
|
|
val.serialize_cbor(&mut buf).unwrap();
|
|
let mut buf_slice = &buf[..];
|
|
let val2 = assert_decodes::<T>(&mut buf_slice);
|
|
assert_eq!(val, val2);
|
|
}
|
|
|
|
mod info {
|
|
use super::*;
|
|
|
|
fn test_response(mut resp: &[u8]) {
|
|
assert_ok(GetInfoResponse::deserialize_cbor(&mut resp));
|
|
}
|
|
|
|
//#[test]
|
|
fn encode_command() {
|
|
let cmd = CborCommand(GetInfoRequest);
|
|
let mut buf = Vec::new();
|
|
cmd.serialize_cbor(&mut buf).unwrap();
|
|
dbg!(serde_cbor::value::Value::deserialize_cbor(&mut (&buf[..])).unwrap());
|
|
panic!()
|
|
}
|
|
|
|
#[test]
|
|
fn response_yubikey() {
|
|
test_response(&[
|
|
170, 1, 131, 102, 85, 50, 70, 95, 86, 50, 104, 70, 73, 68, 79, 95, 50, 95, 48, 108,
|
|
70, 73, 68, 79, 95, 50, 95, 49, 95, 80, 82, 69, 2, 130, 107, 99, 114, 101, 100, 80,
|
|
114, 111, 116, 101, 99, 116, 107, 104, 109, 97, 99, 45, 115, 101, 99, 114, 101,
|
|
116, 3, 80, 185, 44, 63, 154, 192, 20, 64, 86, 136, 127, 20, 10, 37, 1, 22, 59, 4,
|
|
165, 98, 114, 107, 245, 98, 117, 112, 245, 100, 112, 108, 97, 116, 244, 105, 99,
|
|
108, 105, 101, 110, 116, 80, 105, 110, 244, 117, 99, 114, 101, 100, 101, 110, 116,
|
|
105, 97, 108, 77, 103, 109, 116, 80, 114, 101, 118, 105, 101, 119, 245, 5, 25, 4,
|
|
176, 6, 129, 1, 7, 8, 8, 24, 128, 9, 129, 99, 117, 115, 98, 10, 130, 162, 99, 97,
|
|
108, 103, 38, 100, 116, 121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45, 107,
|
|
101, 121, 162, 99, 97, 108, 103, 39, 100, 116, 121, 112, 101, 106, 112, 117, 98,
|
|
108, 105, 99, 45, 107, 101, 121,
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn response_solokey() {
|
|
test_response(&[
|
|
168, 1, 131, 102, 85, 50, 70, 95, 86, 50, 104, 70, 73, 68, 79, 95, 50, 95, 48, 108,
|
|
70, 73, 68, 79, 95, 50, 95, 49, 95, 80, 82, 69, 2, 130, 107, 104, 109, 97, 99, 45,
|
|
115, 101, 99, 114, 101, 116, 107, 99, 114, 101, 100, 80, 114, 111, 116, 101, 99,
|
|
116, 3, 80, 136, 118, 99, 27, 212, 160, 66, 127, 87, 115, 14, 199, 28, 158, 2, 121,
|
|
4, 165, 98, 114, 107, 245, 98, 117, 112, 245, 100, 112, 108, 97, 116, 244, 104, 99,
|
|
114, 101, 100, 77, 103, 109, 116, 245, 105, 99, 108, 105, 101, 110, 116, 80, 105,
|
|
110, 244, 5, 25, 4, 176, 6, 129, 1, 7, 20, 8, 24, 128,
|
|
]);
|
|
}
|
|
}
|
|
|
|
mod client_pin {
|
|
use super::*;
|
|
|
|
use crate::protocol::GetClientPinRequest;
|
|
|
|
fn test_request(mut req: &[u8]) {
|
|
assert_ok(GetClientPinRequest::deserialize_cbor(&mut req));
|
|
}
|
|
|
|
fn test_response(mut resp: &[u8]) {
|
|
let res = GetClientPinResponse::deserialize_cbor(&mut resp).unwrap();
|
|
//let cose = res.key_agreement;
|
|
//dbg!(cose.alg);
|
|
//assert_ne!(cose.alg, PublicKeyCredentialAlgorithm::Unknown);
|
|
/*let mut buf = Vec::new();
|
|
cose.serialize_cbor(&mut buf).unwrap();
|
|
let mut buf_slice = &buf[..];
|
|
assert_eq!(cose, CoseKey::deserialize_cbor(&mut buf_slice).unwrap())*/
|
|
}
|
|
|
|
#[test]
|
|
fn req_key_agreement() {
|
|
test_request(&[162, 1, 1, 2, 2])
|
|
}
|
|
|
|
fn cose_key<'a>() -> CoseKey<'a> {
|
|
CoseKey {
|
|
type_: PublicKeyCredentialType::PublicKey,
|
|
id: Cow::Owned(serde_bytes::ByteBuf::from(vec![8, 3, 4, 5])),
|
|
alg: PublicKeyCredentialAlgorithm::PS512,
|
|
parameters: vec![
|
|
(-3, serde_cbor::value::Value::Text("test".into())),
|
|
(
|
|
-42,
|
|
serde_cbor::value::Value::Bytes("test".as_bytes().to_vec()),
|
|
),
|
|
]
|
|
.into_iter()
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn cose_key_round() {
|
|
encode_round(cose_key());
|
|
}
|
|
|
|
#[test]
|
|
fn client_pin_resp_round() {
|
|
encode_round(GetClientPinResponse {
|
|
__bump: (),
|
|
key_agreement: Some(cose_key()),
|
|
pin_auth_token: Some(Cow::Owned(serde_bytes::ByteBuf::from(vec![8, 3, 4, 5]))),
|
|
pin_retries: 3,
|
|
requires_power_cycle: true,
|
|
uv_retries: 1,
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn resp_key_agreement_yubikey() {
|
|
test_response(&[
|
|
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 225, 230, 133, 231, 92, 119, 250,
|
|
236, 61, 49, 83, 182, 138, 31, 226, 185, 149, 235, 126, 130, 32, 69, 185, 206, 169,
|
|
0, 247, 169, 221, 63, 98, 253, 34, 88, 32, 61, 125, 120, 237, 105, 178, 59, 168,
|
|
222, 89, 214, 218, 225, 237, 207, 166, 25, 51, 4, 85, 200, 172, 177, 121, 208, 241,
|
|
75, 16, 68, 234, 86, 56,
|
|
]);
|
|
}
|
|
|
|
// SoloKey v1 fw 4.0.0
|
|
#[test]
|
|
fn resp_key_agreement_solokey() {
|
|
test_response(&[
|
|
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 9, 161, 111, 235, 155, 109, 166,
|
|
62, 78, 140, 241, 254, 59, 243, 234, 160, 36, 11, 234, 22, 156, 39, 195, 18, 114,
|
|
187, 7, 51, 117, 33, 163, 39, 34, 88, 32, 122, 88, 3, 24, 219, 125, 161, 38, 156,
|
|
117, 45, 246, 233, 246, 32, 124, 155, 33, 236, 78, 216, 17, 50, 134, 30, 80, 78,
|
|
82, 247, 155, 238, 60,
|
|
])
|
|
}
|
|
|
|
// Trezor Model T fw 2.3.0
|
|
#[test]
|
|
fn resp_key_agreement_trezor() {
|
|
test_response(&[
|
|
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 164, 211, 77, 255, 139, 183, 45,
|
|
143, 125, 177, 191, 110, 155, 139, 204, 44, 59, 191, 143, 107, 179, 129, 182, 9,
|
|
254, 209, 183, 7, 135, 188, 110, 111, 34, 88, 32, 255, 220, 244, 80, 159, 87, 162,
|
|
4, 52, 93, 145, 18, 189, 11, 246, 139, 99, 180, 132, 151, 79, 3, 220, 96, 108, 107,
|
|
45, 138, 23, 64, 241, 27,
|
|
]);
|
|
}
|
|
}
|
|
|
|
mod make_credential {
|
|
use super::*;
|
|
|
|
fn rp_entity<'a>() -> PublicKeyCredentialRpEntity<'a> {
|
|
PublicKeyCredentialRpEntity {
|
|
id: Cow::Borrowed("test"),
|
|
name: Some("Test".into()),
|
|
icon: None,
|
|
}
|
|
}
|
|
|
|
fn user_entity<'a>() -> PublicKeyCredentialUserEntity<'a> {
|
|
PublicKeyCredentialUserEntity {
|
|
id: Cow::Borrowed(serde_bytes::Bytes::new(&[0u8])),
|
|
name: Some("Tester".into()),
|
|
icon: None,
|
|
}
|
|
}
|
|
|
|
fn pubkey_cred_desc<'a>() -> PublicKeyCredentialDescriptor<'a> {
|
|
PublicKeyCredentialDescriptor {
|
|
type_: Default::default(),
|
|
id: Cow::Owned(serde_bytes::ByteBuf::from(vec![1, 2, 3, 4])),
|
|
}
|
|
}
|
|
|
|
fn authenticator_options<'a>() -> AuthenticatorOptions<'a> {
|
|
AuthenticatorOptions::credential(false, true)
|
|
}
|
|
|
|
fn make_credential_request<'a>() -> MakeCredentialRequest<'a> {
|
|
MakeCredentialRequest {
|
|
__bump: (),
|
|
client_data_hash: Cow::Owned(serde_bytes::ByteBuf::from(
|
|
vec![0u8; 32].into_boxed_slice(),
|
|
)),
|
|
//client_data_hash: Cow::Owned(vec![0u8; 32]),
|
|
rp: rp_entity(),
|
|
user: user_entity(),
|
|
pubkey_cred_params: Cow::Owned(vec![PublicKeyCredentialParameters {
|
|
__bump: (),
|
|
type_: Default::default(),
|
|
alg: PublicKeyCredentialAlgorithm::EdDSA,
|
|
}]),
|
|
exclude_list: Cow::Borrowed(&[]),
|
|
extensions: Default::default(),
|
|
options: Some(authenticator_options()),
|
|
pin_auth_param: None,
|
|
pin_auth_protocol: None,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn rp_entity_round() {
|
|
encode_round(rp_entity());
|
|
}
|
|
|
|
#[test]
|
|
fn user_entity_round() {
|
|
encode_round(user_entity());
|
|
}
|
|
|
|
#[test]
|
|
fn pubkey_cred_desc_round() {
|
|
encode_round(pubkey_cred_desc());
|
|
}
|
|
|
|
#[test]
|
|
fn authenticator_options_round() {
|
|
encode_round(authenticator_options());
|
|
}
|
|
|
|
#[test]
|
|
fn make_credential_request_round() {
|
|
encode_round(make_credential_request());
|
|
}
|
|
|
|
#[test]
|
|
fn test_make_credential_request() {
|
|
assert_decodes::<MakeCredentialRequest<'_>>(&[
|
|
166, 1, 88, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 162, 98, 105, 100, 105, 99, 116, 97, 112, 95, 100,
|
|
101, 109, 111, 100, 110, 97, 109, 101, 111, 99, 116, 97, 112, 95, 104, 109, 97, 99,
|
|
32, 99, 114, 97, 116, 101, 3, 162, 98, 105, 100, 65, 0, 100, 110, 97, 109, 101,
|
|
103, 101, 120, 97, 109, 112, 108, 101, 4, 129, 162, 99, 97, 108, 103, 38, 100, 116,
|
|
121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45, 107, 101, 121, 6, 161, 107,
|
|
104, 109, 97, 99, 45, 115, 101, 99, 114, 101, 116, 245, 7, 161, 98, 114, 107, 245,
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_make_credential_response_yubikey() {
|
|
assert_decodes::<MakeCredentialResponse<'_>>(&[
|
|
163, 1, 102, 112, 97, 99, 107, 101, 100, 2, 88, 162, 171, 147, 255, 145, 49, 113,
|
|
135, 145, 80, 61, 246, 246, 160, 31, 189, 65, 0, 129, 154, 207, 25, 28, 121, 3,
|
|
211, 79, 224, 82, 111, 17, 229, 163, 193, 0, 0, 0, 1, 185, 44, 63, 154, 192, 20,
|
|
64, 86, 136, 127, 20, 10, 37, 1, 22, 59, 0, 16, 56, 155, 5, 107, 163, 252, 17, 198,
|
|
217, 36, 74, 82, 82, 163, 168, 238, 165, 1, 2, 3, 38, 32, 1, 33, 88, 32, 246, 69,
|
|
134, 25, 161, 218, 253, 105, 245, 206, 238, 87, 169, 160, 244, 100, 85, 68, 186,
|
|
94, 20, 17, 74, 164, 37, 197, 153, 114, 27, 77, 12, 71, 34, 88, 32, 147, 225, 251,
|
|
119, 11, 173, 253, 130, 178, 46, 109, 204, 252, 135, 33, 39, 43, 40, 108, 72, 208,
|
|
254, 126, 40, 22, 146, 46, 193, 33, 148, 202, 33, 161, 107, 104, 109, 97, 99, 45,
|
|
115, 101, 99, 114, 101, 116, 245, 3, 163, 99, 97, 108, 103, 38, 99, 115, 105, 103,
|
|
88, 70, 48, 68, 2, 32, 84, 4, 232, 22, 111, 249, 130, 31, 242, 175, 108, 239, 65,
|
|
144, 88, 177, 197, 158, 176, 10, 62, 240, 108, 24, 70, 236, 240, 32, 84, 142, 84,
|
|
148, 2, 32, 48, 47, 250, 108, 99, 157, 93, 204, 51, 124, 180, 62, 0, 114, 44, 247,
|
|
62, 255, 173, 153, 226, 228, 246, 153, 106, 212, 125, 151, 216, 119, 6, 51, 99,
|
|
120, 53, 99, 129, 89, 2, 194, 48, 130, 2, 190, 48, 130, 1, 166, 160, 3, 2, 1, 2, 2,
|
|
4, 64, 2, 121, 168, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 48,
|
|
46, 49, 44, 48, 42, 6, 3, 85, 4, 3, 19, 35, 89, 117, 98, 105, 99, 111, 32, 85, 50,
|
|
70, 32, 82, 111, 111, 116, 32, 67, 65, 32, 83, 101, 114, 105, 97, 108, 32, 52, 53,
|
|
55, 50, 48, 48, 54, 51, 49, 48, 32, 23, 13, 49, 52, 48, 56, 48, 49, 48, 48, 48, 48,
|
|
48, 48, 90, 24, 15, 50, 48, 53, 48, 48, 57, 48, 52, 48, 48, 48, 48, 48, 48, 90, 48,
|
|
111, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 83, 69, 49, 18, 48, 16, 6, 3, 85, 4, 10,
|
|
12, 9, 89, 117, 98, 105, 99, 111, 32, 65, 66, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12,
|
|
25, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116,
|
|
101, 115, 116, 97, 116, 105, 111, 110, 49, 40, 48, 38, 6, 3, 85, 4, 3, 12, 31, 89,
|
|
117, 98, 105, 99, 111, 32, 85, 50, 70, 32, 69, 69, 32, 83, 101, 114, 105, 97, 108,
|
|
32, 49, 48, 55, 51, 57, 48, 52, 48, 52, 48, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206,
|
|
61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 92, 183, 14, 166, 108,
|
|
19, 242, 191, 224, 255, 147, 132, 208, 179, 67, 32, 72, 205, 160, 182, 251, 135,
|
|
80, 27, 114, 155, 230, 205, 77, 104, 6, 173, 224, 82, 102, 118, 173, 253, 212, 111,
|
|
46, 81, 100, 79, 18, 119, 101, 79, 42, 240, 208, 143, 150, 204, 85, 59, 181, 241,
|
|
69, 21, 191, 190, 157, 208, 163, 108, 48, 106, 48, 34, 6, 9, 43, 6, 1, 4, 1, 130,
|
|
196, 10, 2, 4, 21, 49, 46, 51, 46, 54, 46, 49, 46, 52, 46, 49, 46, 52, 49, 52, 56,
|
|
50, 46, 49, 46, 49, 48, 19, 6, 11, 43, 6, 1, 4, 1, 130, 229, 28, 2, 1, 1, 4, 4, 3,
|
|
2, 5, 32, 48, 33, 6, 11, 43, 6, 1, 4, 1, 130, 229, 28, 1, 1, 4, 4, 18, 4, 16, 185,
|
|
44, 63, 154, 192, 20, 64, 86, 136, 127, 20, 10, 37, 1, 22, 59, 48, 12, 6, 3, 85,
|
|
29, 19, 1, 1, 255, 4, 2, 48, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11,
|
|
5, 0, 3, 130, 1, 1, 0, 178, 135, 228, 70, 6, 168, 222, 188, 192, 19, 50, 245, 198,
|
|
202, 144, 206, 49, 48, 38, 11, 143, 119, 70, 32, 95, 26, 212, 142, 183, 131, 163,
|
|
27, 203, 145, 6, 133, 148, 202, 215, 181, 164, 219, 166, 56, 19, 126, 137, 211, 62,
|
|
42, 127, 182, 177, 112, 53, 114, 251, 8, 40, 44, 156, 108, 20, 26, 216, 239, 65,
|
|
215, 196, 174, 225, 140, 84, 245, 139, 253, 241, 199, 255, 223, 122, 146, 16, 202,
|
|
58, 191, 10, 86, 249, 39, 227, 85, 188, 164, 114, 179, 123, 51, 166, 237, 90, 251,
|
|
177, 194, 198, 16, 48, 142, 90, 179, 172, 38, 187, 61, 67, 206, 255, 19, 62, 224,
|
|
23, 181, 128, 70, 157, 53, 230, 151, 80, 242, 72, 66, 230, 96, 23, 121, 13, 115,
|
|
110, 4, 235, 191, 239, 228, 182, 36, 77, 28, 113, 29, 179, 14, 249, 48, 148, 234,
|
|
149, 229, 125, 159, 77, 99, 29, 84, 158, 243, 239, 9, 238, 91, 25, 196, 23, 194,
|
|
78, 205, 63, 185, 139, 80, 252, 42, 181, 125, 218, 103, 220, 157, 38, 122, 65, 173,
|
|
118, 102, 181, 9, 90, 248, 34, 84, 4, 210, 153, 44, 123, 218, 167, 60, 78, 214, 10,
|
|
198, 118, 78, 12, 99, 149, 216, 51, 133, 4, 255, 149, 205, 33, 212, 170, 0, 51, 73,
|
|
130, 174, 184, 115, 38, 198, 190, 19, 50, 241, 59, 18, 174, 164, 223, 232, 233,
|
|
214, 248, 221, 184, 56, 3, 149, 249, 136,
|
|
]);
|
|
}
|
|
|
|
//#[test]
|
|
fn test_make_credential_requestt() {
|
|
let mut buf = Vec::new();
|
|
make_credential_request().serialize_cbor(&mut buf);
|
|
dbg!(serde_cbor::value::Value::deserialize_cbor(&mut (&buf[..])));
|
|
panic!()
|
|
}
|
|
}
|
|
|
|
mod get_assertion {
|
|
use super::*;
|
|
|
|
fn get_assertion_request<'a>() -> GetAssertionRequest<'a> {
|
|
GetAssertionRequest {
|
|
__bump: (),
|
|
rp_id: Cow::from("test"),
|
|
client_data_hash: Cow::Borrowed(serde_bytes::Bytes::new(&[0u8; 32])),
|
|
allow_list: Default::default(),
|
|
extensions: Default::default(),
|
|
options: Some(AuthenticatorOptions::assertion(true, true)),
|
|
pin_auth_param: None,
|
|
pin_auth_protocol: None,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn get_assertion_request_round() {
|
|
encode_round(get_assertion_request());
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_assertion_request() {
|
|
assert_decodes::<GetAssertionRequest<'_>>(&[
|
|
164, 1, 105, 99, 116, 97, 112, 95, 100, 101, 109, 111, 2, 88, 32, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
|
|
129, 162, 98, 105, 100, 80, 188, 116, 69, 227, 50, 124, 140, 13, 30, 132, 51, 122,
|
|
137, 240, 91, 67, 100, 116, 121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45,
|
|
107, 101, 121, 4, 161, 107, 104, 109, 97, 99, 45, 115, 101, 99, 114, 101, 116, 163,
|
|
1, 164, 32, 1, 33, 88, 32, 119, 92, 235, 161, 245, 203, 239, 97, 4, 180, 198, 43,
|
|
156, 66, 208, 88, 40, 254, 162, 90, 152, 46, 153, 212, 147, 117, 76, 46, 193, 231,
|
|
4, 129, 34, 88, 32, 227, 183, 102, 71, 152, 54, 189, 245, 231, 140, 17, 239, 248,
|
|
139, 194, 225, 94, 86, 39, 203, 242, 183, 41, 143, 108, 65, 243, 121, 181, 253, 40,
|
|
226, 1, 2, 2, 88, 32, 242, 81, 144, 103, 36, 192, 242, 17, 225, 70, 80, 167, 100,
|
|
158, 79, 232, 146, 127, 211, 190, 229, 47, 211, 8, 189, 170, 216, 129, 226, 255,
|
|
216, 76, 3, 80, 153, 134, 155, 103, 213, 108, 13, 108, 122, 96, 197, 205, 186, 193,
|
|
20, 37,
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_assertion_response_yubikey() {
|
|
assert_decodes::<GetAssertionResponse<'_>>(&[
|
|
164, 1, 162, 98, 105, 100, 80, 14, 2, 90, 14, 176, 127, 23, 26, 112, 189, 7, 253,
|
|
218, 142, 157, 153, 100, 116, 121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45,
|
|
107, 101, 121, 2, 88, 84, 171, 147, 255, 145, 49, 113, 135, 145, 80, 61, 246, 246,
|
|
160, 31, 189, 65, 0, 129, 154, 207, 25, 28, 121, 3, 211, 79, 224, 82, 111, 17, 229,
|
|
163, 129, 0, 0, 0, 7, 161, 107, 104, 109, 97, 99, 45, 115, 101, 99, 114, 101, 116,
|
|
88, 32, 223, 41, 90, 109, 42, 82, 208, 6, 206, 171, 212, 226, 224, 237, 130, 9, 52,
|
|
59, 28, 158, 133, 142, 189, 70, 175, 16, 189, 130, 15, 251, 139, 75, 3, 88, 71, 48,
|
|
69, 2, 33, 0, 176, 239, 65, 249, 233, 130, 83, 116, 67, 49, 5, 215, 3, 172, 65,
|
|
176, 179, 91, 198, 165, 224, 84, 82, 229, 230, 24, 215, 98, 219, 48, 28, 240, 2,
|
|
32, 60, 46, 255, 221, 206, 172, 31, 249, 85, 244, 133, 71, 125, 94, 0, 91, 50, 224,
|
|
43, 30, 113, 145, 254, 193, 198, 82, 240, 172, 32, 253, 156, 90, 4, 161, 98, 105,
|
|
100, 65, 0,
|
|
]);
|
|
}
|
|
#[test]
|
|
fn test_get_assertion_response_solokey() {
|
|
assert_decodes::<GetAssertionResponse<'_>>(&[
|
|
163, 1, 162, 98, 105, 100, 88, 70, 178, 60, 31, 172, 224, 56, 238, 158, 64, 8, 252,
|
|
234, 231, 234, 32, 67, 42, 251, 118, 141, 152, 72, 220, 19, 42, 24, 149, 131, 4,
|
|
78, 50, 46, 88, 99, 171, 147, 255, 145, 49, 113, 135, 145, 80, 61, 246, 246, 160,
|
|
31, 189, 65, 0, 129, 154, 207, 25, 28, 121, 3, 211, 79, 224, 82, 111, 17, 229, 163,
|
|
241, 64, 0, 0, 100, 116, 121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45, 107,
|
|
101, 121, 2, 88, 84, 171, 147, 255, 145, 49, 113, 135, 145, 80, 61, 246, 246, 160,
|
|
31, 189, 65, 0, 129, 154, 207, 25, 28, 121, 3, 211, 79, 224, 82, 111, 17, 229, 163,
|
|
129, 0, 0, 64, 254, 161, 107, 104, 109, 97, 99, 45, 115, 101, 99, 114, 101, 116,
|
|
88, 32, 108, 143, 197, 14, 100, 162, 70, 237, 198, 31, 36, 164, 199, 214, 252, 153,
|
|
25, 20, 137, 18, 158, 15, 158, 132, 30, 104, 148, 80, 11, 15, 104, 36, 3, 88, 70,
|
|
48, 68, 2, 33, 0, 169, 159, 135, 26, 0, 124, 121, 110, 127, 51, 238, 77, 27, 168,
|
|
200, 106, 177, 163, 145, 8, 242, 81, 20, 22, 1, 110, 133, 249, 228, 173, 14, 55, 2,
|
|
31, 77, 250, 13, 108, 46, 220, 50, 62, 166, 232, 158, 158, 36, 157, 115, 46, 209,
|
|
141, 201, 105, 120, 98, 160, 127, 55, 19, 69, 102, 13, 76, 95,
|
|
]);
|
|
}
|
|
}
|
|
}
|