diff --git a/src/lib.rs b/src/lib.rs index 367deb8..71bc454 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ use config::Command; use config::{Config, Slot}; use configure::DeviceModeConfig; use hmacmode::Hmac; -use manager::{Flags, Frame}; +use manager::{read_serial_from_device, Flags, Frame}; use otpmode::Aes128Block; use rusb::{Context, UsbContext}; use sec::{crc16, CRC_RESIDUAL_OK}; @@ -39,6 +39,7 @@ type Result<T> = ::std::result::Result<T, YubicoError>; #[derive(Clone, Debug, PartialEq)] pub struct Yubikey { pub name: String, + pub serial: u32, pub product_id: u16, pub vendor_id: u16, pub bus_id: u8, @@ -61,13 +62,11 @@ impl Yubico { for device in self.context.devices().unwrap().iter() { let descr = device.device_descriptor().unwrap(); if descr.vendor_id() == VENDOR_ID { - let name = device - .open() - .unwrap() - .read_product_string_ascii(&descr) - .unwrap(); + let name = device.open()?.read_product_string_ascii(&descr)?; + let serial = read_serial_from_device(device.clone())?; let yubikey = Yubikey { name: name, + serial: serial, product_id: descr.product_id(), vendor_id: descr.vendor_id(), bus_id: device.bus_number(), @@ -86,13 +85,11 @@ impl Yubico { for device in self.context.devices().unwrap().iter() { let descr = device.device_descriptor().unwrap(); if descr.vendor_id() == VENDOR_ID { - let name = device - .open() - .unwrap() - .read_product_string_ascii(&descr) - .unwrap(); + let name = device.open()?.read_product_string_ascii(&descr)?; + let serial = read_serial_from_device(device.clone())?; let yubikey = Yubikey { name: name, + serial: serial, product_id: descr.product_id(), vendor_id: descr.vendor_id(), bus_id: device.bus_number(), @@ -117,7 +114,11 @@ impl Yubico { let d = device_config.to_frame(conf.command); let mut buf = [0; 8]; - match manager::open_device(&mut self.context, conf.yubikey) { + match manager::open_device( + &mut self.context, + conf.yubikey.bus_id, + conf.yubikey.address_id, + ) { Ok((mut handle, interfaces)) => { manager::wait( &mut handle, @@ -142,7 +143,11 @@ impl Yubico { } pub fn read_serial_number(&mut self, conf: Config) -> Result<u32> { - match manager::open_device(&mut self.context, conf.yubikey) { + match manager::open_device( + &mut self.context, + conf.yubikey.bus_id, + conf.yubikey.address_id, + ) { Ok((mut handle, interfaces)) => { let challenge = [0; 64]; let command = Command::DeviceSerial; @@ -178,7 +183,11 @@ impl Yubico { pub fn challenge_response_hmac(&mut self, chall: &[u8], conf: Config) -> Result<Hmac> { let mut hmac = Hmac([0; 20]); - match manager::open_device(&mut self.context, conf.yubikey) { + match manager::open_device( + &mut self.context, + conf.yubikey.bus_id, + conf.yubikey.address_id, + ) { Ok((mut handle, interfaces)) => { let mut challenge = [0; 64]; @@ -225,7 +234,11 @@ impl Yubico { block: GenericArray::clone_from_slice(&[0; 16]), }; - match manager::open_device(&mut self.context, conf.yubikey) { + match manager::open_device( + &mut self.context, + conf.yubikey.bus_id, + conf.yubikey.address_id, + ) { Ok((mut handle, interfaces)) => { let mut challenge = [0; 64]; //(&mut challenge[..6]).copy_from_slice(chall); diff --git a/src/manager.rs b/src/manager.rs index b909109..f5f4b8d 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -1,12 +1,12 @@ use crate::config::Command; use crate::sec::crc16; use crate::yubicoerror::YubicoError; -use rusb::{request_type, Context, DeviceHandle, Direction, Recipient, RequestType, UsbContext}; +use rusb::{ + request_type, Context, Device, DeviceHandle, Direction, Recipient, RequestType, UsbContext, +}; use std::time::Duration; use std::{slice, thread}; -use crate::Yubikey; - const DATA_SIZE: usize = 64; const HID_GET_REPORT: u8 = 0x01; const HID_SET_REPORT: u8 = 0x09; @@ -19,9 +19,40 @@ bitflags! { } } +pub fn read_serial_from_device(device: Device<Context>) -> Result<u32, YubicoError> { + let mut context = Context::new()?; + let mut handle = open_device(&mut context, device.bus_number(), device.address())?; + let challenge = [0; 64]; + let command = Command::DeviceSerial; + + let d = Frame::new(challenge, command); // FixMe: do not need a challange + let mut buf = [0; 8]; + wait( + &mut handle.0, + |f| !f.contains(Flags::SLOT_WRITE_FLAG), + &mut buf, + )?; + + write_frame(&mut handle.0, &d)?; + + // Read the response. + let mut response = [0; 36]; + read_response(&mut handle.0, &mut response)?; + + // Check response. + if crc16(&response[..6]) != crate::sec::CRC_RESIDUAL_OK { + return Err(YubicoError::WrongCRC); + } + + let serial = structure!("2I").unpack(response[..8].to_vec())?; + + Ok(serial.0) +} + pub fn open_device( context: &mut Context, - yubikey: Yubikey, + bus_id: u8, + address_id: u8, ) -> Result<(DeviceHandle<Context>, Vec<u8>), YubicoError> { let devices = match context.devices() { Ok(device) => device, @@ -38,7 +69,7 @@ pub fn open_device( } }; - if device.bus_number() == yubikey.bus_id && device.address() == yubikey.address_id { + if device.bus_number() == bus_id && device.address() == address_id { match device.open() { Ok(mut handle) => { let config = match device.config_descriptor(0) {