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