Initial commit

This commit is contained in:
Jean-Michel Picod
2020-01-28 15:09:10 +01:00
commit f91d2fd3db
90 changed files with 31123 additions and 0 deletions

296
src/ctap/hid/send.rs Normal file
View File

@@ -0,0 +1,296 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::{CtapHid, HidPacket, Message};
pub struct HidPacketIterator(Option<MessageSplitter>);
impl HidPacketIterator {
pub fn new(message: Message) -> Option<HidPacketIterator> {
let splitter = MessageSplitter::new(message);
if splitter.is_some() {
Some(HidPacketIterator(splitter))
} else {
None
}
}
pub fn none() -> HidPacketIterator {
HidPacketIterator(None)
}
}
impl Iterator for HidPacketIterator {
type Item = HidPacket;
fn next(&mut self) -> Option<HidPacket> {
match &mut self.0 {
Some(splitter) => splitter.next(),
None => None,
}
}
}
pub struct MessageSplitter {
message: Message,
packet: HidPacket,
seq: Option<u8>,
i: usize,
}
impl MessageSplitter {
// Try to split this message into an iterator of HID packets. This fails if the message is too
// long to fit into a sequence of HID packets (which is limited to 7609 bytes).
pub fn new(message: Message) -> Option<MessageSplitter> {
if message.payload.len() > 7609 {
None
} else {
// Cache the CID, as it is constant for all packets in this message.
let mut packet = [0; 64];
packet[..4].copy_from_slice(&message.cid);
Some(MessageSplitter {
message,
packet,
seq: None,
i: 0,
})
}
}
// Copy as many bytes as possible from data to dst, and return how many bytes are copied.
// Contrary to copy_from_slice, this doesn't require slices of the same length.
// All unused bytes in dst are set to zero, as if the data was padded with zeros to match.
fn consume_data(dst: &mut [u8], data: &[u8]) -> usize {
let dst_len = dst.len();
let data_len = data.len();
if data_len <= dst_len {
// data fits in dst, copy all the bytes.
dst[..data_len].copy_from_slice(data);
for byte in dst[data_len..].iter_mut() {
*byte = 0;
}
data_len
} else {
// Fill all of dst.
dst.copy_from_slice(&data[..dst_len]);
dst_len
}
}
}
impl Iterator for MessageSplitter {
type Item = HidPacket;
fn next(&mut self) -> Option<HidPacket> {
let payload_len = self.message.payload.len();
match self.seq {
None => {
// First, send an initialization packet.
self.packet[4] = self.message.cmd | CtapHid::TYPE_INIT_BIT;
self.packet[5] = (payload_len >> 8) as u8;
self.packet[6] = payload_len as u8;
self.seq = Some(0);
self.i =
MessageSplitter::consume_data(&mut self.packet[7..], &self.message.payload);
Some(self.packet)
}
Some(seq) => {
// Send the next continuation packet, if any.
if self.i < payload_len {
self.packet[4] = seq;
self.seq = Some(seq + 1);
self.i += MessageSplitter::consume_data(
&mut self.packet[5..],
&self.message.payload[self.i..],
);
Some(self.packet)
} else {
None
}
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
fn assert_packet_output_equality(message: Message, expected_packets: Vec<HidPacket>) {
let packets: Vec<HidPacket> = HidPacketIterator::new(message).unwrap().collect();
assert_eq!(packets.len(), expected_packets.len());
for (packet, expected_packet) in packets.iter().zip(expected_packets.iter()) {
assert_eq!(packet as &[u8], expected_packet as &[u8]);
}
}
#[test]
fn test_hid_packet_iterator_single_packet() {
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0x4C,
payload: vec![0xAA, 0xBB],
};
let expected_packets: Vec<HidPacket> = vec![[
0x12, 0x34, 0x56, 0x78, 0xCC, 0x00, 0x02, 0xAA, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]];
assert_packet_output_equality(message, expected_packets);
}
#[test]
fn test_hid_packet_iterator_big_single_packet() {
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0x4C,
payload: vec![0xAA; 64 - 7],
};
let expected_packets: Vec<HidPacket> = vec![[
0x12, 0x34, 0x56, 0x78, 0xCC, 0x00, 0x39, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
]];
assert_packet_output_equality(message, expected_packets);
}
#[test]
fn test_hid_packet_iterator_two_packets() {
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0x4C,
payload: vec![0xAA; 64 - 7 + 1],
};
let expected_packets: Vec<HidPacket> = vec![
[
0x12, 0x34, 0x56, 0x78, 0xCC, 0x00, 0x3A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
],
[
0x12, 0x34, 0x56, 0x78, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
];
assert_packet_output_equality(message, expected_packets);
}
#[test]
fn test_hid_packet_iterator_two_full_packets() {
let mut payload = vec![0xAA; 64 - 7];
payload.extend(vec![0xBB; 64 - 5]);
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0x4C,
payload,
};
let expected_packets: Vec<HidPacket> = vec![
[
0x12, 0x34, 0x56, 0x78, 0xCC, 0x00, 0x74, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
],
[
0x12, 0x34, 0x56, 0x78, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
],
];
assert_packet_output_equality(message, expected_packets);
}
#[test]
fn test_hid_packet_iterator_max_packets() {
let mut payload = vec![0xFF; 64 - 7];
for i in 0..128 {
payload.extend(vec![i + 1; 64 - 5]);
}
// Sanity check for the length of the payload.
assert_eq!((64 - 7) + 128 * (64 - 5), 0x1db9);
assert_eq!(7609, 0x1db9);
assert_eq!(payload.len(), 0x1db9);
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0xAB,
payload,
};
let mut expected_packets = Vec::new();
expected_packets.push([
0x12, 0x34, 0x56, 0x78, 0xAB, 0x1D, 0xB9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
]);
for i in 0..128 {
let mut packet: HidPacket = [0; 64];
packet[0] = 0x12;
packet[1] = 0x34;
packet[2] = 0x56;
packet[3] = 0x78;
packet[4] = i;
for byte in packet.iter_mut().skip(5) {
*byte = i + 1;
}
expected_packets.push(packet);
}
assert_packet_output_equality(message, expected_packets);
}
#[test]
fn test_hid_packet_iterator_payload_one_too_large() {
let payload = vec![0xFF; (64 - 7) + 128 * (64 - 5) + 1];
assert_eq!(payload.len(), 0x1dba);
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0xAB,
payload,
};
assert!(HidPacketIterator::new(message).is_none());
}
#[test]
fn test_hid_packet_iterator_payload_way_too_large() {
// Check that overflow of u16 doesn't bypass the size limit.
let payload = vec![0xFF; 0x10000];
let message = Message {
cid: [0x12, 0x34, 0x56, 0x78],
cmd: 0xAB,
payload,
};
assert!(HidPacketIterator::new(message).is_none());
}
// TODO(kaczmarczyck) implement and test limits (maximum bytes and packets)
}