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

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;
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.

View File

@@ -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!(

View File

@@ -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);

View File

@@ -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,

View File

@@ -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)

View File

@@ -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(

View File

@@ -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);

View File

@@ -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> {

View File

@@ -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],

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::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>;
}

View File

@@ -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()
}
}

View File

@@ -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};

View File

@@ -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,18 +14,48 @@ 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 {
fn check(&self, cid: ChannelID) -> Result<(), Ctap2StatusCode> {
check_user_presence(cid)
@@ -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.

View File

@@ -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};

View File

@@ -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
}

View File

@@ -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;