Move remaining customizations to new file (#473)
This commit is contained in:
@@ -179,6 +179,31 @@ pub trait Customization {
|
||||
// the key.
|
||||
// ###########################################################################
|
||||
|
||||
/// Sets the maximum blob size stored with the credBlob extension.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - The length must be at least 32.
|
||||
fn max_cred_blob_length(&self) -> usize;
|
||||
|
||||
/// Limits the number of considered entries in credential lists.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - This value, if present, must be at least 1 (more is preferred).
|
||||
///
|
||||
/// Depending on your memory, you can use Some(n) to limit request sizes in
|
||||
/// MakeCredential and GetAssertion. This affects allowList and excludeList.
|
||||
fn max_credential_count_in_list(&self) -> Option<usize>;
|
||||
|
||||
/// Limits the size of largeBlobs the authenticator stores.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - The allowed size must be at least 1024.
|
||||
/// - The array must fit into the shards reserved in storage/key.rs.
|
||||
fn max_large_blob_array_size(&self) -> usize;
|
||||
|
||||
/// Limits the number of RP IDs that can change the minimum PIN length.
|
||||
///
|
||||
/// # Invariant
|
||||
@@ -193,6 +218,27 @@ pub trait Customization {
|
||||
/// in default_min_pin_length_rp_ids() should be allowed to change the minimum
|
||||
/// PIN length.
|
||||
fn max_rp_ids_length(&self) -> usize;
|
||||
|
||||
/// Sets the number of resident keys you can store.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - The storage key CREDENTIALS must fit at least this number of credentials.
|
||||
///
|
||||
/// Limiting the number of resident keys permits to ensure a minimum number of
|
||||
/// counter increments.
|
||||
/// Let:
|
||||
/// - P the number of pages (NUM_PAGES in the board definition)
|
||||
/// - K the maximum number of resident keys (max_supported_resident_keys())
|
||||
/// - S the maximum size of a resident key (about 500)
|
||||
/// - C the number of erase cycles (10000)
|
||||
/// - I the minimum number of counter increments
|
||||
///
|
||||
/// We have: I = (P * 4084 - 5107 - K * S) / 8 * C
|
||||
///
|
||||
/// With P=20 and K=150, we have I=2M which is enough for 500 increments per day
|
||||
/// for 10 years.
|
||||
fn max_supported_resident_keys(&self) -> usize;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -207,7 +253,11 @@ pub struct CustomizationImpl {
|
||||
pub max_pin_retries: u8,
|
||||
pub use_batch_attestation: bool,
|
||||
pub use_signature_counter: bool,
|
||||
pub max_cred_blob_length: usize,
|
||||
pub max_credential_count_in_list: Option<usize>,
|
||||
pub max_large_blob_array_size: usize,
|
||||
pub max_rp_ids_length: usize,
|
||||
pub max_supported_resident_keys: usize,
|
||||
}
|
||||
|
||||
pub const DEFAULT_CUSTOMIZATION: CustomizationImpl = CustomizationImpl {
|
||||
@@ -221,7 +271,11 @@ pub const DEFAULT_CUSTOMIZATION: CustomizationImpl = CustomizationImpl {
|
||||
max_pin_retries: 8,
|
||||
use_batch_attestation: false,
|
||||
use_signature_counter: true,
|
||||
max_cred_blob_length: 32,
|
||||
max_credential_count_in_list: None,
|
||||
max_large_blob_array_size: 2048,
|
||||
max_rp_ids_length: 8,
|
||||
max_supported_resident_keys: 150,
|
||||
};
|
||||
|
||||
impl Customization for CustomizationImpl {
|
||||
@@ -276,13 +330,33 @@ impl Customization for CustomizationImpl {
|
||||
self.use_signature_counter
|
||||
}
|
||||
|
||||
fn max_cred_blob_length(&self) -> usize {
|
||||
self.max_cred_blob_length
|
||||
}
|
||||
|
||||
fn max_credential_count_in_list(&self) -> Option<usize> {
|
||||
self.max_credential_count_in_list
|
||||
}
|
||||
|
||||
fn max_large_blob_array_size(&self) -> usize {
|
||||
self.max_large_blob_array_size
|
||||
}
|
||||
|
||||
fn max_rp_ids_length(&self) -> usize {
|
||||
self.max_rp_ids_length
|
||||
}
|
||||
|
||||
fn max_supported_resident_keys(&self) -> usize {
|
||||
self.max_supported_resident_keys
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn is_valid(customization: &impl Customization) -> bool {
|
||||
// Two invariants are currently tested in different files:
|
||||
// - storage.rs: if max_large_blob_array_size() fits the shards
|
||||
// - storage/key.rs: if max_supported_resident_keys() fits CREDENTIALS
|
||||
|
||||
// Max message size must be between 1024 and 7609.
|
||||
if customization.max_msg_size() < 1024 || customization.max_msg_size() > 7609 {
|
||||
return false;
|
||||
@@ -323,6 +397,23 @@ pub fn is_valid(customization: &impl Customization) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Max cred blob length should be at least 32.
|
||||
if customization.max_cred_blob_length() < 32 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Max credential count in list should be positive if exists.
|
||||
if let Some(count) = customization.max_credential_count_in_list() {
|
||||
if count < 1 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Max large blob array size should not be less than 1024.
|
||||
if customization.max_large_blob_array_size() < 1024 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default min pin length rp ids must be non-empty if max rp ids length is 0.
|
||||
if customization.max_rp_ids_length() == 0
|
||||
&& customization.default_min_pin_length_rp_ids().is_empty()
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::customization::{MAX_CREDENTIAL_COUNT_IN_LIST, MAX_LARGE_BLOB_ARRAY_SIZE};
|
||||
use super::data_formats::{
|
||||
extract_array, extract_bool, extract_byte_string, extract_map, extract_text_string,
|
||||
extract_unsigned, ok_or_missing, ClientPinSubCommand, ConfigSubCommand, ConfigSubCommandParams,
|
||||
@@ -205,10 +204,8 @@ impl TryFrom<cbor::Value> for AuthenticatorMakeCredentialParameters {
|
||||
let exclude_list = match exclude_list {
|
||||
Some(entry) => {
|
||||
let exclude_list_vec = extract_array(entry)?;
|
||||
let list_len = MAX_CREDENTIAL_COUNT_IN_LIST.unwrap_or(exclude_list_vec.len());
|
||||
let exclude_list = exclude_list_vec
|
||||
.into_iter()
|
||||
.take(list_len)
|
||||
.map(PublicKeyCredentialDescriptor::try_from)
|
||||
.collect::<Result<Vec<PublicKeyCredentialDescriptor>, Ctap2StatusCode>>()?;
|
||||
Some(exclude_list)
|
||||
@@ -283,10 +280,8 @@ impl TryFrom<cbor::Value> for AuthenticatorGetAssertionParameters {
|
||||
let allow_list = match allow_list {
|
||||
Some(entry) => {
|
||||
let allow_list_vec = extract_array(entry)?;
|
||||
let list_len = MAX_CREDENTIAL_COUNT_IN_LIST.unwrap_or(allow_list_vec.len());
|
||||
let allow_list = allow_list_vec
|
||||
.into_iter()
|
||||
.take(list_len)
|
||||
.map(PublicKeyCredentialDescriptor::try_from)
|
||||
.collect::<Result<Vec<PublicKeyCredentialDescriptor>, Ctap2StatusCode>>()?;
|
||||
Some(allow_list)
|
||||
@@ -431,9 +426,6 @@ impl TryFrom<cbor::Value> for AuthenticatorLargeBlobsParameters {
|
||||
if set.is_some() && offset == 0 {
|
||||
match length {
|
||||
None => return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
|
||||
Some(len) if len > MAX_LARGE_BLOB_ARRAY_SIZE => {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_LARGE_BLOB_STORAGE_FULL)
|
||||
}
|
||||
Some(len) if len < MIN_LARGE_BLOB_LEN => {
|
||||
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright 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.
|
||||
|
||||
//! This file contains all customizable constants.
|
||||
//!
|
||||
//! If you adapt them, make sure to run the tests before flashing the firmware.
|
||||
//! Our deploy script enforces the invariants.
|
||||
|
||||
// ###########################################################################
|
||||
// Constants for performance optimization or adapting to different hardware.
|
||||
//
|
||||
// Those constants may be modified before compilation to tune the behavior of
|
||||
// the key.
|
||||
// ###########################################################################
|
||||
|
||||
/// Sets the maximum blob size stored with the credBlob extension.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - The length must be at least 32.
|
||||
pub const MAX_CRED_BLOB_LENGTH: usize = 32;
|
||||
|
||||
/// Limits the number of considered entries in credential lists.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - This value, if present, must be at least 1 (more is preferred).
|
||||
///
|
||||
/// Depending on your memory, you can use Some(n) to limit request sizes in
|
||||
/// MakeCredential and GetAssertion. This affects allowList and excludeList.
|
||||
pub const MAX_CREDENTIAL_COUNT_IN_LIST: Option<usize> = None;
|
||||
|
||||
/// Limits the size of largeBlobs the authenticator stores.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - The allowed size must be at least 1024.
|
||||
/// - The array must fit into the shards reserved in storage/key.rs.
|
||||
pub const MAX_LARGE_BLOB_ARRAY_SIZE: usize = 2048;
|
||||
|
||||
/// Sets the number of resident keys you can store.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// - The storage key CREDENTIALS must fit at least this number of credentials.
|
||||
///
|
||||
/// Limiting the number of resident keys permits to ensure a minimum number of
|
||||
/// counter increments.
|
||||
/// Let:
|
||||
/// - P the number of pages (NUM_PAGES in the board definition)
|
||||
/// - K the maximum number of resident keys (MAX_SUPPORTED_RESIDENT_KEYS)
|
||||
/// - S the maximum size of a resident key (about 500)
|
||||
/// - C the number of erase cycles (10000)
|
||||
/// - I the minimum number of counter increments
|
||||
///
|
||||
/// We have: I = (P * 4084 - 5107 - K * S) / 8 * C
|
||||
///
|
||||
/// With P=20 and K=150, we have I=2M which is enough for 500 increments per day
|
||||
/// for 10 years.
|
||||
pub const MAX_SUPPORTED_RESIDENT_KEYS: usize = 150;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::assertions_on_constants)]
|
||||
fn test_invariants() {
|
||||
// Two invariants are currently tested in different files:
|
||||
// - storage.rs: if MAX_LARGE_BLOB_ARRAY_SIZE fits the shards
|
||||
// - storage/key.rs: if MAX_SUPPORTED_RESIDENT_KEYS fits CREDENTIALS
|
||||
assert!(MAX_CRED_BLOB_LENGTH >= 32);
|
||||
if let Some(count) = MAX_CREDENTIAL_COUNT_IN_LIST {
|
||||
assert!(count >= 1);
|
||||
}
|
||||
assert!(MAX_LARGE_BLOB_ARRAY_SIZE >= 1024);
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,11 @@ impl LargeBlobs {
|
||||
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_LENGTH);
|
||||
}
|
||||
if offset == 0 {
|
||||
// Checks for offset and length are already done in command.
|
||||
self.expected_length =
|
||||
length.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
|
||||
if self.expected_length > env.customization().max_large_blob_array_size() {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_LARGE_BLOB_STORAGE_FULL);
|
||||
}
|
||||
self.expected_next_offset = 0;
|
||||
}
|
||||
if offset != self.expected_next_offset {
|
||||
|
||||
@@ -20,7 +20,6 @@ mod credential_management;
|
||||
mod crypto_wrapper;
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
mod ctap1;
|
||||
pub mod customization;
|
||||
pub mod data_formats;
|
||||
pub mod hid;
|
||||
mod key_material;
|
||||
@@ -43,9 +42,6 @@ use self::command::{
|
||||
use self::config_command::process_config;
|
||||
use self::credential_management::process_credential_management;
|
||||
use self::crypto_wrapper::{aes256_cbc_decrypt, aes256_cbc_encrypt};
|
||||
use self::customization::{
|
||||
MAX_CREDENTIAL_COUNT_IN_LIST, MAX_CRED_BLOB_LENGTH, MAX_LARGE_BLOB_ARRAY_SIZE,
|
||||
};
|
||||
use self::data_formats::{
|
||||
AuthenticatorTransport, CoseKey, CoseSignature, CredentialProtectionPolicy,
|
||||
EnterpriseAttestationMode, GetAssertionExtensions, PackedAttestationStatement,
|
||||
@@ -776,7 +772,7 @@ impl CtapState {
|
||||
let has_cred_blob_output = extensions.cred_blob.is_some();
|
||||
let cred_blob = extensions
|
||||
.cred_blob
|
||||
.filter(|c| options.rk && c.len() <= MAX_CRED_BLOB_LENGTH);
|
||||
.filter(|c| options.rk && c.len() <= env.customization().max_cred_blob_length());
|
||||
let cred_blob_output = if has_cred_blob_output {
|
||||
Some(cred_blob.is_some())
|
||||
} else {
|
||||
@@ -1215,15 +1211,20 @@ impl CtapState {
|
||||
PinUvAuthProtocol::V2 as u64,
|
||||
PinUvAuthProtocol::V1 as u64,
|
||||
]),
|
||||
max_credential_count_in_list: MAX_CREDENTIAL_COUNT_IN_LIST.map(|c| c as u64),
|
||||
max_credential_count_in_list: env
|
||||
.customization()
|
||||
.max_credential_count_in_list()
|
||||
.map(|c| c as u64),
|
||||
max_credential_id_length: Some(CREDENTIAL_ID_SIZE as u64),
|
||||
transports: Some(vec![AuthenticatorTransport::Usb]),
|
||||
algorithms: Some(vec![ES256_CRED_PARAM]),
|
||||
max_serialized_large_blob_array: Some(MAX_LARGE_BLOB_ARRAY_SIZE as u64),
|
||||
max_serialized_large_blob_array: Some(
|
||||
env.customization().max_large_blob_array_size() as u64,
|
||||
),
|
||||
force_pin_change: Some(storage::has_force_pin_change(env)?),
|
||||
min_pin_length: storage::min_pin_length(env)?,
|
||||
firmware_version: None,
|
||||
max_cred_blob_length: Some(MAX_CRED_BLOB_LENGTH as u64),
|
||||
max_cred_blob_length: Some(env.customization().max_cred_blob_length() as u64),
|
||||
max_rp_ids_for_set_min_pin_length: Some(
|
||||
env.customization().max_rp_ids_length() as u64
|
||||
),
|
||||
@@ -1525,14 +1526,14 @@ mod test {
|
||||
},
|
||||
0x05 => env.customization().max_msg_size() as u64,
|
||||
0x06 => cbor_array![2, 1],
|
||||
0x07 => MAX_CREDENTIAL_COUNT_IN_LIST.map(|c| c as u64),
|
||||
0x07 => env.customization().max_credential_count_in_list().map(|c| c as u64),
|
||||
0x08 => CREDENTIAL_ID_SIZE as u64,
|
||||
0x09 => cbor_array!["usb"],
|
||||
0x0A => cbor_array![ES256_CRED_PARAM],
|
||||
0x0B => MAX_LARGE_BLOB_ARRAY_SIZE as u64,
|
||||
0x0B => env.customization().max_large_blob_array_size() as u64,
|
||||
0x0C => false,
|
||||
0x0D => storage::min_pin_length(&mut env).unwrap() as u64,
|
||||
0x0F => MAX_CRED_BLOB_LENGTH as u64,
|
||||
0x0F => env.customization().max_cred_blob_length() as u64,
|
||||
0x10 => env.customization().max_rp_ids_length() as u64,
|
||||
0x14 => storage::remaining_credentials(&mut env).unwrap() as u64,
|
||||
};
|
||||
@@ -1877,7 +1878,7 @@ mod test {
|
||||
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
|
||||
|
||||
let extensions = MakeCredentialExtensions {
|
||||
cred_blob: Some(vec![0xCB; MAX_CRED_BLOB_LENGTH + 1]),
|
||||
cred_blob: Some(vec![0xCB; env.customization().max_cred_blob_length() + 1]),
|
||||
..Default::default()
|
||||
};
|
||||
let mut make_credential_params = create_minimal_make_credential_parameters();
|
||||
|
||||
@@ -16,7 +16,6 @@ mod key;
|
||||
|
||||
use crate::api::customization::Customization;
|
||||
use crate::ctap::client_pin::PIN_AUTH_LENGTH;
|
||||
use crate::ctap::customization::{MAX_LARGE_BLOB_ARRAY_SIZE, MAX_SUPPORTED_RESIDENT_KEYS};
|
||||
use crate::ctap::data_formats::{
|
||||
extract_array, extract_text_string, CredentialProtectionPolicy, PublicKeyCredentialSource,
|
||||
PublicKeyCredentialUserEntity,
|
||||
@@ -90,7 +89,7 @@ pub fn get_credential(
|
||||
key: usize,
|
||||
) -> Result<PublicKeyCredentialSource, Ctap2StatusCode> {
|
||||
let min_key = key::CREDENTIALS.start;
|
||||
if key < min_key || key >= min_key + MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
if key < min_key || key >= min_key + env.customization().max_supported_resident_keys() {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
|
||||
}
|
||||
let credential_entry = env
|
||||
@@ -154,15 +153,16 @@ pub fn store_credential(
|
||||
env: &mut impl Env,
|
||||
new_credential: PublicKeyCredentialSource,
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
||||
// Holds the key of the existing credential if this is an update.
|
||||
let mut old_key = None;
|
||||
let min_key = key::CREDENTIALS.start;
|
||||
// Holds whether a key is used (indices are shifted by min_key).
|
||||
let mut keys = vec![false; MAX_SUPPORTED_RESIDENT_KEYS];
|
||||
let mut keys = vec![false; max_supported_resident_keys];
|
||||
let mut iter_result = Ok(());
|
||||
let iter = iter_credentials(env, &mut iter_result)?;
|
||||
for (key, credential) in iter {
|
||||
if key < min_key || key - min_key >= MAX_SUPPORTED_RESIDENT_KEYS || keys[key - min_key] {
|
||||
if key < min_key || key - min_key >= max_supported_resident_keys || keys[key - min_key] {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
|
||||
}
|
||||
keys[key - min_key] = true;
|
||||
@@ -176,14 +176,14 @@ pub fn store_credential(
|
||||
}
|
||||
}
|
||||
iter_result?;
|
||||
if old_key.is_none() && keys.iter().filter(|&&x| x).count() >= MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
if old_key.is_none() && keys.iter().filter(|&&x| x).count() >= max_supported_resident_keys {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_KEY_STORE_FULL);
|
||||
}
|
||||
let key = match old_key {
|
||||
// This is a new credential being added, we need to allocate a free key. We choose the
|
||||
// first available key.
|
||||
None => key::CREDENTIALS
|
||||
.take(MAX_SUPPORTED_RESIDENT_KEYS)
|
||||
.take(max_supported_resident_keys)
|
||||
.find(|key| !keys[key - min_key])
|
||||
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?,
|
||||
// This is an existing credential being updated, we reuse its key.
|
||||
@@ -233,7 +233,8 @@ pub fn count_credentials(env: &mut impl Env) -> Result<usize, Ctap2StatusCode> {
|
||||
|
||||
/// Returns the estimated number of credentials that can still be stored.
|
||||
pub fn remaining_credentials(env: &mut impl Env) -> Result<usize, Ctap2StatusCode> {
|
||||
MAX_SUPPORTED_RESIDENT_KEYS
|
||||
env.customization()
|
||||
.max_supported_resident_keys()
|
||||
.checked_sub(count_credentials(env)?)
|
||||
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)
|
||||
}
|
||||
@@ -459,7 +460,7 @@ pub fn commit_large_blob_array(
|
||||
large_blob_array: &[u8],
|
||||
) -> Result<(), Ctap2StatusCode> {
|
||||
// This input should have been caught at caller level.
|
||||
if large_blob_array.len() > MAX_LARGE_BLOB_ARRAY_SIZE {
|
||||
if large_blob_array.len() > env.customization().max_large_blob_array_size() {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
|
||||
}
|
||||
Ok(fragment::write(
|
||||
@@ -768,7 +769,7 @@ mod test {
|
||||
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
||||
|
||||
let mut credential_ids = vec![];
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
for i in 0..env.customization().max_supported_resident_keys() {
|
||||
let user_handle = (i as u32).to_ne_bytes().to_vec();
|
||||
let credential_source = create_credential_source(env.rng(), "example.com", user_handle);
|
||||
credential_ids.push(credential_source.credential_id.clone());
|
||||
@@ -835,7 +836,8 @@ mod test {
|
||||
let mut env = TestEnv::new();
|
||||
assert_eq!(count_credentials(&mut env).unwrap(), 0);
|
||||
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
||||
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(env.rng(), "example.com", user_handle);
|
||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||
@@ -844,7 +846,7 @@ mod test {
|
||||
let credential_source = create_credential_source(
|
||||
env.rng(),
|
||||
"example.com",
|
||||
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
|
||||
vec![max_supported_resident_keys as u8],
|
||||
);
|
||||
assert_eq!(
|
||||
store_credential(&mut env, credential_source),
|
||||
@@ -852,7 +854,7 @@ mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
count_credentials(&mut env).unwrap(),
|
||||
MAX_SUPPORTED_RESIDENT_KEYS
|
||||
max_supported_resident_keys
|
||||
);
|
||||
}
|
||||
|
||||
@@ -883,7 +885,8 @@ mod test {
|
||||
);
|
||||
|
||||
reset(&mut env).unwrap();
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
let max_supported_resident_keys = env.customization().max_supported_resident_keys();
|
||||
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(env.rng(), "example.com", user_handle);
|
||||
assert!(store_credential(&mut env, credential_source).is_ok());
|
||||
@@ -892,7 +895,7 @@ mod test {
|
||||
let credential_source = create_credential_source(
|
||||
env.rng(),
|
||||
"example.com",
|
||||
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
|
||||
vec![max_supported_resident_keys as u8],
|
||||
);
|
||||
assert_eq!(
|
||||
store_credential(&mut env, credential_source),
|
||||
@@ -900,7 +903,7 @@ mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
count_credentials(&mut env).unwrap(),
|
||||
MAX_SUPPORTED_RESIDENT_KEYS
|
||||
max_supported_resident_keys
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1147,7 +1150,7 @@ mod test {
|
||||
let mut env = TestEnv::new();
|
||||
|
||||
assert!(
|
||||
MAX_LARGE_BLOB_ARRAY_SIZE
|
||||
env.customization().max_large_blob_array_size()
|
||||
<= env.store().max_value_length()
|
||||
* (key::LARGE_BLOB_SHARDS.end - key::LARGE_BLOB_SHARDS.start)
|
||||
);
|
||||
|
||||
@@ -84,8 +84,9 @@ make_partition! {
|
||||
|
||||
/// The credentials.
|
||||
///
|
||||
/// Depending on `MAX_SUPPORTED_RESIDENT_KEYS`, only a prefix of those keys is used. Each
|
||||
/// board may configure `MAX_SUPPORTED_RESIDENT_KEYS` depending on the storage size.
|
||||
/// Depending on `Customization::max_supported_resident_keys()`, only a prefix of those keys is used.
|
||||
/// Each board may configure `Customization::max_supported_resident_keys()` depending on the
|
||||
/// storage size.
|
||||
CREDENTIALS = 1700..2000;
|
||||
|
||||
/// Storage for the serialized large blob array.
|
||||
@@ -138,11 +139,17 @@ make_partition! {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::api::customization::Customization;
|
||||
use crate::env::test::TestEnv;
|
||||
use crate::env::Env;
|
||||
|
||||
#[test]
|
||||
fn enough_credentials() {
|
||||
use crate::ctap::customization::MAX_SUPPORTED_RESIDENT_KEYS;
|
||||
assert!(MAX_SUPPORTED_RESIDENT_KEYS <= CREDENTIALS.end - CREDENTIALS.start);
|
||||
let env = TestEnv::new();
|
||||
assert!(
|
||||
env.customization().max_supported_resident_keys()
|
||||
<= CREDENTIALS.end - CREDENTIALS.start
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
28
src/env/test/customization.rs
vendored
28
src/env/test/customization.rs
vendored
@@ -14,7 +14,11 @@ pub struct TestCustomization {
|
||||
pub max_pin_retries: u8,
|
||||
pub use_batch_attestation: bool,
|
||||
pub use_signature_counter: bool,
|
||||
pub max_cred_blob_length: usize,
|
||||
pub max_credential_count_in_list: Option<usize>,
|
||||
pub max_large_blob_array_size: usize,
|
||||
pub max_rp_ids_length: usize,
|
||||
pub max_supported_resident_keys: usize,
|
||||
}
|
||||
|
||||
impl Customization for TestCustomization {
|
||||
@@ -62,9 +66,25 @@ impl Customization for TestCustomization {
|
||||
self.use_signature_counter
|
||||
}
|
||||
|
||||
fn max_cred_blob_length(&self) -> usize {
|
||||
self.max_cred_blob_length
|
||||
}
|
||||
|
||||
fn max_credential_count_in_list(&self) -> Option<usize> {
|
||||
self.max_credential_count_in_list
|
||||
}
|
||||
|
||||
fn max_large_blob_array_size(&self) -> usize {
|
||||
self.max_large_blob_array_size
|
||||
}
|
||||
|
||||
fn max_rp_ids_length(&self) -> usize {
|
||||
self.max_rp_ids_length
|
||||
}
|
||||
|
||||
fn max_supported_resident_keys(&self) -> usize {
|
||||
self.max_supported_resident_keys
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CustomizationImpl> for TestCustomization {
|
||||
@@ -80,7 +100,11 @@ impl From<CustomizationImpl> for TestCustomization {
|
||||
max_pin_retries,
|
||||
use_batch_attestation,
|
||||
use_signature_counter,
|
||||
max_cred_blob_length,
|
||||
max_credential_count_in_list,
|
||||
max_large_blob_array_size,
|
||||
max_rp_ids_length,
|
||||
max_supported_resident_keys,
|
||||
} = c;
|
||||
|
||||
let default_min_pin_length_rp_ids = default_min_pin_length_rp_ids
|
||||
@@ -104,7 +128,11 @@ impl From<CustomizationImpl> for TestCustomization {
|
||||
max_pin_retries,
|
||||
use_batch_attestation,
|
||||
use_signature_counter,
|
||||
max_cred_blob_length,
|
||||
max_credential_count_in_list,
|
||||
max_large_blob_array_size,
|
||||
max_rp_ids_length,
|
||||
max_supported_resident_keys,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user