Merge branch 'develop' into command-cred-mgmt
This commit is contained in:
@@ -106,8 +106,7 @@ a few things you can personalize:
|
||||
check [WebAuthn](https://www.w3.org/TR/webauthn/#signature-counter) for
|
||||
documentation.
|
||||
1. Depending on your available flash storage, choose an appropriate maximum
|
||||
number of supported residential keys and number of pages in
|
||||
`ctap/storage.rs`.
|
||||
number of supported resident keys and number of pages in `ctap/storage.rs`.
|
||||
1. Change the default level for the credProtect extension in `ctap/mod.rs`.
|
||||
When changing the default, resident credentials become undiscoverable without
|
||||
user verification. This helps privacy, but can make usage less comfortable
|
||||
|
||||
@@ -1222,7 +1222,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_residential_process_make_credential() {
|
||||
fn test_resident_process_make_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
@@ -1241,7 +1241,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_residential_process_make_credential() {
|
||||
fn test_non_resident_process_make_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
@@ -1553,7 +1553,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_residential_process_get_assertion() {
|
||||
fn test_resident_process_get_assertion() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
@@ -1656,7 +1656,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_residential_process_get_assertion_hmac_secret() {
|
||||
fn test_resident_process_get_assertion_hmac_secret() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let user_immediately_present = |_| Ok(());
|
||||
@@ -1708,7 +1708,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_residential_process_get_assertion_with_cred_protect() {
|
||||
fn test_resident_process_get_assertion_with_cred_protect() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let private_key = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let credential_id = rng.gen_uniform_u8x32().to_vec();
|
||||
|
||||
@@ -38,11 +38,11 @@ use crypto::rng256::Rng256;
|
||||
// number of pages. This may improve in the future. Currently, using 20 pages gives between 20ms and
|
||||
// 240ms per operation. The rule of thumb is between 1ms and 12ms per additional page.
|
||||
//
|
||||
// Limiting the number of residential keys permits to ensure a minimum number of counter increments.
|
||||
// Limiting the number of resident keys permits to ensure a minimum number of counter increments.
|
||||
// Let:
|
||||
// - P the number of pages (NUM_PAGES)
|
||||
// - K the maximum number of residential keys (MAX_SUPPORTED_RESIDENTIAL_KEYS)
|
||||
// - S the maximum size of a residential key (about 500)
|
||||
// - 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
|
||||
//
|
||||
@@ -50,7 +50,7 @@ use crypto::rng256::Rng256;
|
||||
//
|
||||
// With P=20 and K=150, we have I=2M which is enough for 500 increments per day for 10 years.
|
||||
const NUM_PAGES: usize = 20;
|
||||
const MAX_SUPPORTED_RESIDENTIAL_KEYS: usize = 150;
|
||||
const MAX_SUPPORTED_RESIDENT_KEYS: usize = 150;
|
||||
|
||||
const MAX_PIN_RETRIES: u8 = 8;
|
||||
const DEFAULT_MIN_PIN_LENGTH: u8 = 4;
|
||||
@@ -132,7 +132,7 @@ impl PersistentStore {
|
||||
/// Returns `CTAP2_ERR_VENDOR_INTERNAL_ERROR` if the key does not hold a valid credential.
|
||||
pub fn get_credential(&self, key: usize) -> Result<PublicKeyCredentialSource, Ctap2StatusCode> {
|
||||
let min_key = key::CREDENTIALS.start;
|
||||
if key < min_key || key >= min_key + MAX_SUPPORTED_RESIDENTIAL_KEYS {
|
||||
if key < min_key || key >= min_key + MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
|
||||
}
|
||||
let credential_entry = self
|
||||
@@ -200,13 +200,11 @@ impl PersistentStore {
|
||||
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_RESIDENTIAL_KEYS];
|
||||
let mut keys = vec![false; MAX_SUPPORTED_RESIDENT_KEYS];
|
||||
let mut iter_result = Ok(());
|
||||
let iter = self.iter_credentials(&mut iter_result)?;
|
||||
for (key, credential) in iter {
|
||||
if key < min_key
|
||||
|| key - min_key >= MAX_SUPPORTED_RESIDENTIAL_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);
|
||||
}
|
||||
@@ -221,16 +219,14 @@ impl PersistentStore {
|
||||
}
|
||||
}
|
||||
iter_result?;
|
||||
if old_key.is_none()
|
||||
&& keys.iter().filter(|&&x| x).count() >= MAX_SUPPORTED_RESIDENTIAL_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_RESIDENTIAL_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.
|
||||
@@ -280,7 +276,7 @@ impl PersistentStore {
|
||||
|
||||
/// Returns the estimated number of credentials that can still be stored.
|
||||
pub fn remaining_credentials(&self) -> Result<usize, Ctap2StatusCode> {
|
||||
MAX_SUPPORTED_RESIDENTIAL_KEYS
|
||||
MAX_SUPPORTED_RESIDENT_KEYS
|
||||
.checked_sub(self.count_credentials()?)
|
||||
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)
|
||||
}
|
||||
@@ -714,7 +710,7 @@ mod test {
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), 0);
|
||||
|
||||
let mut credential_ids = vec![];
|
||||
for i in 0..MAX_SUPPORTED_RESIDENTIAL_KEYS {
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
let user_handle = i.to_ne_bytes().to_vec();
|
||||
let credential_source = create_credential_source(&mut rng, "example.com", user_handle);
|
||||
credential_ids.push(credential_source.credential_id.clone());
|
||||
@@ -788,7 +784,7 @@ mod test {
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
assert_eq!(persistent_store.count_credentials().unwrap(), 0);
|
||||
|
||||
for i in 0..MAX_SUPPORTED_RESIDENTIAL_KEYS {
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
let user_handle = i.to_ne_bytes().to_vec();
|
||||
let credential_source = create_credential_source(&mut rng, "example.com", user_handle);
|
||||
assert!(persistent_store.store_credential(credential_source).is_ok());
|
||||
@@ -797,7 +793,7 @@ mod test {
|
||||
let credential_source = create_credential_source(
|
||||
&mut rng,
|
||||
"example.com",
|
||||
vec![MAX_SUPPORTED_RESIDENTIAL_KEYS as u8],
|
||||
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
|
||||
);
|
||||
assert_eq!(
|
||||
persistent_store.store_credential(credential_source),
|
||||
@@ -805,7 +801,7 @@ mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
persistent_store.count_credentials().unwrap(),
|
||||
MAX_SUPPORTED_RESIDENTIAL_KEYS
|
||||
MAX_SUPPORTED_RESIDENT_KEYS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -837,7 +833,7 @@ mod test {
|
||||
.is_some());
|
||||
|
||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||
for i in 0..MAX_SUPPORTED_RESIDENTIAL_KEYS {
|
||||
for i in 0..MAX_SUPPORTED_RESIDENT_KEYS {
|
||||
let user_handle = i.to_ne_bytes().to_vec();
|
||||
let credential_source = create_credential_source(&mut rng, "example.com", user_handle);
|
||||
assert!(persistent_store.store_credential(credential_source).is_ok());
|
||||
@@ -846,7 +842,7 @@ mod test {
|
||||
let credential_source = create_credential_source(
|
||||
&mut rng,
|
||||
"example.com",
|
||||
vec![MAX_SUPPORTED_RESIDENTIAL_KEYS as u8],
|
||||
vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
|
||||
);
|
||||
assert_eq!(
|
||||
persistent_store.store_credential(credential_source),
|
||||
@@ -854,7 +850,7 @@ mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
persistent_store.count_credentials().unwrap(),
|
||||
MAX_SUPPORTED_RESIDENTIAL_KEYS
|
||||
MAX_SUPPORTED_RESIDENT_KEYS
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ make_partition! {
|
||||
|
||||
/// The credentials.
|
||||
///
|
||||
/// Depending on `MAX_SUPPORTED_RESIDENTIAL_KEYS`, only a prefix of those keys is used. Each
|
||||
/// board may configure `MAX_SUPPORTED_RESIDENTIAL_KEYS` depending on the storage size.
|
||||
/// 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.
|
||||
CREDENTIALS = 1700..2000;
|
||||
|
||||
/// The secret of the CredRandom feature.
|
||||
@@ -127,8 +127,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn enough_credentials() {
|
||||
use super::super::MAX_SUPPORTED_RESIDENTIAL_KEYS;
|
||||
assert!(MAX_SUPPORTED_RESIDENTIAL_KEYS <= CREDENTIALS.end - CREDENTIALS.start);
|
||||
use super::super::MAX_SUPPORTED_RESIDENT_KEYS;
|
||||
assert!(MAX_SUPPORTED_RESIDENT_KEYS <= CREDENTIALS.end - CREDENTIALS.start);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user