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
This commit is contained in:
@@ -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"]
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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<isize> = 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<TestEnv>) -> 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<TestEnv>) {
|
||||
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<TestEnv>) {
|
||||
// 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<HidPacket> = 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))
|
||||
);
|
||||
}
|
||||
|
||||
156
src/clock.rs
Normal file
156
src/clock.rs
Normal file
@@ -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<const CLOCK_FREQUENCY: u32>(libtock_drivers::timer::Timer<'static>);
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<const CLOCK_FREQUENCY: u32> LibtockClock<CLOCK_FREQUENCY> {
|
||||
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<const CLOCK_FREQUENCY: u32> fmt::Debug for LibtockClock<CLOCK_FREQUENCY> {
|
||||
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<ClockInt> = 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<const CLOCK_FREQUENCY: u32> embedded_time::Clock for LibtockClock<CLOCK_FREQUENCY> {
|
||||
// TODO: Implement and use a 24-bits TimeInt for Nordic
|
||||
type T = ClockInt;
|
||||
|
||||
const SCALING_FACTOR: embedded_time::fraction::Fraction =
|
||||
<embedded_time::fraction::Fraction>::new(1, CLOCK_FREQUENCY);
|
||||
|
||||
fn try_now(&self) -> Result<embedded_time::Instant<Self>, 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<CtapClock>;
|
||||
|
||||
#[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 =
|
||||
<embedded_time::fraction::Fraction>::new(1, TEST_CLOCK_FREQUENCY_HZ);
|
||||
|
||||
fn try_now(&self) -> Result<embedded_time::Instant<Self>, 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);
|
||||
}
|
||||
}
|
||||
@@ -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<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
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<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
// 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<ResponseData, Ctap2StatusCode> {
|
||||
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!(
|
||||
|
||||
@@ -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<BTreeSet<String>, 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<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||
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<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||
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<ResponseData, Ctap2StatusCode> {
|
||||
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,
|
||||
|
||||
@@ -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<Vec<u8>, 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<u8> {
|
||||
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,8 +699,12 @@ mod test {
|
||||
&key_handle,
|
||||
);
|
||||
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE)
|
||||
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(
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<isize> = Duration::from_ms(100);
|
||||
const WINK_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(5000);
|
||||
const TIMEOUT_DURATION: Milliseconds<ClockInt> = Milliseconds(100 as ClockInt);
|
||||
const WINK_TIMEOUT_DURATION: Milliseconds<ClockInt> = 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<Message> {
|
||||
match self
|
||||
.assembler
|
||||
.parse_packet(packet, Timestamp::<isize>::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<isize> = Timestamp::from_ms(0);
|
||||
|
||||
fn process_messages(
|
||||
env: &mut TestEnv,
|
||||
ctap_hid: &mut CtapHid,
|
||||
@@ -527,12 +518,14 @@ mod test {
|
||||
) -> Option<Vec<Message>> {
|
||||
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);
|
||||
|
||||
|
||||
@@ -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<isize>,
|
||||
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<isize>,
|
||||
timestamp: CtapInstant,
|
||||
) -> Result<Option<Message>, (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<isize>,
|
||||
timestamp: CtapInstant,
|
||||
) -> Result<Option<Message>, (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<isize> = 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],
|
||||
|
||||
192
src/ctap/mod.rs
192
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<isize> = Duration::from_ms(10000);
|
||||
pub const TOUCH_TIMEOUT: Milliseconds<ClockInt> = Milliseconds(TOUCH_TIMEOUT_MS);
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
const U2F_UP_PROMPT_TIMEOUT: Milliseconds<ClockInt> = Milliseconds(10000 as ClockInt);
|
||||
// TODO(kaczmarczyck) 2.1 allows Reset after Reset and 15 seconds?
|
||||
const RESET_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(10000);
|
||||
const STATEFUL_COMMAND_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(30000);
|
||||
const RESET_TIMEOUT_DURATION: Milliseconds<ClockInt> = Milliseconds(10000 as ClockInt);
|
||||
const STATEFUL_COMMAND_TIMEOUT_DURATION: Milliseconds<ClockInt> = 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<u8> {
|
||||
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<ResponseData, Ctap2StatusCode> {
|
||||
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<ResponseData, Ctap2StatusCode> {
|
||||
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<ResponseData, Ctap2StatusCode> {
|
||||
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);
|
||||
|
||||
@@ -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,30 +26,27 @@ impl TimedPermission {
|
||||
TimedPermission::Waiting
|
||||
}
|
||||
|
||||
pub fn granted(now: ClockValue, grant_duration: Duration<isize>) -> TimedPermission {
|
||||
TimedPermission::Granted(now.wrapping_add(grant_duration))
|
||||
pub fn granted(now: CtapInstant, grant_duration: Milliseconds<ClockInt>) -> 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) {
|
||||
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<isize>,
|
||||
request_duration: Milliseconds<ClockInt>,
|
||||
// This is the timeout duration of button touches.
|
||||
presence_duration: Duration<isize>,
|
||||
presence_duration: Milliseconds<ClockInt>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
impl U2fUserPresenceState {
|
||||
pub fn new(
|
||||
request_duration: Duration<isize>,
|
||||
presence_duration: Duration<isize>,
|
||||
request_duration: Milliseconds<ClockInt>,
|
||||
presence_duration: Milliseconds<ClockInt>,
|
||||
) -> 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<isize> = Duration::from_ms(1000);
|
||||
const PRESENCE_DURATION: Duration<isize> = 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<u64> {
|
||||
Milliseconds::new(1000)
|
||||
}
|
||||
|
||||
fn presence_duration() -> Milliseconds<u64> {
|
||||
Milliseconds::new(1000)
|
||||
}
|
||||
|
||||
fn epsilon() -> Milliseconds<u64> {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<isize> = Duration::from_ms(30000);
|
||||
const INITIAL_USAGE_TIME_LIMIT: Milliseconds<ClockInt> = 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<isize> = 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());
|
||||
|
||||
8
src/env/tock/mod.rs
vendored
8
src/env/tock/mod.rs
vendored
@@ -211,7 +211,7 @@ pub fn switch_off_leds() {
|
||||
}
|
||||
|
||||
const KEEPALIVE_DELAY_MS: isize = 100;
|
||||
pub const KEEPALIVE_DELAY: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS);
|
||||
pub const KEEPALIVE_DELAY_TOCK: Duration<isize> = 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() {
|
||||
|
||||
13
src/lib.rs
13
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<E: Env> Ctap<E> {
|
||||
/// 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<E: Env> Ctap<E> {
|
||||
&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);
|
||||
}
|
||||
|
||||
50
src/main.rs
50
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<isize> = 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) {
|
||||
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", &timer);
|
||||
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<ClockInt> = 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::<f64>::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::<u64>::try_from(now.duration_since_epoch())
|
||||
.unwrap()
|
||||
.0;
|
||||
writeln!(
|
||||
Console::new(),
|
||||
"{} at {}.{:06} s",
|
||||
|
||||
Reference in New Issue
Block a user