Move three dependent customizations into new file

* default_min_pin_length(_rp_ids) and max_rp_ids_length

* Did some backing store tricks to make the list configurable in
  TestCustomization.
This commit is contained in:
Howard Yang
2022-04-14 18:17:45 +08:00
parent 74b472d9cb
commit 4da060f799
7 changed files with 187 additions and 69 deletions

View File

@@ -19,36 +19,6 @@
use crate::ctap::data_formats::EnterpriseAttestationMode;
// ###########################################################################
// Constants for adjusting privacy and protection levels.
// ###########################################################################
/// Sets the initial minimum PIN length in code points.
///
/// # Invariant
///
/// - The minimum PIN length must be at least 4.
/// - The minimum PIN length must be at most 63.
/// - DEFAULT_MIN_PIN_LENGTH_RP_IDS must be non-empty if MAX_RP_IDS_LENGTH is 0.
///
/// Requiring longer PINs can help establish trust between users and relying
/// parties. It makes user verification harder to break, but less convenient.
/// NIST recommends at least 6-digit PINs in section 5.1.9.1:
/// https://pages.nist.gov/800-63-3/sp800-63b.html
///
/// Reset reverts the minimum PIN length to this DEFAULT_MIN_PIN_LENGTH.
pub const DEFAULT_MIN_PIN_LENGTH: u8 = 4;
/// Lists relying parties that can read the minimum PIN length.
///
/// # Invariant
///
/// - DEFAULT_MIN_PIN_LENGTH_RP_IDS must be non-empty if MAX_RP_IDS_LENGTH is 0
///
/// Only the RP IDs listed in DEFAULT_MIN_PIN_LENGTH_RP_IDS are allowed to read
/// the minimum PIN length with the minPinLength extension.
pub const DEFAULT_MIN_PIN_LENGTH_RP_IDS: &[&str] = &[];
/// Enforces the alwaysUv option.
///
/// When setting to true, commands require a PIN.
@@ -171,21 +141,6 @@ pub const MAX_CREDENTIAL_COUNT_IN_LIST: Option<usize> = None;
/// - The array must fit into the shards reserved in storage/key.rs.
pub const MAX_LARGE_BLOB_ARRAY_SIZE: usize = 2048;
/// Limits the number of RP IDs that can change the minimum PIN length.
///
/// # Invariant
///
/// - If this value is 0, DEFAULT_MIN_PIN_LENGTH_RP_IDS must be non-empty.
///
/// You can use this constant to have an upper limit in storage requirements.
/// This might be useful if you want to more reliably predict the remaining
/// storage. Stored string can still be of arbitrary length though, until RP ID
/// truncation is implemented.
/// Outside of memory considerations, you can set this value to 0 if only RP IDs
/// in DEFAULT_MIN_PIN_LENGTH_RP_IDS should be allowed to change the minimum PIN
/// length.
pub const MAX_RP_IDS_LENGTH: usize = 8;
/// Sets the number of resident keys you can store.
///
/// # Invariant
@@ -217,8 +172,6 @@ mod test {
// 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!(DEFAULT_MIN_PIN_LENGTH >= 4);
assert!(DEFAULT_MIN_PIN_LENGTH <= 63);
assert!(!USE_BATCH_ATTESTATION || ENTERPRISE_ATTESTATION_MODE.is_none());
if let Some(EnterpriseAttestationMode::VendorFacilitated) = ENTERPRISE_ATTESTATION_MODE {
assert!(!ENTERPRISE_RP_ID_LIST.is_empty());
@@ -231,8 +184,5 @@ mod test {
assert!(count >= 1);
}
assert!(MAX_LARGE_BLOB_ARRAY_SIZE >= 1024);
if MAX_RP_IDS_LENGTH == 0 {
assert!(!DEFAULT_MIN_PIN_LENGTH_RP_IDS.is_empty());
}
}
}

View File

@@ -45,8 +45,7 @@ use self::credential_management::process_credential_management;
use self::crypto_wrapper::{aes256_cbc_decrypt, aes256_cbc_encrypt};
use self::customization::{
ENTERPRISE_ATTESTATION_MODE, ENTERPRISE_RP_ID_LIST, MAX_CREDENTIAL_COUNT_IN_LIST,
MAX_CRED_BLOB_LENGTH, MAX_LARGE_BLOB_ARRAY_SIZE, MAX_RP_IDS_LENGTH, USE_BATCH_ATTESTATION,
USE_SIGNATURE_COUNTER,
MAX_CRED_BLOB_LENGTH, MAX_LARGE_BLOB_ARRAY_SIZE, USE_BATCH_ATTESTATION, USE_SIGNATURE_COUNTER,
};
use self::data_formats::{
AuthenticatorTransport, CoseKey, CoseSignature, CredentialProtectionPolicy,
@@ -1224,7 +1223,9 @@ impl CtapState {
min_pin_length: storage::min_pin_length(env)?,
firmware_version: None,
max_cred_blob_length: Some(MAX_CRED_BLOB_LENGTH as u64),
max_rp_ids_for_set_min_pin_length: Some(MAX_RP_IDS_LENGTH as u64),
max_rp_ids_for_set_min_pin_length: Some(
env.customization().max_rp_ids_length() as u64
),
certifications: None,
remaining_discoverable_credentials: Some(
storage::remaining_credentials(env)? as u64
@@ -1531,7 +1532,7 @@ mod test {
0x0C => false,
0x0D => storage::min_pin_length(&mut env).unwrap() as u64,
0x0F => MAX_CRED_BLOB_LENGTH as u64,
0x10 => MAX_RP_IDS_LENGTH as u64,
0x10 => env.customization().max_rp_ids_length() as u64,
0x14 => storage::remaining_credentials(&mut env).unwrap() as u64,
};

View File

@@ -14,10 +14,10 @@
mod key;
use crate::api::customization::Customization;
use crate::ctap::client_pin::PIN_AUTH_LENGTH;
use crate::ctap::customization::{
DEFAULT_MIN_PIN_LENGTH, DEFAULT_MIN_PIN_LENGTH_RP_IDS, ENFORCE_ALWAYS_UV,
MAX_LARGE_BLOB_ARRAY_SIZE, MAX_PIN_RETRIES, MAX_RP_IDS_LENGTH, MAX_SUPPORTED_RESIDENT_KEYS,
ENFORCE_ALWAYS_UV, MAX_LARGE_BLOB_ARRAY_SIZE, MAX_PIN_RETRIES, MAX_SUPPORTED_RESIDENT_KEYS,
};
use crate::ctap::data_formats::{
extract_array, extract_text_string, CredentialProtectionPolicy, PublicKeyCredentialSource,
@@ -384,7 +384,7 @@ pub fn reset_pin_retries(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
/// Returns the minimum PIN length.
pub fn min_pin_length(env: &mut impl Env) -> Result<u8, Ctap2StatusCode> {
match env.store().find(key::MIN_PIN_LENGTH)? {
None => Ok(DEFAULT_MIN_PIN_LENGTH),
None => Ok(env.customization().default_min_pin_length()),
Some(value) if value.len() == 1 => Ok(value[0]),
_ => Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR),
}
@@ -401,7 +401,8 @@ pub fn min_pin_length_rp_ids(env: &mut impl Env) -> Result<Vec<String>, Ctap2Sta
let rp_ids = env.store().find(key::MIN_PIN_LENGTH_RP_IDS)?.map_or_else(
|| {
Some(
DEFAULT_MIN_PIN_LENGTH_RP_IDS
env.customization()
.default_min_pin_length_rp_ids()
.iter()
.map(|&s| String::from(s))
.collect(),
@@ -419,13 +420,13 @@ pub fn set_min_pin_length_rp_ids(
min_pin_length_rp_ids: Vec<String>,
) -> Result<(), Ctap2StatusCode> {
let mut min_pin_length_rp_ids = min_pin_length_rp_ids;
for &rp_id in DEFAULT_MIN_PIN_LENGTH_RP_IDS.iter() {
for &rp_id in env.customization().default_min_pin_length_rp_ids().iter() {
let rp_id = String::from(rp_id);
if !min_pin_length_rp_ids.contains(&rp_id) {
min_pin_length_rp_ids.push(rp_id);
}
}
if min_pin_length_rp_ids.len() > MAX_RP_IDS_LENGTH {
if min_pin_length_rp_ids.len() > env.customization().max_rp_ids_length() {
return Err(Ctap2StatusCode::CTAP2_ERR_KEY_STORE_FULL);
}
Ok(env.store().insert(
@@ -1111,7 +1112,10 @@ mod test {
let mut env = TestEnv::new();
// The minimum PIN length is initially at the default.
assert_eq!(min_pin_length(&mut env).unwrap(), DEFAULT_MIN_PIN_LENGTH);
assert_eq!(
min_pin_length(&mut env).unwrap(),
env.customization().default_min_pin_length()
);
// Changes by the setter are reflected by the getter..
let new_min_pin_length = 8;
@@ -1126,13 +1130,13 @@ mod test {
// The minimum PIN length RP IDs are initially at the default.
assert_eq!(
min_pin_length_rp_ids(&mut env).unwrap(),
DEFAULT_MIN_PIN_LENGTH_RP_IDS
env.customization().default_min_pin_length_rp_ids()
);
// Changes by the setter are reflected by the getter.
let mut rp_ids = vec![String::from("example.com")];
assert_eq!(set_min_pin_length_rp_ids(&mut env, rp_ids.clone()), Ok(()));
for &rp_id in DEFAULT_MIN_PIN_LENGTH_RP_IDS.iter() {
for &rp_id in env.customization().default_min_pin_length_rp_ids().iter() {
let rp_id = String::from(rp_id);
if !rp_ids.contains(&rp_id) {
rp_ids.push(rp_id);

View File

@@ -110,7 +110,7 @@ make_partition! {
/// The minimum PIN length.
///
/// If the entry is absent, the minimum PIN length is `DEFAULT_MIN_PIN_LENGTH`.
/// If the entry is absent, the minimum PIN length is `Customization::default_min_pin_length()`.
MIN_PIN_LENGTH = 2043;
/// The number of PIN retries.