diff --git a/examples/is_configured.rs b/examples/is_configured.rs new file mode 100644 index 0000000..16085cb --- /dev/null +++ b/examples/is_configured.rs @@ -0,0 +1,26 @@ +use challenge_response::{config::Slot, ChallengeResponse, Device}; + +fn main() { + let mut cr = ChallengeResponse::new().unwrap(); + let device = cr.find_device().unwrap(); + + println!("Checking configuration for device: {:?}", device.name); + + check_slot(&mut cr, &device, Slot::Slot1); + check_slot(&mut cr, &device, Slot::Slot2); +} + +fn check_slot(cr: &mut ChallengeResponse, device: &Device, slot: Slot) { + match cr.is_configured(device.clone(), slot.clone()) { + Ok(configured) => { + println!( + "Slot {:?} is {}configured", + slot, + if configured { "" } else { "not " } + ); + } + Err(e) => { + eprintln!("Error checking slot {:?}: {:?}", slot, e); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 49c3cdc..78ca5e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ use error::ChallengeResponseError; use hmacmode::Hmac; use otpmode::Aes128Block; use sec::{crc16, CRC_RESIDUAL_OK}; -use usb::{Backend, BackendType, Flags, Frame, CHALLENGE_SIZE}; +use usb::{Backend, BackendType, Flags, Frame, Status, CHALLENGE_SIZE}; pub use usb::Device; @@ -71,6 +71,54 @@ impl ChallengeResponse { .read_serial_from_device(conf.device.bus_id, conf.device.address_id) } + pub fn read_status(&mut self, conf: Config) -> Result { + let (mut handle, interfaces) = self + .backend + .open_device(conf.device.bus_id, conf.device.address_id)?; + + let challenge = [0; CHALLENGE_SIZE]; + let command = Command::DeviceConfig; + + let d = Frame::new(challenge, command); + let mut buf = [0; usb::STATUS_UPDATE_PAYLOAD_SIZE]; + self.backend + .wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?; + + self.backend.write_frame(&mut handle, &d)?; + + // Read the response. + let mut response = [0; usb::RESPONSE_SIZE]; + self.backend.read_response(&mut handle, &mut response)?; + self.backend.close_device(handle, interfaces)?; + + // Check response. + if crc16(&response[..8]) != CRC_RESIDUAL_OK { + return Err(ChallengeResponseError::WrongCRC); + } + + let slice = &response[..6]; + let array: [u8; 6] = slice.try_into().unwrap(); + let status: Status = unsafe { std::mem::transmute(array) }; + + Ok(status) + } + + pub fn is_configured(&mut self, device: Device, slot: Slot) -> Result { + let conf = Config::new_from(device); + let status = self.read_status(conf)?; + + if status.pgm_seq == 0 { + return Ok(false); + } + + let configured = match slot { + Slot::Slot1 => (status.touch_level & 1) != 0, + Slot::Slot2 => (status.touch_level & 2) != 0, + }; + + Ok(configured) + } + pub 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]; diff --git a/src/usb.rs b/src/usb.rs index 98c8290..681c64f 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -61,6 +61,16 @@ pub struct Frame { filler: [u8; 3], } +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct Status { + pub version_major: u8, + pub version_minor: u8, + pub version_build: u8, + pub pgm_seq: u8, + pub touch_level: u16, +} + impl Frame { pub fn new(payload: [u8; PAYLOAD_SIZE], command: Command) -> Self { let mut f = Frame {