Add Storage and UpgradeStorage to Env

This commit is contained in:
Julien Cretin
2022-03-03 16:36:45 +01:00
parent d6e4c66562
commit c4a27bf935
21 changed files with 438 additions and 399 deletions

View File

@@ -17,7 +17,7 @@
extern crate lang_items; extern crate lang_items;
use core::fmt::Write; use core::fmt::Write;
use ctap2::embedded_flash::new_storage; use ctap2::env::tock::steal_storage;
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
use libtock_drivers::led; use libtock_drivers::led;
use libtock_drivers::result::FlexUnwrap; use libtock_drivers::result::FlexUnwrap;
@@ -37,7 +37,7 @@ fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
fn main() { fn main() {
led::get(1).flex_unwrap().on().flex_unwrap(); // red on dongle led::get(1).flex_unwrap().on().flex_unwrap(); // red on dongle
let mut storage = new_storage().unwrap(); let mut storage = unsafe { steal_storage() }.unwrap();
let num_pages = storage.num_pages(); let num_pages = storage.num_pages();
writeln!(Console::new(), "Erase {} pages of storage:", num_pages).unwrap(); writeln!(Console::new(), "Erase {} pages of storage:", num_pages).unwrap();
for page in 0..num_pages { for page in 0..num_pages {

View File

@@ -21,7 +21,8 @@ use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use alloc::{format, vec}; use alloc::{format, vec};
use core::fmt::Write; use core::fmt::Write;
use ctap2::embedded_flash::{new_storage, Storage}; use ctap2::env::tock::{steal_storage, TockEnv};
use ctap2::env::Env;
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
use libtock_drivers::timer::{self, Duration, Timer, Timestamp}; use libtock_drivers::timer::{self, Duration, Timer, Timestamp};
use persistent_store::Store; use persistent_store::Store;
@@ -40,9 +41,9 @@ fn measure<T>(timer: &Timer, operation: impl FnOnce() -> T) -> (T, Duration<f64>
} }
// Only use one store at a time. // Only use one store at a time.
unsafe fn boot_store(erase: bool) -> Store<Storage> { unsafe fn boot_store(erase: bool) -> Store<<TockEnv as Env>::Storage> {
use persistent_store::Storage; use persistent_store::Storage;
let mut storage = new_storage().unwrap(); let mut storage = steal_storage().unwrap();
let num_pages = storage.num_pages(); let num_pages = storage.num_pages();
if erase { if erase {
for page in 0..num_pages { for page in 0..num_pages {
@@ -59,7 +60,7 @@ struct StorageConfig {
fn storage_config() -> StorageConfig { fn storage_config() -> StorageConfig {
use persistent_store::Storage; use persistent_store::Storage;
let storage = new_storage().unwrap(); let storage = unsafe { steal_storage() }.unwrap();
StorageConfig { StorageConfig {
num_pages: storage.num_pages(), num_pages: storage.num_pages(),
} }

6
src/api/mod.rs Normal file
View File

@@ -0,0 +1,6 @@
//! APIs for the environment.
//!
//! The [environment](crate::env::Env) is split into components. Each component has an API described
//! by a trait. This module gathers the API of those components.
pub mod upgrade_storage;

View File

@@ -14,6 +14,8 @@
use persistent_store::StorageResult; use persistent_store::StorageResult;
pub(crate) mod helper;
/// Accessors to storage locations used for upgrading from a CTAP command. /// Accessors to storage locations used for upgrading from a CTAP command.
pub trait UpgradeStorage { pub trait UpgradeStorage {
/// Reads a slice of the partition, if within bounds. /// Reads a slice of the partition, if within bounds.

View File

@@ -21,6 +21,7 @@ use super::response::{AuthenticatorClientPinResponse, ResponseData};
use super::status_code::Ctap2StatusCode; use super::status_code::Ctap2StatusCode;
use super::storage::PersistentStore; use super::storage::PersistentStore;
use super::token_state::PinUvAuthTokenState; use super::token_state::PinUvAuthTokenState;
use crate::env::Env;
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::str; use alloc::str;
use alloc::string::String; use alloc::string::String;
@@ -75,8 +76,8 @@ fn decrypt_pin(
/// The new PIN is passed encrypted, so it is first decrypted and stripped from /// The new PIN is passed encrypted, so it is first decrypted and stripped from
/// padding. Next, it is checked against the PIN policy. Last, it is hashed and /// padding. Next, it is checked against the PIN policy. Last, it is hashed and
/// truncated for persistent storage. /// truncated for persistent storage.
fn check_and_store_new_pin( fn check_and_store_new_pin<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
shared_secret: &dyn SharedSecret, shared_secret: &dyn SharedSecret,
new_pin_enc: Vec<u8>, new_pin_enc: Vec<u8>,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
@@ -155,10 +156,10 @@ impl ClientPin {
/// Decrypts the encrypted pin_hash and compares it to the stored pin_hash. /// Decrypts the encrypted pin_hash and compares it to the stored pin_hash.
/// Resets or decreases the PIN retries, depending on success or failure. /// Resets or decreases the PIN retries, depending on success or failure.
/// Also, in case of failure, the key agreement key is randomly reset. /// Also, in case of failure, the key agreement key is randomly reset.
fn verify_pin_hash_enc( fn verify_pin_hash_enc<E: Env>(
&mut self, &mut self,
rng: &mut impl Rng256, rng: &mut impl Rng256,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
pin_uv_auth_protocol: PinUvAuthProtocol, pin_uv_auth_protocol: PinUvAuthProtocol,
shared_secret: &dyn SharedSecret, shared_secret: &dyn SharedSecret,
pin_hash_enc: Vec<u8>, pin_hash_enc: Vec<u8>,
@@ -194,9 +195,9 @@ impl ClientPin {
Ok(()) Ok(())
} }
fn process_get_pin_retries( fn process_get_pin_retries<E: Env>(
&self, &self,
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
Ok(AuthenticatorClientPinResponse { Ok(AuthenticatorClientPinResponse {
key_agreement: None, key_agreement: None,
@@ -222,9 +223,9 @@ impl ClientPin {
}) })
} }
fn process_set_pin( fn process_set_pin<E: Env>(
&mut self, &mut self,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin_params: AuthenticatorClientPinParameters, client_pin_params: AuthenticatorClientPinParameters,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
let AuthenticatorClientPinParameters { let AuthenticatorClientPinParameters {
@@ -249,10 +250,10 @@ impl ClientPin {
Ok(()) Ok(())
} }
fn process_change_pin( fn process_change_pin<E: Env>(
&mut self, &mut self,
rng: &mut impl Rng256, rng: &mut impl Rng256,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin_params: AuthenticatorClientPinParameters, client_pin_params: AuthenticatorClientPinParameters,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
let AuthenticatorClientPinParameters { let AuthenticatorClientPinParameters {
@@ -289,10 +290,10 @@ impl ClientPin {
Ok(()) Ok(())
} }
fn process_get_pin_token( fn process_get_pin_token<E: Env>(
&mut self, &mut self,
rng: &mut impl Rng256, rng: &mut impl Rng256,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin_params: AuthenticatorClientPinParameters, client_pin_params: AuthenticatorClientPinParameters,
now: ClockValue, now: ClockValue,
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
@@ -359,10 +360,10 @@ impl ClientPin {
Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND) Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND)
} }
fn process_get_pin_uv_auth_token_using_pin_with_permissions( fn process_get_pin_uv_auth_token_using_pin_with_permissions<E: Env>(
&mut self, &mut self,
rng: &mut impl Rng256, rng: &mut impl Rng256,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
mut client_pin_params: AuthenticatorClientPinParameters, mut client_pin_params: AuthenticatorClientPinParameters,
now: ClockValue, now: ClockValue,
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
@@ -389,10 +390,10 @@ impl ClientPin {
} }
/// Processes the authenticatorClientPin command. /// Processes the authenticatorClientPin command.
pub fn process_command( pub fn process_command<E: Env>(
&mut self, &mut self,
rng: &mut impl Rng256, rng: &mut impl Rng256,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin_params: AuthenticatorClientPinParameters, client_pin_params: AuthenticatorClientPinParameters,
now: ClockValue, now: ClockValue,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
@@ -570,11 +571,10 @@ impl ClientPin {
pin_uv_auth_token: [u8; PIN_TOKEN_LENGTH], pin_uv_auth_token: [u8; PIN_TOKEN_LENGTH],
pin_uv_auth_protocol: PinUvAuthProtocol, pin_uv_auth_protocol: PinUvAuthProtocol,
) -> ClientPin { ) -> ClientPin {
use crypto::rng256::ThreadRng256; let mut env = crate::env::test::TestEnv::new();
let mut rng = ThreadRng256 {};
let (key_agreement_key_v1, key_agreement_key_v2) = match pin_uv_auth_protocol { let (key_agreement_key_v1, key_agreement_key_v2) = match pin_uv_auth_protocol {
PinUvAuthProtocol::V1 => (key_agreement_key, crypto::ecdh::SecKey::gensk(&mut rng)), PinUvAuthProtocol::V1 => (key_agreement_key, crypto::ecdh::SecKey::gensk(env.rng())),
PinUvAuthProtocol::V2 => (crypto::ecdh::SecKey::gensk(&mut rng), key_agreement_key), PinUvAuthProtocol::V2 => (crypto::ecdh::SecKey::gensk(env.rng()), key_agreement_key),
}; };
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);
@@ -594,15 +594,15 @@ impl ClientPin {
mod test { mod test {
use super::super::pin_protocol::authenticate_pin_uv_auth_token; use super::super::pin_protocol::authenticate_pin_uv_auth_token;
use super::*; use super::*;
use crate::env::test::TestEnv;
use alloc::vec; use alloc::vec;
use crypto::rng256::ThreadRng256;
use libtock_drivers::timer::Duration; use libtock_drivers::timer::Duration;
const CLOCK_FREQUENCY_HZ: usize = 32768; const CLOCK_FREQUENCY_HZ: usize = 32768;
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); 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(persistent_store: &mut PersistentStore) { fn set_standard_pin<E: Env>(persistent_store: &mut PersistentStore<E>) {
let mut pin = [0u8; 64]; let mut pin = [0u8; 64];
pin[..4].copy_from_slice(b"1234"); pin[..4].copy_from_slice(b"1234");
let mut pin_hash = [0u8; 16]; let mut pin_hash = [0u8; 16];
@@ -613,10 +613,10 @@ mod test {
/// Fails on PINs bigger than 64 bytes. /// Fails on PINs bigger than 64 bytes.
fn encrypt_pin(shared_secret: &dyn SharedSecret, pin: Vec<u8>) -> Vec<u8> { fn encrypt_pin(shared_secret: &dyn SharedSecret, pin: Vec<u8>) -> Vec<u8> {
assert!(pin.len() <= 64); assert!(pin.len() <= 64);
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut padded_pin = [0u8; 64]; let mut padded_pin = [0u8; 64];
padded_pin[..pin.len()].copy_from_slice(&pin[..]); padded_pin[..pin.len()].copy_from_slice(&pin[..]);
shared_secret.encrypt(&mut rng, &padded_pin).unwrap() shared_secret.encrypt(env.rng(), &padded_pin).unwrap()
} }
/// Generates a ClientPin instance and a shared secret for testing. /// Generates a ClientPin instance and a shared secret for testing.
@@ -628,8 +628,8 @@ mod test {
fn create_client_pin_and_shared_secret( fn create_client_pin_and_shared_secret(
pin_uv_auth_protocol: PinUvAuthProtocol, pin_uv_auth_protocol: PinUvAuthProtocol,
) -> (ClientPin, Box<dyn SharedSecret>) { ) -> (ClientPin, Box<dyn SharedSecret>) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pk = key_agreement_key.genpk(); let pk = key_agreement_key.genpk();
let key_agreement = CoseKey::from(pk); let key_agreement = CoseKey::from(pk);
let pin_uv_auth_token = [0x91; PIN_TOKEN_LENGTH]; let pin_uv_auth_token = [0x91; PIN_TOKEN_LENGTH];
@@ -649,7 +649,7 @@ mod test {
pin_uv_auth_protocol: PinUvAuthProtocol, pin_uv_auth_protocol: PinUvAuthProtocol,
sub_command: ClientPinSubCommand, sub_command: ClientPinSubCommand,
) -> (ClientPin, AuthenticatorClientPinParameters) { ) -> (ClientPin, AuthenticatorClientPinParameters) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol); let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
let pin = b"1234"; let pin = b"1234";
@@ -658,12 +658,12 @@ mod test {
let pin_hash = Sha256::hash(&padded_pin); let pin_hash = Sha256::hash(&padded_pin);
let new_pin_enc = shared_secret let new_pin_enc = shared_secret
.as_ref() .as_ref()
.encrypt(&mut rng, &padded_pin) .encrypt(env.rng(), &padded_pin)
.unwrap(); .unwrap();
let pin_uv_auth_param = shared_secret.as_ref().authenticate(&new_pin_enc); let pin_uv_auth_param = shared_secret.as_ref().authenticate(&new_pin_enc);
let pin_hash_enc = shared_secret let pin_hash_enc = shared_secret
.as_ref() .as_ref()
.encrypt(&mut rng, &pin_hash[..16]) .encrypt(env.rng(), &pin_hash[..16])
.unwrap(); .unwrap();
let (permissions, permissions_rp_id) = match sub_command { let (permissions, permissions_rp_id) = match sub_command {
ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions
@@ -691,8 +691,8 @@ mod test {
#[test] #[test]
fn test_mix_pin_protocols() { fn test_mix_pin_protocols() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let client_pin = ClientPin::new(&mut rng); let client_pin = ClientPin::new(env.rng());
let pin_protocol_v1 = client_pin.get_pin_protocol(PinUvAuthProtocol::V1); let pin_protocol_v1 = client_pin.get_pin_protocol(PinUvAuthProtocol::V1);
let pin_protocol_v2 = client_pin.get_pin_protocol(PinUvAuthProtocol::V2); let pin_protocol_v2 = client_pin.get_pin_protocol(PinUvAuthProtocol::V2);
let message = vec![0xAA; 16]; let message = vec![0xAA; 16];
@@ -703,38 +703,38 @@ mod test {
let shared_secret_v2 = pin_protocol_v2 let shared_secret_v2 = pin_protocol_v2
.decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V2) .decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V2)
.unwrap(); .unwrap();
let ciphertext = shared_secret_v1.encrypt(&mut rng, &message).unwrap(); let ciphertext = shared_secret_v1.encrypt(env.rng(), &message).unwrap();
let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap(); let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext); assert_ne!(&message, &plaintext);
let ciphertext = shared_secret_v2.encrypt(&mut rng, &message).unwrap(); let ciphertext = shared_secret_v2.encrypt(env.rng(), &message).unwrap();
let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap(); let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext); assert_ne!(&message, &plaintext);
let fake_secret_v1 = pin_protocol_v1 let fake_secret_v1 = pin_protocol_v1
.decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V1) .decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V1)
.unwrap(); .unwrap();
let ciphertext = shared_secret_v1.encrypt(&mut rng, &message).unwrap(); let ciphertext = shared_secret_v1.encrypt(env.rng(), &message).unwrap();
let plaintext = fake_secret_v1.decrypt(&ciphertext).unwrap(); let plaintext = fake_secret_v1.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext); assert_ne!(&message, &plaintext);
let ciphertext = fake_secret_v1.encrypt(&mut rng, &message).unwrap(); let ciphertext = fake_secret_v1.encrypt(env.rng(), &message).unwrap();
let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap(); let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext); assert_ne!(&message, &plaintext);
let fake_secret_v2 = pin_protocol_v2 let fake_secret_v2 = pin_protocol_v2
.decapsulate(pin_protocol_v1.get_public_key(), PinUvAuthProtocol::V2) .decapsulate(pin_protocol_v1.get_public_key(), PinUvAuthProtocol::V2)
.unwrap(); .unwrap();
let ciphertext = shared_secret_v2.encrypt(&mut rng, &message).unwrap(); let ciphertext = shared_secret_v2.encrypt(env.rng(), &message).unwrap();
let plaintext = fake_secret_v2.decrypt(&ciphertext).unwrap(); let plaintext = fake_secret_v2.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext); assert_ne!(&message, &plaintext);
let ciphertext = fake_secret_v2.encrypt(&mut rng, &message).unwrap(); let ciphertext = fake_secret_v2.encrypt(env.rng(), &message).unwrap();
let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap(); let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext); assert_ne!(&message, &plaintext);
} }
fn test_helper_verify_pin_hash_enc(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_verify_pin_hash_enc(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
let pin_protocol = client_pin.get_pin_protocol(pin_uv_auth_protocol); let pin_protocol = client_pin.get_pin_protocol(pin_uv_auth_protocol);
let shared_secret = pin_protocol let shared_secret = pin_protocol
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol) .decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
@@ -746,10 +746,13 @@ mod test {
]; ];
persistent_store.set_pin(&pin_hash, 4).unwrap(); persistent_store.set_pin(&pin_hash, 4).unwrap();
let pin_hash_enc = shared_secret.as_ref().encrypt(&mut rng, &pin_hash).unwrap(); let pin_hash_enc = shared_secret
.as_ref()
.encrypt(env.rng(), &pin_hash)
.unwrap();
assert_eq!( assert_eq!(
client_pin.verify_pin_hash_enc( client_pin.verify_pin_hash_enc(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
pin_uv_auth_protocol, pin_uv_auth_protocol,
shared_secret.as_ref(), shared_secret.as_ref(),
@@ -761,7 +764,7 @@ mod test {
let pin_hash_enc = vec![0xEE; 16]; let pin_hash_enc = vec![0xEE; 16];
assert_eq!( assert_eq!(
client_pin.verify_pin_hash_enc( client_pin.verify_pin_hash_enc(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
pin_uv_auth_protocol, pin_uv_auth_protocol,
shared_secret.as_ref(), shared_secret.as_ref(),
@@ -770,11 +773,14 @@ mod test {
Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID) Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
); );
let pin_hash_enc = shared_secret.as_ref().encrypt(&mut rng, &pin_hash).unwrap(); let pin_hash_enc = shared_secret
.as_ref()
.encrypt(env.rng(), &pin_hash)
.unwrap();
client_pin.consecutive_pin_mismatches = 3; client_pin.consecutive_pin_mismatches = 3;
assert_eq!( assert_eq!(
client_pin.verify_pin_hash_enc( client_pin.verify_pin_hash_enc(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
pin_uv_auth_protocol, pin_uv_auth_protocol,
shared_secret.as_ref(), shared_secret.as_ref(),
@@ -787,7 +793,7 @@ mod test {
let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH - 1]; let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH - 1];
assert_eq!( assert_eq!(
client_pin.verify_pin_hash_enc( client_pin.verify_pin_hash_enc(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
pin_uv_auth_protocol, pin_uv_auth_protocol,
shared_secret.as_ref(), shared_secret.as_ref(),
@@ -799,7 +805,7 @@ mod test {
let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH + 1]; let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH + 1];
assert_eq!( assert_eq!(
client_pin.verify_pin_hash_enc( client_pin.verify_pin_hash_enc(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
pin_uv_auth_protocol, pin_uv_auth_protocol,
shared_secret.as_ref(), shared_secret.as_ref(),
@@ -824,8 +830,8 @@ mod test {
pin_uv_auth_protocol, pin_uv_auth_protocol,
ClientPinSubCommand::GetPinRetries, ClientPinSubCommand::GetPinRetries,
); );
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let expected_response = Some(AuthenticatorClientPinResponse { let expected_response = Some(AuthenticatorClientPinResponse {
key_agreement: None, key_agreement: None,
pin_uv_auth_token: None, pin_uv_auth_token: None,
@@ -834,7 +840,7 @@ mod test {
}); });
assert_eq!( assert_eq!(
client_pin.process_command( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
params.clone(), params.clone(),
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -850,7 +856,7 @@ mod test {
power_cycle_state: Some(true), power_cycle_state: Some(true),
}); });
assert_eq!( assert_eq!(
client_pin.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE), client_pin.process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE),
Ok(ResponseData::AuthenticatorClientPin(expected_response)) Ok(ResponseData::AuthenticatorClientPin(expected_response))
); );
} }
@@ -870,8 +876,8 @@ mod test {
pin_uv_auth_protocol, pin_uv_auth_protocol,
ClientPinSubCommand::GetKeyAgreement, ClientPinSubCommand::GetKeyAgreement,
); );
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let expected_response = Some(AuthenticatorClientPinResponse { let expected_response = Some(AuthenticatorClientPinResponse {
key_agreement: params.key_agreement.clone(), key_agreement: params.key_agreement.clone(),
pin_uv_auth_token: None, pin_uv_auth_token: None,
@@ -879,7 +885,7 @@ mod test {
power_cycle_state: None, power_cycle_state: None,
}); });
assert_eq!( assert_eq!(
client_pin.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE), client_pin.process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE),
Ok(ResponseData::AuthenticatorClientPin(expected_response)) Ok(ResponseData::AuthenticatorClientPin(expected_response))
); );
} }
@@ -897,10 +903,10 @@ mod test {
fn test_helper_process_set_pin(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_process_set_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let (mut client_pin, params) = let (mut client_pin, params) =
create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::SetPin); create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::SetPin);
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!( assert_eq!(
client_pin.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE), client_pin.process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE),
Ok(ResponseData::AuthenticatorClientPin(None)) Ok(ResponseData::AuthenticatorClientPin(None))
); );
} }
@@ -925,8 +931,8 @@ mod test {
params.pin_uv_auth_protocol, params.pin_uv_auth_protocol,
) )
.unwrap(); .unwrap();
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
let mut auth_param_data = params.new_pin_enc.clone().unwrap(); let mut auth_param_data = params.new_pin_enc.clone().unwrap();
@@ -935,7 +941,7 @@ mod test {
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( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
params.clone(), params.clone(),
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -947,7 +953,7 @@ mod test {
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( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
bad_params, bad_params,
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -959,7 +965,7 @@ mod test {
persistent_store.decr_pin_retries().unwrap(); persistent_store.decr_pin_retries().unwrap();
} }
assert_eq!( assert_eq!(
client_pin.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE), client_pin.process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE),
Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED) Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED)
); );
} }
@@ -986,13 +992,13 @@ mod test {
params.pin_uv_auth_protocol, params.pin_uv_auth_protocol,
) )
.unwrap(); .unwrap();
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
let response = client_pin let response = client_pin
.process_command( .process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
params.clone(), params.clone(),
DUMMY_CLOCK_VALUE, DUMMY_CLOCK_VALUE,
@@ -1033,7 +1039,7 @@ mod test {
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( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
bad_params, bad_params,
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -1057,13 +1063,13 @@ mod test {
pin_uv_auth_protocol, pin_uv_auth_protocol,
ClientPinSubCommand::GetPinToken, ClientPinSubCommand::GetPinToken,
); );
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
assert_eq!(persistent_store.force_pin_change(), Ok(())); assert_eq!(persistent_store.force_pin_change(), Ok(()));
assert_eq!( assert_eq!(
client_pin.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE), client_pin.process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE),
Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID), Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID),
); );
} }
@@ -1092,13 +1098,13 @@ mod test {
params.pin_uv_auth_protocol, params.pin_uv_auth_protocol,
) )
.unwrap(); .unwrap();
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
let response = client_pin let response = client_pin
.process_command( .process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
params.clone(), params.clone(),
DUMMY_CLOCK_VALUE, DUMMY_CLOCK_VALUE,
@@ -1139,7 +1145,7 @@ mod test {
bad_params.permissions = Some(0x00); bad_params.permissions = Some(0x00);
assert_eq!( assert_eq!(
client_pin.process_command( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
bad_params, bad_params,
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -1151,7 +1157,7 @@ mod test {
bad_params.permissions_rp_id = None; bad_params.permissions_rp_id = None;
assert_eq!( assert_eq!(
client_pin.process_command( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
bad_params, bad_params,
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -1163,7 +1169,7 @@ mod test {
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( client_pin.process_command(
&mut rng, env.rng(),
&mut persistent_store, &mut persistent_store,
bad_params, bad_params,
DUMMY_CLOCK_VALUE DUMMY_CLOCK_VALUE
@@ -1189,13 +1195,13 @@ mod test {
pin_uv_auth_protocol, pin_uv_auth_protocol,
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions, ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
); );
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
assert_eq!(persistent_store.force_pin_change(), Ok(())); assert_eq!(persistent_store.force_pin_change(), Ok(()));
assert_eq!( assert_eq!(
client_pin.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE), client_pin.process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE),
Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID) Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
); );
} }
@@ -1215,8 +1221,8 @@ mod test {
} }
fn test_helper_decrypt_pin(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_decrypt_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let pin_protocol = PinProtocol::new(&mut rng); let pin_protocol = PinProtocol::new(env.rng());
let shared_secret = pin_protocol let shared_secret = pin_protocol
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol) .decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
.unwrap(); .unwrap();
@@ -1259,9 +1265,9 @@ mod test {
} }
fn test_helper_check_and_store_new_pin(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_check_and_store_new_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let pin_protocol = PinProtocol::new(&mut rng); let pin_protocol = PinProtocol::new(env.rng());
let shared_secret = pin_protocol let shared_secret = pin_protocol
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol) .decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
.unwrap(); .unwrap();
@@ -1317,10 +1323,10 @@ mod test {
cred_random: &[u8; 32], cred_random: &[u8; 32],
salt: Vec<u8>, salt: Vec<u8>,
) -> Result<Vec<u8>, Ctap2StatusCode> { ) -> Result<Vec<u8>, Ctap2StatusCode> {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol); let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
let salt_enc = shared_secret.as_ref().encrypt(&mut rng, &salt).unwrap(); let salt_enc = shared_secret.as_ref().encrypt(env.rng(), &salt).unwrap();
let salt_auth = shared_secret.authenticate(&salt_enc); let salt_auth = shared_secret.authenticate(&salt_enc);
let hmac_secret_input = GetAssertionHmacSecretInput { let hmac_secret_input = GetAssertionHmacSecretInput {
key_agreement: client_pin key_agreement: client_pin
@@ -1330,12 +1336,12 @@ mod test {
salt_auth, salt_auth,
pin_uv_auth_protocol, pin_uv_auth_protocol,
}; };
let output = client_pin.process_hmac_secret(&mut rng, hmac_secret_input, cred_random); let output = client_pin.process_hmac_secret(env.rng(), hmac_secret_input, cred_random);
output.map(|v| shared_secret.as_ref().decrypt(&v).unwrap()) output.map(|v| shared_secret.as_ref().decrypt(&v).unwrap())
} }
fn test_helper_process_hmac_secret_bad_salt_auth(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_process_hmac_secret_bad_salt_auth(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol); let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
let cred_random = [0xC9; 32]; let cred_random = [0xC9; 32];
@@ -1350,7 +1356,7 @@ mod test {
salt_auth, salt_auth,
pin_uv_auth_protocol, pin_uv_auth_protocol,
}; };
let output = client_pin.process_hmac_secret(&mut rng, hmac_secret_input, &cred_random); let output = client_pin.process_hmac_secret(env.rng(), hmac_secret_input, &cred_random);
assert_eq!(output, Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)); assert_eq!(output, Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID));
} }
@@ -1451,8 +1457,8 @@ mod test {
#[test] #[test]
fn test_has_permission() { fn test_has_permission() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
client_pin.pin_uv_auth_token_state.set_permissions(0x7F); client_pin.pin_uv_auth_token_state.set_permissions(0x7F);
for permission in PinPermission::into_enum_iter() { for permission in PinPermission::into_enum_iter() {
assert_eq!( assert_eq!(
@@ -1475,8 +1481,8 @@ mod test {
#[test] #[test]
fn test_has_no_rp_id_permission() { fn test_has_no_rp_id_permission() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
assert_eq!(client_pin.has_no_rp_id_permission(), Ok(())); assert_eq!(client_pin.has_no_rp_id_permission(), Ok(()));
client_pin client_pin
.pin_uv_auth_token_state .pin_uv_auth_token_state
@@ -1489,8 +1495,8 @@ mod test {
#[test] #[test]
fn test_has_no_or_rp_id_permission() { fn test_has_no_or_rp_id_permission() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
assert_eq!(client_pin.has_no_or_rp_id_permission("example.com"), Ok(())); assert_eq!(client_pin.has_no_or_rp_id_permission("example.com"), Ok(()));
client_pin client_pin
.pin_uv_auth_token_state .pin_uv_auth_token_state
@@ -1504,8 +1510,8 @@ mod test {
#[test] #[test]
fn test_has_no_or_rp_id_hash_permission() { fn test_has_no_or_rp_id_hash_permission() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
let rp_id_hash = Sha256::hash(b"example.com"); let rp_id_hash = Sha256::hash(b"example.com");
assert_eq!( assert_eq!(
client_pin.has_no_or_rp_id_hash_permission(&rp_id_hash), client_pin.has_no_or_rp_id_hash_permission(&rp_id_hash),
@@ -1526,8 +1532,8 @@ mod test {
#[test] #[test]
fn test_ensure_rp_id_permission() { fn test_ensure_rp_id_permission() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
assert_eq!(client_pin.ensure_rp_id_permission("example.com"), Ok(())); assert_eq!(client_pin.ensure_rp_id_permission("example.com"), Ok(()));
assert_eq!( assert_eq!(
client_pin client_pin
@@ -1544,8 +1550,8 @@ mod test {
#[test] #[test]
fn test_verify_pin_uv_auth_token() { fn test_verify_pin_uv_auth_token() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
let message = [0xAA]; let message = [0xAA];
client_pin client_pin
.pin_uv_auth_token_state .pin_uv_auth_token_state
@@ -1618,8 +1624,8 @@ mod test {
#[test] #[test]
fn test_verify_pin_uv_auth_token_not_in_use() { fn test_verify_pin_uv_auth_token_not_in_use() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let client_pin = ClientPin::new(&mut rng); let client_pin = ClientPin::new(env.rng());
let message = [0xAA]; let message = [0xAA];
let pin_uv_auth_token_v1 = client_pin let pin_uv_auth_token_v1 = client_pin
@@ -1640,8 +1646,8 @@ mod test {
#[test] #[test]
fn test_reset() { fn test_reset() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut client_pin = ClientPin::new(&mut rng); let mut client_pin = ClientPin::new(env.rng());
let public_key_v1 = client_pin.pin_protocol_v1.get_public_key(); let public_key_v1 = client_pin.pin_protocol_v1.get_public_key();
let public_key_v2 = client_pin.pin_protocol_v2.get_public_key(); let public_key_v2 = client_pin.pin_protocol_v2.get_public_key();
let token_v1 = *client_pin.pin_protocol_v1.get_pin_uv_auth_token(); let token_v1 = *client_pin.pin_protocol_v1.get_pin_uv_auth_token();
@@ -1650,7 +1656,7 @@ mod test {
client_pin client_pin
.pin_uv_auth_token_state .pin_uv_auth_token_state
.set_permissions_rp_id(Some(String::from("example.com"))); .set_permissions_rp_id(Some(String::from("example.com")));
client_pin.reset(&mut rng); client_pin.reset(env.rng());
assert_ne!(public_key_v1, client_pin.pin_protocol_v1.get_public_key()); assert_ne!(public_key_v1, client_pin.pin_protocol_v1.get_public_key());
assert_ne!(public_key_v2, client_pin.pin_protocol_v2.get_public_key()); assert_ne!(public_key_v2, client_pin.pin_protocol_v2.get_public_key());
assert_ne!( assert_ne!(
@@ -1676,13 +1682,13 @@ mod test {
PinUvAuthProtocol::V2, PinUvAuthProtocol::V2,
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions, ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
); );
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
params.permissions = Some(0xFF); params.permissions = Some(0xFF);
assert!(client_pin assert!(client_pin
.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE) .process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE)
.is_ok()); .is_ok());
for permission in PinPermission::into_enum_iter() { for permission in PinPermission::into_enum_iter() {
assert_eq!( assert_eq!(
@@ -1723,13 +1729,13 @@ mod test {
PinUvAuthProtocol::V2, PinUvAuthProtocol::V2,
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions, ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
); );
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
set_standard_pin(&mut persistent_store); set_standard_pin(&mut persistent_store);
params.permissions = Some(0xFF); params.permissions = Some(0xFF);
assert!(client_pin assert!(client_pin
.process_command(&mut rng, &mut persistent_store, params, DUMMY_CLOCK_VALUE) .process_command(env.rng(), &mut persistent_store, params, DUMMY_CLOCK_VALUE)
.is_ok()); .is_ok());
for permission in PinPermission::into_enum_iter() { for permission in PinPermission::into_enum_iter() {
assert_eq!( assert_eq!(

View File

@@ -19,11 +19,12 @@ use super::data_formats::{ConfigSubCommand, ConfigSubCommandParams, SetMinPinLen
use super::response::ResponseData; use super::response::ResponseData;
use super::status_code::Ctap2StatusCode; use super::status_code::Ctap2StatusCode;
use super::storage::PersistentStore; use super::storage::PersistentStore;
use crate::env::Env;
use alloc::vec; use alloc::vec;
/// Processes the subcommand enableEnterpriseAttestation for AuthenticatorConfig. /// Processes the subcommand enableEnterpriseAttestation for AuthenticatorConfig.
fn process_enable_enterprise_attestation( fn process_enable_enterprise_attestation<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
if ENTERPRISE_ATTESTATION_MODE.is_some() { if ENTERPRISE_ATTESTATION_MODE.is_some() {
persistent_store.enable_enterprise_attestation()?; persistent_store.enable_enterprise_attestation()?;
@@ -34,16 +35,16 @@ fn process_enable_enterprise_attestation(
} }
/// Processes the subcommand toggleAlwaysUv for AuthenticatorConfig. /// Processes the subcommand toggleAlwaysUv for AuthenticatorConfig.
fn process_toggle_always_uv( fn process_toggle_always_uv<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
persistent_store.toggle_always_uv()?; persistent_store.toggle_always_uv()?;
Ok(ResponseData::AuthenticatorConfig) Ok(ResponseData::AuthenticatorConfig)
} }
/// Processes the subcommand setMinPINLength for AuthenticatorConfig. /// Processes the subcommand setMinPINLength for AuthenticatorConfig.
fn process_set_min_pin_length( fn process_set_min_pin_length<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
params: SetMinPinLengthParams, params: SetMinPinLengthParams,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
let SetMinPinLengthParams { let SetMinPinLengthParams {
@@ -74,8 +75,8 @@ fn process_set_min_pin_length(
} }
/// Processes the AuthenticatorConfig command. /// Processes the AuthenticatorConfig command.
pub fn process_config( pub fn process_config<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin: &mut ClientPin, client_pin: &mut ClientPin,
params: AuthenticatorConfigParameters, params: AuthenticatorConfigParameters,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
@@ -129,13 +130,13 @@ mod test {
use crate::ctap::customization::ENFORCE_ALWAYS_UV; use crate::ctap::customization::ENFORCE_ALWAYS_UV;
use crate::ctap::data_formats::PinUvAuthProtocol; use crate::ctap::data_formats::PinUvAuthProtocol;
use crate::ctap::pin_protocol::authenticate_pin_uv_auth_token; use crate::ctap::pin_protocol::authenticate_pin_uv_auth_token;
use crypto::rng256::ThreadRng256; use crate::env::test::TestEnv;
#[test] #[test]
fn test_process_enable_enterprise_attestation() { fn test_process_enable_enterprise_attestation() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -161,9 +162,9 @@ mod test {
#[test] #[test]
fn test_process_toggle_always_uv() { fn test_process_toggle_always_uv() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -197,9 +198,9 @@ mod test {
} }
fn test_helper_process_toggle_always_uv_with_pin(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_process_toggle_always_uv_with_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut 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);
@@ -268,9 +269,9 @@ mod test {
#[test] #[test]
fn test_process_set_min_pin_length() { fn test_process_set_min_pin_length() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -313,9 +314,9 @@ mod test {
#[test] #[test]
fn test_process_set_min_pin_length_rp_ids() { fn test_process_set_min_pin_length_rp_ids() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -390,9 +391,9 @@ mod test {
#[test] #[test]
fn test_process_set_min_pin_length_force_pin_change_implicit() { fn test_process_set_min_pin_length_force_pin_change_implicit() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -414,9 +415,9 @@ mod test {
#[test] #[test]
fn test_process_set_min_pin_length_force_pin_change_explicit() { fn test_process_set_min_pin_length_force_pin_change_explicit() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -446,9 +447,9 @@ mod test {
#[test] #[test]
fn test_process_config_vendor_prototype() { fn test_process_config_vendor_prototype() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);

View File

@@ -23,6 +23,7 @@ use super::response::{AuthenticatorCredentialManagementResponse, ResponseData};
use super::status_code::Ctap2StatusCode; use super::status_code::Ctap2StatusCode;
use super::storage::PersistentStore; use super::storage::PersistentStore;
use super::{StatefulCommand, StatefulPermission}; use super::{StatefulCommand, StatefulPermission};
use crate::env::Env;
use alloc::collections::BTreeSet; use alloc::collections::BTreeSet;
use alloc::string::String; use alloc::string::String;
use alloc::vec; use alloc::vec;
@@ -32,8 +33,8 @@ use crypto::Hash256;
use libtock_drivers::timer::ClockValue; 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( fn get_stored_rp_ids<E: Env>(
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
) -> Result<BTreeSet<String>, Ctap2StatusCode> { ) -> Result<BTreeSet<String>, Ctap2StatusCode> {
let mut rp_set = BTreeSet::new(); let mut rp_set = BTreeSet::new();
let mut iter_result = Ok(()); let mut iter_result = Ok(());
@@ -108,8 +109,8 @@ fn enumerate_credentials_response(
/// Check if the token permissions have the correct associated RP ID. /// Check if the token permissions have the correct associated RP ID.
/// ///
/// Either no RP ID is associated, or the RP ID matches the stored credential. /// Either no RP ID is associated, or the RP ID matches the stored credential.
fn check_rp_id_permissions( fn check_rp_id_permissions<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin: &mut ClientPin, client_pin: &mut ClientPin,
credential_id: &[u8], credential_id: &[u8],
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
@@ -122,8 +123,8 @@ fn check_rp_id_permissions(
} }
/// Processes the subcommand getCredsMetadata for CredentialManagement. /// Processes the subcommand getCredsMetadata for CredentialManagement.
fn process_get_creds_metadata( fn process_get_creds_metadata<E: Env>(
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
Ok(AuthenticatorCredentialManagementResponse { Ok(AuthenticatorCredentialManagementResponse {
existing_resident_credentials_count: Some(persistent_store.count_credentials()? as u64), existing_resident_credentials_count: Some(persistent_store.count_credentials()? as u64),
@@ -135,8 +136,8 @@ fn process_get_creds_metadata(
} }
/// Processes the subcommand enumerateRPsBegin for CredentialManagement. /// Processes the subcommand enumerateRPsBegin for CredentialManagement.
fn process_enumerate_rps_begin( fn process_enumerate_rps_begin<E: Env>(
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
stateful_command_permission: &mut StatefulPermission, stateful_command_permission: &mut StatefulPermission,
now: ClockValue, now: ClockValue,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
@@ -155,8 +156,8 @@ fn process_enumerate_rps_begin(
} }
/// Processes the subcommand enumerateRPsGetNextRP for CredentialManagement. /// Processes the subcommand enumerateRPsGetNextRP for CredentialManagement.
fn process_enumerate_rps_get_next_rp( fn process_enumerate_rps_get_next_rp<E: Env>(
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
stateful_command_permission: &mut StatefulPermission, stateful_command_permission: &mut StatefulPermission,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
let rp_id_index = stateful_command_permission.next_enumerate_rp()?; let rp_id_index = stateful_command_permission.next_enumerate_rp()?;
@@ -170,8 +171,8 @@ fn process_enumerate_rps_get_next_rp(
} }
/// Processes the subcommand enumerateCredentialsBegin for CredentialManagement. /// Processes the subcommand enumerateCredentialsBegin for CredentialManagement.
fn process_enumerate_credentials_begin( fn process_enumerate_credentials_begin<E: Env>(
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
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,
@@ -207,8 +208,8 @@ fn process_enumerate_credentials_begin(
} }
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement. /// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
fn process_enumerate_credentials_get_next_credential( fn process_enumerate_credentials_get_next_credential<E: Env>(
persistent_store: &PersistentStore, persistent_store: &PersistentStore<E>,
stateful_command_permission: &mut StatefulPermission, stateful_command_permission: &mut StatefulPermission,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
let credential_key = stateful_command_permission.next_enumerate_credential()?; let credential_key = stateful_command_permission.next_enumerate_credential()?;
@@ -217,8 +218,8 @@ fn process_enumerate_credentials_get_next_credential(
} }
/// Processes the subcommand deleteCredential for CredentialManagement. /// Processes the subcommand deleteCredential for CredentialManagement.
fn process_delete_credential( fn process_delete_credential<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin: &mut ClientPin, client_pin: &mut ClientPin,
sub_command_params: CredentialManagementSubCommandParameters, sub_command_params: CredentialManagementSubCommandParameters,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
@@ -231,8 +232,8 @@ fn process_delete_credential(
} }
/// Processes the subcommand updateUserInformation for CredentialManagement. /// Processes the subcommand updateUserInformation for CredentialManagement.
fn process_update_user_information( fn process_update_user_information<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin: &mut ClientPin, client_pin: &mut ClientPin,
sub_command_params: CredentialManagementSubCommandParameters, sub_command_params: CredentialManagementSubCommandParameters,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
@@ -248,8 +249,8 @@ fn process_update_user_information(
} }
/// Processes the CredentialManagement command and all its subcommands. /// Processes the CredentialManagement command and all its subcommands.
pub fn process_credential_management( pub fn process_credential_management<E: Env>(
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
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,

View File

@@ -178,10 +178,10 @@ impl Ctap1Command {
const VENDOR_SPECIFIC_FIRST: u8 = 0x40; const VENDOR_SPECIFIC_FIRST: u8 = 0x40;
const VENDOR_SPECIFIC_LAST: u8 = 0xBF; const VENDOR_SPECIFIC_LAST: u8 = 0xBF;
pub fn process_command( pub fn process_command<E: Env>(
env: &mut impl Env, env: &mut E,
message: &[u8], message: &[u8],
ctap_state: &mut CtapState, ctap_state: &mut CtapState<E>,
clock_value: ClockValue, clock_value: ClockValue,
) -> Result<Vec<u8>, Ctap1StatusCode> { ) -> Result<Vec<u8>, Ctap1StatusCode> {
if !ctap_state if !ctap_state
@@ -243,11 +243,11 @@ impl Ctap1Command {
// +------+-------------------+-----------------+------------+--------------------+ // +------+-------------------+-----------------+------------+--------------------+
// + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) | // + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
// +------+-------------------+-----------------+------------+--------------------+ // +------+-------------------+-----------------+------------+--------------------+
fn process_register( fn process_register<E: Env>(
env: &mut impl Env, env: &mut E,
challenge: [u8; 32], challenge: [u8; 32],
application: [u8; 32], application: [u8; 32],
ctap_state: &mut CtapState, ctap_state: &mut CtapState<E>,
) -> Result<Vec<u8>, Ctap1StatusCode> { ) -> Result<Vec<u8>, Ctap1StatusCode> {
let sk = crypto::ecdsa::SecKey::gensk(env.rng()); let sk = crypto::ecdsa::SecKey::gensk(env.rng());
let pk = sk.genpk(); let pk = sk.genpk();
@@ -307,13 +307,13 @@ impl Ctap1Command {
// +-------------------+---------+--------------+-----------------+ // +-------------------+---------+--------------+-----------------+
// + application (32B) | UP (1B) | Counter (4B) | challenge (32B) | // + application (32B) | UP (1B) | Counter (4B) | challenge (32B) |
// +-------------------+---------+--------------+-----------------+ // +-------------------+---------+--------------+-----------------+
fn process_authenticate( fn process_authenticate<E: Env>(
env: &mut impl Env, env: &mut E,
challenge: [u8; 32], challenge: [u8; 32],
application: [u8; 32], application: [u8; 32],
key_handle: Vec<u8>, key_handle: Vec<u8>,
flags: Ctap1Flags, flags: Ctap1Flags,
ctap_state: &mut CtapState, ctap_state: &mut CtapState<E>,
) -> Result<Vec<u8>, Ctap1StatusCode> { ) -> Result<Vec<u8>, Ctap1StatusCode> {
let credential_source = ctap_state let credential_source = ctap_state
.decrypt_credential_source(key_handle, &application) .decrypt_credential_source(key_handle, &application)

View File

@@ -146,12 +146,12 @@ impl CtapHid {
// Process an incoming USB HID packet, and optionally returns a list of outgoing packets to // Process an incoming USB HID packet, and optionally returns a list of outgoing packets to
// send as a reply. // send as a reply.
pub fn process_hid_packet( pub fn process_hid_packet<E: Env>(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
packet: &HidPacket, packet: &HidPacket,
clock_value: ClockValue, clock_value: ClockValue,
ctap_state: &mut CtapState, ctap_state: &mut CtapState<E>,
) -> HidPacketIterator { ) -> HidPacketIterator {
// TODO: Send COMMAND_KEEPALIVE every 100ms? // TODO: Send COMMAND_KEEPALIVE every 100ms?
match self match self
@@ -442,10 +442,10 @@ mod test {
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ); const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0); const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
fn process_messages( fn process_messages<E: Env>(
env: &mut impl Env, env: &mut E,
ctap_hid: &mut CtapHid, ctap_hid: &mut CtapHid,
ctap_state: &mut CtapState, ctap_state: &mut CtapState<E>,
request: Vec<Message>, request: Vec<Message>,
) -> Option<Vec<Message>> { ) -> Option<Vec<Message>> {
let mut result = Vec::new(); let mut result = Vec::new();
@@ -466,10 +466,10 @@ mod test {
Some(result) Some(result)
} }
fn cid_from_init( fn cid_from_init<E: Env>(
env: &mut impl Env, env: &mut E,
ctap_hid: &mut CtapHid, ctap_hid: &mut CtapHid,
ctap_state: &mut CtapState, ctap_state: &mut CtapState<E>,
) -> ChannelID { ) -> ChannelID {
let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
let reply = process_messages( let reply = process_messages(

View File

@@ -18,6 +18,7 @@ use super::customization::MAX_MSG_SIZE;
use super::response::{AuthenticatorLargeBlobsResponse, ResponseData}; use super::response::{AuthenticatorLargeBlobsResponse, ResponseData};
use super::status_code::Ctap2StatusCode; use super::status_code::Ctap2StatusCode;
use super::storage::PersistentStore; use super::storage::PersistentStore;
use crate::env::Env;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
@@ -44,9 +45,9 @@ impl LargeBlobs {
} }
/// Process the large blob command. /// Process the large blob command.
pub fn process_command( pub fn process_command<E: Env>(
&mut self, &mut self,
persistent_store: &mut PersistentStore, persistent_store: &mut PersistentStore<E>,
client_pin: &mut ClientPin, client_pin: &mut ClientPin,
large_blobs_params: AuthenticatorLargeBlobsParameters, large_blobs_params: AuthenticatorLargeBlobsParameters,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
@@ -137,13 +138,13 @@ mod test {
use super::super::data_formats::PinUvAuthProtocol; use super::super::data_formats::PinUvAuthProtocol;
use super::super::pin_protocol::authenticate_pin_uv_auth_token; use super::super::pin_protocol::authenticate_pin_uv_auth_token;
use super::*; use super::*;
use crypto::rng256::ThreadRng256; use crate::env::test::TestEnv;
#[test] #[test]
fn test_process_command_get_empty() { fn test_process_command_get_empty() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -173,9 +174,9 @@ mod test {
#[test] #[test]
fn test_process_command_commit_and_get() { fn test_process_command_commit_and_get() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -236,9 +237,9 @@ mod test {
#[test] #[test]
fn test_process_command_commit_unexpected_offset() { fn test_process_command_commit_unexpected_offset() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -283,9 +284,9 @@ mod test {
#[test] #[test]
fn test_process_command_commit_unexpected_length() { fn test_process_command_commit_unexpected_length() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -330,9 +331,9 @@ mod test {
#[test] #[test]
fn test_process_command_commit_end_offset_overflow() { fn test_process_command_commit_end_offset_overflow() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -354,9 +355,9 @@ mod test {
#[test] #[test]
fn test_process_command_commit_unexpected_hash() { fn test_process_command_commit_unexpected_hash() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut client_pin =
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1); ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
@@ -383,9 +384,9 @@ mod test {
} }
fn test_helper_process_command_commit_with_pin(pin_uv_auth_protocol: PinUvAuthProtocol) { fn test_helper_process_command_commit_with_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng); let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
let pin_uv_auth_token = [0x55; 32]; let pin_uv_auth_token = [0x55; 32];
let mut client_pin = let mut 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);

View File

@@ -64,7 +64,7 @@ use self::storage::PersistentStore;
use self::timed_permission::TimedPermission; use self::timed_permission::TimedPermission;
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
use self::timed_permission::U2fUserPresenceState; use self::timed_permission::U2fUserPresenceState;
use crate::embedded_flash::{UpgradeLocations, UpgradeStorage}; use crate::api::upgrade_storage::UpgradeStorage;
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};
@@ -161,7 +161,7 @@ fn truncate_to_char_boundary(s: &str, mut max: usize) -> &str {
/// The upgrade hash is computed over the firmware image and all metadata, /// The upgrade hash is computed over the firmware image and all metadata,
/// except the hash itself. /// except the hash itself.
fn parse_metadata( fn parse_metadata(
upgrade_locations: &UpgradeLocations, upgrade_locations: &impl UpgradeStorage,
metadata: &[u8], metadata: &[u8],
) -> Result<[u8; 32], Ctap2StatusCode> { ) -> Result<[u8; 32], Ctap2StatusCode> {
const METADATA_LEN: usize = 40; const METADATA_LEN: usize = 40;
@@ -330,20 +330,21 @@ impl StatefulPermission {
// This struct currently holds all state, not only the persistent memory. The persistent members are // This struct currently holds all state, not only the persistent memory. The persistent members are
// in the persistent store field. // in the persistent store field.
pub struct CtapState { pub struct CtapState<E: Env> {
persistent_store: PersistentStore, persistent_store: PersistentStore<E>,
client_pin: ClientPin, client_pin: ClientPin,
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
pub(crate) u2f_up_state: U2fUserPresenceState, pub(crate) u2f_up_state: U2fUserPresenceState,
// The state initializes to Reset and its timeout, and never goes back to Reset. // The state initializes to Reset and its timeout, and never goes back to Reset.
stateful_command_permission: StatefulPermission, stateful_command_permission: StatefulPermission,
large_blobs: LargeBlobs, large_blobs: LargeBlobs,
upgrade_locations: Option<UpgradeLocations>, // Upgrade support is optional.
upgrade_locations: Option<E::UpgradeStorage>,
} }
impl CtapState { impl<E: Env> CtapState<E> {
pub fn new(env: &mut impl Env, now: ClockValue) -> CtapState { pub fn new(env: &mut E, now: ClockValue) -> Self {
let persistent_store = PersistentStore::new(env.rng()); let persistent_store = PersistentStore::new(env);
let client_pin = ClientPin::new(env.rng()); let client_pin = ClientPin::new(env.rng());
CtapState { CtapState {
persistent_store, persistent_store,
@@ -355,7 +356,7 @@ impl CtapState {
), ),
stateful_command_permission: StatefulPermission::new_reset(now), stateful_command_permission: StatefulPermission::new_reset(now),
large_blobs: LargeBlobs::new(), large_blobs: LargeBlobs::new(),
upgrade_locations: UpgradeLocations::new().ok(), upgrade_locations: env.upgrade_storage().ok(),
} }
} }
@@ -369,7 +370,7 @@ impl CtapState {
pub fn increment_global_signature_counter( pub fn increment_global_signature_counter(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
if USE_SIGNATURE_COUNTER { if USE_SIGNATURE_COUNTER {
let increment = env.rng().gen_uniform_u32x8()[0] % 8 + 1; let increment = env.rng().gen_uniform_u32x8()[0] % 8 + 1;
@@ -393,7 +394,7 @@ impl CtapState {
// compatible with U2F. // compatible with U2F.
pub fn encrypt_key_handle( pub fn encrypt_key_handle(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
private_key: crypto::ecdsa::SecKey, private_key: crypto::ecdsa::SecKey,
application: &[u8; 32], application: &[u8; 32],
) -> Result<Vec<u8>, Ctap2StatusCode> { ) -> Result<Vec<u8>, Ctap2StatusCode> {
@@ -454,7 +455,7 @@ impl CtapState {
pub fn process_command( pub fn process_command(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
command_cbor: &[u8], command_cbor: &[u8],
cid: ChannelID, cid: ChannelID,
now: ClockValue, now: ClockValue,
@@ -557,7 +558,7 @@ impl CtapState {
fn pin_uv_auth_precheck( fn pin_uv_auth_precheck(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
pin_uv_auth_param: &Option<Vec<u8>>, pin_uv_auth_param: &Option<Vec<u8>>,
pin_uv_auth_protocol: Option<PinUvAuthProtocol>, pin_uv_auth_protocol: Option<PinUvAuthProtocol>,
cid: ChannelID, cid: ChannelID,
@@ -579,7 +580,7 @@ impl CtapState {
fn process_make_credential( fn process_make_credential(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
make_credential_params: AuthenticatorMakeCredentialParameters, make_credential_params: AuthenticatorMakeCredentialParameters,
cid: ChannelID, cid: ChannelID,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
@@ -837,7 +838,7 @@ impl CtapState {
// and returns the correct Get(Next)Assertion response. // and returns the correct Get(Next)Assertion response.
fn assertion_response( fn assertion_response(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
mut credential: PublicKeyCredentialSource, mut credential: PublicKeyCredentialSource,
assertion_input: AssertionInput, assertion_input: AssertionInput,
number_of_credentials: Option<usize>, number_of_credentials: Option<usize>,
@@ -945,7 +946,7 @@ impl CtapState {
fn process_get_assertion( fn process_get_assertion(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
get_assertion_params: AuthenticatorGetAssertionParameters, get_assertion_params: AuthenticatorGetAssertionParameters,
cid: ChannelID, cid: ChannelID,
now: ClockValue, now: ClockValue,
@@ -1071,7 +1072,7 @@ impl CtapState {
fn process_get_next_assertion( fn process_get_next_assertion(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
now: ClockValue, now: ClockValue,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
self.stateful_command_permission self.stateful_command_permission
@@ -1157,7 +1158,7 @@ impl CtapState {
fn process_reset( fn process_reset(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
cid: ChannelID, cid: ChannelID,
now: ClockValue, now: ClockValue,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
@@ -1183,7 +1184,7 @@ impl CtapState {
fn process_selection( fn process_selection(
&self, &self,
env: &mut impl Env, env: &mut E,
cid: ChannelID, cid: ChannelID,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
env.user_presence().check(cid)?; env.user_presence().check(cid)?;
@@ -1192,7 +1193,7 @@ impl CtapState {
fn process_vendor_configure( fn process_vendor_configure(
&mut self, &mut self,
env: &mut impl Env, env: &mut E,
params: AuthenticatorVendorConfigureParameters, params: AuthenticatorVendorConfigureParameters,
cid: ChannelID, cid: ChannelID,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {

View File

@@ -26,7 +26,7 @@ use crate::ctap::data_formats::{
use crate::ctap::key_material; use crate::ctap::key_material;
use crate::ctap::status_code::Ctap2StatusCode; use crate::ctap::status_code::Ctap2StatusCode;
use crate::ctap::INITIAL_SIGNATURE_COUNTER; use crate::ctap::INITIAL_SIGNATURE_COUNTER;
use crate::embedded_flash::{new_storage, Storage}; use crate::env::Env;
use alloc::string::String; use alloc::string::String;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
@@ -56,22 +56,22 @@ struct PinProperties {
} }
/// CTAP persistent storage. /// CTAP persistent storage.
pub struct PersistentStore { pub struct PersistentStore<E: Env> {
store: persistent_store::Store<Storage>, store: persistent_store::Store<E::Storage>,
} }
impl PersistentStore { impl<E: Env> PersistentStore<E> {
/// Gives access to the persistent store. /// Gives access to the persistent store.
/// ///
/// # Safety /// # Safety
/// ///
/// This should be at most one instance of persistent store per program lifetime. /// This should be at most one instance of persistent store per program lifetime.
pub fn new(rng: &mut impl Rng256) -> PersistentStore { pub fn new(env: &mut E) -> Self {
let storage = new_storage().ok().unwrap(); let storage = env.storage().ok().unwrap();
let mut store = PersistentStore { let mut store = PersistentStore {
store: persistent_store::Store::new(storage).ok().unwrap(), store: persistent_store::Store::new(storage).ok().unwrap(),
}; };
store.init(rng).ok().unwrap(); store.init(env.rng()).ok().unwrap();
store store
} }
@@ -265,7 +265,7 @@ impl PersistentStore {
pub fn iter_credentials<'a>( pub fn iter_credentials<'a>(
&'a self, &'a self,
result: &'a mut Result<(), Ctap2StatusCode>, result: &'a mut Result<(), Ctap2StatusCode>,
) -> Result<IterCredentials<'a>, Ctap2StatusCode> { ) -> Result<IterCredentials<'a, E>, Ctap2StatusCode> {
IterCredentials::new(&self.store, result) IterCredentials::new(&self.store, result)
} }
@@ -655,9 +655,9 @@ impl From<persistent_store::StoreError> for Ctap2StatusCode {
} }
/// Iterator for credentials. /// Iterator for credentials.
pub struct IterCredentials<'a> { pub struct IterCredentials<'a, E: Env> {
/// The store being iterated. /// The store being iterated.
store: &'a persistent_store::Store<Storage>, store: &'a persistent_store::Store<E::Storage>,
/// The store iterator. /// The store iterator.
iter: persistent_store::StoreIter<'a>, iter: persistent_store::StoreIter<'a>,
@@ -669,12 +669,12 @@ pub struct IterCredentials<'a> {
result: &'a mut Result<(), Ctap2StatusCode>, result: &'a mut Result<(), Ctap2StatusCode>,
} }
impl<'a> IterCredentials<'a> { impl<'a, E: Env> IterCredentials<'a, E> {
/// Creates a credential iterator. /// Creates a credential iterator.
fn new( fn new(
store: &'a persistent_store::Store<Storage>, store: &'a persistent_store::Store<E::Storage>,
result: &'a mut Result<(), Ctap2StatusCode>, result: &'a mut Result<(), Ctap2StatusCode>,
) -> Result<IterCredentials<'a>, Ctap2StatusCode> { ) -> Result<Self, Ctap2StatusCode> {
let iter = store.iter()?; let iter = store.iter()?;
Ok(IterCredentials { Ok(IterCredentials {
store, store,
@@ -696,7 +696,7 @@ impl<'a> IterCredentials<'a> {
} }
} }
impl<'a> Iterator for IterCredentials<'a> { impl<'a, E: Env> Iterator for IterCredentials<'a, E> {
type Item = (usize, PublicKeyCredentialSource); type Item = (usize, PublicKeyCredentialSource);
fn next(&mut self) -> Option<(usize, PublicKeyCredentialSource)> { fn next(&mut self) -> Option<(usize, PublicKeyCredentialSource)> {
@@ -752,6 +752,7 @@ fn serialize_min_pin_length_rp_ids(rp_ids: Vec<String>) -> Result<Vec<u8>, Ctap2
mod test { mod test {
use super::*; use super::*;
use crate::ctap::data_formats::{PublicKeyCredentialSource, PublicKeyCredentialType}; use crate::ctap::data_formats::{PublicKeyCredentialSource, PublicKeyCredentialType};
use crate::env::test::TestEnv;
use crypto::rng256::{Rng256, ThreadRng256}; use crypto::rng256::{Rng256, ThreadRng256};
fn create_credential_source( fn create_credential_source(
@@ -778,24 +779,24 @@ mod test {
#[test] #[test]
fn test_store() { fn test_store() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
let credential_source = create_credential_source(&mut rng, "example.com", vec![]); let credential_source = create_credential_source(env.rng(), "example.com", vec![]);
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
assert!(persistent_store.count_credentials().unwrap() > 0); assert!(persistent_store.count_credentials().unwrap() > 0);
} }
#[test] #[test]
fn test_delete_credential() { fn test_delete_credential() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
let mut credential_ids = vec![]; let mut credential_ids = vec![];
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS { for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
let user_handle = (i as u32).to_ne_bytes().to_vec(); let user_handle = (i as u32).to_ne_bytes().to_vec();
let credential_source = create_credential_source(&mut rng, "example.com", user_handle); let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
credential_ids.push(credential_source.credential_id.clone()); credential_ids.push(credential_source.credential_id.clone());
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
assert_eq!(persistent_store.count_credentials().unwrap(), i + 1); assert_eq!(persistent_store.count_credentials().unwrap(), i + 1);
@@ -810,8 +811,8 @@ mod test {
#[test] #[test]
fn test_update_credential() { fn test_update_credential() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let user = PublicKeyCredentialUserEntity { let user = PublicKeyCredentialUserEntity {
// User ID is ignored. // User ID is ignored.
user_id: vec![0x00], user_id: vec![0x00],
@@ -824,7 +825,7 @@ mod test {
Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS) Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)
); );
let credential_source = create_credential_source(&mut rng, "example.com", vec![0x1D]); let credential_source = create_credential_source(env.rng(), "example.com", vec![0x1D]);
let credential_id = credential_source.credential_id.clone(); let credential_id = credential_source.credential_id.clone();
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
let stored_credential = persistent_store let stored_credential = persistent_store
@@ -848,12 +849,12 @@ mod test {
#[test] #[test]
fn test_credential_order() { fn test_credential_order() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let credential_source = create_credential_source(&mut rng, "example.com", vec![]); let credential_source = create_credential_source(env.rng(), "example.com", vec![]);
let current_latest_creation = credential_source.creation_order; let current_latest_creation = credential_source.creation_order;
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
let mut credential_source = create_credential_source(&mut rng, "example.com", vec![]); let mut credential_source = create_credential_source(env.rng(), "example.com", vec![]);
credential_source.creation_order = persistent_store.new_creation_order().unwrap(); credential_source.creation_order = persistent_store.new_creation_order().unwrap();
assert!(credential_source.creation_order > current_latest_creation); assert!(credential_source.creation_order > current_latest_creation);
let current_latest_creation = credential_source.creation_order; let current_latest_creation = credential_source.creation_order;
@@ -863,18 +864,18 @@ mod test {
#[test] #[test]
fn test_fill_store() { fn test_fill_store() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS { for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
let user_handle = (i as u32).to_ne_bytes().to_vec(); let user_handle = (i as u32).to_ne_bytes().to_vec();
let credential_source = create_credential_source(&mut rng, "example.com", user_handle); let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
assert_eq!(persistent_store.count_credentials().unwrap(), i + 1); assert_eq!(persistent_store.count_credentials().unwrap(), i + 1);
} }
let credential_source = create_credential_source( let credential_source = create_credential_source(
&mut rng, env.rng(),
"example.com", "example.com",
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8], vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
); );
@@ -890,12 +891,12 @@ mod test {
#[test] #[test]
fn test_overwrite() { fn test_overwrite() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
// These should have different IDs. // These should have different IDs.
let credential_source0 = create_credential_source(&mut rng, "example.com", vec![0x00]); let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
let credential_source1 = create_credential_source(&mut rng, "example.com", vec![0x00]); let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x00]);
let credential_id0 = credential_source0.credential_id.clone(); let credential_id0 = credential_source0.credential_id.clone();
let credential_id1 = credential_source1.credential_id.clone(); let credential_id1 = credential_source1.credential_id.clone();
@@ -915,15 +916,15 @@ mod test {
.unwrap() .unwrap()
.is_some()); .is_some());
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS { for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
let user_handle = (i as u32).to_ne_bytes().to_vec(); let user_handle = (i as u32).to_ne_bytes().to_vec();
let credential_source = create_credential_source(&mut rng, "example.com", user_handle); let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
assert_eq!(persistent_store.count_credentials().unwrap(), i + 1); assert_eq!(persistent_store.count_credentials().unwrap(), i + 1);
} }
let credential_source = create_credential_source( let credential_source = create_credential_source(
&mut rng, env.rng(),
"example.com", "example.com",
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8], vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
); );
@@ -939,12 +940,12 @@ mod test {
#[test] #[test]
fn test_get_credential() { fn test_get_credential() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let credential_source0 = create_credential_source(&mut rng, "example.com", vec![0x00]); let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
let credential_source1 = create_credential_source(&mut rng, "example.com", vec![0x01]); let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]);
let credential_source2 = let credential_source2 =
create_credential_source(&mut rng, "another.example.com", vec![0x02]); create_credential_source(env.rng(), "another.example.com", vec![0x02]);
let credential_sources = vec![credential_source0, credential_source1, credential_source2]; let credential_sources = vec![credential_source0, credential_source1, credential_source2];
for credential_source in credential_sources.into_iter() { for credential_source in credential_sources.into_iter() {
let cred_id = credential_source.credential_id.clone(); let cred_id = credential_source.credential_id.clone();
@@ -957,11 +958,11 @@ mod test {
#[test] #[test]
fn test_find() { fn test_find() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
let credential_source0 = create_credential_source(&mut rng, "example.com", vec![0x00]); let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
let credential_source1 = create_credential_source(&mut rng, "example.com", vec![0x01]); let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]);
let id0 = credential_source0.credential_id.clone(); let id0 = credential_source0.credential_id.clone();
let key0 = credential_source0.private_key.clone(); let key0 = credential_source0.private_key.clone();
assert!(persistent_store assert!(persistent_store
@@ -997,13 +998,13 @@ mod test {
#[test] #[test]
fn test_find_with_cred_protect() { fn test_find_with_cred_protect() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
let private_key = crypto::ecdsa::SecKey::gensk(&mut rng); let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: rng.gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key, private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x00], user_handle: vec![0x00],
@@ -1025,8 +1026,8 @@ mod test {
#[test] #[test]
fn test_master_keys() { fn test_master_keys() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// Master keys stay the same within the same CTAP reset cycle. // Master keys stay the same within the same CTAP reset cycle.
let master_keys_1 = persistent_store.master_keys().unwrap(); let master_keys_1 = persistent_store.master_keys().unwrap();
@@ -1038,7 +1039,7 @@ mod test {
// same keys. // same keys.
let master_encryption_key = master_keys_1.encryption.to_vec(); let master_encryption_key = master_keys_1.encryption.to_vec();
let master_hmac_key = master_keys_1.hmac.to_vec(); let master_hmac_key = master_keys_1.hmac.to_vec();
persistent_store.reset(&mut rng).unwrap(); persistent_store.reset(env.rng()).unwrap();
let master_keys_3 = persistent_store.master_keys().unwrap(); let master_keys_3 = persistent_store.master_keys().unwrap();
assert!(master_keys_3.encryption != master_encryption_key.as_slice()); assert!(master_keys_3.encryption != master_encryption_key.as_slice());
assert!(master_keys_3.hmac != master_hmac_key.as_slice()); assert!(master_keys_3.hmac != master_hmac_key.as_slice());
@@ -1046,8 +1047,8 @@ mod test {
#[test] #[test]
fn test_cred_random_secret() { fn test_cred_random_secret() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// CredRandom secrets stay the same within the same CTAP reset cycle. // CredRandom secrets stay the same within the same CTAP reset cycle.
let cred_random_with_uv_1 = persistent_store.cred_random_secret(true).unwrap(); let cred_random_with_uv_1 = persistent_store.cred_random_secret(true).unwrap();
@@ -1059,7 +1060,7 @@ mod test {
// CredRandom secrets change after reset. This test may fail if the random generator produces the // CredRandom secrets change after reset. This test may fail if the random generator produces the
// same keys. // same keys.
persistent_store.reset(&mut rng).unwrap(); persistent_store.reset(env.rng()).unwrap();
let cred_random_with_uv_3 = persistent_store.cred_random_secret(true).unwrap(); let cred_random_with_uv_3 = persistent_store.cred_random_secret(true).unwrap();
let cred_random_without_uv_3 = persistent_store.cred_random_secret(false).unwrap(); let cred_random_without_uv_3 = persistent_store.cred_random_secret(false).unwrap();
assert!(cred_random_with_uv_1 != cred_random_with_uv_3); assert!(cred_random_with_uv_1 != cred_random_with_uv_3);
@@ -1068,15 +1069,15 @@ mod test {
#[test] #[test]
fn test_pin_hash_and_length() { fn test_pin_hash_and_length() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// Pin hash is initially not set. // Pin hash is initially not set.
assert!(persistent_store.pin_hash().unwrap().is_none()); assert!(persistent_store.pin_hash().unwrap().is_none());
assert!(persistent_store.pin_code_point_length().unwrap().is_none()); assert!(persistent_store.pin_code_point_length().unwrap().is_none());
// Setting the pin sets the pin hash. // Setting the pin sets the pin hash.
let random_data = rng.gen_uniform_u8x32(); let random_data = env.rng().gen_uniform_u8x32();
assert_eq!(random_data.len(), 2 * PIN_AUTH_LENGTH); assert_eq!(random_data.len(), 2 * PIN_AUTH_LENGTH);
let pin_hash_1 = *array_ref!(random_data, 0, PIN_AUTH_LENGTH); let pin_hash_1 = *array_ref!(random_data, 0, PIN_AUTH_LENGTH);
let pin_hash_2 = *array_ref!(random_data, PIN_AUTH_LENGTH, PIN_AUTH_LENGTH); let pin_hash_2 = *array_ref!(random_data, PIN_AUTH_LENGTH, PIN_AUTH_LENGTH);
@@ -1096,15 +1097,15 @@ mod test {
); );
// Resetting the storage resets the pin hash. // Resetting the storage resets the pin hash.
persistent_store.reset(&mut rng).unwrap(); persistent_store.reset(env.rng()).unwrap();
assert!(persistent_store.pin_hash().unwrap().is_none()); assert!(persistent_store.pin_hash().unwrap().is_none());
assert!(persistent_store.pin_code_point_length().unwrap().is_none()); assert!(persistent_store.pin_code_point_length().unwrap().is_none());
} }
#[test] #[test]
fn test_pin_retries() { fn test_pin_retries() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// The pin retries is initially at the maximum. // The pin retries is initially at the maximum.
assert_eq!(persistent_store.pin_retries(), Ok(MAX_PIN_RETRIES)); assert_eq!(persistent_store.pin_retries(), Ok(MAX_PIN_RETRIES));
@@ -1126,8 +1127,8 @@ mod test {
#[test] #[test]
fn test_persistent_keys() { fn test_persistent_keys() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// Make sure the attestation are absent. There is no batch attestation in tests. // Make sure the attestation are absent. There is no batch attestation in tests.
assert!(persistent_store assert!(persistent_store
@@ -1151,7 +1152,7 @@ mod test {
assert_eq!(&persistent_store.aaguid().unwrap(), key_material::AAGUID); assert_eq!(&persistent_store.aaguid().unwrap(), key_material::AAGUID);
// The persistent keys stay initialized and preserve their value after a reset. // The persistent keys stay initialized and preserve their value after a reset.
persistent_store.reset(&mut rng).unwrap(); persistent_store.reset(env.rng()).unwrap();
assert_eq!( assert_eq!(
&persistent_store.attestation_private_key().unwrap().unwrap(), &persistent_store.attestation_private_key().unwrap().unwrap(),
&dummy_key &dummy_key
@@ -1165,8 +1166,8 @@ mod test {
#[test] #[test]
fn test_min_pin_length() { fn test_min_pin_length() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// The minimum PIN length is initially at the default. // The minimum PIN length is initially at the default.
assert_eq!( assert_eq!(
@@ -1187,8 +1188,8 @@ mod test {
#[test] #[test]
fn test_min_pin_length_rp_ids() { fn test_min_pin_length_rp_ids() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
// The minimum PIN length RP IDs are initially at the default. // The minimum PIN length RP IDs are initially at the default.
assert_eq!( assert_eq!(
@@ -1213,8 +1214,8 @@ mod test {
#[test] #[test]
fn test_max_large_blob_array_size() { fn test_max_large_blob_array_size() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let persistent_store = PersistentStore::new(&mut rng); let persistent_store = PersistentStore::new(&mut env);
assert!( assert!(
MAX_LARGE_BLOB_ARRAY_SIZE MAX_LARGE_BLOB_ARRAY_SIZE
@@ -1225,8 +1226,8 @@ mod test {
#[test] #[test]
fn test_commit_get_large_blob_array() { fn test_commit_get_large_blob_array() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let large_blob_array = vec![0x01, 0x02, 0x03]; let large_blob_array = vec![0x01, 0x02, 0x03];
assert!(persistent_store assert!(persistent_store
@@ -1248,8 +1249,8 @@ mod test {
#[test] #[test]
fn test_commit_get_large_blob_array_overwrite() { fn test_commit_get_large_blob_array_overwrite() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let large_blob_array = vec![0x11; 5]; let large_blob_array = vec![0x11; 5];
assert!(persistent_store assert!(persistent_store
@@ -1272,8 +1273,8 @@ mod test {
#[test] #[test]
fn test_commit_get_large_blob_array_no_commit() { fn test_commit_get_large_blob_array_no_commit() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let persistent_store = PersistentStore::new(&mut rng); let persistent_store = PersistentStore::new(&mut env);
let empty_blob_array = vec![ let empty_blob_array = vec![
0x80, 0x76, 0xBE, 0x8B, 0x52, 0x8D, 0x00, 0x75, 0xF7, 0xAA, 0xE9, 0x8D, 0x6F, 0xA5, 0x80, 0x76, 0xBE, 0x8B, 0x52, 0x8D, 0x00, 0x75, 0xF7, 0xAA, 0xE9, 0x8D, 0x6F, 0xA5,
@@ -1289,8 +1290,8 @@ mod test {
#[test] #[test]
fn test_global_signature_counter() { fn test_global_signature_counter() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
let mut counter_value = 1; let mut counter_value = 1;
assert_eq!( assert_eq!(
@@ -1311,8 +1312,8 @@ mod test {
#[test] #[test]
fn test_force_pin_change() { fn test_force_pin_change() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert!(!persistent_store.has_force_pin_change().unwrap()); assert!(!persistent_store.has_force_pin_change().unwrap());
assert_eq!(persistent_store.force_pin_change(), Ok(())); assert_eq!(persistent_store.force_pin_change(), Ok(()));
@@ -1323,20 +1324,20 @@ mod test {
#[test] #[test]
fn test_enterprise_attestation() { fn test_enterprise_attestation() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
assert!(!persistent_store.enterprise_attestation().unwrap()); assert!(!persistent_store.enterprise_attestation().unwrap());
assert_eq!(persistent_store.enable_enterprise_attestation(), Ok(())); assert_eq!(persistent_store.enable_enterprise_attestation(), Ok(()));
assert!(persistent_store.enterprise_attestation().unwrap()); assert!(persistent_store.enterprise_attestation().unwrap());
persistent_store.reset(&mut rng).unwrap(); persistent_store.reset(env.rng()).unwrap();
assert!(!persistent_store.enterprise_attestation().unwrap()); assert!(!persistent_store.enterprise_attestation().unwrap());
} }
#[test] #[test]
fn test_always_uv() { fn test_always_uv() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut env);
if ENFORCE_ALWAYS_UV { if ENFORCE_ALWAYS_UV {
assert!(persistent_store.has_always_uv().unwrap()); assert!(persistent_store.has_always_uv().unwrap());
@@ -1355,11 +1356,11 @@ mod test {
#[test] #[test]
fn test_serialize_deserialize_credential() { fn test_serialize_deserialize_credential() {
let mut rng = ThreadRng256 {}; let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(&mut rng); let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
let credential = PublicKeyCredentialSource { let credential = PublicKeyCredentialSource {
key_type: PublicKeyCredentialType::PublicKey, key_type: PublicKeyCredentialType::PublicKey,
credential_id: rng.gen_uniform_u8x32().to_vec(), credential_id: env.rng().gen_uniform_u8x32().to_vec(),
private_key, private_key,
rp_id: String::from("example.com"), rp_id: String::from("example.com"),
user_handle: vec![0x00], user_handle: vec![0x00],

View File

@@ -1,65 +0,0 @@
// Copyright 2019-2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(feature = "std")]
mod buffer_upgrade;
mod helper;
#[cfg(not(feature = "std"))]
mod syscall;
mod upgrade_storage;
pub use upgrade_storage::UpgradeStorage;
/// Definitions for production.
#[cfg(not(feature = "std"))]
mod prod {
use super::syscall::{SyscallStorage, SyscallUpgradeStorage};
pub type Storage = SyscallStorage;
pub fn new_storage() -> persistent_store::StorageResult<Storage> {
Storage::new()
}
pub type UpgradeLocations = SyscallUpgradeStorage;
}
#[cfg(not(feature = "std"))]
pub use self::prod::{new_storage, Storage, UpgradeLocations};
/// Definitions for testing.
#[cfg(feature = "std")]
mod test {
use super::buffer_upgrade::BufferUpgradeStorage;
pub type Storage = persistent_store::BufferStorage;
pub fn new_storage() -> persistent_store::StorageResult<Storage> {
// Use the Nordic configuration.
const PAGE_SIZE: usize = 0x1000;
const NUM_PAGES: usize = 20;
let store = vec![0xff; NUM_PAGES * PAGE_SIZE].into_boxed_slice();
let options = persistent_store::BufferOptions {
word_size: 4,
page_size: PAGE_SIZE,
max_word_writes: 2,
max_page_erases: 10000,
strict_mode: true,
};
Ok(Storage::new(store, options))
}
pub type UpgradeLocations = BufferUpgradeStorage;
}
#[cfg(feature = "std")]
pub use self::test::{new_storage, Storage, UpgradeLocations};

14
src/env/mod.rs vendored
View File

@@ -1,6 +1,8 @@
use crate::api::upgrade_storage::UpgradeStorage;
use crate::ctap::hid::ChannelID; use crate::ctap::hid::ChannelID;
use crate::ctap::status_code::Ctap2StatusCode; use crate::ctap::status_code::Ctap2StatusCode;
use crypto::rng256::Rng256; use crypto::rng256::Rng256;
use persistent_store::{Storage, StorageResult};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod test; pub mod test;
@@ -17,7 +19,19 @@ pub trait UserPresence {
pub trait Env { pub trait Env {
type Rng: Rng256; type Rng: Rng256;
type UserPresence: UserPresence; type UserPresence: UserPresence;
type Storage: Storage;
type UpgradeStorage: UpgradeStorage;
fn rng(&mut self) -> &mut Self::Rng; fn rng(&mut self) -> &mut Self::Rng;
fn user_presence(&mut self) -> &mut Self::UserPresence; fn user_presence(&mut self) -> &mut Self::UserPresence;
/// Returns the unique storage instance.
///
/// This function is called at most once. Implementation may panic if called more than once.
fn storage(&mut self) -> StorageResult<Self::Storage>;
/// Returns the unique upgrade storage instance.
///
/// This function is called at most once. Implementation may panic if called more than once.
fn upgrade_storage(&mut self) -> StorageResult<Self::UpgradeStorage>;
} }

View File

@@ -1,7 +1,11 @@
use self::upgrade_storage::BufferUpgradeStorage;
use crate::ctap::hid::ChannelID; use crate::ctap::hid::ChannelID;
use crate::ctap::status_code::Ctap2StatusCode; use crate::ctap::status_code::Ctap2StatusCode;
use crate::env::{Env, UserPresence}; use crate::env::{Env, UserPresence};
use crypto::rng256::ThreadRng256; use crypto::rng256::ThreadRng256;
use persistent_store::{BufferOptions, BufferStorage, StorageResult};
mod upgrade_storage;
pub struct TestEnv { pub struct TestEnv {
rng: ThreadRng256, rng: ThreadRng256,
@@ -37,6 +41,8 @@ impl UserPresence for TestUserPresence {
impl Env for TestEnv { impl Env for TestEnv {
type Rng = ThreadRng256; type Rng = ThreadRng256;
type UserPresence = TestUserPresence; type UserPresence = TestUserPresence;
type Storage = BufferStorage;
type UpgradeStorage = BufferUpgradeStorage;
fn rng(&mut self) -> &mut Self::Rng { fn rng(&mut self) -> &mut Self::Rng {
&mut self.rng &mut self.rng
@@ -45,4 +51,23 @@ impl Env for TestEnv {
fn user_presence(&mut self) -> &mut Self::UserPresence { fn user_presence(&mut self) -> &mut Self::UserPresence {
&mut self.user_presence &mut self.user_presence
} }
fn storage(&mut self) -> StorageResult<Self::Storage> {
// Use the Nordic configuration.
const PAGE_SIZE: usize = 0x1000;
const NUM_PAGES: usize = 20;
let store = vec![0xff; NUM_PAGES * PAGE_SIZE].into_boxed_slice();
let options = BufferOptions {
word_size: 4,
page_size: PAGE_SIZE,
max_word_writes: 2,
max_page_erases: 10000,
strict_mode: true,
};
Ok(BufferStorage::new(store, options))
}
fn upgrade_storage(&mut self) -> StorageResult<Self::UpgradeStorage> {
BufferUpgradeStorage::new()
}
} }

View File

@@ -12,8 +12,8 @@
// 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::helper::ModRange; use crate::api::upgrade_storage::helper::ModRange;
use super::upgrade_storage::UpgradeStorage; use crate::api::upgrade_storage::UpgradeStorage;
use alloc::boxed::Box; use alloc::boxed::Box;
use persistent_store::{StorageError, StorageResult}; use persistent_store::{StorageError, StorageResult};

View File

@@ -1,9 +1,11 @@
use self::storage::{SyscallStorage, SyscallUpgradeStorage};
use crate::ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket}; use crate::ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket};
use crate::ctap::status_code::Ctap2StatusCode; use crate::ctap::status_code::Ctap2StatusCode;
use crate::env::{Env, UserPresence}; use crate::env::{Env, UserPresence};
use core::cell::Cell; use core::cell::Cell;
#[cfg(feature = "debug_ctap")] #[cfg(feature = "debug_ctap")]
use core::fmt::Write; use core::fmt::Write;
use core::sync::atomic::{AtomicBool, Ordering};
use crypto::rng256::TockRng256; use crypto::rng256::TockRng256;
use libtock_core::result::{CommandError, EALREADY}; use libtock_core::result::{CommandError, EALREADY};
use libtock_drivers::buttons::{self, ButtonState}; use libtock_drivers::buttons::{self, ButtonState};
@@ -12,18 +14,48 @@ use libtock_drivers::console::Console;
use libtock_drivers::result::{FlexUnwrap, TockError}; use libtock_drivers::result::{FlexUnwrap, TockError};
use libtock_drivers::timer::Duration; use libtock_drivers::timer::Duration;
use libtock_drivers::{led, timer, usb_ctap_hid}; use libtock_drivers::{led, timer, usb_ctap_hid};
use persistent_store::StorageResult;
mod storage;
pub struct TockEnv { pub struct TockEnv {
rng: TockRng256, rng: TockRng256,
storage: bool,
upgrade_storage: bool,
} }
impl TockEnv { impl TockEnv {
pub fn new() -> Self { /// Returns the unique instance of the Tock environment.
let rng = TockRng256 {}; ///
TockEnv { rng } /// This function returns `Some` the first time it is called. Afterwards, it repeatedly returns
/// `None`.
pub fn new() -> Option<Self> {
// Make sure the environment was not already taken.
static TAKEN: AtomicBool = AtomicBool::new(false);
if TAKEN.fetch_or(true, Ordering::SeqCst) {
return None;
}
Some(TockEnv {
rng: TockRng256 {},
storage: false,
upgrade_storage: false,
})
} }
} }
/// Creates a new storage instance.
///
/// # Safety
///
/// It is probably technically memory-safe to hame multiple storage instances at the same time, but
/// for extra precaution we mark the function as unsafe. To ensure correct usage, this function
/// should only be called if the previous storage instance was dropped.
// This function is exposed for example binaries testing the hardware. This could probably be
// cleaned up by having the persistent store return its storage.
pub unsafe fn steal_storage() -> StorageResult<SyscallStorage> {
SyscallStorage::new()
}
impl UserPresence for TockEnv { impl UserPresence for TockEnv {
fn check(&self, cid: ChannelID) -> Result<(), Ctap2StatusCode> { fn check(&self, cid: ChannelID) -> Result<(), Ctap2StatusCode> {
check_user_presence(cid) check_user_presence(cid)
@@ -33,6 +65,8 @@ impl UserPresence for TockEnv {
impl Env for TockEnv { impl Env for TockEnv {
type Rng = TockRng256; type Rng = TockRng256;
type UserPresence = Self; type UserPresence = Self;
type Storage = SyscallStorage;
type UpgradeStorage = SyscallUpgradeStorage;
fn rng(&mut self) -> &mut Self::Rng { fn rng(&mut self) -> &mut Self::Rng {
&mut self.rng &mut self.rng
@@ -41,6 +75,18 @@ impl Env for TockEnv {
fn user_presence(&mut self) -> &mut Self::UserPresence { fn user_presence(&mut self) -> &mut Self::UserPresence {
self self
} }
fn storage(&mut self) -> StorageResult<Self::Storage> {
assert!(!self.storage);
self.storage = true;
unsafe { steal_storage() }
}
fn upgrade_storage(&mut self) -> StorageResult<Self::UpgradeStorage> {
assert!(!self.upgrade_storage);
self.upgrade_storage = true;
SyscallUpgradeStorage::new()
}
} }
// Returns whether the keepalive was sent, or false if cancelled. // Returns whether the keepalive was sent, or false if cancelled.

View File

@@ -12,8 +12,8 @@
// 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::helper::{find_slice, is_aligned, ModRange}; use crate::api::upgrade_storage::helper::{find_slice, is_aligned, ModRange};
use super::upgrade_storage::UpgradeStorage; use crate::api::upgrade_storage::UpgradeStorage;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cell::Cell; use core::cell::Cell;
use libtock_core::{callback, syscalls}; use libtock_core::{callback, syscalls};

View File

@@ -24,19 +24,18 @@ use crate::ctap::CtapState;
use crate::env::Env; use crate::env::Env;
use libtock_drivers::timer::ClockValue; use libtock_drivers::timer::ClockValue;
pub mod api;
// 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;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
mod ctap; mod ctap;
// Store example binaries use the flash directly. Eventually, they should access it from env::tock.
pub mod embedded_flash;
pub mod env; pub mod env;
/// CTAP implementation parameterized by its environment. /// CTAP implementation parameterized by its environment.
pub struct Ctap<E: Env> { pub struct Ctap<E: Env> {
env: E, env: E,
state: CtapState, state: CtapState<E>,
hid: CtapHid, hid: CtapHid,
} }
@@ -50,7 +49,7 @@ impl<E: Env> Ctap<E> {
Ctap { env, state, hid } Ctap { env, state, hid }
} }
pub fn state(&mut self) -> &mut CtapState { pub fn state(&mut self) -> &mut CtapState<E> {
&mut self.state &mut self.state
} }

View File

@@ -57,7 +57,7 @@ fn main() {
} }
let boot_time = timer.get_current_clock().flex_unwrap(); let boot_time = timer.get_current_clock().flex_unwrap();
let env = TockEnv::new(); let env = TockEnv::new().unwrap();
let mut ctap = ctap2::Ctap::new(env, boot_time); let mut ctap = ctap2::Ctap::new(env, boot_time);
let mut led_counter = 0; let mut led_counter = 0;