From 55d3369d9e7f68bb0c836c8143778b2918f01ba5 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 19 Feb 2019 12:58:07 +0000 Subject: Use ssmarshal to generate the response data Previously, we manually constructed the data to sent with a Get_Report response. This patch introduces the Response struct which can be serialized using ssmarshal. As Serialize is only implemented for arrays with a length up to 32, we have to use the serde-big-array crate for the data field. As the command ID might not be recognized by us, we use a raw u8 value instead of the CommandId enum. --- src/device.rs | 62 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/device.rs b/src/device.rs index 300ce56..5fd0aed 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,6 +1,8 @@ // Copyright 2019 Robin Krahl // SPDX-License-Identifier: GPL-3.0-or-later +use serde::Serialize; +use serde_big_array::big_array; use usb_device::bus::{UsbBus, UsbBusAllocator}; use usb_device::device::{UsbDevice, UsbDeviceBuilder, UsbVidPid}; @@ -20,6 +22,8 @@ const REPORT_DESCRIPTOR: &[u8] = &[ 0x75, 0x08, 0x95, 0x40, 0xB1, 0x02, 0xC0, ]; +big_array! { BigArray; COMMAND_LEN, } + enum_u8! { #[derive(Clone, Copy, Debug, PartialEq)] pub enum DeviceStatus { @@ -47,6 +51,30 @@ enum_u8! { } } +#[derive(Serialize)] +struct Response { + pub device_status: DeviceStatus, + pub command_id: u8, + pub last_crc: [u8; 4], + pub command_status: CommandStatus, + #[serde(with = "BigArray")] + pub data: [u8; COMMAND_LEN], + pub crc: u32, +} + +impl Response { + fn new(device_status: DeviceStatus, command_id: u8) -> Response { + Response { + device_status, + command_id, + last_crc: [0; 4], + command_status: CommandStatus::NotSupported, + data: [0; COMMAND_LEN], + crc: 0, + } + } +} + pub struct Nitrokey { buf: [u8; REPORT_LEN], } @@ -77,36 +105,18 @@ impl HidDevice for Nitrokey { return Err(()); } - const PREFIX_LEN: usize = 7; - const SUFFIX_LEN: usize = 4; - const PREFIX_END: usize = PREFIX_LEN; - const SUFFIX_START: usize = REPORT_LEN - SUFFIX_LEN; - let mut buf = [0; COMMAND_LEN]; - - let device_status = DeviceStatus::Ok; - let command_id = self.buf[0]; - let command_status = if let Ok(command_id) = CommandId::try_from(command_id) { - command_id.execute(&self.buf[1..60], &mut buf) + 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) } else { CommandStatus::UnknownCommand }; + // TODO: calculate actual CRC + response.crc = 1; // libnitrokey accepts any non-zero value - let pre_data: [u8; PREFIX_LEN] = [ - device_status.into(), // device status - command_id, // command_id - self.buf[60], - self.buf[61], - self.buf[62], - self.buf[63], // last_command_crc - command_status.into(), // last_command_status - ]; - let post_data: [u8; SUFFIX_LEN] = [ - 0x00, 0x00, 0x00, 0x01, // crc -- libnitrokey accepts any non-zero value - ]; - - self.buf[..PREFIX_END].copy_from_slice(&pre_data); - self.buf[PREFIX_END..SUFFIX_START].copy_from_slice(&buf); - self.buf[SUFFIX_START..].copy_from_slice(&post_data); + let len = ssmarshal::serialize(&mut self.buf, &response).map_err(|_| ())?; + assert!(len == REPORT_LEN); Ok(&self.buf) } -- cgit v1.2.3