impl make credential
This commit is contained in:
parent
9737a006e7
commit
33229a0b3c
@ -8,6 +8,8 @@ use std::collections::{BTreeMap, HashMap};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use failure::_core::marker::PhantomData;
|
||||||
|
|
||||||
#[deny(missing_debug_implementations)]
|
#[deny(missing_debug_implementations)]
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ pub enum CborRequests {
|
|||||||
// 0x05
|
// 0x05
|
||||||
____Unused,
|
____Unused,
|
||||||
// 0x06
|
// 0x06
|
||||||
ClientPin,
|
ClientPin(GetClientPinRequest),
|
||||||
// 0x07
|
// 0x07
|
||||||
Reset,
|
Reset,
|
||||||
// 0x08
|
// 0x08
|
||||||
@ -58,7 +60,7 @@ pub enum CborRequests {
|
|||||||
|
|
||||||
pub type GetInfoRequest = ();
|
pub type GetInfoRequest = ();
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize,Eq, PartialEq )]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct GetInfoResponse {
|
pub struct GetInfoResponse {
|
||||||
/// Not used in protocol but required to bump the packed index to 0x01
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
// 0x00
|
// 0x00
|
||||||
@ -100,7 +102,7 @@ pub struct GetInfoResponse {
|
|||||||
default_cred_protect: CredProtect,
|
default_cred_protect: CredProtect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct GetInfoOptions {
|
pub struct GetInfoOptions {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
plat: bool,
|
plat: bool,
|
||||||
@ -118,7 +120,7 @@ pub struct GetInfoOptions {
|
|||||||
config: bool,
|
config: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct PublicKeyCredentialParameters {
|
pub struct PublicKeyCredentialParameters {
|
||||||
/// Not used in protocol but required to bump the packed index to 0x01
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
// 0x00
|
// 0x00
|
||||||
@ -131,10 +133,13 @@ pub struct PublicKeyCredentialParameters {
|
|||||||
alg: PublicKeyCredentialAlgorithm,
|
alg: PublicKeyCredentialAlgorithm,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub enum PublicKeyCredentialType {
|
pub enum PublicKeyCredentialType {
|
||||||
#[serde(rename = "public-key")]
|
#[serde(rename = "public-key")]
|
||||||
PublicKey = 0,
|
PublicKey = 0,
|
||||||
|
NoTwo = 2,
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PublicKeyCredentialType {
|
impl Default for PublicKeyCredentialType {
|
||||||
@ -143,11 +148,13 @@ impl Default for PublicKeyCredentialType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, FromPrimitive, ToPrimitive, Eq, PartialEq)]
|
#[derive(Debug, Clone, FromPrimitive, ToPrimitive, Eq, PartialEq)]
|
||||||
pub enum PublicKeyCredentialAlgorithm {
|
pub enum PublicKeyCredentialAlgorithm {
|
||||||
ES256 = -7,
|
ES256 = -7,
|
||||||
// Unsupported
|
// Unsupported
|
||||||
EdDSA = -8,
|
EdDSA = -8,
|
||||||
|
// Compatibility reasons
|
||||||
|
ECDH_ES_HKDF_256 = -25,
|
||||||
// Unsupported
|
// Unsupported
|
||||||
ES384 = -35,
|
ES384 = -35,
|
||||||
// Unsupported
|
// Unsupported
|
||||||
@ -214,7 +221,7 @@ impl<'de> Deserialize<'de> for PublicKeyCredentialAlgorithm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub enum CredProtect {
|
pub enum CredProtect {
|
||||||
VerificationOptional,
|
VerificationOptional,
|
||||||
VerificationOptionalWithCredentialIDList,
|
VerificationOptionalWithCredentialIDList,
|
||||||
@ -227,7 +234,7 @@ impl Default for CredProtect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct GetClientPinRequest {
|
pub struct GetClientPinRequest {
|
||||||
/// Not used in protocol but required to bump the packed index to 0x01
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
// 0x00
|
// 0x00
|
||||||
@ -252,7 +259,7 @@ pub struct GetClientPinRequest {
|
|||||||
#[serde(rename = "pinHashEnc", with = "serde_bytes", default)]
|
#[serde(rename = "pinHashEnc", with = "serde_bytes", default)]
|
||||||
pin_hash_enc: Vec<u8>,
|
pin_hash_enc: Vec<u8>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub enum GetClientPinSubommand {
|
pub enum GetClientPinSubommand {
|
||||||
/// Not used in protocol but required to bump the packed index to 0x01
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
// 0x00
|
// 0x00
|
||||||
@ -280,7 +287,7 @@ pub enum GetClientPinSubommand {
|
|||||||
GetUVRetries,
|
GetUVRetries,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct GetClientPinResponse {
|
pub struct GetClientPinResponse {
|
||||||
/// Not used in protocol but required to bump the packed index to 0x01
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
// 0x00
|
// 0x00
|
||||||
@ -312,32 +319,13 @@ pub struct GetClientPinResponse {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct CoseKey {
|
pub struct CoseKey {
|
||||||
/// Not used in protocol but required to bump the packed index to 0x01
|
|
||||||
// 0x00
|
|
||||||
// #[serde(default)]
|
|
||||||
//__bump: (),
|
|
||||||
// 0x01
|
// 0x01
|
||||||
//#[serde(rename = "type", default)]
|
|
||||||
type_: PublicKeyCredentialType,
|
type_: PublicKeyCredentialType,
|
||||||
// 0x02
|
// 0x02
|
||||||
//#[serde(with = "serde_bytes", default)]
|
|
||||||
id: Vec<u8>,
|
id: Vec<u8>,
|
||||||
// 0x03
|
// 0x03
|
||||||
alg: PublicKeyCredentialAlgorithm,
|
alg: PublicKeyCredentialAlgorithm,
|
||||||
parameters: BTreeMap<i32, serde_cbor::value::Value>,
|
// remainder
|
||||||
}
|
|
||||||
|
|
||||||
#[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>,
|
parameters: BTreeMap<i32, serde_cbor::value::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +334,9 @@ impl Serialize for CoseKey {
|
|||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
let mut s = serializer.serialize_map(Some(self.parameters.len() + 2 + (!self.id.is_empty()) as usize))?;
|
let mut s = serializer.serialize_map(Some(
|
||||||
|
self.parameters.len() + 2 + (!self.id.is_empty()) as usize,
|
||||||
|
))?;
|
||||||
s.serialize_entry(&0x01, &self.type_);
|
s.serialize_entry(&0x01, &self.type_);
|
||||||
if !self.id.is_empty() {
|
if !self.id.is_empty() {
|
||||||
s.serialize_entry(&0x02, &self.id);
|
s.serialize_entry(&0x02, &self.id);
|
||||||
@ -364,15 +354,17 @@ impl<'de> Deserialize<'de> for CoseKey {
|
|||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
|
|
||||||
enum Field {
|
enum Field {
|
||||||
Type, Alg, Id, Other(i32)
|
Type,
|
||||||
|
Alg,
|
||||||
|
Id,
|
||||||
|
Other(i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Field {
|
impl<'de> Deserialize<'de> for Field {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct FieldVisitor;
|
struct FieldVisitor;
|
||||||
|
|
||||||
@ -384,8 +376,8 @@ impl<'de> Deserialize<'de> for CoseKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
match value {
|
match value {
|
||||||
"alg" => Ok(Field::Alg),
|
"alg" => Ok(Field::Alg),
|
||||||
@ -394,24 +386,38 @@ impl<'de> Deserialize<'de> for CoseKey {
|
|||||||
_ => Err(de::Error::unknown_field(value, &["type", "alg", "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>
|
fn visit_i64<E>(self, value: i64) -> Result<Field, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
match value {
|
match value {
|
||||||
0x01 => Ok(Field::Type),
|
0x01 => Ok(Field::Type),
|
||||||
0x02 => Ok(Field::Id),
|
0x02 => Ok(Field::Id),
|
||||||
0x03=> Ok(Field::Alg),
|
0x03 => Ok(Field::Alg),
|
||||||
other => Ok(Field::Other(other as i32)),
|
other => Ok(Field::Other(other as i32)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_u64<E>(self, value: u64) -> Result<Field, E>
|
fn visit_u64<E>(self, value: u64) -> Result<Field, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
let signed: i64 = value as i64;
|
let signed: i64 = value as i64;
|
||||||
self.visit_i64(signed)
|
self.visit_i64(signed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,16 +444,18 @@ impl<'de> Deserialize<'de> for CoseKey {
|
|||||||
let mut parameters: BTreeMap<i32, serde_cbor::value::Value> = BTreeMap::new();
|
let mut parameters: BTreeMap<i32, serde_cbor::value::Value> = BTreeMap::new();
|
||||||
while let Some(k) = map.next_key()? {
|
while let Some(k) = map.next_key()? {
|
||||||
match k {
|
match k {
|
||||||
Field::Type => type_ = Some(map.next_value()?),
|
Field::Type => type_ = Some(map.next_value()?),
|
||||||
Field::Id => id = Some(map.next_value()?),
|
Field::Id => id = Some(map.next_value()?),
|
||||||
Field::Alg => alg = Some(map.next_value()?),
|
Field::Alg => alg = Some(map.next_value()?),
|
||||||
Field::Other(i) => {parameters.insert(i, 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 type_ = type_.ok_or_else(|| serde::de::Error::missing_field("type"))?;
|
||||||
let id = id.map(|id| id.into_vec()).unwrap_or_else(|| vec![]);
|
let id = id.map(|id| id.into_vec()).unwrap_or_else(|| vec![]);
|
||||||
let alg = alg.ok_or_else(|| serde::de::Error::missing_field("alg"))?;
|
let alg = alg.ok_or_else(|| serde::de::Error::missing_field("alg"))?;
|
||||||
Ok(CoseKey{
|
Ok(CoseKey {
|
||||||
type_,
|
type_,
|
||||||
id,
|
id,
|
||||||
alg,
|
alg,
|
||||||
@ -460,13 +468,246 @@ impl<'de> Deserialize<'de> for CoseKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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: 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 ,[u8]>,
|
||||||
|
#[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 ,[u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, Default, Clone, PartialEq, Eq)]
|
||||||
|
pub struct AuthenticatorOptions<'a> {
|
||||||
|
rk: bool,
|
||||||
|
uv: bool,
|
||||||
|
other: BTreeMap<Cow<'a, str>, bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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.other.len() + [self.rk, self.uv].iter().filter(|o| **o).count(),
|
||||||
|
))?;
|
||||||
|
for (k, v) in &[("rk", self.rk), ("uv", self.uv)] {
|
||||||
|
if *v {
|
||||||
|
s.serialize_entry(k, v)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (k, v) in &self.other {
|
||||||
|
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 {
|
||||||
|
RK,
|
||||||
|
UV,
|
||||||
|
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("type, alg, id or other")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
"rk" => Ok(Field::RK),
|
||||||
|
"uv" => Ok(Field::UV),
|
||||||
|
other => Ok(Field::Other(other.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
b"rk" => Ok(Field::RK),
|
||||||
|
b"uv" => Ok(Field::UV),
|
||||||
|
_ => Err(de::Error::unknown_field(
|
||||||
|
&format!("{:?}", value),
|
||||||
|
&["rk", "uv"],
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_identifier(FieldVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AuthenticatorOptionsVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for AuthenticatorOptionsVisitor {
|
||||||
|
type Value = AuthenticatorOptions<'static>;
|
||||||
|
|
||||||
|
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 = AuthenticatorOptions::default();
|
||||||
|
while let Some(k) = map.next_key()? {
|
||||||
|
match k {
|
||||||
|
Field::RK => options.rk = map.next_value()?,
|
||||||
|
Field::UV => options.uv = map.next_value()?,
|
||||||
|
Field::Other(i) => {
|
||||||
|
options.other.insert(Cow::Owned(i), map.next_value()?);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(AuthenticatorOptionsVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone,Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct MakeCredentialResponse {
|
||||||
|
/// Not used in protocol but required to bump the packed index to 0x01
|
||||||
|
// 0x00
|
||||||
|
#[serde(default)]
|
||||||
|
__bump: (),
|
||||||
|
// 0x01
|
||||||
|
fmt: String,
|
||||||
|
// 0x02
|
||||||
|
#[serde(rename = "authData", with = "serde_bytes")]
|
||||||
|
auth_data: Vec<u8>,
|
||||||
|
// 0x03
|
||||||
|
#[serde(rename = "attStmt")]
|
||||||
|
attestation_statement: BTreeMap<serde_cbor::value::Value, serde_cbor::value::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn assert_ok<O: Debug, E: Debug>(res: Result<O, E>) {
|
fn assert_ok<O: Debug, E: Debug>(res: Result<O, E>) {
|
||||||
assert!(dbg!(res).is_ok())
|
assert!(dbg!(res).is_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 = T::deserialize_cbor(&mut buf_slice).unwrap();
|
||||||
|
assert_eq!(val, val2);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod info {
|
mod info {
|
||||||
@ -477,7 +718,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn response_yubikey() {
|
fn response_yubikey() {
|
||||||
test_response(&[
|
test_response(&[
|
||||||
170, 1, 131, 102, 85, 50, 70, 95, 86, 50, 104, 70, 73, 68, 79, 95, 50, 95, 48, 108,
|
170, 1, 131, 102, 85, 50, 70, 95, 86, 50, 104, 70, 73, 68, 79, 95, 50, 95, 48, 108,
|
||||||
@ -495,7 +735,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn response_solokey() {
|
fn response_solokey() {
|
||||||
test_response(&[
|
test_response(&[
|
||||||
168, 1, 131, 102, 85, 50, 70, 95, 86, 50, 104, 70, 73, 68, 79, 95, 50, 95, 48, 108,
|
168, 1, 131, 102, 85, 50, 70, 95, 86, 50, 104, 70, 73, 68, 79, 95, 50, 95, 48, 108,
|
||||||
@ -520,8 +759,8 @@ mod test {
|
|||||||
|
|
||||||
fn test_response(mut resp: &[u8]) {
|
fn test_response(mut resp: &[u8]) {
|
||||||
let res = GetClientPinResponse::deserialize_cbor(&mut resp).unwrap();
|
let res = GetClientPinResponse::deserialize_cbor(&mut resp).unwrap();
|
||||||
let cose = res.key_agreement.unwrap();
|
//let cose = res.key_agreement;
|
||||||
dbg!(cose.alg);
|
//dbg!(cose.alg);
|
||||||
//assert_ne!(cose.alg, PublicKeyCredentialAlgorithm::Unknown);
|
//assert_ne!(cose.alg, PublicKeyCredentialAlgorithm::Unknown);
|
||||||
/*let mut buf = Vec::new();
|
/*let mut buf = Vec::new();
|
||||||
cose.serialize_cbor(&mut buf).unwrap();
|
cose.serialize_cbor(&mut buf).unwrap();
|
||||||
@ -534,23 +773,41 @@ mod test {
|
|||||||
test_request(&[162, 1, 1, 2, 2])
|
test_request(&[162, 1, 1, 2, 2])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn cose_key() -> CoseKey {
|
||||||
fn cose_key_round() {
|
CoseKey {
|
||||||
let key = CoseKey{
|
|
||||||
type_: PublicKeyCredentialType::PublicKey,
|
type_: PublicKeyCredentialType::PublicKey,
|
||||||
id: vec![1u8, 3 ,4, 5],
|
id: vec![8, 3, 4, 5],
|
||||||
alg: PublicKeyCredentialAlgorithm::PS512,
|
alg: PublicKeyCredentialAlgorithm::PS512,
|
||||||
parameters: vec![(-3, serde_cbor::value::Value::Text("test".into()))].into_iter().collect()
|
parameters: vec![
|
||||||
};
|
(-3, serde_cbor::value::Value::Text("test".into())),
|
||||||
let mut buf = Vec::new();
|
(
|
||||||
key.serialize_cbor(&mut buf).unwrap();
|
-42,
|
||||||
let mut buf_slice = &buf[..];
|
serde_cbor::value::Value::Bytes("test".as_bytes().to_vec()),
|
||||||
let key2 = CoseKey::deserialize_cbor(&mut buf_slice).unwrap();
|
),
|
||||||
assert_eq!(key, key2);
|
]
|
||||||
|
.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: vec![1, 2, 3, 4],
|
||||||
|
pin_retries: 3,
|
||||||
|
requires_power_cycle: true,
|
||||||
|
uv_retries: 1,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn resp_key_agreement_yubikey() {
|
fn resp_key_agreement_yubikey() {
|
||||||
test_response(&[
|
test_response(&[
|
||||||
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 225, 230, 133, 231, 92, 119, 250,
|
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 225, 230, 133, 231, 92, 119, 250,
|
||||||
@ -563,7 +820,6 @@ mod test {
|
|||||||
|
|
||||||
// SoloKey v1 fw 4.0.0
|
// SoloKey v1 fw 4.0.0
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn resp_key_agreement_solokey() {
|
fn resp_key_agreement_solokey() {
|
||||||
test_response(&[
|
test_response(&[
|
||||||
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 9, 161, 111, 235, 155, 109, 166,
|
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 9, 161, 111, 235, 155, 109, 166,
|
||||||
@ -576,7 +832,6 @@ mod test {
|
|||||||
|
|
||||||
// Trezor Model T fw 2.3.0
|
// Trezor Model T fw 2.3.0
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn resp_key_agreement_trezor() {
|
fn resp_key_agreement_trezor() {
|
||||||
test_response(&[
|
test_response(&[
|
||||||
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 164, 211, 77, 255, 139, 183, 45,
|
161, 1, 165, 1, 2, 3, 56, 24, 32, 1, 33, 88, 32, 164, 211, 77, 255, 139, 183, 45,
|
||||||
@ -587,6 +842,81 @@ mod test {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(&[0u8]),
|
||||||
|
name: Some("Tester".into()),
|
||||||
|
icon: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pubkey_cred_desc<'a>() -> PublicKeyCredentialDescriptor<'a> {
|
||||||
|
PublicKeyCredentialDescriptor{
|
||||||
|
type_: Default::default(),
|
||||||
|
id: Cow::Owned(vec![1, 2, 3, 4])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn authenticator_options<'a>() -> AuthenticatorOptions<'a> {
|
||||||
|
AuthenticatorOptions{
|
||||||
|
rk: false,
|
||||||
|
uv: true,
|
||||||
|
other: vec![(Cow::Borrowed("whatever the future may bring"), true)].into_iter().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_credential_request<'a>() -> MakeCredentialRequest<'a> {
|
||||||
|
MakeCredentialRequest{
|
||||||
|
__bump: (),
|
||||||
|
client_data_hash: Cow::Owned(serde_bytes::ByteBuf::from(vec![0u8; 32].into_boxed_slice())),
|
||||||
|
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: 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]
|
//#[test]
|
||||||
fn vec_layout() {
|
fn vec_layout() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user