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, &register_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