response enum

This commit is contained in:
shimun 2020-05-06 23:47:33 +02:00
parent 317f5ebdb4
commit 48604d165b
Signed by: shimun
GPG Key ID: E81D8382DC2F971B
2 changed files with 122 additions and 14 deletions

View File

@ -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
View 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 {}