1extern crate rusb;
2
3#[macro_use]
4extern crate structure;
5
6extern crate aes;
7extern crate block_modes;
8extern crate hmac;
9extern crate rand;
10extern crate sha1;
11#[macro_use]
12extern crate bitflags;
13
14pub mod config;
15pub mod configure;
16pub mod hmacmode;
17mod manager;
18pub mod otpmode;
19pub mod sec;
20pub mod yubicoerror;
21
22use aes::cipher::generic_array::GenericArray;
23
24use config::Command;
25use config::{Config, Slot};
26use configure::DeviceModeConfig;
27use hmacmode::Hmac;
28use manager::{Flags, Frame};
29use otpmode::Aes128Block;
30use rusb::{Context, UsbContext};
31use sec::{crc16, CRC_RESIDUAL_OK};
32use yubicoerror::YubicoError;
33
34const VENDOR_ID: u16 = 0x1050;
35
36type Result<T> = ::std::result::Result<T, YubicoError>;
38
39#[derive(Clone, Debug, PartialEq)]
40pub struct Yubikey {
41 pub name: Option<String>,
42 pub serial: Option<u32>,
43 pub product_id: u16,
44 pub vendor_id: u16,
45 pub bus_id: u8,
46 pub address_id: u8,
47}
48
49pub struct Yubico {
50 context: Context,
51}
52
53impl Yubico {
54 pub fn new() -> Self {
56 Yubico {
57 context: Context::new().unwrap(),
58 }
59 }
60
61 pub fn read_serial_from_device(&mut self, device: rusb::Device<Context>) -> Result<u32> {
62 let mut handle =
64 manager::open_device(&mut self.context, device.bus_number(), device.address())?;
65 let challenge = [0; 64];
66 let command = Command::DeviceSerial;
67
68 let d = Frame::new(challenge, command); let mut buf = [0; 8];
70 manager::wait(
71 &mut handle.0,
72 |f| !f.contains(Flags::SLOT_WRITE_FLAG),
73 &mut buf,
74 )?;
75
76 manager::write_frame(&mut handle.0, &d)?;
77
78 let mut response = [0; 36];
80 manager::read_response(&mut handle.0, &mut response)?;
81
82 drop(handle); if crc16(&response[..6]) != crate::sec::CRC_RESIDUAL_OK {
86 return Err(YubicoError::WrongCRC);
87 }
88
89 let serial = structure!("2I").unpack(response[..8].to_vec())?;
90
91 Ok(serial.0)
92 }
93
94 pub fn find_yubikey(&mut self) -> Result<Yubikey> {
95 for device in self.context.devices().unwrap().iter() {
96 let descr = device.device_descriptor().unwrap();
97 if descr.vendor_id() == VENDOR_ID {
98 let name = device.open()?.read_product_string_ascii(&descr).ok();
99 let serial = self.read_serial_from_device(device.clone()).ok();
100 let yubikey = Yubikey {
101 name: name,
102 serial: serial,
103 product_id: descr.product_id(),
104 vendor_id: descr.vendor_id(),
105 bus_id: device.bus_number(),
106 address_id: device.address(),
107 };
108
109 return Ok(yubikey);
110 }
111 }
112
113 Err(YubicoError::DeviceNotFound)
114 }
115
116 pub fn find_yubikey_from_serial(&mut self, serial: u32) -> Result<Yubikey> {
117 for device in self.context.devices().unwrap().iter() {
118 let descr = device.device_descriptor().unwrap();
119 if descr.vendor_id() == VENDOR_ID {
120 let name = device.open()?.read_product_string_ascii(&descr).ok();
121 let fetched_serial = match self.read_serial_from_device(device.clone()).ok() {
122 Some(s) => s,
123 None => 0,
124 };
125 if serial == fetched_serial {
126 let yubikey = Yubikey {
127 name: name,
128 serial: Some(serial),
129 product_id: descr.product_id(),
130 vendor_id: descr.vendor_id(),
131 bus_id: device.bus_number(),
132 address_id: device.address(),
133 };
134
135 return Ok(yubikey);
136 }
137 }
138 }
139
140 Err(YubicoError::DeviceNotFound)
141 }
142
143 pub fn find_all_yubikeys(&mut self) -> Result<Vec<Yubikey>> {
144 let mut result: Vec<Yubikey> = Vec::new();
145 for device in self.context.devices().unwrap().iter() {
146 let descr = device.device_descriptor().unwrap();
147 if descr.vendor_id() == VENDOR_ID {
148 let name = device.open()?.read_product_string_ascii(&descr).ok();
149 let serial = self.read_serial_from_device(device.clone()).ok();
150 let yubikey = Yubikey {
151 name: name,
152 serial: serial,
153 product_id: descr.product_id(),
154 vendor_id: descr.vendor_id(),
155 bus_id: device.bus_number(),
156 address_id: device.address(),
157 };
158 result.push(yubikey);
159 }
160 }
161
162 if !result.is_empty() {
163 return Ok(result);
164 }
165
166 Err(YubicoError::DeviceNotFound)
167 }
168
169 pub fn write_config(
170 &mut self,
171 conf: Config,
172 device_config: &mut DeviceModeConfig,
173 ) -> Result<()> {
174 let d = device_config.to_frame(conf.command);
175 let mut buf = [0; 8];
176
177 match manager::open_device(
178 &mut self.context,
179 conf.yubikey.bus_id,
180 conf.yubikey.address_id,
181 ) {
182 Ok((mut handle, interfaces)) => {
183 manager::wait(
184 &mut handle,
185 |f| !f.contains(Flags::SLOT_WRITE_FLAG),
186 &mut buf,
187 )?;
188
189 manager::write_frame(&mut handle, &d)?;
192 manager::wait(
193 &mut handle,
194 |f| !f.contains(Flags::SLOT_WRITE_FLAG),
195 &mut buf,
196 )?;
197 manager::close_device(handle, interfaces)?;
198
199 Ok(())
200 }
201 Err(error) => Err(error),
202 }
203 }
204
205 pub fn read_serial_number(&mut self, conf: Config) -> Result<u32> {
206 match manager::open_device(
207 &mut self.context,
208 conf.yubikey.bus_id,
209 conf.yubikey.address_id,
210 ) {
211 Ok((mut handle, interfaces)) => {
212 let challenge = [0; 64];
213 let command = Command::DeviceSerial;
214
215 let d = Frame::new(challenge, command); let mut buf = [0; 8];
217 manager::wait(
218 &mut handle,
219 |f| !f.contains(manager::Flags::SLOT_WRITE_FLAG),
220 &mut buf,
221 )?;
222
223 manager::write_frame(&mut handle, &d)?;
224
225 let mut response = [0; 36];
227 manager::read_response(&mut handle, &mut response)?;
228 manager::close_device(handle, interfaces)?;
229
230 if crc16(&response[..6]) != CRC_RESIDUAL_OK {
232 return Err(YubicoError::WrongCRC);
233 }
234
235 let serial = structure!("2I").unpack(response[..8].to_vec())?;
236
237 Ok(serial.0)
238 }
239 Err(error) => Err(error),
240 }
241 }
242
243 pub fn challenge_response_hmac(&mut self, chall: &[u8], conf: Config) -> Result<Hmac> {
244 let mut hmac = Hmac([0; 20]);
245
246 match manager::open_device(
247 &mut self.context,
248 conf.yubikey.bus_id,
249 conf.yubikey.address_id,
250 ) {
251 Ok((mut handle, interfaces)) => {
252 let mut challenge = [0; 64];
253
254 if conf.variable && chall.last() == Some(&0) {
255 challenge = [0xff; 64];
256 }
257
258 let mut command = Command::ChallengeHmac1;
259 if let Slot::Slot2 = conf.slot {
260 command = Command::ChallengeHmac2;
261 }
262
263 (&mut challenge[..chall.len()]).copy_from_slice(chall);
264 let d = Frame::new(challenge, command);
265 let mut buf = [0; 8];
266 manager::wait(
267 &mut handle,
268 |f| !f.contains(manager::Flags::SLOT_WRITE_FLAG),
269 &mut buf,
270 )?;
271
272 manager::write_frame(&mut handle, &d)?;
273
274 let mut response = [0; 36];
276 manager::read_response(&mut handle, &mut response)?;
277 manager::close_device(handle, interfaces)?;
278
279 if crc16(&response[..22]) != CRC_RESIDUAL_OK {
281 return Err(YubicoError::WrongCRC);
282 }
283
284 hmac.0.clone_from_slice(&response[..20]);
285
286 Ok(hmac)
287 }
288 Err(error) => Err(error),
289 }
290 }
291
292 pub fn challenge_response_otp(&mut self, chall: &[u8], conf: Config) -> Result<Aes128Block> {
293 let mut block = Aes128Block {
294 block: GenericArray::clone_from_slice(&[0; 16]),
295 };
296
297 match manager::open_device(
298 &mut self.context,
299 conf.yubikey.bus_id,
300 conf.yubikey.address_id,
301 ) {
302 Ok((mut handle, interfaces)) => {
303 let mut challenge = [0; 64];
304 let mut command = Command::ChallengeOtp1;
307 if let Slot::Slot2 = conf.slot {
308 command = Command::ChallengeOtp2;
309 }
310
311 (&mut challenge[..chall.len()]).copy_from_slice(chall);
312 let d = Frame::new(challenge, command);
313 let mut buf = [0; 8];
314 eprintln!("Step 1 done");
315 let mut response = [0; 36];
316 manager::wait(
317 &mut handle,
318 |f| !f.contains(manager::Flags::SLOT_WRITE_FLAG),
319 &mut buf,
320 )?;
321 eprintln!("Step 2 done");
322 manager::write_frame(&mut handle, &d)?;
323 eprintln!("Step 3 done");
324 manager::read_response(&mut handle, &mut response)?;
325 eprintln!("Step 4 done");
326 manager::close_device(handle, interfaces)?;
327 eprintln!("Step 5 done");
328
329 if crc16(&response[..18]) != CRC_RESIDUAL_OK {
331 return Err(YubicoError::WrongCRC);
332 }
333
334 block.block.copy_from_slice(&response[..16]);
335
336 Ok(block)
337 }
338 Err(error) => Err(error),
339 }
340 }
341}