Clock trait (#596)

* adds generic Env parameters

* adds Clock type to Env

* use new Clock

* TockTimer improvements

* new Clock interface

* addressed comments

* renames constants to milliseconds, other style fixes

* removes all cargo fmt artifacts
This commit is contained in:
kaczmarczyck
2023-02-28 17:35:42 +01:00
committed by GitHub
parent 963549f9bb
commit 73c60d8740
31 changed files with 1163 additions and 1463 deletions

View File

@@ -12,22 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::api::clock::Clock;
use crate::ctap::client_pin::PinPermission;
use crate::ctap::status_code::Ctap2StatusCode;
use crate::ctap::timed_permission::TimedPermission;
use crate::env::Env;
use alloc::string::String;
use crypto::sha256::Sha256;
use crypto::Hash256;
use embedded_time::duration::Milliseconds;
use crate::clock::{ClockInt, CtapInstant};
/// Timeout for auth tokens.
///
/// This usage time limit is correct for USB, BLE, and internal.
/// NFC only allows 19.8 seconds.
/// TODO(#15) multiplex over transports, add NFC
const INITIAL_USAGE_TIME_LIMIT: Milliseconds<ClockInt> = Milliseconds(30000 as ClockInt);
const INITIAL_USAGE_TIME_LIMIT_MS: usize = 30000;
/// Implements pinUvAuthToken state from section 6.5.2.1.
///
@@ -35,22 +33,22 @@ const INITIAL_USAGE_TIME_LIMIT: Milliseconds<ClockInt> = Milliseconds(30000 as C
/// built-in user verification. Therefore, we never cache user presence.
///
/// This implementation does not use a rolling timer.
pub struct PinUvAuthTokenState {
pub struct PinUvAuthTokenState<E: Env> {
// Relies on the fact that all permissions are represented by powers of two.
permissions_set: u8,
permissions_rp_id: Option<String>,
usage_timer: TimedPermission,
usage_timer: <E::Clock as Clock>::Timer,
user_verified: bool,
in_use: bool,
}
impl PinUvAuthTokenState {
impl<E: Env> PinUvAuthTokenState<E> {
/// Creates a pinUvAuthToken state without permissions.
pub fn new() -> PinUvAuthTokenState {
pub fn new() -> Self {
PinUvAuthTokenState {
permissions_set: 0,
permissions_rp_id: None,
usage_timer: TimedPermission::waiting(),
usage_timer: <E::Clock as Clock>::Timer::default(),
user_verified: false,
in_use: false,
}
@@ -113,19 +111,18 @@ impl PinUvAuthTokenState {
}
/// Starts the timer for pinUvAuthToken usage.
pub fn begin_using_pin_uv_auth_token(&mut self, now: CtapInstant) {
pub fn begin_using_pin_uv_auth_token(&mut self, env: &mut E) {
self.user_verified = true;
self.usage_timer = TimedPermission::granted(now, INITIAL_USAGE_TIME_LIMIT);
self.usage_timer = env.clock().make_timer(INITIAL_USAGE_TIME_LIMIT_MS);
self.in_use = true;
}
/// Updates the usage timer, and disables the pinUvAuthToken on timeout.
pub fn pin_uv_auth_token_usage_timer_observer(&mut self, now: CtapInstant) {
pub fn pin_uv_auth_token_usage_timer_observer(&mut self, env: &mut E) {
if !self.in_use {
return;
}
self.usage_timer = self.usage_timer.check_expiration(now);
if !self.usage_timer.is_granted(now) {
if env.clock().is_elapsed(&self.usage_timer) {
self.stop_using_pin_uv_auth_token();
}
}
@@ -149,7 +146,7 @@ impl PinUvAuthTokenState {
pub fn stop_using_pin_uv_auth_token(&mut self) {
self.permissions_rp_id = None;
self.permissions_set = 0;
self.usage_timer = TimedPermission::waiting();
self.usage_timer = <E::Clock as Clock>::Timer::default();
self.user_verified = false;
self.in_use = false;
}
@@ -158,27 +155,28 @@ impl PinUvAuthTokenState {
#[cfg(test)]
mod test {
use super::*;
use crate::env::test::TestEnv;
use enum_iterator::IntoEnumIterator;
#[test]
fn test_observer() {
let mut token_state = PinUvAuthTokenState::new();
let mut now: CtapInstant = CtapInstant::new(0);
token_state.begin_using_pin_uv_auth_token(now);
let mut env = TestEnv::new();
let mut token_state = PinUvAuthTokenState::<TestEnv>::new();
token_state.begin_using_pin_uv_auth_token(&mut env);
assert!(token_state.is_in_use());
now = now + Milliseconds(100_u32);
token_state.pin_uv_auth_token_usage_timer_observer(now);
env.clock().advance(100);
token_state.pin_uv_auth_token_usage_timer_observer(&mut env);
assert!(token_state.is_in_use());
now = now + INITIAL_USAGE_TIME_LIMIT;
token_state.pin_uv_auth_token_usage_timer_observer(now);
env.clock().advance(INITIAL_USAGE_TIME_LIMIT_MS);
token_state.pin_uv_auth_token_usage_timer_observer(&mut env);
assert!(!token_state.is_in_use());
}
#[test]
fn test_stop() {
let mut token_state = PinUvAuthTokenState::new();
let now: CtapInstant = CtapInstant::new(0);
token_state.begin_using_pin_uv_auth_token(now);
let mut env = TestEnv::new();
let mut token_state = PinUvAuthTokenState::<TestEnv>::new();
token_state.begin_using_pin_uv_auth_token(&mut env);
assert!(token_state.is_in_use());
token_state.stop_using_pin_uv_auth_token();
assert!(!token_state.is_in_use());
@@ -186,7 +184,7 @@ mod test {
#[test]
fn test_permissions() {
let mut token_state = PinUvAuthTokenState::new();
let mut token_state = PinUvAuthTokenState::<TestEnv>::new();
token_state.set_permissions(0xFF);
for permission in PinPermission::into_enum_iter() {
assert_eq!(token_state.has_permission(permission), Ok(()));
@@ -211,7 +209,7 @@ mod test {
#[test]
fn test_permissions_rp_id_none() {
let mut token_state = PinUvAuthTokenState::new();
let mut token_state = PinUvAuthTokenState::<TestEnv>::new();
let example_hash = Sha256::hash(b"example.com");
token_state.set_permissions_rp_id(None);
assert_eq!(token_state.has_no_permissions_rp_id(), Ok(()));
@@ -227,7 +225,7 @@ mod test {
#[test]
fn test_permissions_rp_id_some() {
let mut token_state = PinUvAuthTokenState::new();
let mut token_state = PinUvAuthTokenState::<TestEnv>::new();
let example_hash = Sha256::hash(b"example.com");
token_state.set_permissions_rp_id(Some(String::from("example.com")));
@@ -262,14 +260,14 @@ mod test {
#[test]
fn test_user_verified_flag() {
let mut token_state = PinUvAuthTokenState::new();
let mut env = TestEnv::new();
let mut token_state = PinUvAuthTokenState::<TestEnv>::new();
assert!(!token_state.get_user_verified_flag_value());
let now: CtapInstant = CtapInstant::new(0);
token_state.begin_using_pin_uv_auth_token(now);
token_state.begin_using_pin_uv_auth_token(&mut env);
assert!(token_state.get_user_verified_flag_value());
token_state.clear_user_verified_flag();
assert!(!token_state.get_user_verified_flag_value());
token_state.begin_using_pin_uv_auth_token(now);
token_state.begin_using_pin_uv_auth_token(&mut env);
assert!(token_state.get_user_verified_flag_value());
token_state.stop_using_pin_uv_auth_token();
assert!(!token_state.get_user_verified_flag_value());