working cbor deserialize
This commit is contained in:
parent
d6b20d0ba4
commit
9737a006e7
@ -23,6 +23,10 @@ rust-crypto = "0.2"
|
|||||||
csv-core = "0.1.6"
|
csv-core = "0.1.6"
|
||||||
derive_builder = "0.9.0"
|
derive_builder = "0.9.0"
|
||||||
crossbeam = { version = "0.7.3", optional = true }
|
crossbeam = { version = "0.7.3", optional = true }
|
||||||
|
serde_derive = "1.0.106"
|
||||||
|
serde = "1.0.106"
|
||||||
|
serde_cbor = "0.11.1"
|
||||||
|
serde_bytes = "0.11.3"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
crossbeam = "0.7.3"
|
crossbeam = "0.7.3"
|
||||||
hex = "0.4.0"
|
hex = "0.4.0"
|
||||||
|
615
src/protocol/cbor.rs
Normal file
615
src/protocol/cbor.rs
Normal file
@ -0,0 +1,615 @@
|
|||||||
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
use serde::de::{Error, MapAccess, Visitor};
|
||||||
|
use serde::ser::{SerializeMap, SerializeStruct};
|
||||||
|
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use serde_cbor::de::IoRead;
|
||||||
|
use serde_cbor::ser::IoWrite;
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
#[deny(missing_debug_implementations)]
|
||||||
|
|
||||||
|
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 {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
|
pub enum CborRequests {
|
||||||
|
__Bump,
|
||||||
|
// 0x01
|
||||||
|
MakeCredential,
|
||||||
|
// 0x02
|
||||||
|
GetAssertion,
|
||||||
|
// 0x03
|
||||||
|
___Unused,
|
||||||
|
// 0x04
|
||||||
|
GetInfo(GetInfoRequest),
|
||||||
|
// 0x05
|
||||||
|
____Unused,
|
||||||
|
// 0x06
|
||||||
|
ClientPin,
|
||||||
|
// 0x07
|
||||||
|
Reset,
|
||||||
|
// 0x08
|
||||||
|
GetNextAssertion,
|
||||||
|
// 0x09
|
||||||
|
BioEnrolment,
|
||||||
|
// 0x0A
|
||||||
|
CredentialManagement,
|
||||||
|
// 0x0B
|
||||||
|
Selection,
|
||||||
|
// 0x0C
|
||||||
|
Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type GetInfoRequest = ();
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize,Eq, PartialEq )]
|
||||||
|
pub struct GetInfoResponse {
|
||||||
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
|
// 0x00
|
||||||
|
#[serde(default)]
|
||||||
|
__bump: (),
|
||||||
|
// 0x01
|
||||||
|
versions: Vec<String>,
|
||||||
|
// 0x02
|
||||||
|
extensions: Vec<String>,
|
||||||
|
// 0x03
|
||||||
|
#[serde(with = "serde_bytes")]
|
||||||
|
aaguid: Vec<u8>,
|
||||||
|
// 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: Vec<u64>,
|
||||||
|
// 0x07
|
||||||
|
#[serde(rename = "maxCredentialCountInList", default)]
|
||||||
|
max_credential_count: u64,
|
||||||
|
// 0x08
|
||||||
|
#[serde(rename = "maxCredentialIdLength", default)]
|
||||||
|
max_credential_id_len: u64,
|
||||||
|
// 0x09
|
||||||
|
#[serde(default)]
|
||||||
|
transports: Vec<String>,
|
||||||
|
// 0x0A
|
||||||
|
#[serde(default)]
|
||||||
|
algorithms: Vec<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, Serialize, 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
|
pub enum PublicKeyCredentialType {
|
||||||
|
#[serde(rename = "public-key")]
|
||||||
|
PublicKey = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PublicKeyCredentialType {
|
||||||
|
fn default() -> Self {
|
||||||
|
PublicKeyCredentialType::PublicKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromPrimitive, ToPrimitive, Eq, PartialEq)]
|
||||||
|
pub enum PublicKeyCredentialAlgorithm {
|
||||||
|
ES256 = -7,
|
||||||
|
// Unsupported
|
||||||
|
EdDSA = -8,
|
||||||
|
// 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 {
|
||||||
|
/// 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", with = "serde_bytes", default)]
|
||||||
|
pin_auth_param: Vec<u8>,
|
||||||
|
// 0x05
|
||||||
|
#[serde(rename = "newPinEnc", with = "serde_bytes", default)]
|
||||||
|
new_pin_enc: Vec<u8>,
|
||||||
|
// 0x06
|
||||||
|
#[serde(rename = "pinHashEnc", with = "serde_bytes", default)]
|
||||||
|
pin_hash_enc: Vec<u8>,
|
||||||
|
}
|
||||||
|
#[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 {
|
||||||
|
/// 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>,
|
||||||
|
// 0x02
|
||||||
|
/// Encrypted pinUvAuthToken using sharedSecret used in subsequent authenticatorMakeCredential authenticatorGetAssertion operations
|
||||||
|
#[serde(rename = "pinUvAuthToken", with = "serde_bytes", default)]
|
||||||
|
pin_auth_token: Vec<u8>,
|
||||||
|
// 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 {
|
||||||
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
|
// 0x00
|
||||||
|
// #[serde(default)]
|
||||||
|
//__bump: (),
|
||||||
|
// 0x01
|
||||||
|
//#[serde(rename = "type", default)]
|
||||||
|
type_: PublicKeyCredentialType,
|
||||||
|
// 0x02
|
||||||
|
//#[serde(with = "serde_bytes", default)]
|
||||||
|
id: Vec<u8>,
|
||||||
|
// 0x03
|
||||||
|
alg: PublicKeyCredentialAlgorithm,
|
||||||
|
parameters: BTreeMap<i32, serde_cbor::value::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct CoseKeyDescriptor {
|
||||||
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
|
// 0x00
|
||||||
|
#[serde(default)]
|
||||||
|
__bump: (),
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
type_: PublicKeyCredentialType,
|
||||||
|
#[serde(with = "serde_bytes", default)]
|
||||||
|
id: Vec<u8>,
|
||||||
|
alg: PublicKeyCredentialAlgorithm,
|
||||||
|
parameters: BTreeMap<i32, serde_cbor::value::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for CoseKey {
|
||||||
|
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<'de> Deserialize<'de> for CoseKey {
|
||||||
|
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_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;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for CoseKeyVisitor {
|
||||||
|
type Value = CoseKey;
|
||||||
|
|
||||||
|
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<serde_bytes::ByteBuf> = 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.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn assert_ok<O: Debug, E: Debug>(res: Result<O, E>) {
|
||||||
|
assert!(dbg!(res).is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
mod info {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn test_response(mut resp: &[u8]) {
|
||||||
|
assert_ok(GetInfoResponse::deserialize_cbor(&mut resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
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]
|
||||||
|
#[ignore]
|
||||||
|
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.unwrap();
|
||||||
|
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])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cose_key_round() {
|
||||||
|
let key = CoseKey{
|
||||||
|
type_: PublicKeyCredentialType::PublicKey,
|
||||||
|
id: vec![1u8, 3 ,4, 5],
|
||||||
|
alg: PublicKeyCredentialAlgorithm::PS512,
|
||||||
|
parameters: vec![(-3, serde_cbor::value::Value::Text("test".into()))].into_iter().collect()
|
||||||
|
};
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
key.serialize_cbor(&mut buf).unwrap();
|
||||||
|
let mut buf_slice = &buf[..];
|
||||||
|
let key2 = CoseKey::deserialize_cbor(&mut buf_slice).unwrap();
|
||||||
|
assert_eq!(key, key2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
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]
|
||||||
|
#[ignore]
|
||||||
|
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]
|
||||||
|
#[ignore]
|
||||||
|
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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[test]
|
||||||
|
fn vec_layout() {
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
struct VecLayout {
|
||||||
|
len: u8,
|
||||||
|
item1: String,
|
||||||
|
item2: String,
|
||||||
|
}
|
||||||
|
let vec = vec!["hello".to_string(), "world".into()];
|
||||||
|
let mut native_bytes = Vec::new();
|
||||||
|
vec.serialize(&mut serde_cbor::Serializer::new(&mut native_bytes).packed_format())
|
||||||
|
.unwrap();
|
||||||
|
let layout = VecLayout {
|
||||||
|
len: 2,
|
||||||
|
item1: "hello".into(),
|
||||||
|
item2: "world".into(),
|
||||||
|
};
|
||||||
|
let mut layout_bytes = Vec::new();
|
||||||
|
layout
|
||||||
|
.serialize(&mut serde_cbor::Serializer::new(&mut layout_bytes).packed_format())
|
||||||
|
.unwrap();
|
||||||
|
layout_bytes.push(0);
|
||||||
|
assert_eq!(dbg!(native_bytes), layout_bytes);
|
||||||
|
}
|
||||||
|
}
|
3
src/protocol/mod.rs
Normal file
3
src/protocol/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod cbor;
|
||||||
|
|
||||||
|
pub use self::cbor::*;
|
Loading…
x
Reference in New Issue
Block a user