diff options
Diffstat (limited to 'src/device.rs')
-rw-r--r-- | src/device.rs | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/src/device.rs b/src/device.rs index 5fd0aed..0df14ae 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,7 +1,7 @@ // Copyright 2019 Robin Krahl <robin.krahl@ireas.org> // SPDX-License-Identifier: GPL-3.0-or-later -use serde::Serialize; +use serde::{Deserialize, Serialize}; use serde_big_array::big_array; use usb_device::bus::{UsbBus, UsbBusAllocator}; use usb_device::device::{UsbDevice, UsbDeviceBuilder, UsbVidPid}; @@ -14,6 +14,7 @@ const VID_CLAY_LOGIC: u16 = 0x20a0; const PID_NITROKEY_PRO: u16 = 0x4108; const REPORT_LEN: usize = 64; +const REQUEST_DATA_LEN: usize = REPORT_LEN - 5; const REPORT_DESCRIPTOR: &[u8] = &[ 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x05, 0x75, 0x01, @@ -22,7 +23,7 @@ const REPORT_DESCRIPTOR: &[u8] = &[ 0x75, 0x08, 0x95, 0x40, 0xB1, 0x02, 0xC0, ]; -big_array! { BigArray; COMMAND_LEN, } +big_array! { BigArray; COMMAND_LEN, REQUEST_DATA_LEN, } enum_u8! { #[derive(Clone, Copy, Debug, PartialEq)] @@ -51,11 +52,19 @@ enum_u8! { } } +#[derive(Deserialize)] +struct Request { + pub command_id: u8, + #[serde(with = "BigArray")] + pub data: [u8; REQUEST_DATA_LEN], + pub crc: u32, +} + #[derive(Serialize)] struct Response { pub device_status: DeviceStatus, pub command_id: u8, - pub last_crc: [u8; 4], + pub last_crc: u32, pub command_status: CommandStatus, #[serde(with = "BigArray")] pub data: [u8; COMMAND_LEN], @@ -63,11 +72,11 @@ struct Response { } impl Response { - fn new(device_status: DeviceStatus, command_id: u8) -> Response { + fn new(device_status: DeviceStatus, command_id: u8, last_crc: u32) -> Response { Response { device_status, command_id, - last_crc: [0; 4], + last_crc, command_status: CommandStatus::NotSupported, data: [0; COMMAND_LEN], crc: 0, @@ -76,12 +85,14 @@ impl Response { } pub struct Nitrokey { + request: Option<Request>, buf: [u8; REPORT_LEN], } impl Nitrokey { pub fn new() -> Self { Nitrokey { + request: None, buf: [0; REPORT_LEN], } } @@ -105,19 +116,23 @@ impl HidDevice for Nitrokey { return Err(()); } - let mut response = Response::new(DeviceStatus::Ok, self.buf[0]); - response.last_crc = [self.buf[60], self.buf[61], self.buf[62], self.buf[63]]; - response.command_status = if let Ok(command_id) = CommandId::try_from(response.command_id) { - command_id.execute(&self.buf[1..60], &mut response.data) + if let Some(ref request) = self.request { + let mut response = Response::new(DeviceStatus::Ok, request.command_id, request.crc); + response.command_status = + if let Ok(command_id) = CommandId::try_from(request.command_id) { + command_id.execute(&request.data, &mut response.data) + } else { + CommandStatus::UnknownCommand + }; + // TODO: calculate actual CRC + response.crc = 1; // libnitrokey accepts any non-zero value + + let len = ssmarshal::serialize(&mut self.buf, &response).map_err(|_| ())?; + assert!(len == REPORT_LEN); + Ok(&self.buf) } else { - CommandStatus::UnknownCommand - }; - // TODO: calculate actual CRC - response.crc = 1; // libnitrokey accepts any non-zero value - - let len = ssmarshal::serialize(&mut self.buf, &response).map_err(|_| ())?; - assert!(len == REPORT_LEN); - Ok(&self.buf) + Err(()) + } } fn set_report( @@ -129,7 +144,9 @@ impl HidDevice for Nitrokey { if report_type != ReportType::Feature || report_id != 0 || data.len() != REPORT_LEN { Err(()) } else { - self.buf.copy_from_slice(data); + let (request, len) = ssmarshal::deserialize(data).map_err(|_| ())?; + assert!(len == REPORT_LEN); + self.request = Some(request); Ok(()) } } |