Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions fuzz/fuzz_targets/u2f_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,8 @@ impl<'a> U2FDevice for TestDevice<'a> {
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
}

fn get_device_info(&self) -> U2FDeviceInfo {
// unwrap is okay, as dev_info must have already been set, else
// a programmer error
self.dev_info.clone().unwrap()
fn get_device_info(&self) -> Option<U2FDeviceInfo> {
self.dev_info.clone()
}

fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
Expand Down
6 changes: 2 additions & 4 deletions fuzz/fuzz_targets/u2f_read_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ impl U2FDevice for TestDevice {
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
}

fn get_device_info(&self) -> U2FDeviceInfo {
// unwrap is okay, as dev_info must have already been set, else
// a programmer error
self.dev_info.clone().unwrap()
fn get_device_info(&self) -> Option<U2FDeviceInfo> {
self.dev_info.clone()
}

fn set_device_info(&mut self, dev_info: U2FDeviceInfo) {
Expand Down
18 changes: 18 additions & 0 deletions src/authenticatorservice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ pub struct RegisterArgs {
pub resident_key_req: ResidentKeyRequirement,
pub extensions: AuthenticationExtensionsClientInputs,
pub pin: Option<Pin>,

/// Register the credential using CTAP1/U2F only.
///
/// The request [must be compatible with CTAP1 authenticators][0].
///
/// When `true`, the library will automatically skip authenticators that don't
/// [support CTAP1][crate::CtapVersionSupport::supports_ctap1].
///
/// [0]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#u2f-authenticatorMakeCredential-interoperability
pub use_ctap1_fallback: bool,
}

Expand All @@ -39,6 +48,15 @@ pub struct SignArgs {
pub user_presence_req: bool,
pub extensions: AuthenticationExtensionsClientInputs,
pub pin: Option<Pin>,

/// Authenticate using CTAP1/U2F only.
///
/// The request [must be compatible with CTAP1 authenticators][0].
///
/// When `true`, the library will automatically skip authenticators that don't
/// [support CTAP1][crate::CtapVersionSupport::supports_ctap1].
///
/// [0]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#u2f-authenticatorGetAssertion-interoperability
pub use_ctap1_fallback: bool,
}

Expand Down
57 changes: 40 additions & 17 deletions src/ctap2/commands/get_assertion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ pub mod test {
};
use crate::transport::device_selector::Device;
use crate::transport::hid::HIDDevice;
use crate::transport::{FidoDevice, FidoDeviceIO, FidoProtocol};
use crate::transport::{CtapVersionSupport, FidoDevice, FidoDeviceIO, FidoProtocol};
use crate::u2ftypes::U2FDeviceInfo;
use rand::{thread_rng, RngCore};
use std::sync::mpsc::channel;
Expand Down Expand Up @@ -966,11 +966,11 @@ pub mod test {
},
Default::default(),
);
let mut device = Device::new("commands/get_assertion").unwrap();
assert_eq!(device.get_protocol(), FidoProtocol::CTAP2);
let mut cid = [0u8; 4];
thread_rng().fill_bytes(&mut cid);
device.set_cid(cid);
let mut device = Device::new_pre_inited(
"commands/get_info",
Capability::CBOR | Capability::NMSG | Capability::WINK,
);
let cid = *device.get_cid();

let mut msg = cid.to_vec();
msg.extend(vec![HIDCmd::Cbor.into(), 0x00, 0x90]);
Expand Down Expand Up @@ -1308,8 +1308,25 @@ pub mod test {
);
}

fn fill_device_ctap1_init(device: &mut Device, cid: [u8; 4]) {
// init
let mut msg = vec![0xFF, 0xFF, 0xFF, 0xFF]; // broadcast
msg.extend([HIDCmd::Init.into(), 0x00, 8]); // cmd + bcnt
msg.extend([0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]); // nonce
device.add_write(&msg, 0);

let mut msg = vec![0xFF, 0xFF, 0xFF, 0xFF]; // broadcast
msg.extend([0x06, 0x00, 17]); // cmd + bcnt
msg.extend([0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]); // nonce
msg.extend(&cid);
msg.push(2); // CTAPHID protocol version identifir
msg.extend([1, 0, 0]); // Device version numbber
msg.push(0x01); // CAPABILITY_WINK
device.add_read(&msg, 0);
}

fn fill_device_ctap1(device: &mut Device, cid: [u8; 4], flags: u8, answer_status: [u8; 2]) {
// ctap2 request
// ctap1 request
let mut msg = cid.to_vec();
msg.extend([HIDCmd::Msg.into(), 0x00, 0x8A]); // cmd + bcnt
msg.extend([0x00, 0x2]); // U2F_AUTHENTICATE
Expand Down Expand Up @@ -1376,13 +1393,15 @@ pub mod test {
Default::default(),
);
let mut device = Device::new("commands/get_assertion").unwrap(); // not really used (all functions ignore it)
// channel id
device.downgrade_to_ctap1();
assert_eq!(device.get_protocol(), FidoProtocol::CTAP1);

let mut cid = [0u8; 4];
thread_rng().fill_bytes(&mut cid);

device.set_cid(cid);
fill_device_ctap1_init(&mut device, cid);
HIDDevice::pre_init(&mut device).expect("pre_init");
assert!(device.supports_ctap1());
assert!(!device.supports_ctap2());
device.downgrade_to_ctap1().expect("failed to downgrade");
assert_eq!(device.get_protocol(), FidoProtocol::CTAP1);

// ctap1 request
let (tx, _rx) = channel();
Expand Down Expand Up @@ -1471,13 +1490,15 @@ pub mod test {
);

let mut device = Device::new("commands/get_assertion").unwrap(); // not really used (all functions ignore it)
// channel id
device.downgrade_to_ctap1();
assert_eq!(device.get_protocol(), FidoProtocol::CTAP1);

let mut cid = [0u8; 4];
thread_rng().fill_bytes(&mut cid);

device.set_cid(cid);
fill_device_ctap1_init(&mut device, cid);
HIDDevice::pre_init(&mut device).expect("pre_init");
assert!(device.supports_ctap1());
assert!(!device.supports_ctap2());
device.downgrade_to_ctap1().expect("failed to downgrade");
assert_eq!(device.get_protocol(), FidoProtocol::CTAP1);

let (tx, _rx) = channel();
assert_matches!(
Expand Down Expand Up @@ -1672,6 +1693,8 @@ pub mod test {
version_build: 0x08,
cap_flags: Capability::WINK | Capability::CBOR,
});
assert!(device.supports_ctap1());
assert!(device.supports_ctap2());
device.set_authenticator_info(AuthenticatorInfo {
versions: vec![AuthenticatorVersion::U2F_V2, AuthenticatorVersion::FIDO_2_0],
extensions: vec!["uvm".to_string(), "hmac-secret".to_string()],
Expand Down
51 changes: 21 additions & 30 deletions src/ctap2/commands/get_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,12 +597,11 @@ impl<'de> Deserialize<'de> for AuthenticatorInfo {
#[cfg(test)]
pub mod tests {
use super::*;
use crate::consts::{Capability, HIDCmd, CID_BROADCAST};
use crate::consts::{Capability, HIDCmd};
use crate::crypto::COSEAlgorithm;
use crate::transport::device_selector::Device;
use crate::transport::platform::device::IN_HID_RPT_SIZE;
use crate::transport::{hid::HIDDevice, FidoDevice, FidoProtocol};
use rand::{thread_rng, RngCore};
use crate::transport::{hid::HIDDevice, CtapVersionSupport, FidoDevice, FidoProtocol};
use serde_cbor::de::from_slice;

// Raw data take from https://github.com/Yubico/python-fido2/blob/master/test/test_ctap2.py
Expand Down Expand Up @@ -958,32 +957,11 @@ pub mod tests {

#[test]
fn test_get_info_ctap2_only() {
let mut device = Device::new("commands/get_info").unwrap();
assert_eq!(device.get_protocol(), FidoProtocol::CTAP2);
let nonce = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01];

// channel id
let mut cid = [0u8; 4];
thread_rng().fill_bytes(&mut cid);

// init packet
let mut msg = CID_BROADCAST.to_vec();
msg.extend(vec![HIDCmd::Init.into(), 0x00, 0x08]); // cmd + bcnt
msg.extend_from_slice(&nonce);
device.add_write(&msg, 0);

// init_resp packet
let mut msg = CID_BROADCAST.to_vec();
msg.extend(vec![
0x06, /* HIDCmd::Init without TYPE_INIT */
0x00, 0x11,
]); // cmd + bcnt
msg.extend_from_slice(&nonce);
msg.extend_from_slice(&cid); // new channel id

// We are setting NMSG, to signal that the device does not support CTAP1
msg.extend(vec![0x02, 0x04, 0x01, 0x08, 0x01 | 0x04 | 0x08]); // versions + flags (wink+cbor+nmsg)
device.add_read(&msg, 0);
let mut device = Device::new_pre_inited(
"commands/get_info",
Capability::CBOR | Capability::NMSG | Capability::WINK,
);
let cid = *device.get_cid();

// ctap2 request
let mut msg = cid.to_vec();
Expand All @@ -1006,7 +984,20 @@ pub mod tests {

assert_eq!(device.get_cid(), &cid);

let dev_info = device.get_device_info();
assert!(!device.supports_ctap1());
assert!(device.supports_ctap2());
assert_eq!(device.get_protocol(), FidoProtocol::CTAP2);
assert_matches!(
device
.downgrade_to_ctap1()
.expect_err("downgrading to CTAP1 should fail when NMSG"),
HIDError::UnexpectedVersion
);
assert_eq!(device.get_protocol(), FidoProtocol::CTAP2);
assert!(!device.supports_ctap1());
assert!(device.supports_ctap2());

let dev_info = device.get_device_info().expect("device info is set");
assert_eq!(
dev_info.cap_flags,
Capability::WINK | Capability::CBOR | Capability::NMSG
Expand Down
54 changes: 8 additions & 46 deletions src/ctap2/commands/get_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,59 +60,21 @@ impl RequestCtap1 for GetVersion {

#[cfg(test)]
pub mod tests {
use crate::consts::{Capability, HIDCmd, CID_BROADCAST, SW_NO_ERROR};
use crate::consts::Capability;
use crate::transport::device_selector::Device;
use crate::transport::{hid::HIDDevice, FidoDevice, FidoProtocol};
use rand::{thread_rng, RngCore};
use crate::CtapVersionSupport;

#[test]
fn test_get_version_ctap1_only() {
let mut device = Device::new("commands/get_version").unwrap();
device.downgrade_to_ctap1();
assert_eq!(device.get_protocol(), FidoProtocol::CTAP1);
let nonce = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01];

// channel id
let mut cid = [0u8; 4];
thread_rng().fill_bytes(&mut cid);

// init packet
let mut msg = CID_BROADCAST.to_vec();
msg.extend([HIDCmd::Init.into(), 0x00, 0x08]); // cmd + bcnt
msg.extend_from_slice(&nonce);
device.add_write(&msg, 0);

// init_resp packet
let mut msg = CID_BROADCAST.to_vec();
msg.extend(vec![
0x06, /* HIDCmd::Init without !TYPE_INIT */
0x00, 0x11,
]); // cmd + bcnt
msg.extend_from_slice(&nonce);
msg.extend_from_slice(&cid); // new channel id

// We are not setting CBOR, to signal that the device does not support CTAP1
msg.extend([0x02, 0x04, 0x01, 0x08, 0x01]); // versions + flags (wink)
device.add_read(&msg, 0);
let mut device = Device::new_pre_inited("commands/get_version", Capability::WINK);

// ctap1 U2F_VERSION request
let mut msg = cid.to_vec();
msg.extend([HIDCmd::Msg.into(), 0x0, 0x7]); // cmd + bcnt
msg.extend([0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0]);
device.add_write(&msg, 0);

// fido response
let mut msg = cid.to_vec();
msg.extend([HIDCmd::Msg.into(), 0x0, 0x08]); // cmd + bcnt
msg.extend([0x55, 0x32, 0x46, 0x5f, 0x56, 0x32]); // 'U2F_V2'
msg.extend(SW_NO_ERROR);
device.add_read(&msg, 0);

device.init().expect("Failed to init device");

assert_eq!(device.get_cid(), &cid);
device.downgrade_to_ctap1().expect("failed to downgrade");
assert_eq!(device.get_protocol(), FidoProtocol::CTAP1);
assert!(device.supports_ctap1());
assert!(!device.supports_ctap2());

let dev_info = device.get_device_info();
let dev_info = device.get_device_info().expect("device info is set");
assert_eq!(dev_info.cap_flags, Capability::WINK);

let result = device.get_authenticator_info();
Expand Down
Loading
Loading