diff options
| author | Robin Krahl <robin.krahl@ireas.org> | 2019-02-18 14:23:10 +0000 | 
|---|---|---|
| committer | Robin Krahl <robin.krahl@ireas.org> | 2019-02-18 15:53:39 +0100 | 
| commit | 7f3cc787d03423aa982ade0fa054bb79be18f6ae (patch) | |
| tree | b709be7792b2b4af527881d354ee73ad62b7e04d | |
| parent | 97e448c1d9921cd084e1da70f3943bead03474ed (diff) | |
| download | ntw-7f3cc787d03423aa982ade0fa054bb79be18f6ae.tar.gz ntw-7f3cc787d03423aa982ade0fa054bb79be18f6ae.tar.bz2 | |
Implement Nitrokey command handling
This patch changes the Get_Report handler in Nitrokey to extract the
command data from the buffer sent with the Set_Report request, to
execute a command based on this data and to write appropriate return
data back to the device.
| -rw-r--r-- | src/device.rs | 78 | 
1 files changed, 76 insertions, 2 deletions
| diff --git a/src/device.rs b/src/device.rs index f7c4fc7..3b6cf46 100644 --- a/src/device.rs +++ b/src/device.rs @@ -5,6 +5,7 @@ use usb_device::bus::{UsbBus, UsbBusAllocator};  use usb_device::device::{UsbDevice, UsbDeviceBuilder, UsbVidPid};  use crate::hid::{HidDevice, Protocol, ReportType, Subclass}; +use crate::util::TryFrom;  const VID_CLAY_LOGIC: u16 = 0x20a0;  const PID_NITROKEY_PRO: u16 = 0x4108; @@ -18,6 +19,40 @@ const REPORT_DESCRIPTOR: &[u8] = &[      0x75, 0x08, 0x95, 0x40, 0xB1, 0x02, 0xC0,  ]; +enum_u8! { +    #[derive(Clone, Copy, Debug, PartialEq)] +    pub enum DeviceStatus { +        Ok = 0, +        Busy = 1, +        Error = 2, +        ReceivedReport = 3, +    } +} + +enum_u8! { +    #[derive(Clone, Copy, Debug, PartialEq)] +    pub enum CommandStatus { +        Ok = 0, +        WrongCrc = 1, +        WrongSlot = 2, +        SlotNotProgrammed = 3, +        WrongPassword = 4, +        NotAuthorized = 5, +        TimestampWarning = 6, +        NoNameError = 7, +        NotSupported = 8, +        UnknownCommand = 9, +        AesDecryptionFailed = 10, +    } +} + +enum_u8! { +    #[derive(Clone, Copy, Debug, PartialEq)] +    pub enum CommandId { +        GetStatus = 0, +    } +} +  pub struct Nitrokey {      buf: [u8; REPORT_LEN],  } @@ -28,6 +63,15 @@ impl Nitrokey {              buf: [0; REPORT_LEN],          }      } + +    fn execute_command( +        &self, +        command_id: CommandId, +        data: &[u8], +    ) -> Result<[u8; 53], CommandStatus> { +        let _ = (command_id, data); +        Err(CommandStatus::UnknownCommand) +    }  }  impl HidDevice for Nitrokey { @@ -44,8 +88,38 @@ impl HidDevice for Nitrokey {      }      fn get_report(&mut self, report_type: ReportType, report_id: u8) -> Result<&[u8], ()> { -        let _ = (report_type, report_id); -        Err(()) +        if report_type != ReportType::Feature || report_id != 0 { +            return Err(()); +        } + +        let device_status = DeviceStatus::Ok; +        let command_id = self.buf[0]; +        let result = if let Ok(command_id) = CommandId::try_from(command_id) { +            self.execute_command(command_id, &self.buf[1..60]) +        } else { +            Err(CommandStatus::UnknownCommand) +        }; +        let (command_status, command_data) = result +            .map(|d| (CommandStatus::Ok, d)) +            .unwrap_or_else(|status| (status, [0; 53])); + +        let pre_data: [u8; 7] = [ +            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; 4] = [ +            0x00, 0x00, 0x00, 0x01, // crc -- libnitrokey accepts any non-zero value +        ]; + +        self.buf[0..7].copy_from_slice(&pre_data); +        self.buf[7..7 + command_data.len()].copy_from_slice(&command_data); +        self.buf[60..64].copy_from_slice(&post_data); +        Ok(&self.buf)      }      fn set_report( | 
