diff --git a/Cargo.toml b/Cargo.toml index 2f0e962..9f786b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "challenge_response" version = "0.0.0-placeholder-version" authors = ["Ashutosh Varma ", "louib "] +edition = "2021" description = "Perform HMAC-SHA1 and OTP challenges with YubiKey, OnlyKey and NitroKey, in pure Rust." license = "MIT OR Apache-2.0" @@ -33,13 +34,15 @@ aes = "0.8" block-modes = "0.9" hmac = "0.12" sha-1 = "0.10" +tokio = { version = "1", features = ["rt", "macros", "time"] } +async-trait = "0.1" [target.'cfg(windows)'.dependencies] rusb = { version = "0.9" } [target.'cfg(not(windows))'.dependencies] rusb = { version = "0.9", optional = true } -nusb = { version = "0.1", optional = true } +nusb = { version = "0.2", optional = true } [dev-dependencies] hex = "0.4" diff --git a/src/configure.rs b/src/configure.rs index 145f0c9..aa2dffa 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -1,9 +1,9 @@ -use config::Command; -use hmacmode::HmacKey; -use otpmode::Aes128Key; -use sec::crc16; +use crate::config::Command; +use crate::hmacmode::HmacKey; +use crate::otpmode::Aes128Key; +use crate::sec::crc16; use std; -use usb::{Frame, PAYLOAD_SIZE}; +use crate::usb::{Frame, PAYLOAD_SIZE}; const FIXED_SIZE: usize = 16; const UID_SIZE: usize = 6; diff --git a/src/error.rs b/src/error.rs index f213437..137d7a3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,7 @@ #[cfg(any(feature = "rusb", target_os = "windows"))] use rusb::Error as usbError; +#[cfg(all(feature = "nusb", not(target_os = "windows")))] +use nusb::{Error as nusbError, transfer::TransferError as nusbTransferError}; use std::error; use std::fmt; use std::io::Error as ioError; @@ -9,6 +11,10 @@ pub enum ChallengeResponseError { IOError(ioError), #[cfg(any(feature = "rusb", target_os = "windows"))] UsbError(usbError), + #[cfg(all(feature = "nusb", not(target_os = "windows")))] + NusbError(nusbError), + #[cfg(all(feature = "nusb", not(target_os = "windows")))] + NusbTransferError(nusbTransferError), CommandNotSupported, DeviceNotFound, OpenDeviceError, @@ -25,6 +31,10 @@ impl fmt::Display for ChallengeResponseError { ChallengeResponseError::IOError(ref err) => write!(f, "IO error: {}", err), #[cfg(any(feature = "rusb", target_os = "windows"))] ChallengeResponseError::UsbError(ref err) => write!(f, "USB error: {}", err), + #[cfg(all(feature = "nusb", not(target_os = "windows")))] + ChallengeResponseError::NusbError(ref err) => write!(f, "NUSB error: {}", err), + #[cfg(all(feature = "nusb", not(target_os = "windows")))] + ChallengeResponseError::NusbTransferError(ref err) => write!(f, "NUSB transfer error: {}", err), ChallengeResponseError::DeviceNotFound => write!(f, "Device not found"), ChallengeResponseError::OpenDeviceError => write!(f, "Can not open device"), ChallengeResponseError::CommandNotSupported => write!(f, "Command Not Supported"), @@ -42,6 +52,10 @@ impl error::Error for ChallengeResponseError { match *self { #[cfg(any(feature = "rusb", target_os = "windows"))] ChallengeResponseError::UsbError(ref err) => Some(err), + #[cfg(all(feature = "nusb", not(target_os = "windows")))] + ChallengeResponseError::NusbError(ref err) => Some(err), + #[cfg(all(feature = "nusb", not(target_os = "windows")))] + ChallengeResponseError::NusbTransferError(ref err) => Some(err), _ => None, } } @@ -59,3 +73,17 @@ impl From for ChallengeResponseError { ChallengeResponseError::UsbError(err) } } + +#[cfg(all(feature = "nusb", not(target_os = "windows")))] +impl From for ChallengeResponseError { + fn from(err: nusbError) -> ChallengeResponseError { + ChallengeResponseError::NusbError(err) + } +} + +#[cfg(all(feature = "nusb", not(target_os = "windows")))] +impl From for ChallengeResponseError { + fn from(err: nusbTransferError) -> ChallengeResponseError { + ChallengeResponseError::NusbTransferError(err) + } +} diff --git a/src/hmacmode.rs b/src/hmacmode.rs index d67631f..f86b2bf 100644 --- a/src/hmacmode.rs +++ b/src/hmacmode.rs @@ -1,5 +1,5 @@ use rand::Rng; -use sec::hmac_sha1; +use crate::sec::hmac_sha1; use std; /// Size of the secret used by the HMAC algorithm diff --git a/src/lib.rs b/src/lib.rs index 49c3cdc..1372888 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ compile_error!("Either the rusb or nusb feature must be enabled for this crate") #[cfg(all(feature = "nusb", not(feature = "rusb"), not(target_os = "windows")))] extern crate nusb; +#[cfg(all(feature = "nusb", not(feature = "rusb"), not(target_os = "windows")))] +extern crate tokio; #[cfg(any(feature = "rusb", target_os = "windows"))] extern crate rusb; @@ -12,6 +14,7 @@ extern crate rusb; extern crate structure; extern crate aes; +extern crate async_trait; extern crate block_modes; extern crate hmac; extern crate rand; @@ -54,50 +57,55 @@ impl ChallengeResponse { Ok(ChallengeResponse { backend }) } - pub fn find_device(&mut self) -> Result { - self.backend.find_device() + pub async fn find_device(&mut self) -> Result { + self.backend.find_device().await } - pub fn find_device_from_serial(&mut self, serial: u32) -> Result { - self.backend.find_device_from_serial(serial) + pub async fn find_device_from_serial(&mut self, serial: u32) -> Result { + self.backend.find_device_from_serial(serial).await } - pub fn find_all_devices(&mut self) -> Result> { - self.backend.find_all_devices() + pub async fn find_all_devices(&mut self) -> Result> { + self.backend.find_all_devices().await } - pub fn read_serial_number(&mut self, conf: Config) -> Result { + pub async fn read_serial_number(&mut self, conf: Config) -> Result { self.backend .read_serial_from_device(conf.device.bus_id, conf.device.address_id) + .await } - pub fn write_config(&mut self, conf: Config, device_config: &mut DeviceModeConfig) -> Result<()> { + pub async fn write_config(&mut self, conf: Config, device_config: &mut DeviceModeConfig) -> Result<()> { let d = device_config.to_frame(conf.command); let mut buf = [0; usb::STATUS_UPDATE_PAYLOAD_SIZE]; let (mut handle, interfaces) = self .backend - .open_device(conf.device.bus_id, conf.device.address_id)?; + .open_device(conf.device.bus_id, conf.device.address_id) + .await?; self.backend - .wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?; + .wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf) + .await?; // TODO: Should check version number. - self.backend.write_frame(&mut handle, &d)?; + self.backend.write_frame(&mut handle, &d).await?; self.backend - .wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?; - self.backend.close_device(handle, interfaces)?; + .wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf) + .await?; + self.backend.close_device(handle, interfaces).await?; Ok(()) } - pub fn challenge_response_hmac(&mut self, chall: &[u8], conf: Config) -> Result { + pub async fn challenge_response_hmac(&mut self, chall: &[u8], conf: Config) -> Result { let mut hmac = Hmac([0; 20]); let (mut handle, interfaces) = self .backend - .open_device(conf.device.bus_id, conf.device.address_id)?; + .open_device(conf.device.bus_id, conf.device.address_id) + .await?; let mut challenge = [0; CHALLENGE_SIZE]; @@ -113,18 +121,20 @@ impl ChallengeResponse { (&mut challenge[..chall.len()]).copy_from_slice(chall); let d = Frame::new(challenge, command); let mut buf = [0; usb::STATUS_UPDATE_PAYLOAD_SIZE]; - self.backend.wait( - &mut handle, - |f| !f.contains(usb::Flags::SLOT_WRITE_FLAG), - &mut buf, - )?; + self.backend + .wait( + &mut handle, + |f| !f.contains(usb::Flags::SLOT_WRITE_FLAG), + &mut buf, + ) + .await?; - self.backend.write_frame(&mut handle, &d)?; + self.backend.write_frame(&mut handle, &d).await?; // Read the response. let mut response = [0; usb::RESPONSE_SIZE]; - self.backend.read_response(&mut handle, &mut response)?; - self.backend.close_device(handle, interfaces)?; + self.backend.read_response(&mut handle, &mut response).await?; + self.backend.close_device(handle, interfaces).await?; // Check response. if crc16(&response[..22]) != CRC_RESIDUAL_OK { @@ -136,14 +146,15 @@ impl ChallengeResponse { Ok(hmac) } - pub fn challenge_response_otp(&mut self, chall: &[u8], conf: Config) -> Result { + pub async fn challenge_response_otp(&mut self, chall: &[u8], conf: Config) -> Result { let mut block = Aes128Block { block: GenericArray::clone_from_slice(&[0; 16]), }; let (mut handle, interfaces) = self .backend - .open_device(conf.device.bus_id, conf.device.address_id)?; + .open_device(conf.device.bus_id, conf.device.address_id) + .await?; let mut challenge = [0; CHALLENGE_SIZE]; @@ -156,17 +167,19 @@ impl ChallengeResponse { let d = Frame::new(challenge, command); let mut buf = [0; usb::STATUS_UPDATE_PAYLOAD_SIZE]; - self.backend.wait( - &mut handle, - |f| !f.contains(usb::Flags::SLOT_WRITE_FLAG), - &mut buf, - )?; + self.backend + .wait( + &mut handle, + |f| !f.contains(usb::Flags::SLOT_WRITE_FLAG), + &mut buf, + ) + .await?; - self.backend.write_frame(&mut handle, &d)?; + self.backend.write_frame(&mut handle, &d).await?; let mut response = [0; usb::RESPONSE_SIZE]; - self.backend.read_response(&mut handle, &mut response)?; - self.backend.close_device(handle, interfaces)?; + self.backend.read_response(&mut handle, &mut response).await?; + self.backend.close_device(handle, interfaces).await?; // Check response. if crc16(&response[..18]) != CRC_RESIDUAL_OK { @@ -183,8 +196,8 @@ impl ChallengeResponse { mod tests { use super::*; - #[test] - fn test_find_device() { + #[tokio::test] + async fn test_find_device() { let mut cr_client = match ChallengeResponse::new() { Ok(c) => c, Err(e) => { @@ -193,13 +206,13 @@ mod tests { } }; - if let Err(e) = cr_client.find_device() { + if let Err(e) = cr_client.find_device().await { assert!(matches!(e, ChallengeResponseError::DeviceNotFound)); }; } - #[test] - fn test_find_all_devices() { + #[tokio::test] + async fn test_find_all_devices() { let mut cr_client = match ChallengeResponse::new() { Ok(c) => c, Err(e) => { @@ -208,7 +221,7 @@ mod tests { } }; - if let Err(e) = cr_client.find_all_devices() { + if let Err(e) = cr_client.find_all_devices().await { assert!(matches!(e, ChallengeResponseError::DeviceNotFound)); }; } diff --git a/src/usb.rs b/src/usb.rs index 0b1b59e..064e954 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -1,9 +1,11 @@ +use async_trait::async_trait; use std::time::Duration; -use std::{slice, thread}; +use std::{slice}; +use tokio::time::sleep; -use config::Command; -use error::ChallengeResponseError; -use sec::crc16; +use crate::config::Command; +use crate::error::ChallengeResponseError; +use crate::sec::crc16; #[cfg(any(feature = "rusb", target_os = "windows"))] pub type BackendType = rusb::RUSBBackend; @@ -84,31 +86,32 @@ pub struct Device { pub address_id: u8, } -pub trait Backend { +#[async_trait(?Send)] +pub trait Backend { fn new() -> Result where Self: Sized; - fn open_device( + async fn open_device( &mut self, bus_id: u8, address_id: u8, ) -> Result<(DeviceHandle, Vec), ChallengeResponseError>; - fn close_device( + async fn close_device( &self, handle: DeviceHandle, interfaces: Vec, ) -> Result<(), ChallengeResponseError>; - fn read(&self, handle: &mut DeviceHandle, buf: &mut [u8]) -> Result; - fn raw_write(&self, handle: &mut DeviceHandle, packet: &[u8]) -> Result<(), ChallengeResponseError>; + async fn read(&self, handle: &mut DeviceHandle, buf: &mut [u8]) -> Result; + async fn raw_write(&self, handle: &mut DeviceHandle, packet: &[u8]) -> Result<(), ChallengeResponseError>; - fn find_device(&mut self) -> Result; - fn find_device_from_serial(&mut self, serial: u32) -> Result; - fn find_all_devices(&mut self) -> Result, ChallengeResponseError>; + async fn find_device(&mut self) -> Result; + async fn find_device_from_serial(&mut self, serial: u32) -> Result; + async fn find_all_devices(&mut self) -> Result, ChallengeResponseError>; - fn write_frame(&self, handle: &mut DeviceHandle, frame: &Frame) -> Result<(), ChallengeResponseError> { + async fn write_frame(&self, handle: &mut DeviceHandle, frame: &Frame) -> Result<(), ChallengeResponseError> { let mut data = unsafe { slice::from_raw_parts(frame as *const Frame as *const u8, 70) }; let mut seq = 0; @@ -121,8 +124,8 @@ pub trait Backend { (&mut packet[..7]).copy_from_slice(a); packet[7] = Flags::SLOT_WRITE_FLAG.bits() + seq; - self.wait(handle, |x| !x.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?; - self.raw_write(handle, &packet)?; + self.wait(handle, |x| !x.contains(Flags::SLOT_WRITE_FLAG), &mut buf).await?; + self.raw_write(handle, &packet).await?; } data = b; seq += 1 @@ -130,14 +133,14 @@ pub trait Backend { Ok(()) } - fn wait bool>( + async fn wait bool + Send>( &self, handle: &mut DeviceHandle, f: F, buf: &mut [u8], ) -> Result<(), ChallengeResponseError> { loop { - self.read(handle, buf)?; + self.read(handle, buf).await?; let flags = Flags::from_bits_truncate(buf[7]); if flags.contains(Flags::SLOT_WRITE_FLAG) || flags.is_empty() { // Should store the version @@ -146,19 +149,19 @@ pub trait Backend { if f(flags) { return Ok(()); } - thread::sleep(Duration::new(0, 1000000)); + sleep(Duration::new(0, 1000000)).await; } } /// Reset the write state after a read. - fn write_reset(&self, handle: &mut DeviceHandle) -> Result<(), ChallengeResponseError> { - self.raw_write(handle, &WRITE_RESET_PAYLOAD)?; + async fn write_reset(&self, handle: &mut DeviceHandle) -> Result<(), ChallengeResponseError> { + self.raw_write(handle, &WRITE_RESET_PAYLOAD).await?; let mut buf = [0; 8]; - self.wait(handle, |x| !x.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?; + self.wait(handle, |x| !x.contains(Flags::SLOT_WRITE_FLAG), &mut buf).await?; Ok(()) } - fn read_response( + async fn read_response( &self, handle: &mut DeviceHandle, response: &mut [u8], @@ -168,10 +171,10 @@ pub trait Backend { handle, |f| f.contains(Flags::RESP_PENDING_FLAG), &mut response[..8], - )?; + ).await?; r0 += 7; loop { - if self.read(handle, &mut response[r0..r0 + 8])? < 8 { + if self.read(handle, &mut response[r0..r0 + 8]).await? < 8 { break; } let flags = Flags::from_bits_truncate(response[r0 + 7]); @@ -187,29 +190,29 @@ pub trait Backend { } r0 += 7; } - self.write_reset(handle)?; + self.write_reset(handle).await?; Ok(r0) } - fn read_serial_from_device( + async fn read_serial_from_device( &mut self, device_bus_id: u8, device_address: u8, ) -> Result { - let (mut handle, interfaces) = self.open_device(device_bus_id, device_address)?; + let (mut handle, interfaces) = self.open_device(device_bus_id, device_address).await?; let challenge = [0; CHALLENGE_SIZE]; let command = Command::DeviceSerial; let d = Frame::new(challenge, command); // FIXME: do not need a challange let mut buf = [0; STATUS_UPDATE_PAYLOAD_SIZE]; - self.wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?; + self.wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf).await?; - self.write_frame(&mut handle, &d)?; + self.write_frame(&mut handle, &d).await?; // Read the response. let mut response = [0; RESPONSE_SIZE]; - self.read_response(&mut handle, &mut response)?; - self.close_device(handle, interfaces)?; + self.read_response(&mut handle, &mut response).await?; + self.close_device(handle, interfaces).await?; // Check response. if crc16(&response[..6]) != crate::sec::CRC_RESIDUAL_OK { diff --git a/src/usb/nusb.rs b/src/usb/nusb.rs index d6e74f0..16c33f2 100644 --- a/src/usb/nusb.rs +++ b/src/usb/nusb.rs @@ -1,40 +1,35 @@ -use nusb::{Device as NUSBDevice, Interface}; - -use error::ChallengeResponseError; use std::time::Duration; -use usb::{Backend, Device, HID_GET_REPORT, HID_SET_REPORT, PRODUCT_ID, REPORT_TYPE_FEATURE, VENDOR_ID}; +use async_trait::async_trait; +use nusb::{transfer::{ControlIn, ControlOut, ControlType, Recipient}, Device as NUSBDevice, Interface}; +use std::future::IntoFuture; + +use crate::error::ChallengeResponseError; +use crate::usb::{Backend, Device, HID_GET_REPORT, HID_SET_REPORT, PRODUCT_ID, REPORT_TYPE_FEATURE, VENDOR_ID}; pub struct NUSBBackend {} +#[async_trait(?Send)] impl Backend for NUSBBackend { fn new() -> Result { Ok(Self {}) } - fn open_device( + async fn open_device( &mut self, bus_id: u8, address_id: u8, ) -> Result<(NUSBDevice, Vec), ChallengeResponseError> { - let nusb_devices = match nusb::list_devices() { - Ok(d) => d, - Err(e) => return Err(e.into()), - }; + let nusb_devices = nusb::list_devices().into_future().await?; for device_info in nusb_devices { - if device_info.bus_number() != bus_id || device_info.device_address() != address_id { + if device_info.busnum() != bus_id || device_info.device_address() != address_id { continue; } - let device = match device_info.open() { - Ok(d) => d, - Err(_) => { - return Err(ChallengeResponseError::OpenDeviceError); - } - }; + let device = device_info.open().into_future().await?; let mut interfaces: Vec = Vec::new(); for interface in device_info.interfaces() { - let interface = match device.detach_and_claim_interface(interface.interface_number()) { + let interface = match device.detach_and_claim_interface(interface.interface_number()).into_future().await { Ok(interface) => interface, Err(_) => continue, }; @@ -47,7 +42,7 @@ impl Backend for NUSBBackend { Err(ChallengeResponseError::DeviceNotFound) } - fn close_device( + async fn close_device( &self, mut _handle: NUSBDevice, _interfaces: Vec, @@ -55,48 +50,39 @@ impl Backend for NUSBBackend { Ok(()) } - fn read(&self, handle: &mut NUSBDevice, buf: &mut [u8]) -> Result { + async fn read(&self, handle: &mut NUSBDevice, buf: &mut [u8]) -> Result { assert_eq!(buf.len(), 8); - let control_type = nusb::transfer::ControlType::Class; - let control_in = nusb::transfer::Control { - control_type, - recipient: nusb::transfer::Recipient::Interface, + let control_in = ControlIn { + control_type: ControlType::Class, + recipient: Recipient::Interface, request: HID_GET_REPORT, value: REPORT_TYPE_FEATURE << 8, index: 0, + length: buf.len() as u16, }; - match handle.control_in_blocking(control_in, buf, Duration::new(2, 0)) { - Ok(r) => Ok(r), - Err(_e) => Err(ChallengeResponseError::CanNotReadFromDevice), - } + let data = handle.control_in(control_in, Duration::new(2, 0)).into_future().await?; + buf.copy_from_slice(&data); + Ok(data.len()) } - fn raw_write(&self, handle: &mut NUSBDevice, packet: &[u8]) -> Result<(), ChallengeResponseError> { - let control_type = nusb::transfer::ControlType::Class; - let control_out = nusb::transfer::Control { - control_type, - recipient: nusb::transfer::Recipient::Interface, + async fn raw_write(&self, handle: &mut NUSBDevice, packet: &[u8]) -> Result<(), ChallengeResponseError> { + let control_out = ControlOut { + control_type: ControlType::Class, + recipient: Recipient::Interface, request: HID_SET_REPORT, value: REPORT_TYPE_FEATURE << 8, index: 0, + data: packet, }; - match handle.control_out_blocking(control_out, packet, Duration::new(2, 0)) { - Ok(bytes_written) => { - if bytes_written != 8 { - Err(ChallengeResponseError::CanNotWriteToDevice) - } else { - Ok(()) - } - } - Err(_) => Err(ChallengeResponseError::CanNotWriteToDevice), - } + handle.control_out(control_out, Duration::new(2, 0)).into_future().await?; + Ok(()) } - fn find_device(&mut self) -> Result { - match self.find_all_devices() { + async fn find_device(&mut self) -> Result { + match self.find_all_devices().await { Ok(devices) => { if !devices.is_empty() { Ok(devices[0].clone()) @@ -108,8 +94,8 @@ impl Backend for NUSBBackend { } } - fn find_device_from_serial(&mut self, serial: u32) -> Result { - let nusb_devices = nusb::list_devices()?; + async fn find_device_from_serial(&mut self, serial: u32) -> Result { + let nusb_devices = nusb::list_devices().into_future().await?; for device_info in nusb_devices { let product_id = device_info.product_id(); let vendor_id = device_info.vendor_id(); @@ -119,7 +105,7 @@ impl Backend for NUSBBackend { } let device_serial = - match self.read_serial_from_device(device_info.bus_number(), device_info.device_address()) { + match self.read_serial_from_device(device_info.busnum(), device_info.device_address()).await { Ok(s) => s, Err(_) => continue, }; @@ -133,7 +119,7 @@ impl Backend for NUSBBackend { serial: Some(serial), product_id, vendor_id, - bus_id: device_info.bus_number(), + bus_id: device_info.busnum(), address_id: device_info.device_address(), }); } @@ -141,9 +127,9 @@ impl Backend for NUSBBackend { Err(ChallengeResponseError::DeviceNotFound) } - fn find_all_devices(&mut self) -> Result, ChallengeResponseError> { + async fn find_all_devices(&mut self) -> Result, ChallengeResponseError> { let mut devices: Vec = Vec::new(); - let nusb_devices = nusb::list_devices()?; + let nusb_devices = nusb::list_devices().into_future().await?; for device_info in nusb_devices { let product_id = device_info.product_id(); let vendor_id = device_info.vendor_id(); @@ -153,7 +139,8 @@ impl Backend for NUSBBackend { } let device_serial = self - .read_serial_from_device(device_info.bus_number(), device_info.device_address()) + .read_serial_from_device(device_info.busnum(), device_info.device_address()) + .await .ok(); devices.push(Device { @@ -164,10 +151,11 @@ impl Backend for NUSBBackend { serial: device_serial, product_id, vendor_id, - bus_id: device_info.bus_number(), + bus_id: device_info.busnum(), address_id: device_info.device_address(), }); } Ok(devices) } } + diff --git a/src/usb/rusb.rs b/src/usb/rusb.rs index 8a115b1..c72b530 100644 --- a/src/usb/rusb.rs +++ b/src/usb/rusb.rs @@ -1,12 +1,14 @@ -use error::ChallengeResponseError; +use async_trait::async_trait; +use crate::error::ChallengeResponseError; use rusb::{request_type, Context, DeviceHandle, Direction, Recipient, RequestType, UsbContext}; use std::time::Duration; -use usb::{Backend, Device, HID_GET_REPORT, HID_SET_REPORT, PRODUCT_ID, REPORT_TYPE_FEATURE, VENDOR_ID}; +use crate::usb::{Backend, Device, HID_GET_REPORT, HID_SET_REPORT, PRODUCT_ID, REPORT_TYPE_FEATURE, VENDOR_ID}; pub struct RUSBBackend { context: Context, } +#[async_trait] impl Backend, u8> for RUSBBackend { fn new() -> Result { let context = match Context::new() { @@ -16,7 +18,7 @@ impl Backend, u8> for RUSBBackend { Ok(Self { context }) } - fn open_device( + async fn open_device( &mut self, bus_id: u8, address_id: u8, @@ -38,7 +40,7 @@ impl Backend, u8> for RUSBBackend { if device.bus_number() == bus_id && device.address() == address_id { match device.open() { - Ok(handle) => { + Ok(mut handle) => { let config = match device.config_descriptor(0) { Ok(c) => c, Err(_) => continue, @@ -78,7 +80,7 @@ impl Backend, u8> for RUSBBackend { } #[cfg(any(target_os = "macos", target_os = "windows"))] - fn close_device( + async fn close_device( &self, _handle: DeviceHandle, _interfaces: Vec, @@ -87,9 +89,9 @@ impl Backend, u8> for RUSBBackend { } #[cfg(not(any(target_os = "macos", target_os = "windows")))] - fn close_device( + async fn close_device( &self, - handle: DeviceHandle, + mut handle: DeviceHandle, interfaces: Vec, ) -> Result<(), ChallengeResponseError> { for interface in interfaces { @@ -99,7 +101,7 @@ impl Backend, u8> for RUSBBackend { Ok(()) } - fn read( + async fn read( &self, handle: &mut DeviceHandle, buf: &mut [u8], @@ -107,24 +109,24 @@ impl Backend, u8> for RUSBBackend { assert_eq!(buf.len(), 8); let reqtype = request_type(Direction::In, RequestType::Class, Recipient::Interface); let value = REPORT_TYPE_FEATURE << 8; - Ok(handle.read_control(reqtype, HID_GET_REPORT, value, 0, buf, Duration::new(2, 0))?) + Ok(handle.read_control(reqtype, HID_GET_REPORT, value, 0, buf, Duration::new(2, 0)).await?) } - fn raw_write( + async fn raw_write( &self, handle: &mut DeviceHandle, packet: &[u8], ) -> Result<(), ChallengeResponseError> { let reqtype = request_type(Direction::Out, RequestType::Class, Recipient::Interface); let value = REPORT_TYPE_FEATURE << 8; - if handle.write_control(reqtype, HID_SET_REPORT, value, 0, &packet, Duration::new(2, 0))? != 8 { + if handle.write_control(reqtype, HID_SET_REPORT, value, 0, &packet, Duration::new(2, 0)).await? != 8 { Err(ChallengeResponseError::CanNotWriteToDevice) } else { Ok(()) } } - fn find_device(&mut self) -> Result { + async fn find_device(&mut self) -> Result { let devices = match self.context.devices() { Ok(d) => d, Err(e) => return Err(ChallengeResponseError::UsbError(e)), @@ -140,6 +142,7 @@ impl Backend, u8> for RUSBBackend { let name = device.open()?.read_product_string_ascii(&descr).ok(); let serial = self .read_serial_from_device(device.bus_number(), device.address()) + .await .ok(); let device = Device { name, @@ -156,7 +159,7 @@ impl Backend, u8> for RUSBBackend { Err(ChallengeResponseError::DeviceNotFound) } - fn find_device_from_serial(&mut self, serial: u32) -> Result { + async fn find_device_from_serial(&mut self, serial: u32) -> Result { let devices = match self.context.devices() { Ok(d) => d, Err(e) => return Err(ChallengeResponseError::UsbError(e)), @@ -172,6 +175,7 @@ impl Backend, u8> for RUSBBackend { let name = device.open()?.read_product_string_ascii(&descr).ok(); let fetched_serial = match self .read_serial_from_device(device.bus_number(), device.address()) + .await .ok() { Some(s) => s, @@ -194,7 +198,7 @@ impl Backend, u8> for RUSBBackend { Err(ChallengeResponseError::DeviceNotFound) } - fn find_all_devices(&mut self) -> Result, ChallengeResponseError> { + async fn find_all_devices(&mut self) -> Result, ChallengeResponseError> { let mut result: Vec = Vec::new(); let devices = match self.context.devices() { Ok(d) => d, @@ -211,6 +215,7 @@ impl Backend, u8> for RUSBBackend { let name = device.open()?.read_product_string_ascii(&descr).ok(); let serial = self .read_serial_from_device(device.bus_number(), device.address()) + .await .ok(); let device = Device { name,