Skip to content

Commit

Permalink
feat: migrate to nusb
Browse files Browse the repository at this point in the history
  • Loading branch information
louib committed Jul 20, 2024
1 parent aa0f30e commit 6b6f6d1
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 54 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ path = "src/lib.rs"
rand = "0.8"
bitflags = "2.4"
rusb = "0.9"
nusb = "0.1"
structure = "0.1"
aes = "0.8"
block-modes = "0.9"
Expand Down
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ cargo run --release --example "challenge_response_otp"
## Read Serial Number

cargo run --release --example "serial_number"

## Find all the connected devices

cargo run --release --example "find_all_devices"
3 changes: 2 additions & 1 deletion examples/challenge_response_hmac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::ops::Deref;
fn main() {
let mut challenge_response = ChallengeResponse::new().unwrap();

if let Ok(device) = challenge_response.find_device() {
if let Ok(device) = challenge_response.find_device_nusb() {
println!(
"Vendor ID: {:?} Product ID {:?}",
device.vendor_id, device.product_id
Expand All @@ -18,6 +18,7 @@ fn main() {
.set_variable_size(true)
.set_mode(Mode::Sha1)
.set_slot(Slot::Slot2);
println!("config: {:?}", config);

// Challenge can not be greater than 64 bytes
let challenge = String::from("mychallenge");
Expand Down
23 changes: 23 additions & 0 deletions examples/find_all_devices.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
extern crate challenge_response;
extern crate hex;

use challenge_response::ChallengeResponse;

fn main() {
let mut challenge_response = ChallengeResponse::new().unwrap();

let devices = match challenge_response.find_all_devices_nusb() {
Ok(devices) => devices,
Err(error) => {
println!("{}", error);
return;
}
};

for device in devices {
println!(
"Vendor ID: {:?} Product ID {:?}",
device.vendor_id, device.product_id
);
}
}
2 changes: 1 addition & 1 deletion examples/serial_number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use challenge_response::ChallengeResponse;
fn main() {
let mut challenge_response = ChallengeResponse::new().unwrap();

if let Ok(device) = challenge_response.find_device() {
if let Ok(device) = challenge_response.find_device_nusb() {
println!(
"Vendor ID: {:?} Product ID {:?}",
device.vendor_id, device.product_id
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum ChallengeResponseError {
DeviceNotFound,
OpenDeviceError,
CanNotWriteToDevice,
CanNotReadFromDevice,
WrongCRC,
ConfigNotWritten,
}
Expand All @@ -25,6 +26,7 @@ impl fmt::Display for ChallengeResponseError {
ChallengeResponseError::CommandNotSupported => write!(f, "Command Not Supported"),
ChallengeResponseError::WrongCRC => write!(f, "Wrong CRC"),
ChallengeResponseError::CanNotWriteToDevice => write!(f, "Can not write to Device"),
ChallengeResponseError::CanNotReadFromDevice => write!(f, "Can not read from Device"),
ChallengeResponseError::ConfigNotWritten => write!(f, "Configuration has failed"),
}
}
Expand Down
82 changes: 65 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#![doc = include_str!("../README.md")]

extern crate nusb;
extern crate rusb;

#[macro_use]
Expand All @@ -17,6 +19,7 @@ pub mod configure;
pub mod error;
pub mod hmacmode;
mod manager;
mod nusb_manager;
pub mod otpmode;
mod sec;

Expand Down Expand Up @@ -77,21 +80,20 @@ impl ChallengeResponse {
}

fn read_serial_from_device(&mut self, device: rusb::Device<Context>) -> Result<u32> {
let (mut handle, interfaces) =
manager::open_device(&mut self.context, device.bus_number(), device.address())?;
let (mut handle, interfaces) = nusb_manager::open_device(device.bus_number(), device.address())?;
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; 8];
manager::wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?;
nusb_manager::wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?;

manager::write_frame(&mut handle, &d)?;
nusb_manager::write_frame(&mut handle, &d)?;

// Read the response.
let mut response = [0; 36];
manager::read_response(&mut handle, &mut response)?;
manager::close_device(handle, interfaces)?;
nusb_manager::read_response(&mut handle, &mut response)?;
nusb_manager::close_device(handle, interfaces)?;

// Check response.
if crc16(&response[..6]) != crate::sec::CRC_RESIDUAL_OK {
Expand Down Expand Up @@ -168,6 +170,51 @@ impl ChallengeResponse {
Err(ChallengeResponseError::DeviceNotFound)
}

pub fn find_device_nusb(&mut self) -> Result<Device> {
match self.find_all_devices_nusb() {
Ok(devices) => {
if !devices.is_empty() {
return Ok(devices[0].clone());
}
Err(ChallengeResponseError::DeviceNotFound)
}
Err(e) => Err(e),
}
}

pub fn find_all_devices_nusb(&mut self) -> Result<Vec<Device>> {
let mut devices: Vec<Device> = Vec::new();
let nusb_devices = nusb::list_devices();
let nusb_devices = nusb_devices.unwrap();
for device_info in nusb_devices {
let product_id = device_info.product_id();
let vendor_id = device_info.vendor_id();

if !VENDOR_ID.contains(&vendor_id) || !PRODUCT_ID.contains(&product_id) {
continue;
}

devices.push(Device {
name: match device_info.manufacturer_string() {
Some(name) => Some(name.to_string()),
None => Some("unknown".to_string()),
},
serial: match device_info.serial_number() {
Some(serial) => match serial.parse::<u32>() {
Ok(s) => Some(s),
Err(_) => None,
},
None => None,
},
product_id,
vendor_id,
bus_id: device_info.bus_number(),
address_id: device_info.device_address(),
});
}
Ok(devices)
}

pub fn find_all_devices(&mut self) -> Result<Vec<Device>> {
let mut result: Vec<Device> = Vec::new();
let devices = match self.context.devices() {
Expand Down Expand Up @@ -223,25 +270,25 @@ impl ChallengeResponse {
}

pub fn read_serial_number(&mut self, conf: Config) -> Result<u32> {
match manager::open_device(&mut self.context, conf.device.bus_id, conf.device.address_id) {
match nusb_manager::open_device(conf.device.bus_id, conf.device.address_id) {
Ok((mut handle, interfaces)) => {
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; 8];
manager::wait(
nusb_manager::wait(
&mut handle,
|f| !f.contains(manager::Flags::SLOT_WRITE_FLAG),
&mut buf,
)?;

manager::write_frame(&mut handle, &d)?;
nusb_manager::write_frame(&mut handle, &d)?;

// Read the response.
let mut response = [0; 36];
manager::read_response(&mut handle, &mut response)?;
manager::close_device(handle, interfaces)?;
nusb_manager::read_response(&mut handle, &mut response)?;
nusb_manager::close_device(handle, interfaces)?;

// Check response.
if crc16(&response[..6]) != CRC_RESIDUAL_OK {
Expand All @@ -257,9 +304,9 @@ impl ChallengeResponse {
}

pub fn challenge_response_hmac(&mut self, chall: &[u8], conf: Config) -> Result<Hmac> {
let mut hmac = Hmac([0; 20]);
let mut hmac = Hmac([0; crate::hmacmode::HMAC_SECRET_SIZE]);

match manager::open_device(&mut self.context, conf.device.bus_id, conf.device.address_id) {
match nusb_manager::open_device(conf.device.bus_id, conf.device.address_id) {
Ok((mut handle, interfaces)) => {
let mut challenge = [0; CHALLENGE_SIZE];

Expand All @@ -274,19 +321,20 @@ impl ChallengeResponse {

(&mut challenge[..chall.len()]).copy_from_slice(chall);
let d = Frame::new(challenge, command);

let mut buf = [0; 8];
manager::wait(
nusb_manager::wait(
&mut handle,
|f| !f.contains(manager::Flags::SLOT_WRITE_FLAG),
&mut buf,
)?;

manager::write_frame(&mut handle, &d)?;
nusb_manager::write_frame(&mut handle, &d)?;

// Read the response.
let mut response = [0; 36];
manager::read_response(&mut handle, &mut response)?;
manager::close_device(handle, interfaces)?;
nusb_manager::read_response(&mut handle, &mut response)?;
nusb_manager::close_device(handle, interfaces)?;

// Check response.
if crc16(&response[..22]) != CRC_RESIDUAL_OK {
Expand Down
74 changes: 39 additions & 35 deletions src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use std::time::Duration;
use std::{slice, thread};

pub(crate) const PAYLOAD_SIZE: usize = 64;
const HID_GET_REPORT: u8 = 0x01;
const HID_SET_REPORT: u8 = 0x09;
const REPORT_TYPE_FEATURE: u16 = 0x03;
pub(crate) const HID_GET_REPORT: u8 = 0x01;
pub(crate) const HID_SET_REPORT: u8 = 0x09;
pub(crate) const REPORT_TYPE_FEATURE: u16 = 0x03;

bitflags! {
pub struct Flags: u8 {
Expand Down Expand Up @@ -37,40 +37,41 @@ pub fn open_device(
}
};

if device.bus_number() == bus_id && device.address() == address_id {
match device.open() {
Ok(handle) => {
let config = match device.config_descriptor(0) {
Ok(c) => c,
Err(_) => continue,
};

let mut _interfaces = Vec::new();
for interface in config.interfaces() {
for usb_int in interface.descriptors() {
match handle.kernel_driver_active(usb_int.interface_number()) {
Ok(true) => {
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
handle.detach_kernel_driver(usb_int.interface_number())?;
}
_ => continue,
};

if handle.active_configuration()? != config.number() {
handle.set_active_configuration(config.number())?;
if device.bus_number() != bus_id || device.address() != address_id {
continue;
}
match device.open() {
Ok(mut handle) => {
let config = match device.config_descriptor(0) {
Ok(c) => c,
Err(_) => continue,
};

let mut _interfaces = Vec::new();
for interface in config.interfaces() {
for usb_int in interface.descriptors() {
match handle.kernel_driver_active(usb_int.interface_number()) {
Ok(true) => {
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
handle.detach_kernel_driver(usb_int.interface_number())?;
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
handle.claim_interface(usb_int.interface_number())?;
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
_interfaces.push(usb_int.interface_number());
_ => continue,
};

if handle.active_configuration()? != config.number() {
handle.set_active_configuration(config.number())?;
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
handle.claim_interface(usb_int.interface_number())?;
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
_interfaces.push(usb_int.interface_number());
}

return Ok((handle, _interfaces));
}
Err(_) => {
return Err(ChallengeResponseError::OpenDeviceError);
}

return Ok((handle, _interfaces));
}
Err(_) => {
return Err(ChallengeResponseError::OpenDeviceError);
}
}
}
Expand All @@ -80,14 +81,17 @@ pub fn open_device(

#[cfg(any(target_os = "macos", target_os = "windows"))]
pub fn close_device(
_handle: DeviceHandle<Context>,
mut _handle: DeviceHandle<Context>,
_interfaces: Vec<u8>,
) -> Result<(), ChallengeResponseError> {
Ok(())
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
pub fn close_device(handle: DeviceHandle<Context>, interfaces: Vec<u8>) -> Result<(), ChallengeResponseError> {
pub fn close_device(
mut handle: DeviceHandle<Context>,
interfaces: Vec<u8>,
) -> Result<(), ChallengeResponseError> {
for interface in interfaces {
handle.release_interface(interface)?;
handle.attach_kernel_driver(interface)?;
Expand Down
Loading

0 comments on commit 6b6f6d1

Please sign in to comment.