Skip to content

Commit b820bd2

Browse files
committed
Add authenticator USB and Firmware details to the C API
Fixes #92
1 parent 2cb1ff0 commit b820bd2

File tree

19 files changed

+363
-34
lines changed

19 files changed

+363
-34
lines changed

examples/main.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,19 @@ fn main() {
6969
app_bytes.clone(),
7070
vec![],
7171
move |rv| {
72-
tx.send(rv.unwrap()).unwrap();
72+
tx.send(rv).unwrap();
7373
},
7474
)
7575
.unwrap();
7676

77-
let register_data = try_or!(rx.recv(), |_| {
77+
let register_result = try_or!(rx.recv(), |_| {
7878
panic!("Problem receiving, unable to continue");
7979
});
80+
let (register_data, device_info) =
81+
register_result.unwrap_or_else(|e| panic!("Registration failed: {:?}", e));
82+
8083
println!("Register result: {}", base64::encode(&register_data));
84+
println!("Device info: {}", &device_info);
8185
println!("Asking a security key to sign now, with the data from the register...");
8286
let credential = u2f_get_key_handle_from_register_response(&register_data).unwrap();
8387
let key_handle = KeyHandle {
@@ -95,15 +99,19 @@ fn main() {
9599
vec![app_bytes],
96100
vec![key_handle],
97101
move |rv| {
98-
tx.send(rv.unwrap()).unwrap();
102+
tx.send(rv).unwrap();
99103
},
100104
)
101105
.unwrap();
102106

103-
let (_, handle_used, sign_data) = try_or!(rx.recv(), |_| {
104-
println!("Problem receiving");
107+
let sign_result = try_or!(rx.recv(), |_| {
108+
panic!("Problem receiving, unable to continue");
105109
});
110+
let (_, handle_used, sign_data, device_info) =
111+
sign_result.unwrap_or_else(|e| panic!("Sign failed: {:?}", e));
112+
106113
println!("Sign result: {}", base64::encode(&sign_data));
107114
println!("Key handle used: {}", base64::encode(&handle_used));
115+
println!("Device info: {}", &device_info);
108116
println!("Done.");
109117
}

fuzz/fuzz_targets/u2f_read.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ extern crate authenticator;
99

1010
use std::{cmp, io};
1111

12-
use authenticator::{sendrecv, U2FDevice};
12+
use authenticator::{sendrecv, U2FDevice, U2FDeviceInfo};
1313
use authenticator::{CID_BROADCAST, MAX_HID_RPT_SIZE};
1414

1515
struct TestDevice<'a> {
1616
cid: [u8; 4],
1717
data: &'a [u8],
18+
dev_info: Option<U2FDeviceInfo>,
1819
}
1920

2021
impl<'a> TestDevice<'a> {
2122
pub fn new(data: &'a [u8]) -> TestDevice {
2223
TestDevice {
2324
cid: CID_BROADCAST,
2425
data,
26+
dev_info: None,
2527
}
2628
}
2729
}
@@ -63,6 +65,20 @@ impl<'a> U2FDevice for TestDevice<'a> {
6365
fn out_rpt_size(&self) -> usize {
6466
MAX_HID_RPT_SIZE
6567
}
68+
69+
fn get_property(&self, _prop_name: &str) -> io::Result<String> {
70+
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
71+
}
72+
73+
fn get_device_info(&self) -> U2FDeviceInfo {
74+
// unwrap is okay, as dev_info must have already been set, else
75+
// a programmer error
76+
self.dev_info.clone().unwrap()
77+
}
78+
79+
fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
80+
self.dev_info = Some(dev_info);
81+
}
6682
}
6783

6884
fuzz_target!(|data: &[u8]| {

fuzz/fuzz_targets/u2f_read_write.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ extern crate authenticator;
99

1010
use std::{cmp, io};
1111

12-
use authenticator::{sendrecv, U2FDevice};
12+
use authenticator::{sendrecv, U2FDevice, U2FDeviceInfo};
1313
use authenticator::{CID_BROADCAST, MAX_HID_RPT_SIZE};
1414

1515
struct TestDevice {
1616
cid: [u8; 4],
1717
data: Vec<u8>,
18+
dev_info: Option<U2FDeviceInfo>,
1819
}
1920

2021
impl TestDevice {
2122
pub fn new() -> TestDevice {
2223
TestDevice {
2324
cid: CID_BROADCAST,
2425
data: vec![],
26+
dev_info: None,
2527
}
2628
}
2729
}
@@ -64,6 +66,20 @@ impl U2FDevice for TestDevice {
6466
fn out_rpt_size(&self) -> usize {
6567
MAX_HID_RPT_SIZE
6668
}
69+
70+
fn get_property(&self, _prop_name: &str) -> io::Result<String> {
71+
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
72+
}
73+
74+
fn get_device_info(&self) -> U2FDeviceInfo {
75+
// unwrap is okay, as dev_info must have already been set, else
76+
// a programmer error
77+
self.dev_info.clone().unwrap()
78+
}
79+
80+
fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
81+
self.dev_info = Some(dev_info);
82+
}
6783
}
6884

6985
fuzz_target!(|data: &[u8]| {

src/capi.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const RESBUF_ID_REGISTRATION: u8 = 0;
2222
const RESBUF_ID_KEYHANDLE: u8 = 1;
2323
const RESBUF_ID_SIGNATURE: u8 = 2;
2424
const RESBUF_ID_APPID: u8 = 3;
25+
const RESBUF_ID_VENDOR_NAME: u8 = 4;
26+
const RESBUF_ID_DEVICE_NAME: u8 = 5;
27+
const RESBUF_ID_FIRMWARE_MAJOR: u8 = 6;
28+
const RESBUF_ID_FIRMWARE_MINOR: u8 = 7;
29+
const RESBUF_ID_FIRMWARE_BUILD: u8 = 8;
2530

2631
// Generates a new 64-bit transaction id with collision probability 2^-32.
2732
fn new_tid() -> u64 {
@@ -233,9 +238,14 @@ pub unsafe extern "C" fn rust_u2f_mgr_register(
233238
key_handles,
234239
move |rv| {
235240
let result = match rv {
236-
Ok(registration) => {
241+
Ok((registration, dev_info)) => {
237242
let mut bufs = HashMap::new();
238243
bufs.insert(RESBUF_ID_REGISTRATION, registration);
244+
bufs.insert(RESBUF_ID_VENDOR_NAME, dev_info.vendor_name);
245+
bufs.insert(RESBUF_ID_DEVICE_NAME, dev_info.device_name);
246+
bufs.insert(RESBUF_ID_FIRMWARE_MAJOR, vec![dev_info.version_major]);
247+
bufs.insert(RESBUF_ID_FIRMWARE_MINOR, vec![dev_info.version_minor]);
248+
bufs.insert(RESBUF_ID_FIRMWARE_BUILD, vec![dev_info.version_build]);
239249
U2FResult::Success(bufs)
240250
}
241251
Err(e) => U2FResult::Error(e),
@@ -288,11 +298,16 @@ pub unsafe extern "C" fn rust_u2f_mgr_sign(
288298
let tid = new_tid();
289299
let res = (*mgr).sign(flags, timeout, challenge, app_ids, key_handles, move |rv| {
290300
let result = match rv {
291-
Ok((app_id, key_handle, signature)) => {
301+
Ok((app_id, key_handle, signature, dev_info)) => {
292302
let mut bufs = HashMap::new();
293303
bufs.insert(RESBUF_ID_KEYHANDLE, key_handle);
294304
bufs.insert(RESBUF_ID_SIGNATURE, signature);
295305
bufs.insert(RESBUF_ID_APPID, app_id);
306+
bufs.insert(RESBUF_ID_VENDOR_NAME, dev_info.vendor_name);
307+
bufs.insert(RESBUF_ID_DEVICE_NAME, dev_info.device_name);
308+
bufs.insert(RESBUF_ID_FIRMWARE_MAJOR, vec![dev_info.version_major]);
309+
bufs.insert(RESBUF_ID_FIRMWARE_MINOR, vec![dev_info.version_minor]);
310+
bufs.insert(RESBUF_ID_FIRMWARE_BUILD, vec![dev_info.version_build]);
296311
U2FResult::Success(bufs)
297312
}
298313
Err(e) => U2FResult::Error(e),

src/consts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ pub const U2F_REGISTER: u8 = 0x01; // Registration command
4545
pub const U2F_AUTHENTICATE: u8 = 0x02; // Authenticate/sign command
4646
pub const U2F_VERSION: u8 = 0x03; // Read version string command
4747

48+
pub const YKPIV_INS_GET_VERSION: u8 = 0xfd; // Get firmware version, yubico ext
49+
4850
// U2F_REGISTER command defines
4951
pub const U2F_REGISTER_ID: u8 = 0x05; // Version 2 registration identifier
5052
pub const U2F_REGISTER_HASH_ID: u8 = 0x00; // Version 2 hash identintifier

src/freebsd/device.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ use std::os::unix::prelude::*;
1111

1212
use crate::consts::{CID_BROADCAST, MAX_HID_RPT_SIZE};
1313
use crate::platform::uhid;
14-
use crate::u2ftypes::U2FDevice;
14+
use crate::u2ftypes::{U2FDevice, U2FDeviceInfo};
1515
use crate::util::from_unix_result;
1616

1717
#[derive(Debug)]
1818
pub struct Device {
1919
path: OsString,
2020
fd: libc::c_int,
2121
cid: [u8; 4],
22+
dev_info: Option<U2FDeviceInfo>,
2223
}
2324

2425
impl Device {
@@ -30,6 +31,7 @@ impl Device {
3031
path,
3132
fd,
3233
cid: CID_BROADCAST,
34+
dev_info: None,
3335
})
3436
}
3537

@@ -93,4 +95,18 @@ impl U2FDevice for Device {
9395
fn out_rpt_size(&self) -> usize {
9496
MAX_HID_RPT_SIZE
9597
}
98+
99+
fn get_property(&self, _prop_name: &str) -> io::Result<String> {
100+
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
101+
}
102+
103+
fn get_device_info(&self) -> U2FDeviceInfo {
104+
// unwrap is okay, as dev_info must have already been set, else
105+
// a programmer error
106+
self.dev_info.clone().unwrap()
107+
}
108+
109+
fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
110+
self.dev_info = Some(dev_info);
111+
}
96112
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ pub struct KeyHandle {
100100
}
101101

102102
pub type AppId = Vec<u8>;
103-
pub type RegisterResult = Vec<u8>;
104-
pub type SignResult = (AppId, Vec<u8>, Vec<u8>);
103+
pub type RegisterResult = (Vec<u8>, u2ftypes::U2FDeviceInfo);
104+
pub type SignResult = (AppId, Vec<u8>, Vec<u8>, u2ftypes::U2FDeviceInfo);
105105

106106
#[derive(Debug, Clone, Copy)]
107107
pub enum Error {

src/linux/device.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::io::{Read, Write};
1010
use std::os::unix::prelude::*;
1111

1212
use crate::consts::CID_BROADCAST;
13-
use crate::platform::hidraw;
14-
use crate::u2ftypes::U2FDevice;
13+
use crate::platform::{hidraw, monitor};
14+
use crate::u2ftypes::{U2FDevice, U2FDeviceInfo};
1515
use crate::util::from_unix_result;
1616

1717
#[derive(Debug)]
@@ -21,6 +21,7 @@ pub struct Device {
2121
in_rpt_size: usize,
2222
out_rpt_size: usize,
2323
cid: [u8; 4],
24+
dev_info: Option<U2FDeviceInfo>,
2425
}
2526

2627
impl Device {
@@ -35,6 +36,7 @@ impl Device {
3536
in_rpt_size,
3637
out_rpt_size,
3738
cid: CID_BROADCAST,
39+
dev_info: None,
3840
})
3941
}
4042

@@ -93,4 +95,18 @@ impl U2FDevice for Device {
9395
fn out_rpt_size(&self) -> usize {
9496
self.out_rpt_size
9597
}
98+
99+
fn get_property(&self, prop_name: &str) -> io::Result<String> {
100+
monitor::get_property_linux(&self.path, prop_name)
101+
}
102+
103+
fn get_device_info(&self) -> U2FDeviceInfo {
104+
// unwrap is okay, as dev_info must have already been set, else
105+
// a programmer error
106+
self.dev_info.clone().unwrap()
107+
}
108+
109+
fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
110+
self.dev_info = Some(dev_info);
111+
}
96112
}

src/linux/monitor.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ where
107107
let f = self.new_device_cb.clone();
108108
let key = path.clone();
109109

110+
debug!("Adding device {}", path.to_string_lossy());
111+
110112
let runloop = RunLoop::new(move |alive| {
111113
if alive() {
112114
f(path, alive);
@@ -119,6 +121,8 @@ where
119121
}
120122

121123
fn remove_device(&mut self, path: &OsString) {
124+
debug!("Removing device {}", path.to_string_lossy());
125+
122126
if let Some(runloop) = self.runloops.remove(path) {
123127
runloop.cancel();
124128
}
@@ -131,3 +135,35 @@ where
131135
}
132136
}
133137
}
138+
139+
pub fn get_property_linux(path: &OsString, prop_name: &str) -> io::Result<String> {
140+
let ctx = libudev::Context::new()?;
141+
142+
let mut enumerator = libudev::Enumerator::new(&ctx)?;
143+
enumerator.match_subsystem(UDEV_SUBSYSTEM)?;
144+
145+
// Iterate all existing devices, since we don't have a syspath
146+
// and libudev-rs doesn't implement opening by devnode.
147+
for dev in enumerator.scan_devices()? {
148+
if dev.devnode().is_some() && dev.devnode().unwrap() == path {
149+
debug!(
150+
"get_property_linux Querying property {} from {}",
151+
prop_name,
152+
dev.syspath().display()
153+
);
154+
155+
let value = dev
156+
.attribute_value(prop_name)
157+
.ok_or(io::ErrorKind::Other)?
158+
.to_string_lossy();
159+
160+
debug!("get_property_linux Fetched Result, {}={}", prop_name, value);
161+
return Ok(value.to_string());
162+
}
163+
}
164+
165+
Err(io::Error::new(
166+
io::ErrorKind::Other,
167+
"Unable to find device",
168+
))
169+
}

0 commit comments

Comments
 (0)