From bb202c8a54f835fd5ebeba7ffc3a23363a14ed41 Mon Sep 17 00:00:00 2001 From: shimun Date: Fri, 10 Apr 2020 20:55:53 +0200 Subject: [PATCH] implement fido 2.1 --- src/cbor.rs | 39 +++++++++++++++++++++++++++++++++------ src/lib.rs | 25 +++++++++++++++++++++++-- src/packet.rs | 9 ++++++++- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/cbor.rs b/src/cbor.rs index 24a6f56..7cdb27a 100644 --- a/src/cbor.rs +++ b/src/cbor.rs @@ -274,6 +274,12 @@ pub struct GetInfoResponse { pub options: OptionsInfo, pub max_msg_size: u16, pub pin_protocols: Vec, + pub max_credential_count_in_list: Option, + pub max_credential_id_len: Option, + pub transports: Vec, + pub algorithms: Vec, + pub max_authenticator_config_len: Option, + pub default_cred_protect: Option, } impl GetInfoResponse { @@ -282,28 +288,49 @@ impl GetInfoResponse { if status != 0 { Err(FidoErrorKind::CborError(CborErrorCode::from(status)))? } - let mut decoder = Decoder::new(Config::default(), reader); + let mut generic = GenericDecoder::new(Config::default(), reader); let mut response = GetInfoResponse::default(); - for _ in 0..decoder.object()? { - match decoder.u8()? { + for _ in 0..generic.borrow_mut().object()? { + match generic.borrow_mut().u8()? { 0x01 => { + let decoder = generic.borrow_mut(); for _ in 0..decoder.array()? { response.versions.push(decoder.text()?); } } 0x02 => { + let decoder = generic.borrow_mut(); for _ in 0..decoder.array()? { response.extensions.push(decoder.text()?); } } - 0x03 => response.aaguid.copy_from_slice(&decoder.bytes()?[..]), - 0x04 => response.options = OptionsInfo::decode(&mut decoder)?, - 0x05 => response.max_msg_size = decoder.u16()?, + 0x03 => response + .aaguid + .copy_from_slice(&generic.borrow_mut().bytes()?[..]), + 0x04 => response.options = OptionsInfo::decode(&mut generic.borrow_mut())?, + 0x05 => response.max_msg_size = generic.borrow_mut().u16()?, 0x06 => { + let decoder = generic.borrow_mut(); for _ in 0..decoder.array()? { response.pin_protocols.push(decoder.u8()?); } } + 0x07 => response.max_credential_count_in_list = Some(generic.borrow_mut().u32()?), + 0x08 => response.max_credential_id_len = Some(generic.borrow_mut().u32()?), + 0x09 => { + let decoder = generic.borrow_mut(); + for _ in 0..decoder.array()? { + response.transports.push(decoder.text()?); + } + } + 0x0A => { + for _ in 0..generic.borrow_mut().array()? { + response.algorithms.push(CoseKey::decode(&mut generic)?); + } + } + 0x0B => response.max_authenticator_config_len = Some(generic.borrow_mut().u32()?), + + 0x0C => response.default_cred_protect = Some(generic.borrow_mut().u8()?), _ => continue, } } diff --git a/src/lib.rs b/src/lib.rs index d30b36f..61739f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,7 @@ use self::hid_linux as hid; use self::packet::CtapCommand; pub use self::util::*; use crate::cbor::{AuthenticatorData, GetAssertionRequest}; +use crate::packet::CtapStatus; use failure::{Fail, ResultExt}; use num_traits::FromPrimitive; use rand::prelude::*; @@ -117,7 +118,7 @@ pub struct FidoCancelHandle { impl FidoCancelHandle { pub fn cancel(&mut self) -> FidoResult<()> { - let payload = &[1u8]; + let payload = &[]; let to_send = payload.len() as u16; let max_payload = (self.packet_size - 7) as usize; let (frame, payload) = payload.split_at(cmp::min(payload.len(), max_payload)); @@ -538,6 +539,26 @@ impl FidoDevice { .map(|cred| (cred, response.auth_data)) } + pub fn ping(&mut self, data: &[u8]) -> FidoResult> { + self.exchange(CtapCommand::Ping, data) + } + + pub fn wink(&mut self) -> FidoResult<()> { + self.send(&CtapCommand::Wink, &[]).map(|_| ()) + } + + fn lock(&mut self, time_sec: u8) -> FidoResult<()> { + self.exchange(CtapCommand::Lock, &[time_sec]).map(|_| ()) + } + + fn keepalive(&mut self) -> FidoResult { + self.exchange(CtapCommand::Keepalive, &[])? + .first() + .cloned() + .and_then(CtapStatus::from_u8) + .ok_or(FidoError::from(FidoErrorKind::CborDecode)) + } + fn cbor(&mut self, request: cbor::Request) -> FidoResult { let mut buf = Cursor::new(Vec::new()); request @@ -556,7 +577,7 @@ impl FidoDevice { } fn send(&mut self, cmd: &CtapCommand, payload: &[u8]) -> FidoResult<()> { - if payload.is_empty() || payload.len() > u16::MAX as usize { + if payload.len() > u16::MAX as usize { Err(FidoErrorKind::WritePacket)? } let to_send = payload.len() as u16; diff --git a/src/packet.rs b/src/packet.rs index e7108e8..3eae0aa 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -13,7 +13,7 @@ use std::io::{Read, Write}; static FRAME_INIT: u8 = 0x80; #[repr(u8)] -#[derive(FromPrimitive, ToPrimitive, PartialEq)] +#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq)] pub enum CtapCommand { Invalid = 0x00, Ping = 0x01, @@ -36,6 +36,13 @@ impl CtapCommand { } } +#[repr(u8)] +#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq)] +pub enum CtapStatus { + Processing = 0x01, + AwaitingUserPresence = 0x02, +} + #[repr(u8)] #[derive(FromPrimitive, Fail, Debug)] pub enum CtapError {