Add Storage and UpgradeStorage to Env
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
extern crate lang_items;
|
||||
|
||||
use core::fmt::Write;
|
||||
use ctap2::embedded_flash::new_storage;
|
||||
use ctap2::env::tock::steal_storage;
|
||||
use libtock_drivers::console::Console;
|
||||
use libtock_drivers::led;
|
||||
use libtock_drivers::result::FlexUnwrap;
|
||||
@@ -37,7 +37,7 @@ fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
|
||||
|
||||
fn main() {
|
||||
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();
|
||||
writeln!(Console::new(), "Erase {} pages of storage:", num_pages).unwrap();
|
||||
for page in 0..num_pages {
|
||||
|
||||
@@ -21,7 +21,8 @@ use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{format, vec};
|
||||
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::timer::{self, Duration, Timer, Timestamp};
|
||||
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.
|
||||
unsafe fn boot_store(erase: bool) -> Store<Storage> {
|
||||
unsafe fn boot_store(erase: bool) -> Store<<TockEnv as Env>::Storage> {
|
||||
use persistent_store::Storage;
|
||||
let mut storage = new_storage().unwrap();
|
||||
let mut storage = steal_storage().unwrap();
|
||||
let num_pages = storage.num_pages();
|
||||
if erase {
|
||||
for page in 0..num_pages {
|
||||
@@ -59,7 +60,7 @@ struct StorageConfig {
|
||||
|
||||
fn storage_config() -> StorageConfig {
|
||||
use persistent_store::Storage;
|
||||
let storage = new_storage().unwrap();
|
||||
let storage = unsafe { steal_storage() }.unwrap();
|
||||
StorageConfig {
|
||||
num_pages: storage.num_pages(),
|
||||
}
|
||||
|
||||
6
src/api/mod.rs
Normal file
6
src/api/mod.rs
Normal 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;
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
use persistent_store::StorageResult;
|
||||
|
||||
pub(crate) mod helper;
|
||||
|
||||
/// Accessors to storage locations used for upgrading from a CTAP command.
|
||||
pub trait UpgradeStorage {
|
||||
/// Reads a slice of the partition, if within bounds.
|
||||
@@ -21,6 +21,7 @@ use super::response::{AuthenticatorClientPinResponse, ResponseData};
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::storage::PersistentStore;
|
||||
use super::token_state::PinUvAuthTokenState;
|
||||
use crate::env::Env;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::str;
|
||||
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
|
||||
/// padding. Next, it is checked against the PIN policy. Last, it is hashed and
|
||||
/// truncated for persistent storage.
|
||||
fn check_and_store_new_pin(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn check_and_store_new_pin<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
shared_secret: &dyn SharedSecret,
|
||||
new_pin_enc: Vec<u8>,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
@@ -155,10 +156,10 @@ impl ClientPin {
|
||||
/// Decrypts the encrypted pin_hash and compares it to the stored pin_hash.
|
||||
/// Resets or decreases the PIN retries, depending on success or failure.
|
||||
/// 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,
|
||||
rng: &mut impl Rng256,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||
shared_secret: &dyn SharedSecret,
|
||||
pin_hash_enc: Vec<u8>,
|
||||
@@ -194,9 +195,9 @@ impl ClientPin {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_get_pin_retries(
|
||||
fn process_get_pin_retries<E: Env>(
|
||||
&self,
|
||||
persistent_store: &PersistentStore,
|
||||
persistent_store: &PersistentStore<E>,
|
||||
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
Ok(AuthenticatorClientPinResponse {
|
||||
key_agreement: None,
|
||||
@@ -222,9 +223,9 @@ impl ClientPin {
|
||||
})
|
||||
}
|
||||
|
||||
fn process_set_pin(
|
||||
fn process_set_pin<E: Env>(
|
||||
&mut self,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin_params: AuthenticatorClientPinParameters,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
let AuthenticatorClientPinParameters {
|
||||
@@ -249,10 +250,10 @@ impl ClientPin {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_change_pin(
|
||||
fn process_change_pin<E: Env>(
|
||||
&mut self,
|
||||
rng: &mut impl Rng256,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin_params: AuthenticatorClientPinParameters,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
let AuthenticatorClientPinParameters {
|
||||
@@ -289,10 +290,10 @@ impl ClientPin {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_get_pin_token(
|
||||
fn process_get_pin_token<E: Env>(
|
||||
&mut self,
|
||||
rng: &mut impl Rng256,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin_params: AuthenticatorClientPinParameters,
|
||||
now: ClockValue,
|
||||
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
@@ -359,10 +360,10 @@ impl ClientPin {
|
||||
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,
|
||||
rng: &mut impl Rng256,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
mut client_pin_params: AuthenticatorClientPinParameters,
|
||||
now: ClockValue,
|
||||
) -> Result<AuthenticatorClientPinResponse, Ctap2StatusCode> {
|
||||
@@ -389,10 +390,10 @@ impl ClientPin {
|
||||
}
|
||||
|
||||
/// Processes the authenticatorClientPin command.
|
||||
pub fn process_command(
|
||||
pub fn process_command<E: Env>(
|
||||
&mut self,
|
||||
rng: &mut impl Rng256,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin_params: AuthenticatorClientPinParameters,
|
||||
now: ClockValue,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
@@ -570,11 +571,10 @@ impl ClientPin {
|
||||
pin_uv_auth_token: [u8; PIN_TOKEN_LENGTH],
|
||||
pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||
) -> ClientPin {
|
||||
use crypto::rng256::ThreadRng256;
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut env = crate::env::test::TestEnv::new();
|
||||
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::V2 => (crypto::ecdh::SecKey::gensk(&mut rng), key_agreement_key),
|
||||
PinUvAuthProtocol::V1 => (key_agreement_key, crypto::ecdh::SecKey::gensk(env.rng())),
|
||||
PinUvAuthProtocol::V2 => (crypto::ecdh::SecKey::gensk(env.rng()), key_agreement_key),
|
||||
};
|
||||
let mut pin_uv_auth_token_state = PinUvAuthTokenState::new();
|
||||
pin_uv_auth_token_state.set_permissions(0xFF);
|
||||
@@ -594,15 +594,15 @@ impl ClientPin {
|
||||
mod test {
|
||||
use super::super::pin_protocol::authenticate_pin_uv_auth_token;
|
||||
use super::*;
|
||||
use crate::env::test::TestEnv;
|
||||
use alloc::vec;
|
||||
use crypto::rng256::ThreadRng256;
|
||||
use libtock_drivers::timer::Duration;
|
||||
|
||||
const CLOCK_FREQUENCY_HZ: usize = 32768;
|
||||
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
|
||||
|
||||
/// Stores a PIN hash corresponding to the dummy PIN "1234".
|
||||
fn set_standard_pin(persistent_store: &mut PersistentStore) {
|
||||
fn set_standard_pin<E: Env>(persistent_store: &mut PersistentStore<E>) {
|
||||
let mut pin = [0u8; 64];
|
||||
pin[..4].copy_from_slice(b"1234");
|
||||
let mut pin_hash = [0u8; 16];
|
||||
@@ -613,10 +613,10 @@ mod test {
|
||||
/// Fails on PINs bigger than 64 bytes.
|
||||
fn encrypt_pin(shared_secret: &dyn SharedSecret, pin: Vec<u8>) -> Vec<u8> {
|
||||
assert!(pin.len() <= 64);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut env = TestEnv::new();
|
||||
let mut padded_pin = [0u8; 64];
|
||||
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.
|
||||
@@ -628,8 +628,8 @@ mod test {
|
||||
fn create_client_pin_and_shared_secret(
|
||||
pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||
) -> (ClientPin, Box<dyn SharedSecret>) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pk = key_agreement_key.genpk();
|
||||
let key_agreement = CoseKey::from(pk);
|
||||
let pin_uv_auth_token = [0x91; PIN_TOKEN_LENGTH];
|
||||
@@ -649,7 +649,7 @@ mod test {
|
||||
pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||
sub_command: ClientPinSubCommand,
|
||||
) -> (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 pin = b"1234";
|
||||
@@ -658,12 +658,12 @@ mod test {
|
||||
let pin_hash = Sha256::hash(&padded_pin);
|
||||
let new_pin_enc = shared_secret
|
||||
.as_ref()
|
||||
.encrypt(&mut rng, &padded_pin)
|
||||
.encrypt(env.rng(), &padded_pin)
|
||||
.unwrap();
|
||||
let pin_uv_auth_param = shared_secret.as_ref().authenticate(&new_pin_enc);
|
||||
let pin_hash_enc = shared_secret
|
||||
.as_ref()
|
||||
.encrypt(&mut rng, &pin_hash[..16])
|
||||
.encrypt(env.rng(), &pin_hash[..16])
|
||||
.unwrap();
|
||||
let (permissions, permissions_rp_id) = match sub_command {
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions
|
||||
@@ -691,8 +691,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_mix_pin_protocols() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let client_pin = ClientPin::new(env.rng());
|
||||
let pin_protocol_v1 = client_pin.get_pin_protocol(PinUvAuthProtocol::V1);
|
||||
let pin_protocol_v2 = client_pin.get_pin_protocol(PinUvAuthProtocol::V2);
|
||||
let message = vec![0xAA; 16];
|
||||
@@ -703,38 +703,38 @@ mod test {
|
||||
let shared_secret_v2 = pin_protocol_v2
|
||||
.decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V2)
|
||||
.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();
|
||||
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();
|
||||
assert_ne!(&message, &plaintext);
|
||||
|
||||
let fake_secret_v1 = pin_protocol_v1
|
||||
.decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V1)
|
||||
.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();
|
||||
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();
|
||||
assert_ne!(&message, &plaintext);
|
||||
|
||||
let fake_secret_v2 = pin_protocol_v2
|
||||
.decapsulate(pin_protocol_v1.get_public_key(), PinUvAuthProtocol::V2)
|
||||
.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();
|
||||
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();
|
||||
assert_ne!(&message, &plaintext);
|
||||
}
|
||||
|
||||
fn test_helper_verify_pin_hash_enc(pin_uv_auth_protocol: PinUvAuthProtocol) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
let pin_protocol = client_pin.get_pin_protocol(pin_uv_auth_protocol);
|
||||
let shared_secret = pin_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();
|
||||
|
||||
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!(
|
||||
client_pin.verify_pin_hash_enc(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
pin_uv_auth_protocol,
|
||||
shared_secret.as_ref(),
|
||||
@@ -761,7 +764,7 @@ mod test {
|
||||
let pin_hash_enc = vec![0xEE; 16];
|
||||
assert_eq!(
|
||||
client_pin.verify_pin_hash_enc(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
pin_uv_auth_protocol,
|
||||
shared_secret.as_ref(),
|
||||
@@ -770,11 +773,14 @@ mod test {
|
||||
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;
|
||||
assert_eq!(
|
||||
client_pin.verify_pin_hash_enc(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
pin_uv_auth_protocol,
|
||||
shared_secret.as_ref(),
|
||||
@@ -787,7 +793,7 @@ mod test {
|
||||
let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH - 1];
|
||||
assert_eq!(
|
||||
client_pin.verify_pin_hash_enc(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
pin_uv_auth_protocol,
|
||||
shared_secret.as_ref(),
|
||||
@@ -799,7 +805,7 @@ mod test {
|
||||
let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH + 1];
|
||||
assert_eq!(
|
||||
client_pin.verify_pin_hash_enc(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
pin_uv_auth_protocol,
|
||||
shared_secret.as_ref(),
|
||||
@@ -824,8 +830,8 @@ mod test {
|
||||
pin_uv_auth_protocol,
|
||||
ClientPinSubCommand::GetPinRetries,
|
||||
);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let expected_response = Some(AuthenticatorClientPinResponse {
|
||||
key_agreement: None,
|
||||
pin_uv_auth_token: None,
|
||||
@@ -834,7 +840,7 @@ mod test {
|
||||
});
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
params.clone(),
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -850,7 +856,7 @@ mod test {
|
||||
power_cycle_state: Some(true),
|
||||
});
|
||||
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))
|
||||
);
|
||||
}
|
||||
@@ -870,8 +876,8 @@ mod test {
|
||||
pin_uv_auth_protocol,
|
||||
ClientPinSubCommand::GetKeyAgreement,
|
||||
);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let expected_response = Some(AuthenticatorClientPinResponse {
|
||||
key_agreement: params.key_agreement.clone(),
|
||||
pin_uv_auth_token: None,
|
||||
@@ -879,7 +885,7 @@ mod test {
|
||||
power_cycle_state: None,
|
||||
});
|
||||
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))
|
||||
);
|
||||
}
|
||||
@@ -897,10 +903,10 @@ mod test {
|
||||
fn test_helper_process_set_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
|
||||
let (mut client_pin, params) =
|
||||
create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::SetPin);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
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))
|
||||
);
|
||||
}
|
||||
@@ -925,8 +931,8 @@ mod test {
|
||||
params.pin_uv_auth_protocol,
|
||||
)
|
||||
.unwrap();
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
|
||||
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);
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
params.clone(),
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -947,7 +953,7 @@ mod test {
|
||||
bad_params.pin_hash_enc = Some(vec![0xEE; 16]);
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
bad_params,
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -959,7 +965,7 @@ mod test {
|
||||
persistent_store.decr_pin_retries().unwrap();
|
||||
}
|
||||
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)
|
||||
);
|
||||
}
|
||||
@@ -986,13 +992,13 @@ mod test {
|
||||
params.pin_uv_auth_protocol,
|
||||
)
|
||||
.unwrap();
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
|
||||
let response = client_pin
|
||||
.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
params.clone(),
|
||||
DUMMY_CLOCK_VALUE,
|
||||
@@ -1033,7 +1039,7 @@ mod test {
|
||||
bad_params.pin_hash_enc = Some(vec![0xEE; 16]);
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
bad_params,
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -1057,13 +1063,13 @@ mod test {
|
||||
pin_uv_auth_protocol,
|
||||
ClientPinSubCommand::GetPinToken,
|
||||
);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
|
||||
assert_eq!(persistent_store.force_pin_change(), Ok(()));
|
||||
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),
|
||||
);
|
||||
}
|
||||
@@ -1092,13 +1098,13 @@ mod test {
|
||||
params.pin_uv_auth_protocol,
|
||||
)
|
||||
.unwrap();
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
|
||||
let response = client_pin
|
||||
.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
params.clone(),
|
||||
DUMMY_CLOCK_VALUE,
|
||||
@@ -1139,7 +1145,7 @@ mod test {
|
||||
bad_params.permissions = Some(0x00);
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
bad_params,
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -1151,7 +1157,7 @@ mod test {
|
||||
bad_params.permissions_rp_id = None;
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
bad_params,
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -1163,7 +1169,7 @@ mod test {
|
||||
bad_params.pin_hash_enc = Some(vec![0xEE; 16]);
|
||||
assert_eq!(
|
||||
client_pin.process_command(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
&mut persistent_store,
|
||||
bad_params,
|
||||
DUMMY_CLOCK_VALUE
|
||||
@@ -1189,13 +1195,13 @@ mod test {
|
||||
pin_uv_auth_protocol,
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
|
||||
);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
|
||||
assert_eq!(persistent_store.force_pin_change(), Ok(()));
|
||||
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)
|
||||
);
|
||||
}
|
||||
@@ -1215,8 +1221,8 @@ mod test {
|
||||
}
|
||||
|
||||
fn test_helper_decrypt_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let pin_protocol = PinProtocol::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let pin_protocol = PinProtocol::new(env.rng());
|
||||
let shared_secret = pin_protocol
|
||||
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
|
||||
.unwrap();
|
||||
@@ -1259,9 +1265,9 @@ mod test {
|
||||
}
|
||||
|
||||
fn test_helper_check_and_store_new_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let pin_protocol = PinProtocol::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let pin_protocol = PinProtocol::new(env.rng());
|
||||
let shared_secret = pin_protocol
|
||||
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
|
||||
.unwrap();
|
||||
@@ -1317,10 +1323,10 @@ mod test {
|
||||
cred_random: &[u8; 32],
|
||||
salt: Vec<u8>,
|
||||
) -> 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 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 hmac_secret_input = GetAssertionHmacSecretInput {
|
||||
key_agreement: client_pin
|
||||
@@ -1330,12 +1336,12 @@ mod test {
|
||||
salt_auth,
|
||||
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())
|
||||
}
|
||||
|
||||
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 cred_random = [0xC9; 32];
|
||||
|
||||
@@ -1350,7 +1356,7 @@ mod test {
|
||||
salt_auth,
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1451,8 +1457,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_has_permission() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
client_pin.pin_uv_auth_token_state.set_permissions(0x7F);
|
||||
for permission in PinPermission::into_enum_iter() {
|
||||
assert_eq!(
|
||||
@@ -1475,8 +1481,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_has_no_rp_id_permission() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
assert_eq!(client_pin.has_no_rp_id_permission(), Ok(()));
|
||||
client_pin
|
||||
.pin_uv_auth_token_state
|
||||
@@ -1489,8 +1495,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_has_no_or_rp_id_permission() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
assert_eq!(client_pin.has_no_or_rp_id_permission("example.com"), Ok(()));
|
||||
client_pin
|
||||
.pin_uv_auth_token_state
|
||||
@@ -1504,8 +1510,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_has_no_or_rp_id_hash_permission() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
let rp_id_hash = Sha256::hash(b"example.com");
|
||||
assert_eq!(
|
||||
client_pin.has_no_or_rp_id_hash_permission(&rp_id_hash),
|
||||
@@ -1526,8 +1532,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_ensure_rp_id_permission() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
assert_eq!(client_pin.ensure_rp_id_permission("example.com"), Ok(()));
|
||||
assert_eq!(
|
||||
client_pin
|
||||
@@ -1544,8 +1550,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_verify_pin_uv_auth_token() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
let message = [0xAA];
|
||||
client_pin
|
||||
.pin_uv_auth_token_state
|
||||
@@ -1618,8 +1624,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_verify_pin_uv_auth_token_not_in_use() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let client_pin = ClientPin::new(env.rng());
|
||||
let message = [0xAA];
|
||||
|
||||
let pin_uv_auth_token_v1 = client_pin
|
||||
@@ -1640,8 +1646,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_reset() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut client_pin = ClientPin::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut client_pin = ClientPin::new(env.rng());
|
||||
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 token_v1 = *client_pin.pin_protocol_v1.get_pin_uv_auth_token();
|
||||
@@ -1650,7 +1656,7 @@ mod test {
|
||||
client_pin
|
||||
.pin_uv_auth_token_state
|
||||
.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_v2, client_pin.pin_protocol_v2.get_public_key());
|
||||
assert_ne!(
|
||||
@@ -1676,13 +1682,13 @@ mod test {
|
||||
PinUvAuthProtocol::V2,
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
|
||||
);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
params.permissions = Some(0xFF);
|
||||
|
||||
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());
|
||||
for permission in PinPermission::into_enum_iter() {
|
||||
assert_eq!(
|
||||
@@ -1723,13 +1729,13 @@ mod test {
|
||||
PinUvAuthProtocol::V2,
|
||||
ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
|
||||
);
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
set_standard_pin(&mut persistent_store);
|
||||
params.permissions = Some(0xFF);
|
||||
|
||||
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());
|
||||
for permission in PinPermission::into_enum_iter() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -19,11 +19,12 @@ use super::data_formats::{ConfigSubCommand, ConfigSubCommandParams, SetMinPinLen
|
||||
use super::response::ResponseData;
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::storage::PersistentStore;
|
||||
use crate::env::Env;
|
||||
use alloc::vec;
|
||||
|
||||
/// Processes the subcommand enableEnterpriseAttestation for AuthenticatorConfig.
|
||||
fn process_enable_enterprise_attestation(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn process_enable_enterprise_attestation<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
if ENTERPRISE_ATTESTATION_MODE.is_some() {
|
||||
persistent_store.enable_enterprise_attestation()?;
|
||||
@@ -34,16 +35,16 @@ fn process_enable_enterprise_attestation(
|
||||
}
|
||||
|
||||
/// Processes the subcommand toggleAlwaysUv for AuthenticatorConfig.
|
||||
fn process_toggle_always_uv(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn process_toggle_always_uv<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
persistent_store.toggle_always_uv()?;
|
||||
Ok(ResponseData::AuthenticatorConfig)
|
||||
}
|
||||
|
||||
/// Processes the subcommand setMinPINLength for AuthenticatorConfig.
|
||||
fn process_set_min_pin_length(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn process_set_min_pin_length<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
params: SetMinPinLengthParams,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
let SetMinPinLengthParams {
|
||||
@@ -74,8 +75,8 @@ fn process_set_min_pin_length(
|
||||
}
|
||||
|
||||
/// Processes the AuthenticatorConfig command.
|
||||
pub fn process_config(
|
||||
persistent_store: &mut PersistentStore,
|
||||
pub fn process_config<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin: &mut ClientPin,
|
||||
params: AuthenticatorConfigParameters,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
@@ -129,13 +130,13 @@ mod test {
|
||||
use crate::ctap::customization::ENFORCE_ALWAYS_UV;
|
||||
use crate::ctap::data_formats::PinUvAuthProtocol;
|
||||
use crate::ctap::pin_protocol::authenticate_pin_uv_auth_token;
|
||||
use crypto::rng256::ThreadRng256;
|
||||
use crate::env::test::TestEnv;
|
||||
|
||||
#[test]
|
||||
fn test_process_enable_enterprise_attestation() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -161,9 +162,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_toggle_always_uv() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
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) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol);
|
||||
@@ -268,9 +269,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_set_min_pin_length() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -313,9 +314,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_set_min_pin_length_rp_ids() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -390,9 +391,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_set_min_pin_length_force_pin_change_implicit() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -414,9 +415,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_set_min_pin_length_force_pin_change_explicit() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -446,9 +447,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_config_vendor_prototype() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
|
||||
@@ -23,6 +23,7 @@ use super::response::{AuthenticatorCredentialManagementResponse, ResponseData};
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::storage::PersistentStore;
|
||||
use super::{StatefulCommand, StatefulPermission};
|
||||
use crate::env::Env;
|
||||
use alloc::collections::BTreeSet;
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
@@ -32,8 +33,8 @@ use crypto::Hash256;
|
||||
use libtock_drivers::timer::ClockValue;
|
||||
|
||||
/// Generates a set with all existing RP IDs.
|
||||
fn get_stored_rp_ids(
|
||||
persistent_store: &PersistentStore,
|
||||
fn get_stored_rp_ids<E: Env>(
|
||||
persistent_store: &PersistentStore<E>,
|
||||
) -> Result<BTreeSet<String>, Ctap2StatusCode> {
|
||||
let mut rp_set = BTreeSet::new();
|
||||
let mut iter_result = Ok(());
|
||||
@@ -108,8 +109,8 @@ fn enumerate_credentials_response(
|
||||
/// 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.
|
||||
fn check_rp_id_permissions(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn check_rp_id_permissions<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin: &mut ClientPin,
|
||||
credential_id: &[u8],
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
@@ -122,8 +123,8 @@ fn check_rp_id_permissions(
|
||||
}
|
||||
|
||||
/// Processes the subcommand getCredsMetadata for CredentialManagement.
|
||||
fn process_get_creds_metadata(
|
||||
persistent_store: &PersistentStore,
|
||||
fn process_get_creds_metadata<E: Env>(
|
||||
persistent_store: &PersistentStore<E>,
|
||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||
Ok(AuthenticatorCredentialManagementResponse {
|
||||
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.
|
||||
fn process_enumerate_rps_begin(
|
||||
persistent_store: &PersistentStore,
|
||||
fn process_enumerate_rps_begin<E: Env>(
|
||||
persistent_store: &PersistentStore<E>,
|
||||
stateful_command_permission: &mut StatefulPermission,
|
||||
now: ClockValue,
|
||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||
@@ -155,8 +156,8 @@ fn process_enumerate_rps_begin(
|
||||
}
|
||||
|
||||
/// Processes the subcommand enumerateRPsGetNextRP for CredentialManagement.
|
||||
fn process_enumerate_rps_get_next_rp(
|
||||
persistent_store: &PersistentStore,
|
||||
fn process_enumerate_rps_get_next_rp<E: Env>(
|
||||
persistent_store: &PersistentStore<E>,
|
||||
stateful_command_permission: &mut StatefulPermission,
|
||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||
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.
|
||||
fn process_enumerate_credentials_begin(
|
||||
persistent_store: &PersistentStore,
|
||||
fn process_enumerate_credentials_begin<E: Env>(
|
||||
persistent_store: &PersistentStore<E>,
|
||||
stateful_command_permission: &mut StatefulPermission,
|
||||
client_pin: &mut ClientPin,
|
||||
sub_command_params: CredentialManagementSubCommandParameters,
|
||||
@@ -207,8 +208,8 @@ fn process_enumerate_credentials_begin(
|
||||
}
|
||||
|
||||
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
|
||||
fn process_enumerate_credentials_get_next_credential(
|
||||
persistent_store: &PersistentStore,
|
||||
fn process_enumerate_credentials_get_next_credential<E: Env>(
|
||||
persistent_store: &PersistentStore<E>,
|
||||
stateful_command_permission: &mut StatefulPermission,
|
||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||
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.
|
||||
fn process_delete_credential(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn process_delete_credential<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin: &mut ClientPin,
|
||||
sub_command_params: CredentialManagementSubCommandParameters,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
@@ -231,8 +232,8 @@ fn process_delete_credential(
|
||||
}
|
||||
|
||||
/// Processes the subcommand updateUserInformation for CredentialManagement.
|
||||
fn process_update_user_information(
|
||||
persistent_store: &mut PersistentStore,
|
||||
fn process_update_user_information<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin: &mut ClientPin,
|
||||
sub_command_params: CredentialManagementSubCommandParameters,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
@@ -248,8 +249,8 @@ fn process_update_user_information(
|
||||
}
|
||||
|
||||
/// Processes the CredentialManagement command and all its subcommands.
|
||||
pub fn process_credential_management(
|
||||
persistent_store: &mut PersistentStore,
|
||||
pub fn process_credential_management<E: Env>(
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
stateful_command_permission: &mut StatefulPermission,
|
||||
client_pin: &mut ClientPin,
|
||||
cred_management_params: AuthenticatorCredentialManagementParameters,
|
||||
|
||||
@@ -178,10 +178,10 @@ impl Ctap1Command {
|
||||
const VENDOR_SPECIFIC_FIRST: u8 = 0x40;
|
||||
const VENDOR_SPECIFIC_LAST: u8 = 0xBF;
|
||||
|
||||
pub fn process_command(
|
||||
env: &mut impl Env,
|
||||
pub fn process_command<E: Env>(
|
||||
env: &mut E,
|
||||
message: &[u8],
|
||||
ctap_state: &mut CtapState,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
clock_value: ClockValue,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||
if !ctap_state
|
||||
@@ -243,11 +243,11 @@ impl Ctap1Command {
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
// + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
fn process_register(
|
||||
env: &mut impl Env,
|
||||
fn process_register<E: Env>(
|
||||
env: &mut E,
|
||||
challenge: [u8; 32],
|
||||
application: [u8; 32],
|
||||
ctap_state: &mut CtapState,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let pk = sk.genpk();
|
||||
@@ -307,13 +307,13 @@ impl Ctap1Command {
|
||||
// +-------------------+---------+--------------+-----------------+
|
||||
// + application (32B) | UP (1B) | Counter (4B) | challenge (32B) |
|
||||
// +-------------------+---------+--------------+-----------------+
|
||||
fn process_authenticate(
|
||||
env: &mut impl Env,
|
||||
fn process_authenticate<E: Env>(
|
||||
env: &mut E,
|
||||
challenge: [u8; 32],
|
||||
application: [u8; 32],
|
||||
key_handle: Vec<u8>,
|
||||
flags: Ctap1Flags,
|
||||
ctap_state: &mut CtapState,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||
let credential_source = ctap_state
|
||||
.decrypt_credential_source(key_handle, &application)
|
||||
|
||||
@@ -146,12 +146,12 @@ impl CtapHid {
|
||||
|
||||
// Process an incoming USB HID packet, and optionally returns a list of outgoing packets to
|
||||
// send as a reply.
|
||||
pub fn process_hid_packet(
|
||||
pub fn process_hid_packet<E: Env>(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
packet: &HidPacket,
|
||||
clock_value: ClockValue,
|
||||
ctap_state: &mut CtapState,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
) -> HidPacketIterator {
|
||||
// TODO: Send COMMAND_KEEPALIVE every 100ms?
|
||||
match self
|
||||
@@ -442,10 +442,10 @@ mod test {
|
||||
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
|
||||
const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
|
||||
|
||||
fn process_messages(
|
||||
env: &mut impl Env,
|
||||
fn process_messages<E: Env>(
|
||||
env: &mut E,
|
||||
ctap_hid: &mut CtapHid,
|
||||
ctap_state: &mut CtapState,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
request: Vec<Message>,
|
||||
) -> Option<Vec<Message>> {
|
||||
let mut result = Vec::new();
|
||||
@@ -466,10 +466,10 @@ mod test {
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn cid_from_init(
|
||||
env: &mut impl Env,
|
||||
fn cid_from_init<E: Env>(
|
||||
env: &mut E,
|
||||
ctap_hid: &mut CtapHid,
|
||||
ctap_state: &mut CtapState,
|
||||
ctap_state: &mut CtapState<E>,
|
||||
) -> ChannelID {
|
||||
let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
|
||||
let reply = process_messages(
|
||||
|
||||
@@ -18,6 +18,7 @@ use super::customization::MAX_MSG_SIZE;
|
||||
use super::response::{AuthenticatorLargeBlobsResponse, ResponseData};
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::storage::PersistentStore;
|
||||
use crate::env::Env;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
@@ -44,9 +45,9 @@ impl LargeBlobs {
|
||||
}
|
||||
|
||||
/// Process the large blob command.
|
||||
pub fn process_command(
|
||||
pub fn process_command<E: Env>(
|
||||
&mut self,
|
||||
persistent_store: &mut PersistentStore,
|
||||
persistent_store: &mut PersistentStore<E>,
|
||||
client_pin: &mut ClientPin,
|
||||
large_blobs_params: AuthenticatorLargeBlobsParameters,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
@@ -137,13 +138,13 @@ mod test {
|
||||
use super::super::data_formats::PinUvAuthProtocol;
|
||||
use super::super::pin_protocol::authenticate_pin_uv_auth_token;
|
||||
use super::*;
|
||||
use crypto::rng256::ThreadRng256;
|
||||
use crate::env::test::TestEnv;
|
||||
|
||||
#[test]
|
||||
fn test_process_command_get_empty() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -173,9 +174,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_command_commit_and_get() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -236,9 +237,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_command_commit_unexpected_offset() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -283,9 +284,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_command_commit_unexpected_length() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -330,9 +331,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_command_commit_end_offset_overflow() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
@@ -354,9 +355,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_command_commit_unexpected_hash() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
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) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let mut client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol);
|
||||
|
||||
@@ -64,7 +64,7 @@ use self::storage::PersistentStore;
|
||||
use self::timed_permission::TimedPermission;
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
use self::timed_permission::U2fUserPresenceState;
|
||||
use crate::embedded_flash::{UpgradeLocations, UpgradeStorage};
|
||||
use crate::api::upgrade_storage::UpgradeStorage;
|
||||
use crate::env::{Env, UserPresence};
|
||||
use alloc::boxed::Box;
|
||||
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,
|
||||
/// except the hash itself.
|
||||
fn parse_metadata(
|
||||
upgrade_locations: &UpgradeLocations,
|
||||
upgrade_locations: &impl UpgradeStorage,
|
||||
metadata: &[u8],
|
||||
) -> Result<[u8; 32], Ctap2StatusCode> {
|
||||
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
|
||||
// in the persistent store field.
|
||||
pub struct CtapState {
|
||||
persistent_store: PersistentStore,
|
||||
pub struct CtapState<E: Env> {
|
||||
persistent_store: PersistentStore<E>,
|
||||
client_pin: ClientPin,
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
pub(crate) u2f_up_state: U2fUserPresenceState,
|
||||
// The state initializes to Reset and its timeout, and never goes back to Reset.
|
||||
stateful_command_permission: StatefulPermission,
|
||||
large_blobs: LargeBlobs,
|
||||
upgrade_locations: Option<UpgradeLocations>,
|
||||
// Upgrade support is optional.
|
||||
upgrade_locations: Option<E::UpgradeStorage>,
|
||||
}
|
||||
|
||||
impl CtapState {
|
||||
pub fn new(env: &mut impl Env, now: ClockValue) -> CtapState {
|
||||
let persistent_store = PersistentStore::new(env.rng());
|
||||
impl<E: Env> CtapState<E> {
|
||||
pub fn new(env: &mut E, now: ClockValue) -> Self {
|
||||
let persistent_store = PersistentStore::new(env);
|
||||
let client_pin = ClientPin::new(env.rng());
|
||||
CtapState {
|
||||
persistent_store,
|
||||
@@ -355,7 +356,7 @@ impl CtapState {
|
||||
),
|
||||
stateful_command_permission: StatefulPermission::new_reset(now),
|
||||
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(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
if USE_SIGNATURE_COUNTER {
|
||||
let increment = env.rng().gen_uniform_u32x8()[0] % 8 + 1;
|
||||
@@ -393,7 +394,7 @@ impl CtapState {
|
||||
// compatible with U2F.
|
||||
pub fn encrypt_key_handle(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
private_key: crypto::ecdsa::SecKey,
|
||||
application: &[u8; 32],
|
||||
) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
@@ -454,7 +455,7 @@ impl CtapState {
|
||||
|
||||
pub fn process_command(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
command_cbor: &[u8],
|
||||
cid: ChannelID,
|
||||
now: ClockValue,
|
||||
@@ -557,7 +558,7 @@ impl CtapState {
|
||||
|
||||
fn pin_uv_auth_precheck(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
pin_uv_auth_param: &Option<Vec<u8>>,
|
||||
pin_uv_auth_protocol: Option<PinUvAuthProtocol>,
|
||||
cid: ChannelID,
|
||||
@@ -579,7 +580,7 @@ impl CtapState {
|
||||
|
||||
fn process_make_credential(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
make_credential_params: AuthenticatorMakeCredentialParameters,
|
||||
cid: ChannelID,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
@@ -837,7 +838,7 @@ impl CtapState {
|
||||
// and returns the correct Get(Next)Assertion response.
|
||||
fn assertion_response(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
mut credential: PublicKeyCredentialSource,
|
||||
assertion_input: AssertionInput,
|
||||
number_of_credentials: Option<usize>,
|
||||
@@ -945,7 +946,7 @@ impl CtapState {
|
||||
|
||||
fn process_get_assertion(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
get_assertion_params: AuthenticatorGetAssertionParameters,
|
||||
cid: ChannelID,
|
||||
now: ClockValue,
|
||||
@@ -1071,7 +1072,7 @@ impl CtapState {
|
||||
|
||||
fn process_get_next_assertion(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
now: ClockValue,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
self.stateful_command_permission
|
||||
@@ -1157,7 +1158,7 @@ impl CtapState {
|
||||
|
||||
fn process_reset(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
cid: ChannelID,
|
||||
now: ClockValue,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
@@ -1183,7 +1184,7 @@ impl CtapState {
|
||||
|
||||
fn process_selection(
|
||||
&self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
cid: ChannelID,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
env.user_presence().check(cid)?;
|
||||
@@ -1192,7 +1193,7 @@ impl CtapState {
|
||||
|
||||
fn process_vendor_configure(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
env: &mut E,
|
||||
params: AuthenticatorVendorConfigureParameters,
|
||||
cid: ChannelID,
|
||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::ctap::data_formats::{
|
||||
use crate::ctap::key_material;
|
||||
use crate::ctap::status_code::Ctap2StatusCode;
|
||||
use crate::ctap::INITIAL_SIGNATURE_COUNTER;
|
||||
use crate::embedded_flash::{new_storage, Storage};
|
||||
use crate::env::Env;
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
@@ -56,22 +56,22 @@ struct PinProperties {
|
||||
}
|
||||
|
||||
/// CTAP persistent storage.
|
||||
pub struct PersistentStore {
|
||||
store: persistent_store::Store<Storage>,
|
||||
pub struct PersistentStore<E: Env> {
|
||||
store: persistent_store::Store<E::Storage>,
|
||||
}
|
||||
|
||||
impl PersistentStore {
|
||||
impl<E: Env> PersistentStore<E> {
|
||||
/// Gives access to the persistent store.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This should be at most one instance of persistent store per program lifetime.
|
||||
pub fn new(rng: &mut impl Rng256) -> PersistentStore {
|
||||
let storage = new_storage().ok().unwrap();
|
||||
pub fn new(env: &mut E) -> Self {
|
||||
let storage = env.storage().ok().unwrap();
|
||||
let mut store = PersistentStore {
|
||||
store: persistent_store::Store::new(storage).ok().unwrap(),
|
||||
};
|
||||
store.init(rng).ok().unwrap();
|
||||
store.init(env.rng()).ok().unwrap();
|
||||
store
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ impl PersistentStore {
|
||||
pub fn iter_credentials<'a>(
|
||||
&'a self,
|
||||
result: &'a mut Result<(), Ctap2StatusCode>,
|
||||
) -> Result<IterCredentials<'a>, Ctap2StatusCode> {
|
||||
) -> Result<IterCredentials<'a, E>, Ctap2StatusCode> {
|
||||
IterCredentials::new(&self.store, result)
|
||||
}
|
||||
|
||||
@@ -655,9 +655,9 @@ impl From<persistent_store::StoreError> for Ctap2StatusCode {
|
||||
}
|
||||
|
||||
/// Iterator for credentials.
|
||||
pub struct IterCredentials<'a> {
|
||||
pub struct IterCredentials<'a, E: Env> {
|
||||
/// The store being iterated.
|
||||
store: &'a persistent_store::Store<Storage>,
|
||||
store: &'a persistent_store::Store<E::Storage>,
|
||||
|
||||
/// The store iterator.
|
||||
iter: persistent_store::StoreIter<'a>,
|
||||
@@ -669,12 +669,12 @@ pub struct IterCredentials<'a> {
|
||||
result: &'a mut Result<(), Ctap2StatusCode>,
|
||||
}
|
||||
|
||||
impl<'a> IterCredentials<'a> {
|
||||
impl<'a, E: Env> IterCredentials<'a, E> {
|
||||
/// Creates a credential iterator.
|
||||
fn new(
|
||||
store: &'a persistent_store::Store<Storage>,
|
||||
store: &'a persistent_store::Store<E::Storage>,
|
||||
result: &'a mut Result<(), Ctap2StatusCode>,
|
||||
) -> Result<IterCredentials<'a>, Ctap2StatusCode> {
|
||||
) -> Result<Self, Ctap2StatusCode> {
|
||||
let iter = store.iter()?;
|
||||
Ok(IterCredentials {
|
||||
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);
|
||||
|
||||
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 {
|
||||
use super::*;
|
||||
use crate::ctap::data_formats::{PublicKeyCredentialSource, PublicKeyCredentialType};
|
||||
use crate::env::test::TestEnv;
|
||||
use crypto::rng256::{Rng256, ThreadRng256};
|
||||
|
||||
fn create_credential_source(
|
||||
@@ -778,24 +779,24 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_store() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
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.count_credentials().unwrap() > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), 0);
|
||||
|
||||
let mut credential_ids = vec![];
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
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());
|
||||
assert!(persistent_store.store_credential(credential_source).is_ok());
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), i + 1);
|
||||
@@ -810,8 +811,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_update_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let user = PublicKeyCredentialUserEntity {
|
||||
// User ID is ignored.
|
||||
user_id: vec![0x00],
|
||||
@@ -824,7 +825,7 @@ mod test {
|
||||
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();
|
||||
assert!(persistent_store.store_credential(credential_source).is_ok());
|
||||
let stored_credential = persistent_store
|
||||
@@ -848,12 +849,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_credential_order() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let credential_source = create_credential_source(&mut rng, "example.com", vec![]);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let credential_source = create_credential_source(env.rng(), "example.com", vec![]);
|
||||
let current_latest_creation = credential_source.creation_order;
|
||||
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();
|
||||
assert!(credential_source.creation_order > current_latest_creation);
|
||||
let current_latest_creation = credential_source.creation_order;
|
||||
@@ -863,18 +864,18 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_fill_store() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), 0);
|
||||
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
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_eq!(persistent_store.count_credentials().unwrap(), i + 1);
|
||||
}
|
||||
let credential_source = create_credential_source(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
"example.com",
|
||||
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
|
||||
);
|
||||
@@ -890,12 +891,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_overwrite() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), 0);
|
||||
// These should have different IDs.
|
||||
let credential_source0 = create_credential_source(&mut rng, "example.com", vec![0x00]);
|
||||
let credential_source1 = 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(env.rng(), "example.com", vec![0x00]);
|
||||
let credential_id0 = credential_source0.credential_id.clone();
|
||||
let credential_id1 = credential_source1.credential_id.clone();
|
||||
|
||||
@@ -915,15 +916,15 @@ mod test {
|
||||
.unwrap()
|
||||
.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 {
|
||||
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_eq!(persistent_store.count_credentials().unwrap(), i + 1);
|
||||
}
|
||||
let credential_source = create_credential_source(
|
||||
&mut rng,
|
||||
env.rng(),
|
||||
"example.com",
|
||||
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
|
||||
);
|
||||
@@ -939,12 +940,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_get_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let credential_source0 = create_credential_source(&mut rng, "example.com", vec![0x00]);
|
||||
let credential_source1 = create_credential_source(&mut rng, "example.com", vec![0x01]);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
|
||||
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]);
|
||||
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];
|
||||
for credential_source in credential_sources.into_iter() {
|
||||
let cred_id = credential_source.credential_id.clone();
|
||||
@@ -957,11 +958,11 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_find() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), 0);
|
||||
let credential_source0 = create_credential_source(&mut rng, "example.com", vec![0x00]);
|
||||
let credential_source1 = create_credential_source(&mut rng, "example.com", vec![0x01]);
|
||||
let credential_source0 = create_credential_source(env.rng(), "example.com", vec![0x00]);
|
||||
let credential_source1 = create_credential_source(env.rng(), "example.com", vec![0x01]);
|
||||
let id0 = credential_source0.credential_id.clone();
|
||||
let key0 = credential_source0.private_key.clone();
|
||||
assert!(persistent_store
|
||||
@@ -997,13 +998,13 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_find_with_cred_protect() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
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 {
|
||||
key_type: PublicKeyCredentialType::PublicKey,
|
||||
credential_id: rng.gen_uniform_u8x32().to_vec(),
|
||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||
private_key,
|
||||
rp_id: String::from("example.com"),
|
||||
user_handle: vec![0x00],
|
||||
@@ -1025,8 +1026,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_master_keys() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// Master keys stay the same within the same CTAP reset cycle.
|
||||
let master_keys_1 = persistent_store.master_keys().unwrap();
|
||||
@@ -1038,7 +1039,7 @@ mod test {
|
||||
// same keys.
|
||||
let master_encryption_key = master_keys_1.encryption.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();
|
||||
assert!(master_keys_3.encryption != master_encryption_key.as_slice());
|
||||
assert!(master_keys_3.hmac != master_hmac_key.as_slice());
|
||||
@@ -1046,8 +1047,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_cred_random_secret() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// CredRandom secrets stay the same within the same CTAP reset cycle.
|
||||
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
|
||||
// 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_without_uv_3 = persistent_store.cred_random_secret(false).unwrap();
|
||||
assert!(cred_random_with_uv_1 != cred_random_with_uv_3);
|
||||
@@ -1068,15 +1069,15 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_pin_hash_and_length() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// Pin hash is initially not set.
|
||||
assert!(persistent_store.pin_hash().unwrap().is_none());
|
||||
assert!(persistent_store.pin_code_point_length().unwrap().is_none());
|
||||
|
||||
// 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);
|
||||
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);
|
||||
@@ -1096,15 +1097,15 @@ mod test {
|
||||
);
|
||||
|
||||
// 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_code_point_length().unwrap().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pin_retries() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// The pin retries is initially at the maximum.
|
||||
assert_eq!(persistent_store.pin_retries(), Ok(MAX_PIN_RETRIES));
|
||||
@@ -1126,8 +1127,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_persistent_keys() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// Make sure the attestation are absent. There is no batch attestation in tests.
|
||||
assert!(persistent_store
|
||||
@@ -1151,7 +1152,7 @@ mod test {
|
||||
assert_eq!(&persistent_store.aaguid().unwrap(), key_material::AAGUID);
|
||||
|
||||
// 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!(
|
||||
&persistent_store.attestation_private_key().unwrap().unwrap(),
|
||||
&dummy_key
|
||||
@@ -1165,8 +1166,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_min_pin_length() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// The minimum PIN length is initially at the default.
|
||||
assert_eq!(
|
||||
@@ -1187,8 +1188,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_min_pin_length_rp_ids() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
// The minimum PIN length RP IDs are initially at the default.
|
||||
assert_eq!(
|
||||
@@ -1213,8 +1214,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_max_large_blob_array_size() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
assert!(
|
||||
MAX_LARGE_BLOB_ARRAY_SIZE
|
||||
@@ -1225,8 +1226,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_commit_get_large_blob_array() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
let large_blob_array = vec![0x01, 0x02, 0x03];
|
||||
assert!(persistent_store
|
||||
@@ -1248,8 +1249,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_commit_get_large_blob_array_overwrite() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
let large_blob_array = vec![0x11; 5];
|
||||
assert!(persistent_store
|
||||
@@ -1272,8 +1273,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_commit_get_large_blob_array_no_commit() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
let empty_blob_array = vec![
|
||||
0x80, 0x76, 0xBE, 0x8B, 0x52, 0x8D, 0x00, 0x75, 0xF7, 0xAA, 0xE9, 0x8D, 0x6F, 0xA5,
|
||||
@@ -1289,8 +1290,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_global_signature_counter() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
let mut counter_value = 1;
|
||||
assert_eq!(
|
||||
@@ -1311,8 +1312,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_force_pin_change() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
assert!(!persistent_store.has_force_pin_change().unwrap());
|
||||
assert_eq!(persistent_store.force_pin_change(), Ok(()));
|
||||
@@ -1323,20 +1324,20 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_enterprise_attestation() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
assert!(!persistent_store.enterprise_attestation().unwrap());
|
||||
assert_eq!(persistent_store.enable_enterprise_attestation(), Ok(()));
|
||||
assert!(persistent_store.enterprise_attestation().unwrap());
|
||||
persistent_store.reset(&mut rng).unwrap();
|
||||
persistent_store.reset(env.rng()).unwrap();
|
||||
assert!(!persistent_store.enterprise_attestation().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_always_uv() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let mut persistent_store = PersistentStore::new(&mut env);
|
||||
|
||||
if ENFORCE_ALWAYS_UV {
|
||||
assert!(persistent_store.has_always_uv().unwrap());
|
||||
@@ -1355,11 +1356,11 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_serialize_deserialize_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let private_key = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let credential = PublicKeyCredentialSource {
|
||||
key_type: PublicKeyCredentialType::PublicKey,
|
||||
credential_id: rng.gen_uniform_u8x32().to_vec(),
|
||||
credential_id: env.rng().gen_uniform_u8x32().to_vec(),
|
||||
private_key,
|
||||
rp_id: String::from("example.com"),
|
||||
user_handle: vec![0x00],
|
||||
|
||||
@@ -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
14
src/env/mod.rs
vendored
@@ -1,6 +1,8 @@
|
||||
use crate::api::upgrade_storage::UpgradeStorage;
|
||||
use crate::ctap::hid::ChannelID;
|
||||
use crate::ctap::status_code::Ctap2StatusCode;
|
||||
use crypto::rng256::Rng256;
|
||||
use persistent_store::{Storage, StorageResult};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod test;
|
||||
@@ -17,7 +19,19 @@ pub trait UserPresence {
|
||||
pub trait Env {
|
||||
type Rng: Rng256;
|
||||
type UserPresence: UserPresence;
|
||||
type Storage: Storage;
|
||||
type UpgradeStorage: UpgradeStorage;
|
||||
|
||||
fn rng(&mut self) -> &mut Self::Rng;
|
||||
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>;
|
||||
}
|
||||
|
||||
25
src/env/test.rs → src/env/test/mod.rs
vendored
25
src/env/test.rs → src/env/test/mod.rs
vendored
@@ -1,7 +1,11 @@
|
||||
use self::upgrade_storage::BufferUpgradeStorage;
|
||||
use crate::ctap::hid::ChannelID;
|
||||
use crate::ctap::status_code::Ctap2StatusCode;
|
||||
use crate::env::{Env, UserPresence};
|
||||
use crypto::rng256::ThreadRng256;
|
||||
use persistent_store::{BufferOptions, BufferStorage, StorageResult};
|
||||
|
||||
mod upgrade_storage;
|
||||
|
||||
pub struct TestEnv {
|
||||
rng: ThreadRng256,
|
||||
@@ -37,6 +41,8 @@ impl UserPresence for TestUserPresence {
|
||||
impl Env for TestEnv {
|
||||
type Rng = ThreadRng256;
|
||||
type UserPresence = TestUserPresence;
|
||||
type Storage = BufferStorage;
|
||||
type UpgradeStorage = BufferUpgradeStorage;
|
||||
|
||||
fn rng(&mut self) -> &mut Self::Rng {
|
||||
&mut self.rng
|
||||
@@ -45,4 +51,23 @@ impl Env for TestEnv {
|
||||
fn user_presence(&mut self) -> &mut Self::UserPresence {
|
||||
&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()
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::helper::ModRange;
|
||||
use super::upgrade_storage::UpgradeStorage;
|
||||
use crate::api::upgrade_storage::helper::ModRange;
|
||||
use crate::api::upgrade_storage::UpgradeStorage;
|
||||
use alloc::boxed::Box;
|
||||
use persistent_store::{StorageError, StorageResult};
|
||||
|
||||
52
src/env/tock.rs → src/env/tock/mod.rs
vendored
52
src/env/tock.rs → src/env/tock/mod.rs
vendored
@@ -1,9 +1,11 @@
|
||||
use self::storage::{SyscallStorage, SyscallUpgradeStorage};
|
||||
use crate::ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket};
|
||||
use crate::ctap::status_code::Ctap2StatusCode;
|
||||
use crate::env::{Env, UserPresence};
|
||||
use core::cell::Cell;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use core::fmt::Write;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use crypto::rng256::TockRng256;
|
||||
use libtock_core::result::{CommandError, EALREADY};
|
||||
use libtock_drivers::buttons::{self, ButtonState};
|
||||
@@ -12,16 +14,46 @@ use libtock_drivers::console::Console;
|
||||
use libtock_drivers::result::{FlexUnwrap, TockError};
|
||||
use libtock_drivers::timer::Duration;
|
||||
use libtock_drivers::{led, timer, usb_ctap_hid};
|
||||
use persistent_store::StorageResult;
|
||||
|
||||
mod storage;
|
||||
|
||||
pub struct TockEnv {
|
||||
rng: TockRng256,
|
||||
storage: bool,
|
||||
upgrade_storage: bool,
|
||||
}
|
||||
|
||||
impl TockEnv {
|
||||
pub fn new() -> Self {
|
||||
let rng = TockRng256 {};
|
||||
TockEnv { rng }
|
||||
/// Returns the unique instance of the Tock environment.
|
||||
///
|
||||
/// 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 {
|
||||
@@ -33,6 +65,8 @@ impl UserPresence for TockEnv {
|
||||
impl Env for TockEnv {
|
||||
type Rng = TockRng256;
|
||||
type UserPresence = Self;
|
||||
type Storage = SyscallStorage;
|
||||
type UpgradeStorage = SyscallUpgradeStorage;
|
||||
|
||||
fn rng(&mut self) -> &mut Self::Rng {
|
||||
&mut self.rng
|
||||
@@ -41,6 +75,18 @@ impl Env for TockEnv {
|
||||
fn user_presence(&mut self) -> &mut Self::UserPresence {
|
||||
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.
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::helper::{find_slice, is_aligned, ModRange};
|
||||
use super::upgrade_storage::UpgradeStorage;
|
||||
use crate::api::upgrade_storage::helper::{find_slice, is_aligned, ModRange};
|
||||
use crate::api::upgrade_storage::UpgradeStorage;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::Cell;
|
||||
use libtock_core::{callback, syscalls};
|
||||
@@ -24,19 +24,18 @@ use crate::ctap::CtapState;
|
||||
use crate::env::Env;
|
||||
use libtock_drivers::timer::ClockValue;
|
||||
|
||||
pub mod api;
|
||||
// Implementation details must be public for testing (in particular fuzzing).
|
||||
#[cfg(feature = "std")]
|
||||
pub mod ctap;
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod ctap;
|
||||
// Store example binaries use the flash directly. Eventually, they should access it from env::tock.
|
||||
pub mod embedded_flash;
|
||||
pub mod env;
|
||||
|
||||
/// CTAP implementation parameterized by its environment.
|
||||
pub struct Ctap<E: Env> {
|
||||
env: E,
|
||||
state: CtapState,
|
||||
state: CtapState<E>,
|
||||
hid: CtapHid,
|
||||
}
|
||||
|
||||
@@ -50,7 +49,7 @@ impl<E: Env> Ctap<E> {
|
||||
Ctap { env, state, hid }
|
||||
}
|
||||
|
||||
pub fn state(&mut self) -> &mut CtapState {
|
||||
pub fn state(&mut self) -> &mut CtapState<E> {
|
||||
&mut self.state
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ fn main() {
|
||||
}
|
||||
|
||||
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 led_counter = 0;
|
||||
|
||||
Reference in New Issue
Block a user