1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #![cfg_attr(feature = "cargo-clippy", allow(clippy::needless_lifetimes))]
6
7 extern crate std;
8
9 use rand::{thread_rng, RngCore};
10 use std::ffi::CString;
11 use std::io;
12 use std::io::{Read, Write};
13
14 use crate::consts::*;
15 use crate::u2ftypes::*;
16 use crate::util::io_err;
17
18 ////////////////////////////////////////////////////////////////////////
19 // Device Commands
20 ////////////////////////////////////////////////////////////////////////
21
u2f_init_device<T>(dev: &mut T) -> bool where T: U2FDevice + Read + Write,22 pub fn u2f_init_device<T>(dev: &mut T) -> bool
23 where
24 T: U2FDevice + Read + Write,
25 {
26 let mut nonce = [0u8; 8];
27 thread_rng().fill_bytes(&mut nonce);
28
29 // Initialize the device and check its version.
30 init_device(dev, &nonce).is_ok() && is_v2_device(dev).unwrap_or(false)
31 }
32
u2f_register<T>(dev: &mut T, challenge: &[u8], application: &[u8]) -> io::Result<Vec<u8>> where T: U2FDevice + Read + Write,33 pub fn u2f_register<T>(dev: &mut T, challenge: &[u8], application: &[u8]) -> io::Result<Vec<u8>>
34 where
35 T: U2FDevice + Read + Write,
36 {
37 if challenge.len() != PARAMETER_SIZE || application.len() != PARAMETER_SIZE {
38 return Err(io::Error::new(
39 io::ErrorKind::InvalidInput,
40 "Invalid parameter sizes",
41 ));
42 }
43
44 let mut register_data = Vec::with_capacity(2 * PARAMETER_SIZE);
45 register_data.extend(challenge);
46 register_data.extend(application);
47
48 let flags = U2F_REQUEST_USER_PRESENCE;
49 let (resp, status) = send_apdu(dev, U2F_REGISTER, flags, ®ister_data)?;
50 status_word_to_result(status, resp)
51 }
52
u2f_sign<T>( dev: &mut T, challenge: &[u8], application: &[u8], key_handle: &[u8], ) -> io::Result<Vec<u8>> where T: U2FDevice + Read + Write,53 pub fn u2f_sign<T>(
54 dev: &mut T,
55 challenge: &[u8],
56 application: &[u8],
57 key_handle: &[u8],
58 ) -> io::Result<Vec<u8>>
59 where
60 T: U2FDevice + Read + Write,
61 {
62 if challenge.len() != PARAMETER_SIZE || application.len() != PARAMETER_SIZE {
63 return Err(io::Error::new(
64 io::ErrorKind::InvalidInput,
65 "Invalid parameter sizes",
66 ));
67 }
68
69 if key_handle.len() > 256 {
70 return Err(io::Error::new(
71 io::ErrorKind::InvalidInput,
72 "Key handle too large",
73 ));
74 }
75
76 let mut sign_data = Vec::with_capacity(2 * PARAMETER_SIZE + 1 + key_handle.len());
77 sign_data.extend(challenge);
78 sign_data.extend(application);
79 sign_data.push(key_handle.len() as u8);
80 sign_data.extend(key_handle);
81
82 let flags = U2F_REQUEST_USER_PRESENCE;
83 let (resp, status) = send_apdu(dev, U2F_AUTHENTICATE, flags, &sign_data)?;
84 status_word_to_result(status, resp)
85 }
86
u2f_is_keyhandle_valid<T>( dev: &mut T, challenge: &[u8], application: &[u8], key_handle: &[u8], ) -> io::Result<bool> where T: U2FDevice + Read + Write,87 pub fn u2f_is_keyhandle_valid<T>(
88 dev: &mut T,
89 challenge: &[u8],
90 application: &[u8],
91 key_handle: &[u8],
92 ) -> io::Result<bool>
93 where
94 T: U2FDevice + Read + Write,
95 {
96 if challenge.len() != PARAMETER_SIZE || application.len() != PARAMETER_SIZE {
97 return Err(io::Error::new(
98 io::ErrorKind::InvalidInput,
99 "Invalid parameter sizes",
100 ));
101 }
102
103 if key_handle.len() > 256 {
104 return Err(io::Error::new(
105 io::ErrorKind::InvalidInput,
106 "Key handle too large",
107 ));
108 }
109
110 let mut sign_data = Vec::with_capacity(2 * PARAMETER_SIZE + 1 + key_handle.len());
111 sign_data.extend(challenge);
112 sign_data.extend(application);
113 sign_data.push(key_handle.len() as u8);
114 sign_data.extend(key_handle);
115
116 let flags = U2F_CHECK_IS_REGISTERED;
117 let (_, status) = send_apdu(dev, U2F_AUTHENTICATE, flags, &sign_data)?;
118 Ok(status == SW_CONDITIONS_NOT_SATISFIED)
119 }
120
121 ////////////////////////////////////////////////////////////////////////
122 // Internal Device Commands
123 ////////////////////////////////////////////////////////////////////////
124
init_device<T>(dev: &mut T, nonce: &[u8]) -> io::Result<()> where T: U2FDevice + Read + Write,125 fn init_device<T>(dev: &mut T, nonce: &[u8]) -> io::Result<()>
126 where
127 T: U2FDevice + Read + Write,
128 {
129 assert_eq!(nonce.len(), INIT_NONCE_SIZE);
130 let raw = sendrecv(dev, U2FHID_INIT, nonce)?;
131 let rsp = U2FHIDInitResp::read(&raw, nonce)?;
132 dev.set_cid(rsp.cid);
133
134 let vendor = dev
135 .get_property("Manufacturer")
136 .unwrap_or_else(|_| String::from("Unknown Vendor"));
137 let product = dev
138 .get_property("Product")
139 .unwrap_or_else(|_| String::from("Unknown Device"));
140
141 dev.set_device_info(U2FDeviceInfo {
142 vendor_name: vendor.as_bytes().to_vec(),
143 device_name: product.as_bytes().to_vec(),
144 version_interface: rsp.version_interface,
145 version_major: rsp.version_major,
146 version_minor: rsp.version_minor,
147 version_build: rsp.version_build,
148 cap_flags: rsp.cap_flags,
149 });
150
151 Ok(())
152 }
153
is_v2_device<T>(dev: &mut T) -> io::Result<bool> where T: U2FDevice + Read + Write,154 fn is_v2_device<T>(dev: &mut T) -> io::Result<bool>
155 where
156 T: U2FDevice + Read + Write,
157 {
158 let (data, status) = send_apdu(dev, U2F_VERSION, 0x00, &[])?;
159 let actual = CString::new(data)?;
160 let expected = CString::new("U2F_V2")?;
161 status_word_to_result(status, actual == expected)
162 }
163
164 ////////////////////////////////////////////////////////////////////////
165 // Error Handling
166 ////////////////////////////////////////////////////////////////////////
167
status_word_to_result<T>(status: [u8; 2], val: T) -> io::Result<T>168 fn status_word_to_result<T>(status: [u8; 2], val: T) -> io::Result<T> {
169 use self::io::ErrorKind::{InvalidData, InvalidInput};
170
171 match status {
172 SW_NO_ERROR => Ok(val),
173 SW_WRONG_DATA => Err(io::Error::new(InvalidData, "wrong data")),
174 SW_WRONG_LENGTH => Err(io::Error::new(InvalidInput, "wrong length")),
175 SW_CONDITIONS_NOT_SATISFIED => Err(io_err("conditions not satisfied")),
176 _ => Err(io_err(&format!("failed with status {:?}", status))),
177 }
178 }
179
180 ////////////////////////////////////////////////////////////////////////
181 // Device Communication Functions
182 ////////////////////////////////////////////////////////////////////////
183
sendrecv<T>(dev: &mut T, cmd: u8, send: &[u8]) -> io::Result<Vec<u8>> where T: U2FDevice + Read + Write,184 pub fn sendrecv<T>(dev: &mut T, cmd: u8, send: &[u8]) -> io::Result<Vec<u8>>
185 where
186 T: U2FDevice + Read + Write,
187 {
188 // Send initialization packet.
189 let mut count = U2FHIDInit::write(dev, cmd, send)?;
190
191 // Send continuation packets.
192 let mut sequence = 0u8;
193 while count < send.len() {
194 count += U2FHIDCont::write(dev, sequence, &send[count..])?;
195 sequence += 1;
196 }
197
198 // Now we read. This happens in 2 chunks: The initial packet, which has the
199 // size we expect overall, then continuation packets, which will fill in
200 // data until we have everything.
201 let mut data = U2FHIDInit::read(dev)?;
202
203 let mut sequence = 0u8;
204 while data.len() < data.capacity() {
205 let max = data.capacity() - data.len();
206 data.extend_from_slice(&U2FHIDCont::read(dev, sequence, max)?);
207 sequence += 1;
208 }
209
210 Ok(data)
211 }
212
send_apdu<T>(dev: &mut T, cmd: u8, p1: u8, send: &[u8]) -> io::Result<(Vec<u8>, [u8; 2])> where T: U2FDevice + Read + Write,213 fn send_apdu<T>(dev: &mut T, cmd: u8, p1: u8, send: &[u8]) -> io::Result<(Vec<u8>, [u8; 2])>
214 where
215 T: U2FDevice + Read + Write,
216 {
217 let apdu = U2FAPDUHeader::serialize(cmd, p1, send)?;
218 let mut data = sendrecv(dev, U2FHID_MSG, &apdu)?;
219
220 if data.len() < 2 {
221 return Err(io_err("unexpected response"));
222 }
223
224 let split_at = data.len() - 2;
225 let status = data.split_off(split_at);
226 Ok((data, [status[0], status[1]]))
227 }
228
229 ////////////////////////////////////////////////////////////////////////
230 // Tests
231 ////////////////////////////////////////////////////////////////////////
232
233 #[cfg(test)]
234 mod tests {
235 use rand::{thread_rng, RngCore};
236
237 use super::{init_device, send_apdu, sendrecv, U2FDevice};
238 use crate::consts::{CID_BROADCAST, SW_NO_ERROR, U2FHID_INIT, U2FHID_MSG, U2FHID_PING};
239
240 mod platform {
241 use std::io;
242 use std::io::{Read, Write};
243
244 use crate::consts::CID_BROADCAST;
245 use crate::u2ftypes::{U2FDevice, U2FDeviceInfo};
246
247 const IN_HID_RPT_SIZE: usize = 64;
248 const OUT_HID_RPT_SIZE: usize = 64;
249
250 pub struct TestDevice {
251 cid: [u8; 4],
252 reads: Vec<[u8; IN_HID_RPT_SIZE]>,
253 writes: Vec<[u8; OUT_HID_RPT_SIZE + 1]>,
254 dev_info: Option<U2FDeviceInfo>,
255 }
256
257 impl TestDevice {
new() -> TestDevice258 pub fn new() -> TestDevice {
259 TestDevice {
260 cid: CID_BROADCAST,
261 reads: vec![],
262 writes: vec![],
263 dev_info: None,
264 }
265 }
266
add_write(&mut self, packet: &[u8], fill_value: u8)267 pub fn add_write(&mut self, packet: &[u8], fill_value: u8) {
268 // Add one to deal with record index check
269 let mut write = [fill_value; OUT_HID_RPT_SIZE + 1];
270 // Make sure we start with a 0, for HID record index
271 write[0] = 0;
272 // Clone packet data in at 1, since front is padded with HID record index
273 write[1..=packet.len()].clone_from_slice(packet);
274 self.writes.push(write);
275 }
276
add_read(&mut self, packet: &[u8], fill_value: u8)277 pub fn add_read(&mut self, packet: &[u8], fill_value: u8) {
278 let mut read = [fill_value; IN_HID_RPT_SIZE];
279 read[..packet.len()].clone_from_slice(packet);
280 self.reads.push(read);
281 }
282 }
283
284 impl Write for TestDevice {
write(&mut self, bytes: &[u8]) -> io::Result<usize>285 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
286 // Pop a vector from the expected writes, check for quality
287 // against bytes array.
288 assert!(!self.writes.is_empty(), "Ran out of expected write values!");
289 let check = self.writes.remove(0);
290 assert_eq!(check.len(), bytes.len());
291 assert_eq!(&check[..], bytes);
292 Ok(bytes.len())
293 }
294
295 // nop
flush(&mut self) -> io::Result<()>296 fn flush(&mut self) -> io::Result<()> {
297 Ok(())
298 }
299 }
300
301 impl Read for TestDevice {
read(&mut self, bytes: &mut [u8]) -> io::Result<usize>302 fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
303 assert!(!self.reads.is_empty(), "Ran out of read values!");
304 let check = self.reads.remove(0);
305 assert_eq!(check.len(), bytes.len());
306 bytes.clone_from_slice(&check[..]);
307 Ok(check.len())
308 }
309 }
310
311 impl Drop for TestDevice {
drop(&mut self)312 fn drop(&mut self) {
313 assert!(self.reads.is_empty());
314 assert!(self.writes.is_empty());
315 }
316 }
317
318 impl U2FDevice for TestDevice {
get_cid<'a>(&'a self) -> &'a [u8; 4]319 fn get_cid<'a>(&'a self) -> &'a [u8; 4] {
320 &self.cid
321 }
322
set_cid(&mut self, cid: [u8; 4])323 fn set_cid(&mut self, cid: [u8; 4]) {
324 self.cid = cid;
325 }
326
in_rpt_size(&self) -> usize327 fn in_rpt_size(&self) -> usize {
328 IN_HID_RPT_SIZE
329 }
330
out_rpt_size(&self) -> usize331 fn out_rpt_size(&self) -> usize {
332 OUT_HID_RPT_SIZE
333 }
334
get_property(&self, prop_name: &str) -> io::Result<String>335 fn get_property(&self, prop_name: &str) -> io::Result<String> {
336 Ok(format!("{} not implemented", prop_name))
337 }
get_device_info(&self) -> U2FDeviceInfo338 fn get_device_info(&self) -> U2FDeviceInfo {
339 self.dev_info.clone().unwrap()
340 }
341
set_device_info(&mut self, dev_info: U2FDeviceInfo)342 fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
343 self.dev_info = Some(dev_info);
344 }
345 }
346 }
347
348 #[test]
test_init_device()349 fn test_init_device() {
350 let mut device = platform::TestDevice::new();
351 let nonce = vec![0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01];
352
353 // channel id
354 let mut cid = [0u8; 4];
355 thread_rng().fill_bytes(&mut cid);
356
357 // init packet
358 let mut msg = CID_BROADCAST.to_vec();
359 msg.extend(vec![U2FHID_INIT, 0x00, 0x08]); // cmd + bcnt
360 msg.extend_from_slice(&nonce);
361 device.add_write(&msg, 0);
362
363 // init_resp packet
364 let mut msg = CID_BROADCAST.to_vec();
365 msg.extend(vec![U2FHID_INIT, 0x00, 0x11]); // cmd + bcnt
366 msg.extend_from_slice(&nonce);
367 msg.extend_from_slice(&cid); // new channel id
368 msg.extend(vec![0x02, 0x04, 0x01, 0x08, 0x01]); // versions + flags
369 device.add_read(&msg, 0);
370
371 init_device(&mut device, &nonce).unwrap();
372 assert_eq!(device.get_cid(), &cid);
373
374 let dev_info = device.get_device_info();
375 assert_eq!(dev_info.version_interface, 0x02);
376 assert_eq!(dev_info.version_major, 0x04);
377 assert_eq!(dev_info.version_minor, 0x01);
378 assert_eq!(dev_info.version_build, 0x08);
379 assert_eq!(dev_info.cap_flags, 0x01);
380 }
381
382 #[test]
test_sendrecv_multiple()383 fn test_sendrecv_multiple() {
384 let mut device = platform::TestDevice::new();
385 let cid = [0x01, 0x02, 0x03, 0x04];
386 device.set_cid(cid);
387
388 // init packet
389 let mut msg = cid.to_vec();
390 msg.extend(vec![U2FHID_PING, 0x00, 0xe4]); // cmd + length = 228
391 // write msg, append [1u8; 57], 171 bytes remain
392 device.add_write(&msg, 1);
393 device.add_read(&msg, 1);
394
395 // cont packet
396 let mut msg = cid.to_vec();
397 msg.push(0x00); // seq = 0
398 // write msg, append [1u8; 59], 112 bytes remaining
399 device.add_write(&msg, 1);
400 device.add_read(&msg, 1);
401
402 // cont packet
403 let mut msg = cid.to_vec();
404 msg.push(0x01); // seq = 1
405 // write msg, append [1u8; 59], 53 bytes remaining
406 device.add_write(&msg, 1);
407 device.add_read(&msg, 1);
408
409 // cont packet
410 let mut msg = cid.to_vec();
411 msg.push(0x02); // seq = 2
412 msg.extend_from_slice(&[1u8; 53]);
413 // write msg, append remaining 53 bytes.
414 device.add_write(&msg, 0);
415 device.add_read(&msg, 0);
416
417 let data = [1u8; 228];
418 let d = sendrecv(&mut device, U2FHID_PING, &data).unwrap();
419 assert_eq!(d.len(), 228);
420 assert_eq!(d, &data[..]);
421 }
422
423 #[test]
test_sendapdu()424 fn test_sendapdu() {
425 let cid = [0x01, 0x02, 0x03, 0x04];
426 let data = [0x01, 0x02, 0x03, 0x04, 0x05];
427 let mut device = platform::TestDevice::new();
428 device.set_cid(cid);
429
430 let mut msg = cid.to_vec();
431 // sendrecv header
432 msg.extend(vec![U2FHID_MSG, 0x00, 0x0e]); // len = 14
433 // apdu header
434 msg.extend(vec![0x00, U2FHID_PING, 0xaa, 0x00, 0x00, 0x00, 0x05]);
435 // apdu data
436 msg.extend_from_slice(&data);
437 device.add_write(&msg, 0);
438
439 // Send data back
440 let mut msg = cid.to_vec();
441 msg.extend(vec![U2FHID_MSG, 0x00, 0x07]);
442 msg.extend_from_slice(&data);
443 msg.extend_from_slice(&SW_NO_ERROR);
444 device.add_read(&msg, 0);
445
446 let (result, status) = send_apdu(&mut device, U2FHID_PING, 0xaa, &data).unwrap();
447 assert_eq!(result, &data);
448 assert_eq!(status, SW_NO_ERROR);
449 }
450
451 #[test]
test_get_property()452 fn test_get_property() {
453 let device = platform::TestDevice::new();
454
455 assert_eq!(device.get_property("a").unwrap(), "a not implemented");
456 }
457 }
458