From 2050f9f2728f8cb1c9e9a14652acb806f9b67d5d Mon Sep 17 00:00:00 2001 From: Shiling Wang <90921790+shilingwangggg@users.noreply.github.com> Date: Thu, 10 Mar 2022 16:18:47 +0100 Subject: [PATCH] Replaced Libtock driver clock with embedded_time::Clock (#422) * Replaced Libtock driver clock with embedded_time::Clock * Add unittest and address some comments * Add unittest and address some comments --- Cargo.toml | 1 + fuzz/fuzz_helper/Cargo.toml | 1 + fuzz/fuzz_helper/src/lib.rs | 26 ++-- src/clock.rs | 156 ++++++++++++++++++++++++ src/ctap/client_pin.rs | 57 ++++----- src/ctap/credential_management.rs | 53 ++++----- src/ctap/ctap1.rs | 132 ++++++++++---------- src/ctap/hid/mod.rs | 57 ++++----- src/ctap/hid/receive.rs | 93 ++++++++------- src/ctap/mod.rs | 192 +++++++++++++++--------------- src/ctap/timed_permission.rs | 119 +++++++++--------- src/ctap/token_state.rs | 28 ++--- src/env/tock/mod.rs | 8 +- src/lib.rs | 13 +- src/main.rs | 64 +++++----- 15 files changed, 587 insertions(+), 413 deletions(-) create mode 100644 src/clock.rs diff --git a/Cargo.toml b/Cargo.toml index c6a13a5..84f0f8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ arrayref = "0.3.6" subtle = { version = "2.2", default-features = false, features = ["nightly"] } # This import explicitly locks the version. serde_json = { version = "=1.0.69", default-features = false, features = ["alloc"] } +embedded-time = "0.12.1" [features] debug_allocations = ["lang_items/debug_allocations"] diff --git a/fuzz/fuzz_helper/Cargo.toml b/fuzz/fuzz_helper/Cargo.toml index 9d4c1d1..05a62c1 100644 --- a/fuzz/fuzz_helper/Cargo.toml +++ b/fuzz/fuzz_helper/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] arrayref = "0.3.6" +embedded-time = "0.12.1" libtock_drivers = { path = "../../third_party/libtock-drivers" } crypto = { path = "../../libraries/crypto", features = ['std'] } sk-cbor = { path = "../../libraries/cbor" } diff --git a/fuzz/fuzz_helper/src/lib.rs b/fuzz/fuzz_helper/src/lib.rs index 7a0d300..c7852fd 100644 --- a/fuzz/fuzz_helper/src/lib.rs +++ b/fuzz/fuzz_helper/src/lib.rs @@ -18,6 +18,7 @@ extern crate lang_items; use arrayref::array_ref; use core::convert::TryFrom; +use ctap2::clock::CtapInstant; use ctap2::ctap::cbor_read; use ctap2::ctap::command::{ AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters, @@ -28,14 +29,9 @@ use ctap2::ctap::hid::send::HidPacketIterator; use ctap2::ctap::hid::{ChannelID, CtapHidCommand, HidPacket, Message}; use ctap2::env::test::TestEnv; use ctap2::Ctap; -use libtock_drivers::timer::{ClockValue, Timestamp}; const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF]; -const CLOCK_FREQUENCY_HZ: usize = 32768; -const DUMMY_TIMESTAMP: Timestamp = Timestamp::from_ms(0); -const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - #[derive(Clone, Copy, PartialEq)] pub enum InputType { CborMakeCredentialParameter, @@ -76,8 +72,9 @@ fn initialize(ctap: &mut Ctap) -> ChannelID { let mut assembler_reply = MessageAssembler::new(); let mut result_cid: ChannelID = Default::default(); for pkt_request in HidPacketIterator::new(message).unwrap() { - for pkt_reply in ctap.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE) { - if let Ok(Some(result)) = assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP) { + for pkt_reply in ctap.process_hid_packet(&pkt_request, CtapInstant::new(0)) { + if let Ok(Some(result)) = assembler_reply.parse_packet(&pkt_reply, CtapInstant::new(0)) + { result_cid.copy_from_slice(&result.payload[8..12]); } } @@ -114,9 +111,9 @@ fn process_message(data: &[u8], ctap: &mut Ctap) { if let Some(hid_packet_iterator) = HidPacketIterator::new(message) { let mut assembler_reply = MessageAssembler::new(); for pkt_request in hid_packet_iterator { - for pkt_reply in ctap.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE) { + for pkt_reply in ctap.process_hid_packet(&pkt_request, CtapInstant::new(0)) { // Only checks for assembling crashes, not for semantics. - let _ = assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP); + let _ = assembler_reply.parse_packet(&pkt_reply, CtapInstant::new(0)); } } } @@ -127,7 +124,7 @@ fn process_message(data: &[u8], ctap: &mut Ctap) { // using an initialized and allocated channel. pub fn process_ctap_any_type(data: &[u8]) { // Initialize ctap state and hid and get the allocated cid. - let mut ctap = Ctap::new(TestEnv::new(), DUMMY_CLOCK_VALUE); + let mut ctap = Ctap::new(TestEnv::new(), CtapInstant::new(0)); let cid = initialize(&mut ctap); // Wrap input as message with the allocated cid. let mut command = cid.to_vec(); @@ -143,7 +140,7 @@ pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) { return; } // Initialize ctap state and hid and get the allocated cid. - let mut ctap = Ctap::new(TestEnv::new(), DUMMY_CLOCK_VALUE); + let mut ctap = Ctap::new(TestEnv::new(), CtapInstant::new(0)); let cid = initialize(&mut ctap); // Wrap input as message with allocated cid and command type. let mut command = cid.to_vec(); @@ -173,10 +170,13 @@ pub fn split_assemble_hid_packets(data: &[u8]) { let packets: Vec = hid_packet_iterator.collect(); if let Some((last_packet, first_packets)) = packets.split_last() { for packet in first_packets { - assert_eq!(assembler.parse_packet(packet, DUMMY_TIMESTAMP), Ok(None)); + assert_eq!( + assembler.parse_packet(packet, CtapInstant::new(0)), + Ok(None) + ); } assert_eq!( - assembler.parse_packet(last_packet, DUMMY_TIMESTAMP), + assembler.parse_packet(last_packet, CtapInstant::new(0)), Ok(Some(message)) ); } diff --git a/src/clock.rs b/src/clock.rs new file mode 100644 index 0000000..dd407e4 --- /dev/null +++ b/src/clock.rs @@ -0,0 +1,156 @@ +#[cfg(not(feature = "std"))] +use alloc::fmt; +use embedded_time::duration::Milliseconds; +pub use embedded_time::Clock; +#[cfg(not(feature = "std"))] +use libtock_drivers::result::FlexUnwrap; + +#[cfg(not(feature = "std"))] +pub struct LibtockClock(libtock_drivers::timer::Timer<'static>); +#[cfg(not(feature = "std"))] +impl LibtockClock { + pub fn new() -> Self { + let boxed_cb = alloc::boxed::Box::new(libtock_drivers::timer::with_callback(|_, _| {})); + let timer = alloc::boxed::Box::leak(boxed_cb).init().flex_unwrap(); + Self(timer) + } +} +#[cfg(not(feature = "std"))] +impl fmt::Debug for LibtockClock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LibtockClock") + .field("CLOCK_FREQUENCY", &CLOCK_FREQUENCY) + .finish() + } +} + +const KEEPALIVE_DELAY_MS: ClockInt = 100; +pub const KEEPALIVE_DELAY: Milliseconds = Milliseconds(KEEPALIVE_DELAY_MS); + +#[cfg(target_pointer_width = "32")] +pub type ClockInt = u32; +#[cfg(target_pointer_width = "64")] +pub type ClockInt = u64; + +#[cfg(not(feature = "std"))] +impl embedded_time::Clock for LibtockClock { + // TODO: Implement and use a 24-bits TimeInt for Nordic + type T = ClockInt; + + const SCALING_FACTOR: embedded_time::fraction::Fraction = + ::new(1, CLOCK_FREQUENCY); + + fn try_now(&self) -> Result, embedded_time::clock::Error> { + let timer = &self.0; + let now = timer.get_current_clock().flex_unwrap(); + Ok(embedded_time::Instant::new(now.num_ticks() as Self::T)) + } +} + +#[cfg(not(feature = "std"))] +pub type CtapClock = LibtockClock<32768>; +#[cfg(feature = "std")] +pub type CtapClock = TestClock; + +pub fn new_clock() -> CtapClock { + CtapClock::new() +} + +pub type CtapInstant = embedded_time::Instant; + +#[cfg(feature = "std")] +pub const TEST_CLOCK_FREQUENCY_HZ: u32 = 32768; + +#[cfg(feature = "std")] +#[derive(Default, Clone, Copy, Debug)] +pub struct TestClock; +#[cfg(feature = "std")] +impl TestClock { + pub fn new() -> Self { + TestClock + } +} + +#[cfg(feature = "std")] +impl embedded_time::Clock for TestClock { + type T = u64; + const SCALING_FACTOR: embedded_time::fraction::Fraction = + ::new(1, TEST_CLOCK_FREQUENCY_HZ); + + fn try_now(&self) -> Result, embedded_time::clock::Error> { + Ok(embedded_time::Instant::new(0)) + } +} + +#[cfg(test)] +mod test { + use super::*; + use embedded_time::duration::{Milliseconds, Seconds}; + + #[test] + fn test_checked_add() { + let now = CtapInstant::new(0); + assert_eq!( + now.checked_add(Seconds::new(1 as ClockInt)), + Some(CtapInstant::new(TEST_CLOCK_FREQUENCY_HZ as ClockInt)) + ); + assert_eq!( + now.checked_add(Seconds::new(1 as ClockInt)), + now.checked_add(Milliseconds::new(1000 as ClockInt)) + ); + } + + #[test] + fn test_checked_add_overflow() { + assert_eq!( + CtapInstant::new(u64::MAX).checked_add(Seconds::new(1 as ClockInt)), + Some(CtapInstant::new(TEST_CLOCK_FREQUENCY_HZ as u64 - 1)) + ); + } + + #[test] + fn test_checked_add_error() { + assert!(CtapInstant::new(0) + .checked_add(Seconds::new(u64::MAX / TEST_CLOCK_FREQUENCY_HZ as ClockInt)) + .is_none()); + assert!(CtapInstant::new(0) + .checked_add(Seconds::new( + u64::MAX / TEST_CLOCK_FREQUENCY_HZ as ClockInt / 2 + )) + .is_some()); + assert!(CtapInstant::new(0) + .checked_add(Seconds::new( + u64::MAX / TEST_CLOCK_FREQUENCY_HZ as ClockInt / 2 + 1 + )) + .is_none()); + } + + #[test] + fn test_duration_since() { + let early = CtapInstant::new(0); + let later = CtapInstant::new(1000); + assert_eq!( + later.checked_duration_since(&early).unwrap().integer(), + 1000 + ); + assert_eq!(early.checked_duration_since(&later), None); + } + + #[test] + fn test_duration_since_overflow() { + let early = CtapInstant::new(u64::MAX); + let later = CtapInstant::new(1000); + assert_eq!( + later.checked_duration_since(&early).unwrap().integer(), + 1001 + ); + assert_eq!(early.checked_duration_since(&later), None); + } + + #[test] + #[should_panic] + fn add_panic() { + let _ = + CtapInstant::new(0) + Seconds(u64::MAX / TEST_CLOCK_FREQUENCY_HZ as ClockInt / 2 + 1); + } +} diff --git a/src/ctap/client_pin.rs b/src/ctap/client_pin.rs index ce3c24f..8d4da7e 100644 --- a/src/ctap/client_pin.rs +++ b/src/ctap/client_pin.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::super::clock::CtapInstant; use super::command::AuthenticatorClientPinParameters; use super::data_formats::{ ok_or_missing, ClientPinSubCommand, CoseKey, GetAssertionHmacSecretInput, PinUvAuthProtocol, @@ -32,7 +33,6 @@ use crypto::sha256::Sha256; use crypto::Hash256; #[cfg(test)] use enum_iterator::IntoEnumIterator; -use libtock_drivers::timer::ClockValue; use subtle::ConstantTimeEq; /// The prefix length of the PIN hash that is stored and compared. @@ -291,7 +291,7 @@ impl ClientPin { &mut self, env: &mut impl Env, client_pin_params: AuthenticatorClientPinParameters, - now: ClockValue, + now: CtapInstant, ) -> Result { let AuthenticatorClientPinParameters { pin_uv_auth_protocol, @@ -359,7 +359,7 @@ impl ClientPin { &mut self, env: &mut impl Env, mut client_pin_params: AuthenticatorClientPinParameters, - now: ClockValue, + now: CtapInstant, ) -> Result { // Mutating client_pin_params is just an optimization to move it into // process_get_pin_token, without cloning permissions_rp_id here. @@ -388,7 +388,7 @@ impl ClientPin { &mut self, env: &mut impl Env, client_pin_params: AuthenticatorClientPinParameters, - now: ClockValue, + now: CtapInstant, ) -> Result { let response = match client_pin_params.sub_command { ClientPinSubCommand::GetPinRetries => Some(self.process_get_pin_retries(env)?), @@ -495,7 +495,7 @@ impl ClientPin { } /// Updates the running timers, triggers timeout events. - pub fn update_timeouts(&mut self, now: ClockValue) { + pub fn update_timeouts(&mut self, now: CtapInstant) { self.pin_uv_auth_token_state .pin_uv_auth_token_usage_timer_observer(now); } @@ -568,9 +568,7 @@ impl ClientPin { }; let mut pin_uv_auth_token_state = PinUvAuthTokenState::new(); pin_uv_auth_token_state.set_permissions(0xFF); - const CLOCK_FREQUENCY_HZ: usize = 32768; - const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - pin_uv_auth_token_state.begin_using_pin_uv_auth_token(DUMMY_CLOCK_VALUE); + pin_uv_auth_token_state.begin_using_pin_uv_auth_token(CtapInstant::new(0)); ClientPin { pin_protocol_v1: PinProtocol::new_test(key_agreement_key_v1, pin_uv_auth_token), pin_protocol_v2: PinProtocol::new_test(key_agreement_key_v2, pin_uv_auth_token), @@ -586,10 +584,7 @@ mod test { use super::*; use crate::env::test::TestEnv; use alloc::vec; - use libtock_drivers::timer::Duration; - - const CLOCK_FREQUENCY_HZ: usize = 32768; - const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); + use embedded_time::duration::Milliseconds; /// Stores a PIN hash corresponding to the dummy PIN "1234". fn set_standard_pin(env: &mut TestEnv) { @@ -822,7 +817,7 @@ mod test { power_cycle_state: Some(false), }); assert_eq!( - client_pin.process_command(&mut env, params.clone(), DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params.clone(), CtapInstant::new(0)), Ok(ResponseData::AuthenticatorClientPin(expected_response)) ); @@ -834,7 +829,7 @@ mod test { power_cycle_state: Some(true), }); assert_eq!( - client_pin.process_command(&mut env, params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params, CtapInstant::new(0)), Ok(ResponseData::AuthenticatorClientPin(expected_response)) ); } @@ -862,7 +857,7 @@ mod test { power_cycle_state: None, }); assert_eq!( - client_pin.process_command(&mut env, params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params, CtapInstant::new(0)), Ok(ResponseData::AuthenticatorClientPin(expected_response)) ); } @@ -882,7 +877,7 @@ mod test { create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::SetPin); let mut env = TestEnv::new(); assert_eq!( - client_pin.process_command(&mut env, params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params, CtapInstant::new(0)), Ok(ResponseData::AuthenticatorClientPin(None)) ); } @@ -915,14 +910,14 @@ mod test { let pin_uv_auth_param = shared_secret.authenticate(&auth_param_data); params.pin_uv_auth_param = Some(pin_uv_auth_param); assert_eq!( - client_pin.process_command(&mut env, params.clone(), DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params.clone(), CtapInstant::new(0)), Ok(ResponseData::AuthenticatorClientPin(None)) ); let mut bad_params = params.clone(); bad_params.pin_hash_enc = Some(vec![0xEE; 16]); assert_eq!( - client_pin.process_command(&mut env, bad_params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, bad_params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID) ); @@ -930,7 +925,7 @@ mod test { storage::decr_pin_retries(&mut env).unwrap(); } assert_eq!( - client_pin.process_command(&mut env, params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED) ); } @@ -961,7 +956,7 @@ mod test { set_standard_pin(&mut env); let response = client_pin - .process_command(&mut env, params.clone(), DUMMY_CLOCK_VALUE) + .process_command(&mut env, params.clone(), CtapInstant::new(0)) .unwrap(); let encrypted_token = match response { ResponseData::AuthenticatorClientPin(Some(response)) => { @@ -997,7 +992,7 @@ mod test { let mut bad_params = params; bad_params.pin_hash_enc = Some(vec![0xEE; 16]); assert_eq!( - client_pin.process_command(&mut env, bad_params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, bad_params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID) ); } @@ -1022,7 +1017,7 @@ mod test { assert_eq!(storage::force_pin_change(&mut env), Ok(())); assert_eq!( - client_pin.process_command(&mut env, params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID), ); } @@ -1055,7 +1050,7 @@ mod test { set_standard_pin(&mut env); let response = client_pin - .process_command(&mut env, params.clone(), DUMMY_CLOCK_VALUE) + .process_command(&mut env, params.clone(), CtapInstant::new(0)) .unwrap(); let encrypted_token = match response { ResponseData::AuthenticatorClientPin(Some(response)) => { @@ -1091,21 +1086,21 @@ mod test { let mut bad_params = params.clone(); bad_params.permissions = Some(0x00); assert_eq!( - client_pin.process_command(&mut env, bad_params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, bad_params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER) ); let mut bad_params = params.clone(); bad_params.permissions_rp_id = None; assert_eq!( - client_pin.process_command(&mut env, bad_params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, bad_params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER) ); let mut bad_params = params; bad_params.pin_hash_enc = Some(vec![0xEE; 16]); assert_eq!( - client_pin.process_command(&mut env, bad_params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, bad_params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID) ); } @@ -1132,7 +1127,7 @@ mod test { assert_eq!(storage::force_pin_change(&mut env), Ok(())); assert_eq!( - client_pin.process_command(&mut env, params, DUMMY_CLOCK_VALUE), + client_pin.process_command(&mut env, params, CtapInstant::new(0)), Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID) ); } @@ -1485,7 +1480,7 @@ mod test { let message = [0xAA]; client_pin .pin_uv_auth_token_state - .begin_using_pin_uv_auth_token(DUMMY_CLOCK_VALUE); + .begin_using_pin_uv_auth_token(CtapInstant::new(0)); let pin_uv_auth_token_v1 = client_pin .get_pin_protocol(PinUvAuthProtocol::V1) @@ -1617,7 +1612,7 @@ mod test { params.permissions = Some(0xFF); assert!(client_pin - .process_command(&mut env, params, DUMMY_CLOCK_VALUE) + .process_command(&mut env, params, CtapInstant::new(0)) .is_ok()); for permission in PinPermission::into_enum_iter() { assert_eq!( @@ -1634,7 +1629,7 @@ mod test { Ok(()) ); - let timeout = DUMMY_CLOCK_VALUE.wrapping_add(Duration::from_ms(30001)); + let timeout = CtapInstant::new(0) + Milliseconds::new(30001_u32); client_pin.update_timeouts(timeout); for permission in PinPermission::into_enum_iter() { assert_eq!( @@ -1663,7 +1658,7 @@ mod test { params.permissions = Some(0xFF); assert!(client_pin - .process_command(&mut env, params, DUMMY_CLOCK_VALUE) + .process_command(&mut env, params, CtapInstant::new(0)) .is_ok()); for permission in PinPermission::into_enum_iter() { assert_eq!( diff --git a/src/ctap/credential_management.rs b/src/ctap/credential_management.rs index c5952b2..61458aa 100644 --- a/src/ctap/credential_management.rs +++ b/src/ctap/credential_management.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::super::clock::CtapInstant; use super::client_pin::{ClientPin, PinPermission}; use super::command::AuthenticatorCredentialManagementParameters; use super::data_formats::{ @@ -30,7 +31,6 @@ use alloc::vec; use alloc::vec::Vec; use crypto::sha256::Sha256; use crypto::Hash256; -use libtock_drivers::timer::ClockValue; /// Generates a set with all existing RP IDs. fn get_stored_rp_ids(env: &mut impl Env) -> Result, Ctap2StatusCode> { @@ -137,7 +137,7 @@ fn process_get_creds_metadata( fn process_enumerate_rps_begin( env: &mut impl Env, stateful_command_permission: &mut StatefulPermission, - now: ClockValue, + now: CtapInstant, ) -> Result { let rp_set = get_stored_rp_ids(env)?; let total_rps = rp_set.len(); @@ -174,7 +174,7 @@ fn process_enumerate_credentials_begin( stateful_command_permission: &mut StatefulPermission, client_pin: &mut ClientPin, sub_command_params: CredentialManagementSubCommandParameters, - now: ClockValue, + now: CtapInstant, ) -> Result { let rp_id_hash = sub_command_params .rp_id_hash @@ -252,7 +252,7 @@ pub fn process_credential_management( stateful_command_permission: &mut StatefulPermission, client_pin: &mut ClientPin, cred_management_params: AuthenticatorCredentialManagementParameters, - now: ClockValue, + now: CtapInstant, ) -> Result { let AuthenticatorCredentialManagementParameters { sub_command, @@ -359,9 +359,6 @@ mod test { use crate::env::Env; use crypto::rng256::Rng256; - const CLOCK_FREQUENCY_HZ: usize = 32768; - const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - fn create_credential_source(rng: &mut impl Rng256) -> PublicKeyCredentialSource { let private_key = crypto::ecdsa::SecKey::gensk(rng); PublicKeyCredentialSource { @@ -388,7 +385,7 @@ mod test { ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol); let credential_source = create_credential_source(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; storage::set_pin(&mut env, &[0u8; 16], 4).unwrap(); @@ -410,7 +407,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let initial_capacity = match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -435,7 +432,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -470,7 +467,7 @@ mod test { let mut credential_source2 = create_credential_source(env.rng()); credential_source2.rp_id = "another.example.com".to_string(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; storage::store_credential(&mut env, credential_source1).unwrap(); @@ -493,7 +490,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let first_rp_id = match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -517,7 +514,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let second_rp_id = match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -542,7 +539,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, @@ -559,7 +556,7 @@ mod test { ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); let credential_source = create_credential_source(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; const NUM_CREDENTIALS: usize = 20; @@ -591,7 +588,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -621,7 +618,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, @@ -643,7 +640,7 @@ mod test { credential_source2.user_display_name = Some("User Two".to_string()); credential_source2.user_icon = Some("icon2".to_string()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; storage::store_credential(&mut env, credential_source1).unwrap(); @@ -673,7 +670,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let first_credential_id = match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -696,7 +693,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let second_credential_id = match cred_management_response.unwrap() { ResponseData::AuthenticatorCredentialManagement(Some(response)) => { @@ -720,7 +717,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, @@ -738,7 +735,7 @@ mod test { let mut credential_source = create_credential_source(env.rng()); credential_source.credential_id = vec![0x1D; 32]; - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; storage::store_credential(&mut env, credential_source).unwrap(); @@ -770,7 +767,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, @@ -788,7 +785,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, @@ -806,7 +803,7 @@ mod test { let mut credential_source = create_credential_source(env.rng()); credential_source.credential_id = vec![0x1D; 32]; - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; storage::store_credential(&mut env, credential_source).unwrap(); @@ -844,7 +841,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, @@ -867,7 +864,7 @@ mod test { #[test] fn test_process_credential_management_invalid_pin_uv_auth_param() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); storage::set_pin(&mut env, &[0u8; 16], 4).unwrap(); @@ -882,7 +879,7 @@ mod test { &mut ctap_state.stateful_command_permission, &mut ctap_state.client_pin, cred_management_params, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( cred_management_response, diff --git a/src/ctap/ctap1.rs b/src/ctap/ctap1.rs index 5b72e69..c847841 100644 --- a/src/ctap/ctap1.rs +++ b/src/ctap/ctap1.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::super::clock::CtapInstant; use super::apdu::{Apdu, ApduStatusCode}; use super::CtapState; use crate::ctap::storage; @@ -20,7 +21,6 @@ use alloc::vec::Vec; use arrayref::array_ref; use core::convert::Into; use core::convert::TryFrom; -use libtock_drivers::timer::ClockValue; // For now, they're the same thing with apdu.rs containing the authoritative definition pub type Ctap1StatusCode = ApduStatusCode; @@ -183,7 +183,7 @@ impl Ctap1Command { env: &mut impl Env, message: &[u8], ctap_state: &mut CtapState, - clock_value: ClockValue, + clock_value: CtapInstant, ) -> Result, Ctap1StatusCode> { if !ctap_state .allows_ctap1(env) @@ -347,16 +347,10 @@ impl Ctap1Command { mod test { use super::super::{key_material, CREDENTIAL_ID_SIZE, USE_SIGNATURE_COUNTER}; use super::*; + use crate::clock::TEST_CLOCK_FREQUENCY_HZ; use crate::env::test::TestEnv; use crypto::Hash256; - const CLOCK_FREQUENCY_HZ: usize = 32768; - const START_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - const TIMEOUT_CLOCK_VALUE: ClockValue = ClockValue::new( - (30001 * CLOCK_FREQUENCY_HZ as isize) / 1000, - CLOCK_FREQUENCY_HZ, - ); - fn create_register_message(application: &[u8; 32]) -> Vec { let mut message = vec![ Ctap1Command::CTAP1_CLA, @@ -400,15 +394,15 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); storage::toggle_always_uv(&mut env).unwrap(); let application = [0x0A; 32]; let message = create_register_message(&application); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_COMMAND_NOT_ALLOWED)); } @@ -417,32 +411,36 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let application = [0x0A; 32]; let message = create_register_message(&application); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); // Certificate and private key are missing assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)); let fake_key = [0x41u8; key_material::ATTESTATION_PRIVATE_KEY_LENGTH]; assert!(storage::set_attestation_private_key(&mut env, &fake_key).is_ok()); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); - let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); + let response = Ctap1Command::process_command( + &mut env, + &message, + &mut ctap_state, + CtapInstant::new(0_u64), + ); // Certificate is still missing assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION)); let fake_cert = [0x99u8; 100]; // Arbitrary length assert!(storage::set_attestation_certificate(&mut env, &fake_cert[..]).is_ok()); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE) + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)) .unwrap(); assert_eq!(response[0], Ctap1Command::LEGACY_BYTE); assert_eq!(response[66], CREDENTIAL_ID_SIZE as u8); @@ -466,7 +464,7 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let application = [0x0A; 32]; let message = create_register_message(&application); @@ -474,7 +472,7 @@ mod test { &mut env, &message[..message.len() - 1], &mut ctap_state, - START_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_LENGTH)); @@ -488,12 +486,14 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); + let timeout_clock_value: CtapInstant = + CtapInstant::new((30001 * TEST_CLOCK_FREQUENCY_HZ as u64) / 1000); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, timeout_clock_value); assert_eq!(response, Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED)); } @@ -503,7 +503,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -513,7 +513,7 @@ mod test { let message = create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED)); } @@ -523,7 +523,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -534,7 +534,7 @@ mod test { let message = create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_DATA)); } @@ -544,7 +544,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -559,22 +559,22 @@ mod test { message.push(0x00); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert!(response.is_ok()); message.push(0x00); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert!(response.is_ok()); message.push(0x00); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert!(response.is_ok()); message.push(0x00); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_LENGTH)); } @@ -584,7 +584,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -596,7 +596,7 @@ mod test { message[0] = 0xEE; let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_CLA_INVALID)); } @@ -606,7 +606,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -618,7 +618,7 @@ mod test { message[1] = 0xEE; let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_INS_INVALID)); } @@ -628,7 +628,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -640,7 +640,7 @@ mod test { message[2] = 0xEE; let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_DATA)); } @@ -658,7 +658,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -668,10 +668,10 @@ mod test { let message = create_authenticate_message(&application, Ctap1Flags::EnforceUpAndSign, &key_handle); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE) + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)) .unwrap(); assert_eq!(response[0], 0x01); check_signature_counter( @@ -686,7 +686,7 @@ mod test { env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); let sk = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let rp_id = "example.com"; let application = crypto::sha256::Sha256::hash(rp_id.as_bytes()); @@ -699,9 +699,13 @@ mod test { &key_handle, ); - let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE) - .unwrap(); + let response = Ctap1Command::process_command( + &mut env, + &message, + &mut ctap_state, + CtapInstant::new((30001 * TEST_CLOCK_FREQUENCY_HZ as u64) / 1000), + ) + .unwrap(); assert_eq!(response[0], 0x01); check_signature_counter( array_ref!(response, 1, 4), @@ -719,12 +723,12 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE); + Ctap1Command::process_command(&mut env, &message, &mut ctap_state, CtapInstant::new(0)); assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_DATA)); } @@ -738,12 +742,16 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| panic!("Unexpected user presence check in CTAP1")); - let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); - ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE); - ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE); - let response = - Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE); + ctap_state.u2f_up_state.consume_up(CtapInstant::new(0)); + ctap_state.u2f_up_state.grant_up(CtapInstant::new(0)); + let response = Ctap1Command::process_command( + &mut env, + &message, + &mut ctap_state, + CtapInstant::new((30001 * TEST_CLOCK_FREQUENCY_HZ as u64) / 1000), + ); assert_eq!(response, Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED)); } } diff --git a/src/ctap/hid/mod.rs b/src/ctap/hid/mod.rs index 568dbce..4249ce5 100644 --- a/src/ctap/hid/mod.rs +++ b/src/ctap/hid/mod.rs @@ -17,6 +17,7 @@ pub mod send; use self::receive::MessageAssembler; use self::send::HidPacketIterator; +use super::super::clock::{ClockInt, CtapInstant}; #[cfg(feature = "with_ctap1")] use super::ctap1; use super::status_code::Ctap2StatusCode; @@ -26,7 +27,7 @@ use crate::env::Env; use alloc::vec; use alloc::vec::Vec; use arrayref::{array_ref, array_refs}; -use libtock_drivers::timer::{ClockValue, Duration, Timestamp}; +use embedded_time::duration::Milliseconds; pub type HidPacket = [u8; 64]; pub type ChannelID = [u8; 4]; @@ -166,18 +167,16 @@ impl CtapHid { const CAPABILITY_CBOR: u8 = 0x04; #[cfg(not(feature = "with_ctap1"))] const CAPABILITY_NMSG: u8 = 0x08; + // Capabilitites currently supported by this device. #[cfg(feature = "with_ctap1")] - const CAPABILITIES: u8 = CtapHid::CAPABILITY_WINK | CtapHid::CAPABILITY_CBOR; + const CAPABILITIES: u8 = Self::CAPABILITY_WINK | Self::CAPABILITY_CBOR; #[cfg(not(feature = "with_ctap1"))] - const CAPABILITIES: u8 = - CtapHid::CAPABILITY_WINK | CtapHid::CAPABILITY_CBOR | CtapHid::CAPABILITY_NMSG; - + const CAPABILITIES: u8 = Self::CAPABILITY_WINK | Self::CAPABILITY_CBOR | Self::CAPABILITY_NMSG; // TODO: Is this timeout duration specified? - const TIMEOUT_DURATION: Duration = Duration::from_ms(100); - const WINK_TIMEOUT_DURATION: Duration = Duration::from_ms(5000); + const TIMEOUT_DURATION: Milliseconds = Milliseconds(100 as ClockInt); + const WINK_TIMEOUT_DURATION: Milliseconds = Milliseconds(5000 as ClockInt); - /// Creates a new idle HID state. pub fn new() -> CtapHid { CtapHid { assembler: MessageAssembler::new(), @@ -209,12 +208,9 @@ impl CtapHid { &mut self, env: &mut impl Env, packet: &HidPacket, - clock_value: ClockValue, + clock_value: CtapInstant, ) -> Option { - match self - .assembler - .parse_packet(packet, Timestamp::::from_clock_value(clock_value)) - { + match self.assembler.parse_packet(packet, clock_value) { Ok(Some(message)) => { debug_ctap!(env, "Received message: {:02x?}", message); self.preprocess_message(message) @@ -331,7 +327,7 @@ impl CtapHid { &mut self, env: &mut impl Env, message: Message, - clock_value: ClockValue, + clock_value: CtapInstant, ctap_state: &mut CtapState, ) -> Message { // If another command arrives, stop winking to prevent accidential button touches. @@ -389,7 +385,7 @@ impl CtapHid { &mut self, env: &mut impl Env, packet: &HidPacket, - clock_value: ClockValue, + clock_value: CtapInstant, ctap_state: &mut CtapState, ) -> HidPacketIterator { if let Some(message) = self.parse_packet(env, packet, clock_value) { @@ -482,7 +478,7 @@ impl CtapHid { } /// Returns whether a wink permission is currently granted. - pub fn should_wink(&self, now: ClockValue) -> bool { + pub fn should_wink(&self, now: CtapInstant) -> bool { self.wink_permission.is_granted(now) } @@ -514,11 +510,6 @@ mod test { use super::*; use crate::env::test::TestEnv; - const CLOCK_FREQUENCY_HZ: usize = 32768; - // Except for tests for timeouts (done in ctap1.rs), transactions are time independant. - const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - const DUMMY_TIMESTAMP: Timestamp = Timestamp::from_ms(0); - fn process_messages( env: &mut TestEnv, ctap_hid: &mut CtapHid, @@ -527,12 +518,14 @@ mod test { ) -> Option> { let mut result = Vec::new(); let mut assembler_reply = MessageAssembler::new(); + // Except for tests for timeouts (done in ctap1.rs), transactions are time independant. + for msg_request in request { for pkt_request in HidPacketIterator::new(msg_request).unwrap() { for pkt_reply in - ctap_hid.process_hid_packet(env, &pkt_request, DUMMY_CLOCK_VALUE, ctap_state) + ctap_hid.process_hid_packet(env, &pkt_request, CtapInstant::new(0), ctap_state) { - match assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP) { + match assembler_reply.parse_packet(&pkt_reply, CtapInstant::new(0)) { Ok(Some(message)) => result.push(message), Ok(None) => (), Err(_) => return None, @@ -584,7 +577,7 @@ mod test { let mut messages = Vec::new(); let mut assembler = MessageAssembler::new(); for packet in HidPacketIterator::new(message.clone()).unwrap() { - match assembler.parse_packet(&packet, DUMMY_TIMESTAMP) { + match assembler.parse_packet(&packet, CtapInstant::new(0)) { Ok(Some(msg)) => messages.push(msg), Ok(None) => (), Err(_) => panic!("Couldn't assemble packet: {:02x?}", &packet as &[u8]), @@ -598,19 +591,19 @@ mod test { #[test] fn test_spurious_continuation_packet() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_hid = CtapHid::new(); let mut packet = [0x00; 64]; packet[0..7].copy_from_slice(&[0xC1, 0xC1, 0xC1, 0xC1, 0x00, 0x51, 0x51]); let mut assembler_reply = MessageAssembler::new(); for pkt_reply in - ctap_hid.process_hid_packet(&mut env, &packet, DUMMY_CLOCK_VALUE, &mut ctap_state) + ctap_hid.process_hid_packet(&mut env, &packet, CtapInstant::new(0), &mut ctap_state) { // Continuation packets are silently ignored. assert_eq!( assembler_reply - .parse_packet(&pkt_reply, DUMMY_TIMESTAMP) + .parse_packet(&pkt_reply, CtapInstant::new(0)) .unwrap(), None ); @@ -620,7 +613,7 @@ mod test { #[test] fn test_command_init() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_hid = CtapHid::new(); let reply = process_messages( @@ -665,7 +658,7 @@ mod test { #[test] fn test_command_init_for_sync() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_hid = CtapHid::new(); let cid = cid_from_init(&mut env, &mut ctap_hid, &mut ctap_state); @@ -685,11 +678,11 @@ mod test { for pkt_reply in ctap_hid.process_hid_packet( &mut env, pkt_request, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), &mut ctap_state, ) { if let Some(message) = assembler_reply - .parse_packet(&pkt_reply, DUMMY_TIMESTAMP) + .parse_packet(&pkt_reply, CtapInstant::new(0)) .unwrap() { result.push(message); @@ -727,7 +720,7 @@ mod test { #[test] fn test_command_ping() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut ctap_hid = CtapHid::new(); let cid = cid_from_init(&mut env, &mut ctap_hid, &mut ctap_state); diff --git a/src/ctap/hid/receive.rs b/src/ctap/hid/receive.rs index c6885a3..8c5a1ea 100644 --- a/src/ctap/hid/receive.rs +++ b/src/ctap/hid/receive.rs @@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::clock::CtapInstant; + use super::super::customization::MAX_MSG_SIZE; use super::{ChannelID, CtapHid, CtapHidCommand, HidPacket, Message, ProcessedPacket}; use alloc::vec::Vec; use core::mem::swap; -use libtock_drivers::timer::Timestamp; // A structure to assemble CTAPHID commands from a series of incoming USB HID packets. pub struct MessageAssembler { @@ -25,7 +26,7 @@ pub struct MessageAssembler { // Current channel ID. cid: ChannelID, // Timestamp of the last packet received on the current channel. - last_timestamp: Timestamp, + last_timestamp: CtapInstant, // Current command. cmd: u8, // Sequence number expected for the next packet. @@ -57,7 +58,7 @@ impl MessageAssembler { MessageAssembler { idle: true, cid: [0, 0, 0, 0], - last_timestamp: Timestamp::from_ms(0), + last_timestamp: CtapInstant::new(0), cmd: 0, seq: 0, remaining_payload_len: 0, @@ -70,7 +71,7 @@ impl MessageAssembler { pub fn reset(&mut self) { self.idle = true; self.cid = [0, 0, 0, 0]; - self.last_timestamp = Timestamp::from_ms(0); + self.last_timestamp = CtapInstant::new(0); self.cmd = 0; self.seq = 0; self.remaining_payload_len = 0; @@ -87,13 +88,13 @@ impl MessageAssembler { pub fn parse_packet( &mut self, packet: &HidPacket, - timestamp: Timestamp, + timestamp: CtapInstant, ) -> Result, (ChannelID, Error)> { // TODO: Support non-full-speed devices (i.e. packet len != 64)? This isn't recommended by // section 8.8.1 let (cid, processed_packet) = CtapHid::process_single_packet(packet); - if !self.idle && timestamp - self.last_timestamp >= CtapHid::TIMEOUT_DURATION { + if !self.idle && timestamp >= self.last_timestamp + CtapHid::TIMEOUT_DURATION { // The current channel timed out. // Save the channel ID and reset the state. let current_cid = self.cid; @@ -160,7 +161,7 @@ impl MessageAssembler { cmd: u8, len: usize, data: &[u8], - timestamp: Timestamp, + timestamp: CtapInstant, ) -> Result, (ChannelID, Error)> { // Reject invalid lengths early to reduce the risk of running out of memory. // TODO: also reject invalid commands early? @@ -198,12 +199,10 @@ impl MessageAssembler { #[cfg(test)] mod test { - use super::*; - use libtock_drivers::timer::Duration; + use crate::ctap::hid::CtapHid; + use embedded_time::duration::Milliseconds; - // Except for tests that exercise timeouts, all packets are synchronized at the same dummy - // timestamp. - const DUMMY_TIMESTAMP: Timestamp = Timestamp::from_ms(0); + use super::*; fn byte_extend(bytes: &[u8], padding: u8) -> HidPacket { let len = bytes.len(); @@ -223,10 +222,12 @@ mod test { #[test] fn test_empty_payload() { let mut assembler = MessageAssembler::new(); + // Except for tests that exercise timeouts, all packets are synchronized at the same dummy + // timestamp. assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -242,7 +243,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -261,7 +262,7 @@ mod test { assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10], 0xFF), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -277,14 +278,14 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -300,21 +301,21 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x80]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -330,7 +331,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x1D, 0xB9]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); @@ -338,7 +339,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); @@ -346,7 +347,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -371,21 +372,21 @@ mod test { &[0x12, 0x34, 0x56, 0x78, 0x80 | cmd as u8, 0x00, 0x80], byte ), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x00], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x01], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -409,21 +410,21 @@ mod test { assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, cid, 0x80 | cmd as u8, 0x00, 0x80], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, cid, 0x00], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, cid, 0x01], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, cid], @@ -440,7 +441,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); @@ -452,7 +453,7 @@ mod test { assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, 0x9A, cmd as u8, 0x00], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Err(([0x12, 0x34, 0x56, 0x9A], Error::UnexpectedChannel)) ); @@ -462,7 +463,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -484,7 +485,7 @@ mod test { assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x10], byte), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -498,7 +499,7 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Err(([0x12, 0x34, 0x56, 0x78], Error::UnexpectedContinuation)) ); @@ -511,14 +512,14 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x80]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Err(([0x12, 0x34, 0x56, 0x78], Error::UnexpectedInit)) ); @@ -530,14 +531,14 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Err(([0x12, 0x34, 0x56, 0x78], Error::UnexpectedSeq)) ); @@ -549,14 +550,14 @@ mod test { assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); assert_eq!( assembler.parse_packet( &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), - DUMMY_TIMESTAMP + CtapHid::TIMEOUT_DURATION + CtapInstant::new(0) + CtapHid::TIMEOUT_DURATION ), Err(([0x12, 0x34, 0x56, 0x78], Error::Timeout)) ); @@ -564,9 +565,9 @@ mod test { #[test] fn test_just_in_time_packets() { - let mut timestamp = DUMMY_TIMESTAMP; + let mut timestamp: CtapInstant = CtapInstant::new(0); // Delay between each packet is just below the threshold. - let delay = CtapHid::TIMEOUT_DURATION - Duration::from_ms(1); + let delay = CtapHid::TIMEOUT_DURATION - Milliseconds(1_u32); let mut assembler = MessageAssembler::new(); assert_eq!( @@ -577,13 +578,13 @@ mod test { Ok(None) ); for seq in 0..0x7F { - timestamp += delay; + timestamp = timestamp + delay; assert_eq!( assembler.parse_packet(&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), timestamp), Ok(None) ); } - timestamp += delay; + timestamp = timestamp + delay; assert_eq!( assembler.parse_packet(&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]), timestamp), Ok(Some(Message { @@ -601,7 +602,7 @@ mod test { assert_eq!( assembler.parse_packet( &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x02, 0x00], 0x51), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(None) ); @@ -612,7 +613,7 @@ mod test { 0x12, 0x34, 0x56, 0x78, 0x86, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 ]), - DUMMY_TIMESTAMP + CtapInstant::new(0) ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], diff --git a/src/ctap/mod.rs b/src/ctap/mod.rs index e4a748c..90a4e99 100644 --- a/src/ctap/mod.rs +++ b/src/ctap/mod.rs @@ -65,6 +65,7 @@ use self::timed_permission::TimedPermission; use self::timed_permission::U2fUserPresenceState; use crate::api::firmware_protection::FirmwareProtection; use crate::api::upgrade_storage::UpgradeStorage; +use crate::clock::{ClockInt, CtapInstant}; use crate::env::{Env, UserPresence}; use alloc::boxed::Box; use alloc::string::{String, ToString}; @@ -78,7 +79,7 @@ use crypto::hmac::{hmac_256, verify_hmac_256}; use crypto::rng256::Rng256; use crypto::sha256::Sha256; use crypto::Hash256; -use libtock_drivers::timer::{ClockValue, Duration}; +use embedded_time::duration::Milliseconds; use sk_cbor as cbor; use sk_cbor::cbor_map_options; @@ -101,12 +102,14 @@ const ED_FLAG: u8 = 0x80; // CTAP2 specification section 6 requires that the depth of nested CBOR structures be limited to at most four levels. const MAX_CBOR_NESTING_DEPTH: i8 = 4; -pub const TOUCH_TIMEOUT_MS: isize = 30000; +pub const TOUCH_TIMEOUT_MS: ClockInt = 30000; #[cfg(feature = "with_ctap1")] -const U2F_UP_PROMPT_TIMEOUT: Duration = Duration::from_ms(10000); +pub const TOUCH_TIMEOUT: Milliseconds = Milliseconds(TOUCH_TIMEOUT_MS); +#[cfg(feature = "with_ctap1")] +const U2F_UP_PROMPT_TIMEOUT: Milliseconds = Milliseconds(10000 as ClockInt); // TODO(kaczmarczyck) 2.1 allows Reset after Reset and 15 seconds? -const RESET_TIMEOUT_DURATION: Duration = Duration::from_ms(10000); -const STATEFUL_COMMAND_TIMEOUT_DURATION: Duration = Duration::from_ms(30000); +const RESET_TIMEOUT_DURATION: Milliseconds = Milliseconds(10000 as ClockInt); +const STATEFUL_COMMAND_TIMEOUT_DURATION: Milliseconds = Milliseconds(30000 as ClockInt); pub const FIDO2_VERSION_STRING: &str = "FIDO_2_0"; #[cfg(feature = "with_ctap1")] @@ -239,7 +242,7 @@ impl StatefulPermission { /// /// Resets are only possible after a power cycle. Therefore, initialization /// means allowing Reset, and Reset cannot be granted later. - pub fn new_reset(now: ClockValue) -> StatefulPermission { + pub fn new_reset(now: CtapInstant) -> StatefulPermission { StatefulPermission { permission: TimedPermission::granted(now, RESET_TIMEOUT_DURATION), command_type: Some(StatefulCommand::Reset), @@ -253,7 +256,7 @@ impl StatefulPermission { } /// Checks the permission timeout. - pub fn check_command_permission(&mut self, now: ClockValue) -> Result<(), Ctap2StatusCode> { + pub fn check_command_permission(&mut self, now: CtapInstant) -> Result<(), Ctap2StatusCode> { if self.permission.is_granted(now) { Ok(()) } else { @@ -270,7 +273,7 @@ impl StatefulPermission { } /// Sets a new command state, and starts a new clock for timeouts. - pub fn set_command(&mut self, now: ClockValue, new_command_type: StatefulCommand) { + pub fn set_command(&mut self, now: CtapInstant, new_command_type: StatefulCommand) { match &new_command_type { // Reset is only allowed after a power cycle. StatefulCommand::Reset => unreachable!(), @@ -335,22 +338,19 @@ pub struct CtapState { } impl CtapState { - pub fn new(env: &mut impl Env, now: ClockValue) -> Self { + pub fn new(env: &mut impl Env, now: CtapInstant) -> Self { storage::init(env).ok().unwrap(); let client_pin = ClientPin::new(env.rng()); CtapState { client_pin, #[cfg(feature = "with_ctap1")] - u2f_up_state: U2fUserPresenceState::new( - U2F_UP_PROMPT_TIMEOUT, - Duration::from_ms(TOUCH_TIMEOUT_MS), - ), + u2f_up_state: U2fUserPresenceState::new(U2F_UP_PROMPT_TIMEOUT, TOUCH_TIMEOUT), stateful_command_permission: StatefulPermission::new_reset(now), large_blobs: LargeBlobs::new(), } } - pub fn update_timeouts(&mut self, now: ClockValue) { + pub fn update_timeouts(&mut self, now: CtapInstant) { // Ignore the result, just update. let _ = self .stateful_command_permission @@ -448,7 +448,7 @@ impl CtapState { env: &mut impl Env, command_cbor: &[u8], cid: ChannelID, - now: ClockValue, + now: CtapInstant, ) -> Vec { let cmd = Command::deserialize(command_cbor); debug_ctap!(env, "Received command: {:#?}", cmd); @@ -457,10 +457,8 @@ impl CtapState { // Correct behavior between CTAP1 and CTAP2 isn't defined yet. Just a guess. #[cfg(feature = "with_ctap1")] { - self.u2f_up_state = U2fUserPresenceState::new( - U2F_UP_PROMPT_TIMEOUT, - Duration::from_ms(TOUCH_TIMEOUT_MS), - ); + self.u2f_up_state = + U2fUserPresenceState::new(U2F_UP_PROMPT_TIMEOUT, TOUCH_TIMEOUT); } match (&command, self.stateful_command_permission.get_command()) { (Command::AuthenticatorGetNextAssertion, Ok(StatefulCommand::GetAssertion(_))) @@ -925,7 +923,7 @@ impl CtapState { env: &mut impl Env, get_assertion_params: AuthenticatorGetAssertionParameters, cid: ChannelID, - now: ClockValue, + now: CtapInstant, ) -> Result { let AuthenticatorGetAssertionParameters { rp_id, @@ -1055,7 +1053,7 @@ impl CtapState { fn process_get_next_assertion( &mut self, env: &mut impl Env, - now: ClockValue, + now: CtapInstant, ) -> Result { self.stateful_command_permission .check_command_permission(now)?; @@ -1136,7 +1134,7 @@ impl CtapState { &mut self, env: &mut impl Env, cid: ChannelID, - now: ClockValue, + now: CtapInstant, ) -> Result { self.stateful_command_permission .check_command_permission(now)?; @@ -1150,10 +1148,7 @@ impl CtapState { self.client_pin.reset(env.rng()); #[cfg(feature = "with_ctap1")] { - self.u2f_up_state = U2fUserPresenceState::new( - U2F_UP_PROMPT_TIMEOUT, - Duration::from_ms(TOUCH_TIMEOUT_MS), - ); + self.u2f_up_state = U2fUserPresenceState::new(U2F_UP_PROMPT_TIMEOUT, TOUCH_TIMEOUT); } Ok(ResponseData::AuthenticatorReset) } @@ -1312,12 +1307,12 @@ impl CtapState { } #[cfg(feature = "with_ctap1")] - pub fn u2f_grant_user_presence(&mut self, now: ClockValue) { + pub fn u2f_grant_user_presence(&mut self, now: CtapInstant) { self.u2f_up_state.grant_up(now) } #[cfg(feature = "with_ctap1")] - pub fn u2f_needs_user_presence(&mut self, now: ClockValue) -> bool { + pub fn u2f_needs_user_presence(&mut self, now: CtapInstant) -> bool { self.u2f_up_state.is_up_needed(now) } } @@ -1336,8 +1331,6 @@ mod test { use crate::env::test::TestEnv; use cbor::{cbor_array, cbor_array_vec, cbor_map}; - const CLOCK_FREQUENCY_HZ: usize = 32768; - const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); // The keep-alive logic in the processing of some commands needs a channel ID to send // keep-alive packets to. // In tests where we define a dummy user-presence check that immediately returns, the channel @@ -1389,9 +1382,9 @@ mod test { #[test] fn test_get_info() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let info_reponse = - ctap_state.process_command(&mut env, &[0x04], DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + ctap_state.process_command(&mut env, &[0x04], DUMMY_CHANNEL_ID, CtapInstant::new(0)); let expected_cbor = cbor_map_options! { 0x01 => cbor_array_vec![vec![ @@ -1501,7 +1494,7 @@ mod test { #[test] fn test_resident_process_make_credential() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let make_credential_params = create_minimal_make_credential_parameters(); let make_credential_response = @@ -1519,7 +1512,7 @@ mod test { #[test] fn test_non_resident_process_make_credential() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.options.rk = false; @@ -1538,7 +1531,7 @@ mod test { #[test] fn test_process_make_credential_unsupported_algorithm() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.pub_key_cred_params = vec![]; @@ -1555,7 +1548,7 @@ mod test { fn test_process_make_credential_credential_excluded() { let mut env = TestEnv::new(); let excluded_private_key = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let excluded_credential_id = vec![0x01, 0x23, 0x45, 0x67]; let make_credential_params = @@ -1587,7 +1580,7 @@ mod test { #[test] fn test_process_make_credential_credential_with_cred_protect() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let test_policy = CredentialProtectionPolicy::UserVerificationOptionalWithCredentialIdList; let make_credential_params = @@ -1638,7 +1631,7 @@ mod test { #[test] fn test_process_make_credential_hmac_secret() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let extensions = MakeCredentialExtensions { hmac_secret: true, @@ -1665,7 +1658,7 @@ mod test { #[test] fn test_process_make_credential_hmac_secret_resident_key() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let extensions = MakeCredentialExtensions { hmac_secret: true, @@ -1691,7 +1684,7 @@ mod test { #[test] fn test_process_make_credential_min_pin_length() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // First part: The extension is ignored, since the RP ID is not on the list. let extensions = MakeCredentialExtensions { @@ -1740,7 +1733,7 @@ mod test { #[test] fn test_process_make_credential_cred_blob_ok() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let extensions = MakeCredentialExtensions { cred_blob: Some(vec![0xCB]), @@ -1772,7 +1765,7 @@ mod test { #[test] fn test_process_make_credential_cred_blob_too_big() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let extensions = MakeCredentialExtensions { cred_blob: Some(vec![0xCB; MAX_CRED_BLOB_LENGTH + 1]), @@ -1804,7 +1797,7 @@ mod test { #[test] fn test_process_make_credential_large_blob_key() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let extensions = MakeCredentialExtensions { large_blob_key: Some(true), @@ -1839,7 +1832,7 @@ mod test { let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); ctap_state.client_pin = client_pin; storage::set_pin(&mut env, &[0x88; 16], 4).unwrap(); @@ -1888,7 +1881,7 @@ mod test { #[test] fn test_non_resident_process_make_credential_with_pin() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); storage::set_pin(&mut env, &[0x88; 16], 4).unwrap(); let mut make_credential_params = create_minimal_make_credential_parameters(); @@ -1908,7 +1901,7 @@ mod test { #[test] fn test_resident_process_make_credential_with_pin() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); storage::set_pin(&mut env, &[0x88; 16], 4).unwrap(); let make_credential_params = create_minimal_make_credential_parameters(); @@ -1923,7 +1916,7 @@ mod test { #[test] fn test_process_make_credential_with_pin_always_uv() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); storage::toggle_always_uv(&mut env).unwrap(); let make_credential_params = create_minimal_make_credential_parameters(); @@ -1951,7 +1944,7 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| Err(Ctap2StatusCode::CTAP2_ERR_KEEPALIVE_CANCEL)); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let make_credential_params = create_minimal_make_credential_parameters(); let make_credential_response = @@ -2046,7 +2039,7 @@ mod test { #[test] fn test_resident_process_get_assertion() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let make_credential_params = create_minimal_make_credential_parameters(); assert!(ctap_state @@ -2069,7 +2062,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); check_assertion_response(get_assertion_response, vec![0x1D], signature_counter, None); @@ -2131,7 +2124,7 @@ mod test { fn test_helper_process_get_assertion_hmac_secret(pin_uv_auth_protocol: PinUvAuthProtocol) { let mut env = TestEnv::new(); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let make_extensions = MakeCredentialExtensions { hmac_secret: true, @@ -2167,7 +2160,7 @@ mod test { let key_agreement_response = ctap_state .client_pin - .process_command(&mut env, client_pin_params, DUMMY_CLOCK_VALUE); + .process_command(&mut env, client_pin_params, CtapInstant::new(0)); let get_assertion_params = get_assertion_hmac_secret_params( key_agreement_key, key_agreement_response.unwrap(), @@ -2178,7 +2171,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert!(get_assertion_response.is_ok()); } @@ -2198,7 +2191,7 @@ mod test { ) { let mut env = TestEnv::new(); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let make_extensions = MakeCredentialExtensions { hmac_secret: true, @@ -2223,7 +2216,7 @@ mod test { let key_agreement_response = ctap_state .client_pin - .process_command(&mut env, client_pin_params, DUMMY_CLOCK_VALUE); + .process_command(&mut env, client_pin_params, CtapInstant::new(0)); let get_assertion_params = get_assertion_hmac_secret_params( key_agreement_key, key_agreement_response.unwrap(), @@ -2234,7 +2227,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert!(get_assertion_response.is_ok()); } @@ -2254,7 +2247,7 @@ mod test { let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let credential_id = env.rng().gen_uniform_u8x32().to_vec(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let cred_desc = PublicKeyCredentialDescriptor { key_type: PublicKeyCredentialType::PublicKey, @@ -2295,7 +2288,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( get_assertion_response, @@ -2318,7 +2311,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); check_assertion_response(get_assertion_response, vec![0x1D], signature_counter, None); @@ -2355,7 +2348,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert_eq!( get_assertion_response, @@ -2368,7 +2361,7 @@ mod test { let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let credential_id = env.rng().gen_uniform_u8x32().to_vec(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let credential = PublicKeyCredentialSource { key_type: PublicKeyCredentialType::PublicKey, @@ -2406,7 +2399,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); let expected_extension_cbor = [ @@ -2426,7 +2419,7 @@ mod test { let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); let credential_id = env.rng().gen_uniform_u8x32().to_vec(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let credential = PublicKeyCredentialSource { key_type: PublicKeyCredentialType::PublicKey, @@ -2464,7 +2457,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let large_blob_key = match get_assertion_response.unwrap() { ResponseData::AuthenticatorGetAssertion(get_assertion_response) => { @@ -2484,7 +2477,7 @@ mod test { let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut make_credential_params = create_minimal_make_credential_parameters(); let user1 = PublicKeyCredentialUserEntity { @@ -2535,7 +2528,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); check_assertion_response_with_user( @@ -2548,7 +2541,7 @@ mod test { ); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); check_assertion_response_with_user( get_assertion_response, user1, @@ -2559,7 +2552,7 @@ mod test { ); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); assert_eq!( get_assertion_response, Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED) @@ -2579,7 +2572,7 @@ mod test { #[test] fn test_process_get_next_assertion_three_credentials_no_uv() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.user.user_id = vec![0x01]; @@ -2622,7 +2615,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); check_assertion_response( @@ -2633,15 +2626,15 @@ mod test { ); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); check_assertion_response(get_assertion_response, vec![0x02], signature_counter, None); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); check_assertion_response(get_assertion_response, vec![0x01], signature_counter, None); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); assert_eq!( get_assertion_response, Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED) @@ -2651,10 +2644,10 @@ mod test { #[test] fn test_process_get_next_assertion_not_allowed() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); assert_eq!( get_assertion_response, Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED) @@ -2687,7 +2680,7 @@ mod test { &mut env, get_assertion_params, DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); assert!(get_assertion_response.is_ok()); @@ -2704,10 +2697,15 @@ mod test { 4 => cbor_array![ES256_CRED_PARAM], }; assert!(cbor_write(cbor_value, &mut command_cbor).is_ok()); - ctap_state.process_command(&mut env, &command_cbor, DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + ctap_state.process_command( + &mut env, + &command_cbor, + DUMMY_CHANNEL_ID, + CtapInstant::new(0), + ); let get_assertion_response = - ctap_state.process_get_next_assertion(&mut env, DUMMY_CLOCK_VALUE); + ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); assert_eq!( get_assertion_response, Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED) @@ -2718,7 +2716,7 @@ mod test { fn test_process_reset() { let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let credential_id = vec![0x01, 0x23, 0x45, 0x67]; let credential_source = PublicKeyCredentialSource { @@ -2739,7 +2737,7 @@ mod test { assert!(storage::count_credentials(&mut env).unwrap() > 0); let reset_reponse = - ctap_state.process_command(&mut env, &[0x07], DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + ctap_state.process_command(&mut env, &[0x07], DUMMY_CHANNEL_ID, CtapInstant::new(0)); let expected_response = vec![0x00]; assert_eq!(reset_reponse, expected_response); assert!(storage::count_credentials(&mut env).unwrap() == 0); @@ -2750,9 +2748,10 @@ mod test { let mut env = TestEnv::new(); env.user_presence() .set(|_| Err(Ctap2StatusCode::CTAP2_ERR_KEEPALIVE_CANCEL)); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); - let reset_reponse = ctap_state.process_reset(&mut env, DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + let reset_reponse = + ctap_state.process_reset(&mut env, DUMMY_CHANNEL_ID, CtapInstant::new(0)); assert_eq!( reset_reponse, @@ -2763,26 +2762,27 @@ mod test { #[test] fn test_process_reset_not_first() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // This is a GetNextAssertion command. - ctap_state.process_command(&mut env, &[0x08], DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + ctap_state.process_command(&mut env, &[0x08], DUMMY_CHANNEL_ID, CtapInstant::new(0)); - let reset_reponse = ctap_state.process_reset(&mut env, DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + let reset_reponse = + ctap_state.process_reset(&mut env, DUMMY_CHANNEL_ID, CtapInstant::new(0)); assert_eq!(reset_reponse, Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)); } #[test] fn test_process_credential_management_unknown_subcommand() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // The subcommand 0xEE does not exist. let reponse = ctap_state.process_command( &mut env, &[0x0A, 0xA1, 0x01, 0x18, 0xEE], DUMMY_CHANNEL_ID, - DUMMY_CLOCK_VALUE, + CtapInstant::new(0), ); let expected_response = vec![Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND as u8]; assert_eq!(reponse, expected_response); @@ -2791,11 +2791,11 @@ mod test { #[test] fn test_process_unknown_command() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // This command does not exist. let reponse = - ctap_state.process_command(&mut env, &[0xDF], DUMMY_CHANNEL_ID, DUMMY_CLOCK_VALUE); + ctap_state.process_command(&mut env, &[0xDF], DUMMY_CHANNEL_ID, CtapInstant::new(0)); let expected_response = vec![Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND as u8]; assert_eq!(reponse, expected_response); } @@ -2804,7 +2804,7 @@ mod test { fn test_encrypt_decrypt_credential() { let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // Usually, the relying party ID or its hash is provided by the client. // We are not testing the correctness of our SHA256 here, only if it is checked. @@ -2824,7 +2824,7 @@ mod test { fn test_encrypt_decrypt_bad_hmac() { let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // Same as above. let rp_id_hash = [0x55; 32]; @@ -2844,7 +2844,7 @@ mod test { #[test] fn test_signature_counter() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let mut last_counter = storage::global_signature_counter(&mut env).unwrap(); assert!(last_counter > 0); @@ -2861,7 +2861,7 @@ mod test { #[test] fn test_vendor_configure() { let mut env = TestEnv::new(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // Nothing should be configured at the beginning let response = ctap_state.process_vendor_configure( @@ -3066,7 +3066,7 @@ mod test { // The test identifier matches partition B. let mut env = TestEnv::new(); let private_key = crypto::ecdsa::SecKey::gensk(env.rng()); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); const METADATA_LEN: usize = 40; let data = vec![0xFF; 0x1000]; @@ -3157,7 +3157,7 @@ mod test { fn test_vendor_upgrade_no_second_partition() { let mut env = TestEnv::new(); env.disable_upgrade_storage(); - let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let data = vec![0xFF; 0x1000]; let hash = Sha256::hash(&data).to_vec(); @@ -3176,7 +3176,7 @@ mod test { #[test] fn test_vendor_upgrade_info() { let mut env = TestEnv::new(); - let ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE); + let ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let partition_address = env.upgrade_storage().unwrap().partition_address(); let upgrade_info_reponse = ctap_state.process_vendor_upgrade_info(&mut env); diff --git a/src/ctap/timed_permission.rs b/src/ctap/timed_permission.rs index 868e9da..326912a 100644 --- a/src/ctap/timed_permission.rs +++ b/src/ctap/timed_permission.rs @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use libtock_drivers::timer::{ClockValue, Duration}; +use super::super::clock::{ClockInt, CtapInstant}; +use embedded_time::duration::Milliseconds; -#[derive(Clone, Copy, Debug)] +#[derive(Debug, Copy, Clone)] pub enum TimedPermission { Waiting, - Granted(ClockValue), + Granted(CtapInstant), } impl TimedPermission { @@ -25,28 +26,25 @@ impl TimedPermission { TimedPermission::Waiting } - pub fn granted(now: ClockValue, grant_duration: Duration) -> TimedPermission { - TimedPermission::Granted(now.wrapping_add(grant_duration)) + pub fn granted(now: CtapInstant, grant_duration: Milliseconds) -> TimedPermission { + // TODO: Should panic or saturate if the grant duration is too big. + TimedPermission::Granted(now.checked_add(grant_duration).unwrap()) } // Checks if the timeout is not reached, false for differing ClockValue frequencies. - pub fn is_granted(&self, now: ClockValue) -> bool { + pub fn is_granted(&self, now: CtapInstant) -> bool { if let TimedPermission::Granted(timeout) = self { - if let Some(remaining_duration) = timeout.wrapping_sub(now) { - return remaining_duration > Duration::from_ms(0); - } + return timeout.checked_duration_since(&now).is_some(); } false } // Consumes the state and returns the current new permission state at time "now". // Returns a new state for differing ClockValue frequencies. - pub fn check_expiration(self, now: ClockValue) -> TimedPermission { + pub fn check_expiration(self, now: CtapInstant) -> TimedPermission { if let TimedPermission::Granted(timeout) = self { - if let Some(remaining_duration) = timeout.wrapping_sub(now) { - if remaining_duration > Duration::from_ms(0) { - return TimedPermission::Granted(timeout); - } + if timeout.checked_duration_since(&now).is_some() { + return TimedPermission::Granted(timeout); } } TimedPermission::Waiting @@ -61,16 +59,16 @@ pub struct U2fUserPresenceState { // Button touch timeouts, while user presence is requested, are saved here. has_up: TimedPermission, // This is the timeout duration of user presence requests. - request_duration: Duration, + request_duration: Milliseconds, // This is the timeout duration of button touches. - presence_duration: Duration, + presence_duration: Milliseconds, } #[cfg(feature = "with_ctap1")] impl U2fUserPresenceState { pub fn new( - request_duration: Duration, - presence_duration: Duration, + request_duration: Milliseconds, + presence_duration: Milliseconds, ) -> U2fUserPresenceState { U2fUserPresenceState { needs_up: TimedPermission::Waiting, @@ -81,7 +79,7 @@ impl U2fUserPresenceState { } // Granting user presence is ignored if it needs activation, but waits. Also cleans up. - pub fn grant_up(&mut self, now: ClockValue) { + pub fn grant_up(&mut self, now: CtapInstant) { self.check_expiration(now); if self.needs_up.is_granted(now) { self.needs_up = TimedPermission::Waiting; @@ -90,7 +88,7 @@ impl U2fUserPresenceState { } // This marks user presence as needed or uses it up if already granted. Also cleans up. - pub fn consume_up(&mut self, now: ClockValue) -> bool { + pub fn consume_up(&mut self, now: CtapInstant) -> bool { self.check_expiration(now); if self.has_up.is_granted(now) { self.has_up = TimedPermission::Waiting; @@ -102,13 +100,13 @@ impl U2fUserPresenceState { } // Returns if user presence was requested. Also cleans up. - pub fn is_up_needed(&mut self, now: ClockValue) -> bool { + pub fn is_up_needed(&mut self, now: CtapInstant) -> bool { self.check_expiration(now); self.needs_up.is_granted(now) } // If you don't regularly call any other function, not cleaning up leads to overflow problems. - pub fn check_expiration(&mut self, now: ClockValue) { + pub fn check_expiration(&mut self, now: CtapInstant) { self.needs_up = self.needs_up.check_expiration(now); self.has_up = self.has_up.check_expiration(now); } @@ -118,18 +116,29 @@ impl U2fUserPresenceState { #[cfg(test)] mod test { use super::*; - use core::isize; - const CLOCK_FREQUENCY_HZ: usize = 32768; - const ZERO: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - const BIG_POSITIVE: ClockValue = ClockValue::new(isize::MAX / 1000 - 1, CLOCK_FREQUENCY_HZ); - const NEGATIVE: ClockValue = ClockValue::new(-1, CLOCK_FREQUENCY_HZ); - const SMALL_NEGATIVE: ClockValue = ClockValue::new(isize::MIN / 1000 + 1, CLOCK_FREQUENCY_HZ); - const REQUEST_DURATION: Duration = Duration::from_ms(1000); - const PRESENCE_DURATION: Duration = Duration::from_ms(1000); + fn zero() -> CtapInstant { + CtapInstant::new(0) + } - fn grant_up_when_needed(start_time: ClockValue) { - let mut u2f_state = U2fUserPresenceState::new(REQUEST_DURATION, PRESENCE_DURATION); + fn big_positive() -> CtapInstant { + CtapInstant::new(u64::MAX / 1000 - 1) + } + + fn request_duration() -> Milliseconds { + Milliseconds::new(1000) + } + + fn presence_duration() -> Milliseconds { + Milliseconds::new(1000) + } + + fn epsilon() -> Milliseconds { + Milliseconds::new(1) + } + + fn grant_up_when_needed(start_time: CtapInstant) { + let mut u2f_state = U2fUserPresenceState::new(request_duration(), presence_duration()); assert!(!u2f_state.consume_up(start_time)); assert!(u2f_state.is_up_needed(start_time)); u2f_state.grant_up(start_time); @@ -137,52 +146,54 @@ mod test { assert!(!u2f_state.consume_up(start_time)); } - fn need_up_timeout(start_time: ClockValue) { - let mut u2f_state = U2fUserPresenceState::new(REQUEST_DURATION, PRESENCE_DURATION); + fn need_up_timeout(start_time: CtapInstant) { + let mut u2f_state = U2fUserPresenceState::new(request_duration(), presence_duration()); assert!(!u2f_state.consume_up(start_time)); assert!(u2f_state.is_up_needed(start_time)); // The timeout excludes equality, so it should be over at this instant. - assert!(!u2f_state.is_up_needed(start_time.wrapping_add(REQUEST_DURATION))); + assert!(!u2f_state.is_up_needed( + start_time + .checked_add(presence_duration() + epsilon()) + .unwrap() + )); } - fn grant_up_timeout(start_time: ClockValue) { - let mut u2f_state = U2fUserPresenceState::new(REQUEST_DURATION, PRESENCE_DURATION); + fn grant_up_timeout(start_time: CtapInstant) { + let mut u2f_state = U2fUserPresenceState::new(request_duration(), presence_duration()); assert!(!u2f_state.consume_up(start_time)); assert!(u2f_state.is_up_needed(start_time)); u2f_state.grant_up(start_time); // The timeout excludes equality, so it should be over at this instant. - assert!(!u2f_state.consume_up(start_time.wrapping_add(PRESENCE_DURATION))); + assert!(!u2f_state.consume_up( + start_time + .checked_add(presence_duration() + epsilon()) + .unwrap() + )); } #[test] fn test_grant_up_timeout() { - grant_up_timeout(ZERO); - grant_up_timeout(BIG_POSITIVE); - grant_up_timeout(NEGATIVE); - grant_up_timeout(SMALL_NEGATIVE); + grant_up_timeout(zero()); + grant_up_timeout(big_positive()); } #[test] fn test_need_up_timeout() { - need_up_timeout(ZERO); - need_up_timeout(BIG_POSITIVE); - need_up_timeout(NEGATIVE); - need_up_timeout(SMALL_NEGATIVE); + need_up_timeout(zero()); + need_up_timeout(big_positive()); } #[test] fn test_grant_up_when_needed() { - grant_up_when_needed(ZERO); - grant_up_when_needed(BIG_POSITIVE); - grant_up_when_needed(NEGATIVE); - grant_up_when_needed(SMALL_NEGATIVE); + grant_up_when_needed(zero()); + grant_up_when_needed(big_positive()); } #[test] fn test_grant_up_without_need() { - let mut u2f_state = U2fUserPresenceState::new(REQUEST_DURATION, PRESENCE_DURATION); - u2f_state.grant_up(ZERO); - assert!(!u2f_state.is_up_needed(ZERO)); - assert!(!u2f_state.consume_up(ZERO)); + let mut u2f_state = U2fUserPresenceState::new(request_duration(), presence_duration()); + u2f_state.grant_up(zero()); + assert!(!u2f_state.is_up_needed(zero())); + assert!(!u2f_state.consume_up(zero())); } } diff --git a/src/ctap/token_state.rs b/src/ctap/token_state.rs index fea0f3c..c281150 100644 --- a/src/ctap/token_state.rs +++ b/src/ctap/token_state.rs @@ -18,14 +18,16 @@ use crate::ctap::timed_permission::TimedPermission; use alloc::string::String; use crypto::sha256::Sha256; use crypto::Hash256; -use libtock_drivers::timer::{ClockValue, Duration}; +use embedded_time::duration::Milliseconds; + +use crate::clock::{ClockInt, CtapInstant}; /// Timeout for auth tokens. /// /// This usage time limit is correct for USB, BLE, and internal. /// NFC only allows 19.8 seconds. /// TODO(#15) multiplex over transports, add NFC -const INITIAL_USAGE_TIME_LIMIT: Duration = Duration::from_ms(30000); +const INITIAL_USAGE_TIME_LIMIT: Milliseconds = Milliseconds(30000 as ClockInt); /// Implements pinUvAuthToken state from section 6.5.2.1. /// @@ -111,14 +113,14 @@ impl PinUvAuthTokenState { } /// Starts the timer for pinUvAuthToken usage. - pub fn begin_using_pin_uv_auth_token(&mut self, now: ClockValue) { + pub fn begin_using_pin_uv_auth_token(&mut self, now: CtapInstant) { self.user_verified = true; self.usage_timer = TimedPermission::granted(now, INITIAL_USAGE_TIME_LIMIT); self.in_use = true; } /// Updates the usage timer, and disables the pinUvAuthToken on timeout. - pub fn pin_uv_auth_token_usage_timer_observer(&mut self, now: ClockValue) { + pub fn pin_uv_auth_token_usage_timer_observer(&mut self, now: CtapInstant) { if !self.in_use { return; } @@ -158,20 +160,16 @@ mod test { use super::*; use enum_iterator::IntoEnumIterator; - const CLOCK_FREQUENCY_HZ: usize = 32768; - const START_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); - const SMALL_DURATION: Duration = Duration::from_ms(100); - #[test] fn test_observer() { let mut token_state = PinUvAuthTokenState::new(); - let mut now = START_CLOCK_VALUE; + let mut now: CtapInstant = CtapInstant::new(0); token_state.begin_using_pin_uv_auth_token(now); assert!(token_state.is_in_use()); - now = now.wrapping_add(SMALL_DURATION); + now = now + Milliseconds(100_u32); token_state.pin_uv_auth_token_usage_timer_observer(now); assert!(token_state.is_in_use()); - now = now.wrapping_add(INITIAL_USAGE_TIME_LIMIT); + now = now + INITIAL_USAGE_TIME_LIMIT; token_state.pin_uv_auth_token_usage_timer_observer(now); assert!(!token_state.is_in_use()); } @@ -179,7 +177,8 @@ mod test { #[test] fn test_stop() { let mut token_state = PinUvAuthTokenState::new(); - token_state.begin_using_pin_uv_auth_token(START_CLOCK_VALUE); + let now: CtapInstant = CtapInstant::new(0); + token_state.begin_using_pin_uv_auth_token(now); assert!(token_state.is_in_use()); token_state.stop_using_pin_uv_auth_token(); assert!(!token_state.is_in_use()); @@ -265,11 +264,12 @@ mod test { fn test_user_verified_flag() { let mut token_state = PinUvAuthTokenState::new(); assert!(!token_state.get_user_verified_flag_value()); - token_state.begin_using_pin_uv_auth_token(START_CLOCK_VALUE); + let now: CtapInstant = CtapInstant::new(0); + token_state.begin_using_pin_uv_auth_token(now); assert!(token_state.get_user_verified_flag_value()); token_state.clear_user_verified_flag(); assert!(!token_state.get_user_verified_flag_value()); - token_state.begin_using_pin_uv_auth_token(START_CLOCK_VALUE); + token_state.begin_using_pin_uv_auth_token(now); assert!(token_state.get_user_verified_flag_value()); token_state.stop_using_pin_uv_auth_token(); assert!(!token_state.get_user_verified_flag_value()); diff --git a/src/env/tock/mod.rs b/src/env/tock/mod.rs index cc22838..3f3933c 100644 --- a/src/env/tock/mod.rs +++ b/src/env/tock/mod.rs @@ -211,7 +211,7 @@ pub fn switch_off_leds() { } const KEEPALIVE_DELAY_MS: isize = 100; -pub const KEEPALIVE_DELAY: Duration = Duration::from_ms(KEEPALIVE_DELAY_MS); +pub const KEEPALIVE_DELAY_TOCK: Duration = Duration::from_ms(KEEPALIVE_DELAY_MS); fn check_user_presence(env: &mut TockEnv, cid: ChannelID) -> Result<(), Ctap2StatusCode> { // The timeout is N times the keepalive delay. @@ -219,7 +219,7 @@ fn check_user_presence(env: &mut TockEnv, cid: ChannelID) -> Result<(), Ctap2Sta crate::ctap::TOUCH_TIMEOUT_MS as usize / KEEPALIVE_DELAY_MS as usize; // First, send a keep-alive packet to notify that the keep-alive status has changed. - send_keepalive_up_needed(env, cid, KEEPALIVE_DELAY)?; + send_keepalive_up_needed(env, cid, KEEPALIVE_DELAY_TOCK)?; // Listen to the button presses. let button_touched = Cell::new(false); @@ -245,7 +245,7 @@ fn check_user_presence(env: &mut TockEnv, cid: ChannelID) -> Result<(), Ctap2Sta keepalive_expired.set(true); }); let mut keepalive = keepalive_callback.init().flex_unwrap(); - let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).flex_unwrap(); + let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY_TOCK).flex_unwrap(); // Wait for a button touch or an alarm. libtock_drivers::util::yieldk_for(|| button_touched.get() || keepalive_expired.get()); @@ -269,7 +269,7 @@ fn check_user_presence(env: &mut TockEnv, cid: ChannelID) -> Result<(), Ctap2Sta // so that LEDs blink with a consistent pattern. if keepalive_expired.get() { // Do not return immediately, because we must clean up still. - keepalive_response = send_keepalive_up_needed(env, cid, KEEPALIVE_DELAY); + keepalive_response = send_keepalive_up_needed(env, cid, KEEPALIVE_DELAY_TOCK); } if button_touched.get() || keepalive_response.is_err() { diff --git a/src/lib.rs b/src/lib.rs index d16ce8d..9cc6ae6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ use crate::ctap::hid::send::HidPacketIterator; use crate::ctap::hid::{CtapHid, HidPacket}; use crate::ctap::CtapState; use crate::env::Env; -use libtock_drivers::timer::ClockValue; +use clock::CtapInstant; // Those macros should eventually be split into trace, debug, info, warn, and error macros when // adding either the defmt or log feature and crate dependency. @@ -42,6 +42,7 @@ macro_rules! debug_ctap { } pub mod api; +pub mod clock; // Implementation details must be public for testing (in particular fuzzing). #[cfg(feature = "std")] pub mod ctap; @@ -60,7 +61,7 @@ impl Ctap { /// Instantiates a CTAP implementation given its environment. // This should only take the environment, but it temporarily takes the boot time until the // clock is part of the environment. - pub fn new(mut env: E, now: ClockValue) -> Self { + pub fn new(mut env: E, now: CtapInstant) -> Self { let state = CtapState::new(&mut env, now); let hid = CtapHid::new(); Ctap { env, state, hid } @@ -74,12 +75,16 @@ impl Ctap { &mut self.hid } - pub fn process_hid_packet(&mut self, packet: &HidPacket, now: ClockValue) -> HidPacketIterator { + pub fn process_hid_packet( + &mut self, + packet: &HidPacket, + now: CtapInstant, + ) -> HidPacketIterator { self.hid .process_hid_packet(&mut self.env, packet, now, &mut self.state) } - pub fn update_timeouts(&mut self, now: ClockValue) { + pub fn update_timeouts(&mut self, now: CtapInstant) { self.state.update_timeouts(now); self.hid.wink_permission = self.hid.wink_permission.check_expiration(now); } diff --git a/src/main.rs b/src/main.rs index 04f4c3b..a3db262 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,21 +24,26 @@ extern crate lang_items; #[cfg(feature = "with_ctap1")] use core::cell::Cell; #[cfg(feature = "debug_ctap")] +use core::convert::TryFrom; +use core::convert::TryInto; +#[cfg(feature = "debug_ctap")] use core::fmt::Write; +#[cfg(feature = "debug_ctap")] +use ctap2::clock::CtapClock; +use ctap2::clock::{new_clock, Clock, ClockInt, KEEPALIVE_DELAY}; #[cfg(feature = "with_ctap1")] use ctap2::env::tock::blink_leds; -use ctap2::env::tock::{switch_off_leds, wink_leds, TockEnv, KEEPALIVE_DELAY}; +use ctap2::env::tock::{switch_off_leds, wink_leds, TockEnv, KEEPALIVE_DELAY_TOCK}; +#[cfg(feature = "debug_ctap")] +use embedded_time::duration::Microseconds; +use embedded_time::duration::Milliseconds; #[cfg(feature = "with_ctap1")] use libtock_drivers::buttons::{self, ButtonState}; #[cfg(feature = "debug_ctap")] use libtock_drivers::console::Console; +#[cfg(feature = "with_ctap1")] use libtock_drivers::result::FlexUnwrap; -use libtock_drivers::timer; use libtock_drivers::timer::Duration; -#[cfg(feature = "debug_ctap")] -use libtock_drivers::timer::Timer; -#[cfg(feature = "debug_ctap")] -use libtock_drivers::timer::Timestamp; use libtock_drivers::usb_ctap_hid; libtock_core::stack_size! {0x4000} @@ -46,17 +51,14 @@ libtock_core::stack_size! {0x4000} const SEND_TIMEOUT: Duration = Duration::from_ms(1000); fn main() { - // Setup the timer with a dummy callback (we only care about reading the current time, but the - // API forces us to set an alarm callback too). - let mut with_callback = timer::with_callback(|_, _| {}); - let timer = with_callback.init().flex_unwrap(); + let clock = new_clock(); // Setup USB driver. if !usb_ctap_hid::setup() { panic!("Cannot setup USB driver"); } - let boot_time = timer.get_current_clock().flex_unwrap(); + let boot_time = clock.try_now().unwrap(); let env = TockEnv::new(); let mut ctap = ctap2::Ctap::new(env, boot_time); @@ -86,17 +88,18 @@ fn main() { } let mut pkt_request = [0; 64]; - let has_packet = match usb_ctap_hid::recv_with_timeout(&mut pkt_request, KEEPALIVE_DELAY) { - Some(usb_ctap_hid::SendOrRecvStatus::Received) => { - #[cfg(feature = "debug_ctap")] - print_packet_notice("Received packet", &timer); - true - } - Some(_) => panic!("Error receiving packet"), - None => false, - }; + let has_packet = + match usb_ctap_hid::recv_with_timeout(&mut pkt_request, KEEPALIVE_DELAY_TOCK) { + Some(usb_ctap_hid::SendOrRecvStatus::Received) => { + #[cfg(feature = "debug_ctap")] + print_packet_notice("Received packet", &clock); + true + } + Some(_) => panic!("Error receiving packet"), + None => false, + }; - let now = timer.get_current_clock().flex_unwrap(); + let now = clock.try_now().unwrap(); #[cfg(feature = "with_ctap1")] { if button_touched.get() { @@ -124,7 +127,7 @@ fn main() { match status { None => { #[cfg(feature = "debug_ctap")] - print_packet_notice("Sending packet timed out", &timer); + print_packet_notice("Sending packet timed out", &clock); // TODO: reset the ctap_hid state. // Since sending the packet timed out, we cancel this reply. break; @@ -132,19 +135,20 @@ fn main() { Some(usb_ctap_hid::SendOrRecvStatus::Error) => panic!("Error sending packet"), Some(usb_ctap_hid::SendOrRecvStatus::Sent) => { #[cfg(feature = "debug_ctap")] - print_packet_notice("Sent packet", &timer); + print_packet_notice("Sent packet", &clock); } Some(usb_ctap_hid::SendOrRecvStatus::Received) => { #[cfg(feature = "debug_ctap")] - print_packet_notice("Received an UNEXPECTED packet", &timer); + print_packet_notice("Received an UNEXPECTED packet", &clock); // TODO: handle this unexpected packet. } } } } - let now = timer.get_current_clock().flex_unwrap(); - if let Some(wait_duration) = now.wrapping_sub(last_led_increment) { + let now = clock.try_now().unwrap(); + if let Some(wait_duration) = now.checked_duration_since(&last_led_increment) { + let wait_duration: Milliseconds = wait_duration.try_into().unwrap(); if wait_duration > KEEPALIVE_DELAY { // Loops quickly when waiting for U2F user presence, so the next LED blink // state is only set if enough time has elapsed. @@ -177,9 +181,11 @@ fn main() { } #[cfg(feature = "debug_ctap")] -fn print_packet_notice(notice_text: &str, timer: &Timer) { - let now = timer.get_current_clock().flex_unwrap(); - let now_us = (Timestamp::::from_clock_value(now).ms() * 1000.0) as u64; +fn print_packet_notice(notice_text: &str, clock: &CtapClock) { + let now = clock.try_now().unwrap(); + let now_us = Microseconds::::try_from(now.duration_since_epoch()) + .unwrap() + .0; writeln!( Console::new(), "{} at {}.{:06} s",