CTAP HID Lock (#605)
* Implements the CTAP HID Lock command This is a direct translation of our internal implementation. * adds more HID Lock tests
This commit is contained in:
@@ -85,7 +85,7 @@ fn initialize(ctap: &mut Ctap<TestEnv>) -> ChannelID {
|
||||
let mut result_cid: ChannelID = Default::default();
|
||||
for pkt_request in HidPacketIterator::new(message).unwrap() {
|
||||
for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) {
|
||||
if let Ok(Some(result)) = assembler_reply.parse_packet(ctap.env(), &pkt_reply) {
|
||||
if let Ok(Some(result)) = assembler_reply.parse_packet(ctap.env(), &pkt_reply, None) {
|
||||
result_cid.copy_from_slice(&result.payload[8..12]);
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) {
|
||||
for pkt_request in hid_packet_iterator {
|
||||
for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) {
|
||||
// Only checks for assembling crashes, not for semantics.
|
||||
let _ = assembler_reply.parse_packet(ctap.env(), &pkt_reply);
|
||||
let _ = assembler_reply.parse_packet(ctap.env(), &pkt_reply, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,10 +264,10 @@ pub fn split_assemble_hid_packets(data: &[u8]) -> arbitrary::Result<()> {
|
||||
let packets: Vec<HidPacket> = hid_packet_iterator.collect();
|
||||
if let Some((last_packet, first_packets)) = packets.split_last() {
|
||||
for packet in first_packets {
|
||||
assert_eq!(assembler.parse_packet(&mut env, packet), Ok(None));
|
||||
assert_eq!(assembler.parse_packet(&mut env, packet, None), Ok(None));
|
||||
}
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, last_packet),
|
||||
assembler.parse_packet(&mut env, last_packet, None),
|
||||
Ok(Some(message))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ pub use self::receive::MessageAssembler;
|
||||
use self::receive::MessageAssembler;
|
||||
pub use self::send::HidPacketIterator;
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use crate::api::clock::Clock;
|
||||
#[cfg(test)]
|
||||
use crate::env::test::TestEnv;
|
||||
use crate::env::Env;
|
||||
@@ -55,7 +56,6 @@ pub type ChannelID = [u8; 4];
|
||||
pub enum CtapHidCommand {
|
||||
Ping = 0x01,
|
||||
Msg = 0x03,
|
||||
// Lock is optional and may be used in the future.
|
||||
Lock = 0x04,
|
||||
Init = 0x06,
|
||||
Wink = 0x08,
|
||||
@@ -92,7 +92,7 @@ pub enum CtapHidError {
|
||||
/// The command in the request is invalid.
|
||||
InvalidCmd = 0x01,
|
||||
/// A parameter in the request is invalid.
|
||||
_InvalidPar = 0x02,
|
||||
InvalidPar = 0x02,
|
||||
/// The length of a message is too big.
|
||||
InvalidLen = 0x03,
|
||||
/// Expected a continuation packet with a specific sequence number, got another sequence number.
|
||||
@@ -187,6 +187,8 @@ pub struct CtapHid<E: Env> {
|
||||
// TODO(kaczmarczyck) We might want to limit or timeout open channels.
|
||||
allocated_cids: usize,
|
||||
capabilities: u8,
|
||||
locked_cid: Option<ChannelID>,
|
||||
lock_timer: <E::Clock as Clock>::Timer,
|
||||
}
|
||||
|
||||
impl<E: Env> CtapHid<E> {
|
||||
@@ -203,17 +205,31 @@ impl<E: Env> CtapHid<E> {
|
||||
assembler: MessageAssembler::default(),
|
||||
allocated_cids: 0,
|
||||
capabilities,
|
||||
locked_cid: None,
|
||||
lock_timer: <E::Clock as Clock>::Timer::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn locked_channel(&mut self, env: &mut E) -> Option<ChannelID> {
|
||||
if env.clock().is_elapsed(&self.lock_timer) {
|
||||
self.locked_cid = None;
|
||||
}
|
||||
self.locked_cid
|
||||
}
|
||||
|
||||
/// Returns whether this transport claims a lock.
|
||||
pub fn has_channel_lock(&mut self, env: &mut E) -> bool {
|
||||
self.locked_channel(env).is_some()
|
||||
}
|
||||
|
||||
/// Parses a packet, and preprocesses some messages and errors.
|
||||
///
|
||||
/// The preprocessed commands are:
|
||||
/// - INIT
|
||||
/// - CANCEL
|
||||
/// - LOCK
|
||||
/// - ERROR
|
||||
/// - Unknown and unexpected commands like KEEPALIVE
|
||||
/// - LOCK is not implemented and currently treated like an unknown command
|
||||
///
|
||||
/// Commands that may still be processed:
|
||||
/// - PING
|
||||
@@ -225,11 +241,23 @@ impl<E: Env> CtapHid<E> {
|
||||
/// Ignoring the others is incorrect behavior. You have to at least replace them with an error
|
||||
/// message:
|
||||
/// `Self::error_message(message.cid, CtapHidError::InvalidCmd)`
|
||||
pub fn parse_packet(&mut self, env: &mut E, packet: &HidPacket) -> Option<Message> {
|
||||
match self.assembler.parse_packet(env, packet) {
|
||||
pub fn parse_packet(
|
||||
&mut self,
|
||||
env: &mut E,
|
||||
packet: &HidPacket,
|
||||
is_transport_disabled: bool,
|
||||
) -> Option<Message> {
|
||||
let locked_cid = if is_transport_disabled {
|
||||
// We use the reserved channel ID to block all valid channels. If we also think we hold
|
||||
// a lock, we wait and rely on timeouts to resolve the deadlock.
|
||||
Some(CHANNEL_RESERVED)
|
||||
} else {
|
||||
self.locked_channel(env)
|
||||
};
|
||||
match self.assembler.parse_packet(env, packet, locked_cid) {
|
||||
Ok(Some(message)) => {
|
||||
debug_ctap!(env, "Received message: {:02x?}", message);
|
||||
self.preprocess_message(message)
|
||||
self.preprocess_message(env, message)
|
||||
}
|
||||
Ok(None) => {
|
||||
// Waiting for more packets to assemble the message, nothing to send for now.
|
||||
@@ -252,10 +280,10 @@ impl<E: Env> CtapHid<E> {
|
||||
/// The preprocessed commands are:
|
||||
/// - INIT
|
||||
/// - CANCEL
|
||||
/// - LOCK
|
||||
/// - ERROR
|
||||
/// - Unknown and unexpected commands like KEEPALIVE
|
||||
/// - LOCK is not implemented and currently treated like an unknown command
|
||||
fn preprocess_message(&mut self, message: Message) -> Option<Message> {
|
||||
fn preprocess_message(&mut self, env: &mut E, message: Message) -> Option<Message> {
|
||||
let cid = message.cid;
|
||||
if !self.has_valid_channel(&message) {
|
||||
return Some(Self::error_message(cid, CtapHidError::InvalidChannel));
|
||||
@@ -306,6 +334,26 @@ impl<E: Env> CtapHid<E> {
|
||||
None
|
||||
}
|
||||
CtapHidCommand::Wink => Some(message),
|
||||
CtapHidCommand::Lock => {
|
||||
if message.payload.len() != 1 {
|
||||
return Some(Self::error_message(cid, CtapHidError::InvalidLen));
|
||||
}
|
||||
if message.payload[0] > 10 {
|
||||
return Some(Self::error_message(cid, CtapHidError::InvalidPar));
|
||||
}
|
||||
if message.payload[0] == 0 {
|
||||
self.locked_cid = None;
|
||||
} else {
|
||||
self.locked_cid = Some(cid);
|
||||
let lock_duration_ms = 1000 * message.payload[0] as usize;
|
||||
self.lock_timer = env.clock().make_timer(lock_duration_ms);
|
||||
}
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Lock,
|
||||
payload: Vec::new(),
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
// Unknown or unsupported command.
|
||||
Some(Self::error_message(cid, CtapHidError::InvalidCmd))
|
||||
@@ -399,6 +447,8 @@ impl<E: Env> CtapHid<E> {
|
||||
assembler: MessageAssembler::default(),
|
||||
allocated_cids: 1,
|
||||
capabilities: 0x0D,
|
||||
locked_cid: None,
|
||||
lock_timer: <E::Clock as Clock>::Timer::default(),
|
||||
},
|
||||
[0x00, 0x00, 0x00, 0x01],
|
||||
)
|
||||
@@ -422,7 +472,7 @@ mod test {
|
||||
let mut messages = Vec::new();
|
||||
let mut assembler = MessageAssembler::<TestEnv>::default();
|
||||
for packet in HidPacketIterator::new(message.clone()).unwrap() {
|
||||
match assembler.parse_packet(&mut env, &packet) {
|
||||
match assembler.parse_packet(&mut env, &packet, None) {
|
||||
Ok(Some(msg)) => messages.push(msg),
|
||||
Ok(None) => (),
|
||||
Err(_) => panic!("Couldn't assemble packet: {:02x?}", &packet as &[u8]),
|
||||
@@ -440,18 +490,19 @@ mod test {
|
||||
let mut packet = [0x00; 64];
|
||||
packet[0..7].copy_from_slice(&[0xC1, 0xC1, 0xC1, 0xC1, 0x00, 0x51, 0x51]);
|
||||
// Continuation packets are silently ignored.
|
||||
assert_eq!(ctap_hid.parse_packet(&mut env, &packet), None);
|
||||
assert_eq!(ctap_hid.parse_packet(&mut env, &packet, false), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_init() {
|
||||
let mut env = TestEnv::default();
|
||||
let mut ctap_hid = CtapHid::<TestEnv>::new(0x0D);
|
||||
let init_message = Message {
|
||||
cid: CHANNEL_BROADCAST,
|
||||
cmd: CtapHidCommand::Init,
|
||||
payload: vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0],
|
||||
};
|
||||
let reply = ctap_hid.preprocess_message(init_message);
|
||||
let reply = ctap_hid.preprocess_message(&mut env, init_message);
|
||||
assert_eq!(
|
||||
reply,
|
||||
Some(Message {
|
||||
@@ -483,9 +534,9 @@ mod test {
|
||||
packet2[4..15].copy_from_slice(&[
|
||||
0x86, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
|
||||
]);
|
||||
assert_eq!(ctap_hid.parse_packet(&mut env, &packet1), None);
|
||||
assert_eq!(ctap_hid.parse_packet(&mut env, &packet1, false), None);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &packet2),
|
||||
ctap_hid.parse_packet(&mut env, &packet2, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Init,
|
||||
@@ -509,7 +560,7 @@ mod test {
|
||||
ping_packet[..4].copy_from_slice(&cid);
|
||||
ping_packet[4..9].copy_from_slice(&[0x81, 0x00, 0x02, 0x99, 0x99]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &ping_packet),
|
||||
ctap_hid.parse_packet(&mut env, &ping_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Ping,
|
||||
@@ -527,7 +578,7 @@ mod test {
|
||||
cancel_packet[..4].copy_from_slice(&cid);
|
||||
cancel_packet[4..7].copy_from_slice(&[0x91, 0x00, 0x00]);
|
||||
|
||||
let response = ctap_hid.parse_packet(&mut env, &cancel_packet);
|
||||
let response = ctap_hid.parse_packet(&mut env, &cancel_packet, false);
|
||||
assert_eq!(response, None);
|
||||
}
|
||||
|
||||
@@ -619,4 +670,153 @@ mod test {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_locked_channel_id() {
|
||||
let mut env = TestEnv::default();
|
||||
let (mut ctap_hid, cid) = CtapHid::<TestEnv>::new_initialized();
|
||||
|
||||
let mut init_packet = [0x00; 64];
|
||||
init_packet[..4].copy_from_slice(&[0xFF; 4]);
|
||||
init_packet[4..15].copy_from_slice(&[
|
||||
0x86, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
|
||||
]);
|
||||
let init_response = ctap_hid
|
||||
.parse_packet(&mut env, &init_packet, false)
|
||||
.unwrap();
|
||||
assert_eq!(init_response.cmd, CtapHidCommand::Init);
|
||||
let new_cid = *array_ref!(init_response.payload, 8, 4);
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&cid);
|
||||
lock_packet[4..8].copy_from_slice(&[0x84, 0x00, 0x01, 0x01]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Lock,
|
||||
payload: vec![]
|
||||
})
|
||||
);
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&new_cid);
|
||||
lock_packet[4..8].copy_from_slice(&[0x84, 0x00, 0x01, 0x00]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid: new_cid,
|
||||
cmd: CtapHidCommand::Error,
|
||||
payload: vec![0x06]
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_locked_transport() {
|
||||
let mut env = TestEnv::default();
|
||||
let (mut ctap_hid, cid) = CtapHid::<TestEnv>::new_initialized();
|
||||
|
||||
let mut ping_packet = [0x00; 64];
|
||||
ping_packet[..4].copy_from_slice(&cid);
|
||||
ping_packet[4..9].copy_from_slice(&[0x81, 0x00, 0x02, 0x99, 0x99]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &ping_packet, true),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Error,
|
||||
payload: vec![0x06]
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_lock_expires() {
|
||||
let mut env = TestEnv::default();
|
||||
let (mut ctap_hid, cid) = CtapHid::<TestEnv>::new_initialized();
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&cid);
|
||||
lock_packet[4..8].copy_from_slice(&[0x84, 0x00, 0x01, 0x01]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Lock,
|
||||
payload: vec![]
|
||||
})
|
||||
);
|
||||
assert!(ctap_hid.has_channel_lock(&mut env));
|
||||
env.clock().advance(999);
|
||||
assert!(ctap_hid.has_channel_lock(&mut env));
|
||||
env.clock().advance(1);
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_lock_releases() {
|
||||
let mut env = TestEnv::default();
|
||||
let (mut ctap_hid, cid) = CtapHid::<TestEnv>::new_initialized();
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&cid);
|
||||
lock_packet[4..8].copy_from_slice(&[0x84, 0x00, 0x01, 0x01]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Lock,
|
||||
payload: vec![]
|
||||
})
|
||||
);
|
||||
assert!(ctap_hid.has_channel_lock(&mut env));
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&cid);
|
||||
lock_packet[4..8].copy_from_slice(&[0x84, 0x00, 0x01, 0x00]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Lock,
|
||||
payload: vec![]
|
||||
})
|
||||
);
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_lock_invalid() {
|
||||
let mut env = TestEnv::default();
|
||||
let (mut ctap_hid, cid) = CtapHid::<TestEnv>::new_initialized();
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&cid);
|
||||
lock_packet[4..8].copy_from_slice(&[0x84, 0x00, 0x01, 0x0B]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Error,
|
||||
payload: vec![0x02]
|
||||
})
|
||||
);
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
|
||||
let mut lock_packet = [0x00; 64];
|
||||
lock_packet[..4].copy_from_slice(&cid);
|
||||
lock_packet[4..9].copy_from_slice(&[0x84, 0x00, 0x02, 0x01, 0x01]);
|
||||
assert_eq!(
|
||||
ctap_hid.parse_packet(&mut env, &lock_packet, false),
|
||||
Some(Message {
|
||||
cid,
|
||||
cmd: CtapHidCommand::Error,
|
||||
payload: vec![0x03]
|
||||
})
|
||||
);
|
||||
assert!(!ctap_hid.has_channel_lock(&mut env));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +78,14 @@ impl<E: Env> MessageAssembler<E> {
|
||||
&mut self,
|
||||
env: &mut E,
|
||||
packet: &HidPacket,
|
||||
locked_cid: Option<ChannelID>,
|
||||
) -> Result<Option<Message>, (ChannelID, CtapHidError)> {
|
||||
// TODO: Support non-full-speed devices (i.e. packet len != 64)? This isn't recommended by
|
||||
// section 8.8.1
|
||||
let (cid, processed_packet) = CtapHid::<E>::process_single_packet(packet);
|
||||
if let Some(locked_cid) = locked_cid {
|
||||
if locked_cid != cid {
|
||||
return Err((cid, CtapHidError::ChannelBusy));
|
||||
}
|
||||
}
|
||||
|
||||
if !self.idle && env.clock().is_elapsed(&self.timer) {
|
||||
// The current channel timed out.
|
||||
@@ -212,7 +216,11 @@ mod test {
|
||||
let mut env = TestEnv::default();
|
||||
let mut assembler = MessageAssembler::default();
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90]),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Cbor,
|
||||
@@ -229,6 +237,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10]),
|
||||
None,
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
@@ -249,6 +258,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10], 0xFF),
|
||||
None,
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
@@ -266,11 +276,16 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Ping,
|
||||
@@ -287,15 +302,24 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x80]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
|
||||
None
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Ping,
|
||||
@@ -312,17 +336,26 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x1D, 0xB9]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
for seq in 0..0x7F {
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]),
|
||||
None
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Ping,
|
||||
@@ -348,6 +381,7 @@ mod test {
|
||||
&[0x12, 0x34, 0x56, 0x78, 0x80 | cmd as u8, 0x00, 0x80],
|
||||
byte
|
||||
),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
@@ -355,6 +389,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x00], byte),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
@@ -362,6 +397,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x01], byte),
|
||||
None,
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
@@ -387,17 +423,24 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, cid, 0x80 | cmd as u8, 0x00, 0x80], byte),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler
|
||||
.parse_packet(&mut env, &byte_extend(&[0x12, 0x34, 0x56, cid, 0x00], byte)),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, cid, 0x00], byte),
|
||||
None
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler
|
||||
.parse_packet(&mut env, &byte_extend(&[0x12, 0x34, 0x56, cid, 0x01], byte)),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, cid, 0x01], byte),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, cid],
|
||||
cmd,
|
||||
@@ -415,6 +458,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
@@ -427,6 +471,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, 0x9A, cmd as u8, 0x00], byte),
|
||||
None,
|
||||
),
|
||||
Err(([0x12, 0x34, 0x56, 0x9A], CtapHidError::ChannelBusy))
|
||||
);
|
||||
@@ -434,7 +479,11 @@ mod test {
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Ping,
|
||||
@@ -457,6 +506,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x10], byte),
|
||||
None,
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
@@ -468,7 +518,11 @@ mod test {
|
||||
// Spurious continuation packet.
|
||||
let seq = i;
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]),
|
||||
None
|
||||
),
|
||||
Err((
|
||||
[0x12, 0x34, 0x56, 0x78],
|
||||
CtapHidError::UnexpectedContinuation
|
||||
@@ -485,11 +539,16 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x80])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x80]),
|
||||
None
|
||||
),
|
||||
Err(([0x12, 0x34, 0x56, 0x78], CtapHidError::InvalidSeq))
|
||||
);
|
||||
}
|
||||
@@ -502,11 +561,16 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]),
|
||||
None
|
||||
),
|
||||
Err(([0x12, 0x34, 0x56, 0x78], CtapHidError::InvalidSeq))
|
||||
);
|
||||
}
|
||||
@@ -519,12 +583,17 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
env.clock().advance(TIMEOUT_DURATION_MS);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
|
||||
None
|
||||
),
|
||||
Err(([0x12, 0x34, 0x56, 0x78], CtapHidError::MsgTimeout))
|
||||
);
|
||||
}
|
||||
@@ -540,19 +609,28 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x1D, 0xB9]),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
for seq in 0..0x7F {
|
||||
env.clock().advance(delay);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]),
|
||||
None
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
}
|
||||
env.clock().advance(delay);
|
||||
assert_eq!(
|
||||
assembler.parse_packet(&mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F])),
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]),
|
||||
None
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Ping,
|
||||
@@ -570,6 +648,7 @@ mod test {
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x02, 0x00], 0x51),
|
||||
None,
|
||||
),
|
||||
Ok(None)
|
||||
);
|
||||
@@ -581,6 +660,7 @@ mod test {
|
||||
0x12, 0x34, 0x56, 0x78, 0x86, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
|
||||
0xDE, 0xF0
|
||||
]),
|
||||
None,
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
@@ -590,5 +670,37 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_locked_channel() {
|
||||
let mut env = TestEnv::default();
|
||||
let mut assembler = MessageAssembler::<TestEnv>::default();
|
||||
assert_eq!(
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10]),
|
||||
Some([0x12, 0x34, 0x56, 0x78]),
|
||||
),
|
||||
Ok(Some(Message {
|
||||
cid: [0x12, 0x34, 0x56, 0x78],
|
||||
cmd: CtapHidCommand::Cbor,
|
||||
payload: vec![0x00; 0x10]
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_other_locked_channel() {
|
||||
let mut env = TestEnv::default();
|
||||
let mut assembler = MessageAssembler::<TestEnv>::default();
|
||||
assert_eq!(
|
||||
assembler.parse_packet(
|
||||
&mut env,
|
||||
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10]),
|
||||
Some([0xAA, 0xAA, 0xAA, 0xAA]),
|
||||
),
|
||||
Err(([0x12, 0x34, 0x56, 0x78], CtapHidError::ChannelBusy))
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: more tests
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
use crypto::sha256::Sha256;
|
||||
use crypto::Hash256;
|
||||
|
||||
/// The length of the truncated hash that as appended to the large blob data.
|
||||
/// The length of the truncated hash that is appended to the large blob data.
|
||||
const TRUNCATED_HASH_LEN: usize = 16;
|
||||
|
||||
pub struct LargeBlobs {
|
||||
|
||||
@@ -56,9 +56,10 @@ impl<E: Env> MainHid<E> {
|
||||
&mut self,
|
||||
env: &mut E,
|
||||
packet: &HidPacket,
|
||||
is_transport_disabled: bool,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
) -> HidPacketIterator {
|
||||
if let Some(message) = self.hid.parse_packet(env, packet) {
|
||||
if let Some(message) = self.hid.parse_packet(env, packet, is_transport_disabled) {
|
||||
let processed_message = self.process_message(env, message, ctap_state);
|
||||
debug_ctap!(env, "Sending message: {:02x?}", processed_message);
|
||||
CtapHid::<E>::split_message(processed_message)
|
||||
@@ -119,6 +120,11 @@ impl<E: Env> MainHid<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this transport claims a lock.
|
||||
pub fn has_channel_lock(&mut self, env: &mut E) -> bool {
|
||||
self.hid.has_channel_lock(env)
|
||||
}
|
||||
|
||||
/// Returns whether a wink permission is currently granted.
|
||||
pub fn should_wink(&self, env: &mut E) -> bool {
|
||||
!env.clock().is_elapsed(&self.wink_permission)
|
||||
@@ -175,7 +181,8 @@ mod test {
|
||||
ping_packet[..4].copy_from_slice(&cid);
|
||||
ping_packet[4..9].copy_from_slice(&[0x81, 0x00, 0x02, 0x99, 0x99]);
|
||||
|
||||
let mut response = main_hid.process_hid_packet(&mut env, &ping_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
main_hid.process_hid_packet(&mut env, &ping_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), Some(ping_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
@@ -190,7 +197,8 @@ mod test {
|
||||
cancel_packet[..4].copy_from_slice(&cid);
|
||||
cancel_packet[4..7].copy_from_slice(&[0x91, 0x00, 0x00]);
|
||||
|
||||
let mut response = main_hid.process_hid_packet(&mut env, &cancel_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
main_hid.process_hid_packet(&mut env, &cancel_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
|
||||
@@ -205,11 +213,31 @@ mod test {
|
||||
wink_packet[..4].copy_from_slice(&cid);
|
||||
wink_packet[4..7].copy_from_slice(&[0x88, 0x00, 0x00]);
|
||||
|
||||
let mut response = main_hid.process_hid_packet(&mut env, &wink_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
main_hid.process_hid_packet(&mut env, &wink_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), Some(wink_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
assert!(main_hid.should_wink(&mut env));
|
||||
env.clock().advance(WINK_TIMEOUT_DURATION_MS);
|
||||
assert!(!main_hid.should_wink(&mut env));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_locked_channels() {
|
||||
let mut env = TestEnv::default();
|
||||
let mut ctap_state = CtapState::<TestEnv>::new(&mut env);
|
||||
let (mut main_hid, cid) = new_initialized();
|
||||
|
||||
let mut ping_packet = [0x00; 64];
|
||||
ping_packet[..4].copy_from_slice(&cid);
|
||||
ping_packet[4..9].copy_from_slice(&[0x81, 0x00, 0x02, 0x99, 0x99]);
|
||||
|
||||
let mut response =
|
||||
main_hid.process_hid_packet(&mut env, &ping_packet, true, &mut ctap_state);
|
||||
let mut error_packet = [0x00; 64];
|
||||
error_packet[..4].copy_from_slice(&cid);
|
||||
error_packet[4..8].copy_from_slice(&[0xBF, 0x00, 0x01, 0x06]);
|
||||
assert_eq!(response.next(), Some(error_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,10 @@ impl<E: Env> VendorHid<E> {
|
||||
&mut self,
|
||||
env: &mut E,
|
||||
packet: &HidPacket,
|
||||
is_transport_disabled: bool,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
) -> HidPacketIterator {
|
||||
if let Some(message) = self.hid.parse_packet(env, packet) {
|
||||
if let Some(message) = self.hid.parse_packet(env, packet, is_transport_disabled) {
|
||||
let processed_message = self.process_message(env, message, ctap_state);
|
||||
debug_ctap!(
|
||||
env,
|
||||
@@ -81,6 +82,11 @@ impl<E: Env> VendorHid<E> {
|
||||
_ => message,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this transport claims a lock.
|
||||
pub fn has_channel_lock(&mut self, env: &mut E) -> bool {
|
||||
self.hid.has_channel_lock(env)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -104,7 +110,8 @@ mod test {
|
||||
ping_packet[..4].copy_from_slice(&cid);
|
||||
ping_packet[4..9].copy_from_slice(&[0x81, 0x00, 0x02, 0x99, 0x99]);
|
||||
|
||||
let mut response = vendor_hid.process_hid_packet(&mut env, &ping_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
vendor_hid.process_hid_packet(&mut env, &ping_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), Some(ping_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
@@ -119,7 +126,8 @@ mod test {
|
||||
cancel_packet[..4].copy_from_slice(&cid);
|
||||
cancel_packet[4..7].copy_from_slice(&[0x91, 0x00, 0x00]);
|
||||
|
||||
let mut response = vendor_hid.process_hid_packet(&mut env, &cancel_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
vendor_hid.process_hid_packet(&mut env, &cancel_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
|
||||
@@ -142,11 +150,32 @@ mod test {
|
||||
error_packet[..4].copy_from_slice(&cid);
|
||||
error_packet[4..8].copy_from_slice(&[0xBF, 0x00, 0x01, 0x01]);
|
||||
|
||||
let mut response = vendor_hid.process_hid_packet(&mut env, &msg_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
vendor_hid.process_hid_packet(&mut env, &msg_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), Some(error_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
|
||||
let mut response = vendor_hid.process_hid_packet(&mut env, &wink_packet, &mut ctap_state);
|
||||
let mut response =
|
||||
vendor_hid.process_hid_packet(&mut env, &wink_packet, false, &mut ctap_state);
|
||||
assert_eq!(response.next(), Some(error_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_locked_channels() {
|
||||
let mut env = TestEnv::default();
|
||||
let mut ctap_state = CtapState::<TestEnv>::new(&mut env);
|
||||
let (mut vendor_hid, cid) = new_initialized();
|
||||
|
||||
let mut ping_packet = [0x00; 64];
|
||||
ping_packet[..4].copy_from_slice(&cid);
|
||||
ping_packet[4..9].copy_from_slice(&[0x81, 0x00, 0x02, 0x99, 0x99]);
|
||||
|
||||
let mut response =
|
||||
vendor_hid.process_hid_packet(&mut env, &ping_packet, true, &mut ctap_state);
|
||||
let mut error_packet = [0x00; 64];
|
||||
error_packet[..4].copy_from_slice(&cid);
|
||||
error_packet[4..8].copy_from_slice(&[0xBF, 0x00, 0x01, 0x06]);
|
||||
assert_eq!(response.next(), Some(error_packet));
|
||||
assert_eq!(response.next(), None);
|
||||
}
|
||||
|
||||
@@ -96,13 +96,22 @@ impl<E: Env> Ctap<E> {
|
||||
) -> HidPacketIterator {
|
||||
match transport {
|
||||
Transport::MainHid => {
|
||||
#[cfg(not(feature = "vendor_hid"))]
|
||||
let is_disabled = false;
|
||||
#[cfg(feature = "vendor_hid")]
|
||||
let is_disabled = self.vendor_hid.has_channel_lock(&mut self.env);
|
||||
self.hid
|
||||
.process_hid_packet(&mut self.env, packet, &mut self.state)
|
||||
.process_hid_packet(&mut self.env, packet, is_disabled, &mut self.state)
|
||||
}
|
||||
#[cfg(feature = "vendor_hid")]
|
||||
Transport::VendorHid => {
|
||||
self.vendor_hid
|
||||
.process_hid_packet(&mut self.env, packet, &mut self.state)
|
||||
let is_disabled = self.hid.has_channel_lock(&mut self.env);
|
||||
self.vendor_hid.process_hid_packet(
|
||||
&mut self.env,
|
||||
packet,
|
||||
is_disabled,
|
||||
&mut self.state,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,3 +130,96 @@ impl<E: Env> Ctap<E> {
|
||||
self.state.u2f_needs_user_presence(&mut self.env)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::env::test::TestEnv;
|
||||
|
||||
/// Assembles a packet for a payload that fits into one packet.
|
||||
fn assemble_packet(cid: &[u8; 4], cmd: u8, payload: &[u8]) -> HidPacket {
|
||||
assert!(payload.len() <= 57);
|
||||
let mut packet = [0x00; 64];
|
||||
packet[..4].copy_from_slice(cid);
|
||||
packet[4] = cmd | 0x80;
|
||||
packet[6] = payload.len() as u8;
|
||||
packet[7..][..payload.len()].copy_from_slice(payload);
|
||||
packet
|
||||
}
|
||||
|
||||
fn init_packet() -> HidPacket {
|
||||
assemble_packet(&[0xFF; 4], 0x06, &[0x55; 8])
|
||||
}
|
||||
|
||||
fn lock_packet(cid: &[u8; 4]) -> HidPacket {
|
||||
assemble_packet(cid, 0x04, &[0x01; 1])
|
||||
}
|
||||
|
||||
fn wink_packet(cid: &[u8; 4]) -> HidPacket {
|
||||
assemble_packet(cid, 0x08, &[])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wink() {
|
||||
let env = TestEnv::default();
|
||||
let mut ctap = Ctap::<TestEnv>::new(env);
|
||||
|
||||
// Send Init, receive Init response and check wink if disabled.
|
||||
let mut init_response = ctap.process_hid_packet(&init_packet(), Transport::MainHid);
|
||||
let response_packet = init_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0x86);
|
||||
let cid = *array_ref!(response_packet, 15, 4);
|
||||
assert!(!ctap.should_wink());
|
||||
|
||||
// Send Wink, receive Wink response and check wink is enabled.
|
||||
let mut lock_response = ctap.process_hid_packet(&wink_packet(&cid), Transport::MainHid);
|
||||
let response_packet = lock_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0x88);
|
||||
assert!(ctap.should_wink());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_locked_channel_id() {
|
||||
let env = TestEnv::default();
|
||||
let mut ctap = Ctap::<TestEnv>::new(env);
|
||||
|
||||
// Send Init, receive Init response.
|
||||
let mut init_response = ctap.process_hid_packet(&init_packet(), Transport::MainHid);
|
||||
let response_packet = init_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0x86);
|
||||
let cid = *array_ref!(response_packet, 15, 4);
|
||||
|
||||
// Send Lock, receive Lock response.
|
||||
let mut lock_response = ctap.process_hid_packet(&lock_packet(&cid), Transport::MainHid);
|
||||
let response_packet = lock_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0x84);
|
||||
|
||||
// Send another Init, receive Error.
|
||||
let mut init_response = ctap.process_hid_packet(&init_packet(), Transport::MainHid);
|
||||
let response_packet = init_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0xBF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "vendor_hid")]
|
||||
fn test_locked_transport() {
|
||||
let env = TestEnv::default();
|
||||
let mut ctap = Ctap::<TestEnv>::new(env);
|
||||
|
||||
// Send Init, receive Init response.
|
||||
let mut init_response = ctap.process_hid_packet(&init_packet(), Transport::MainHid);
|
||||
let response_packet = init_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0x86);
|
||||
let cid = *array_ref!(response_packet, 15, 4);
|
||||
|
||||
// Send Lock, receive Lock response.
|
||||
let mut lock_response = ctap.process_hid_packet(&lock_packet(&cid), Transport::MainHid);
|
||||
let response_packet = lock_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0x84);
|
||||
|
||||
// Send Init on other transport, receive Error.
|
||||
let mut init_response = ctap.process_hid_packet(&init_packet(), Transport::VendorHid);
|
||||
let response_packet = init_response.next().unwrap();
|
||||
assert_eq!(response_packet[4], 0xBF);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user