response enum
This commit is contained in:
parent
317f5ebdb4
commit
48604d165b
@ -2,7 +2,7 @@
|
||||
use failure::_core::marker::PhantomData;
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use serde::de::{Error, MapAccess, Visitor};
|
||||
use serde::ser::{SerializeMap, SerializeStruct};
|
||||
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_cbor::de::IoRead;
|
||||
use serde_cbor::ser::IoWrite;
|
||||
@ -28,13 +28,14 @@ pub trait CborDeserializable<'a>: Deserialize<'a> {
|
||||
|
||||
impl<'a, T: Deserialize<'a>> CborDeserializable<'a> for T {}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub enum CborRequests<'a> {
|
||||
pub enum CborRequest<'a> {
|
||||
__Bump,
|
||||
// 0x01
|
||||
MakeCredential,
|
||||
MakeCredential(MakeCredentialRequest<'a>),
|
||||
// 0x02
|
||||
GetAssertion,
|
||||
GetAssertion(GetAssertionRequest<'a>),
|
||||
// 0x03
|
||||
___Unused,
|
||||
// 0x04
|
||||
@ -44,7 +45,7 @@ pub enum CborRequests<'a> {
|
||||
// 0x06
|
||||
ClientPin(GetClientPinRequest<'a>),
|
||||
// 0x07
|
||||
Reset,
|
||||
Reset(Reset),
|
||||
// 0x08
|
||||
GetNextAssertion,
|
||||
// 0x09
|
||||
@ -57,21 +58,106 @@ pub enum CborRequests<'a> {
|
||||
Config,
|
||||
}
|
||||
|
||||
pub type GetInfoRequest = ();
|
||||
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 {
|
||||
pub struct GetInfoResponse<'a> {
|
||||
/// Not used in protocol but required to bump the packed index to 0x01
|
||||
// 0x00
|
||||
#[serde(default)]
|
||||
__bump: (),
|
||||
// 0x01
|
||||
versions: Vec<String>,
|
||||
versions: Cow<'a, [Cow<'a, str>]>,
|
||||
// 0x02
|
||||
extensions: Vec<String>,
|
||||
extensions: Cow<'a, [Cow<'a, str>]>,
|
||||
// 0x03
|
||||
#[serde(with = "serde_bytes")]
|
||||
aaguid: Vec<u8>,
|
||||
aaguid: Cow<'a, serde_bytes::Bytes>,
|
||||
// 0x04
|
||||
options: GetInfoOptions,
|
||||
// FIDO2.1 from here on therefore optional
|
||||
@ -80,7 +166,7 @@ pub struct GetInfoResponse {
|
||||
max_msg_size: u64,
|
||||
// 0x06
|
||||
#[serde(rename = "pinUvAuthProtocols")]
|
||||
pin_auth_protocols: Vec<u64>,
|
||||
pin_auth_protocols: Cow<'a, [u64]>,
|
||||
// 0x07
|
||||
#[serde(rename = "maxCredentialCountInList", default)]
|
||||
max_credential_count: u64,
|
||||
@ -89,10 +175,10 @@ pub struct GetInfoResponse {
|
||||
max_credential_id_len: u64,
|
||||
// 0x09
|
||||
#[serde(default)]
|
||||
transports: Vec<String>,
|
||||
transports: Cow<'a, [Cow<'a, str>]>,
|
||||
// 0x0A
|
||||
#[serde(default)]
|
||||
algorithms: Vec<PublicKeyCredentialParameters>,
|
||||
algorithms: Cow<'a, [Cow<'a, PublicKeyCredentialParameters>]>,
|
||||
// 0x0B
|
||||
#[serde(rename = "maxAuthenticatorConfigLength", default)]
|
||||
max_config_len: u64,
|
||||
@ -272,6 +358,7 @@ pub struct GetClientPinRequest<'a> {
|
||||
#[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
|
||||
@ -790,6 +877,9 @@ pub struct GetAssertionResponse<'a> {
|
||||
credential_selected: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Reset;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
@ -826,6 +916,15 @@ mod test {
|
||||
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(&[
|
||||
|
9
src/transport/mod.rs
Normal file
9
src/transport/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::protocol::{CborRequest, CborResponse};
|
||||
|
||||
pub trait CtapTransport {
|
||||
type Error;
|
||||
|
||||
fn cbor<'a>(&mut self, command: &CborRequest<'a>) -> Result<CborResponse, Self::Error>;
|
||||
}
|
||||
|
||||
pub enum CtapCommand {}
|
Loading…
x
Reference in New Issue
Block a user