Merge pull request #260 from kaczmarczyck/resident-naming

Resident naming
This commit is contained in:
kaczmarczyck
2021-01-14 18:18:36 +01:00
committed by GitHub
4 changed files with 27 additions and 32 deletions

View File

@@ -106,8 +106,7 @@ a few things you can personalize:
check [WebAuthn](https://www.w3.org/TR/webauthn/#signature-counter) for check [WebAuthn](https://www.w3.org/TR/webauthn/#signature-counter) for
documentation. documentation.
1. Depending on your available flash storage, choose an appropriate maximum 1. Depending on your available flash storage, choose an appropriate maximum
number of supported residential keys and number of pages in number of supported resident keys and number of pages in `ctap/storage.rs`.
`ctap/storage.rs`.
1. Change the default level for the credProtect extension in `ctap/mod.rs`. 1. Change the default level for the credProtect extension in `ctap/mod.rs`.
When changing the default, resident credentials become undiscoverable without When changing the default, resident credentials become undiscoverable without
user verification. This helps privacy, but can make usage less comfortable user verification. This helps privacy, but can make usage less comfortable

View File

@@ -1195,7 +1195,7 @@ mod test {
} }
#[test] #[test]
fn test_residential_process_make_credential() { fn test_resident_process_make_credential() {
let mut rng = ThreadRng256 {}; let mut rng = ThreadRng256 {};
let user_immediately_present = |_| Ok(()); let user_immediately_present = |_| Ok(());
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE); let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
@@ -1214,7 +1214,7 @@ mod test {
} }
#[test] #[test]
fn test_non_residential_process_make_credential() { fn test_non_resident_process_make_credential() {
let mut rng = ThreadRng256 {}; let mut rng = ThreadRng256 {};
let user_immediately_present = |_| Ok(()); let user_immediately_present = |_| Ok(());
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE); let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
@@ -1526,7 +1526,7 @@ mod test {
} }
#[test] #[test]
fn test_residential_process_get_assertion() { fn test_resident_process_get_assertion() {
let mut rng = ThreadRng256 {}; let mut rng = ThreadRng256 {};
let user_immediately_present = |_| Ok(()); let user_immediately_present = |_| Ok(());
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE); let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
@@ -1629,7 +1629,7 @@ mod test {
} }
#[test] #[test]
fn test_residential_process_get_assertion_hmac_secret() { fn test_resident_process_get_assertion_hmac_secret() {
let mut rng = ThreadRng256 {}; let mut rng = ThreadRng256 {};
let sk = crypto::ecdh::SecKey::gensk(&mut rng); let sk = crypto::ecdh::SecKey::gensk(&mut rng);
let user_immediately_present = |_| Ok(()); let user_immediately_present = |_| Ok(());
@@ -1681,7 +1681,7 @@ mod test {
} }
#[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 mut rng = ThreadRng256 {};
let private_key = crypto::ecdsa::SecKey::gensk(&mut rng); let private_key = crypto::ecdsa::SecKey::gensk(&mut rng);
let credential_id = rng.gen_uniform_u8x32().to_vec(); let credential_id = rng.gen_uniform_u8x32().to_vec();

View File

@@ -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 // 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. // 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: // Let:
// - P the number of pages (NUM_PAGES) // - P the number of pages (NUM_PAGES)
// - K the maximum number of residential keys (MAX_SUPPORTED_RESIDENTIAL_KEYS) // - K the maximum number of resident keys (MAX_SUPPORTED_RESIDENT_KEYS)
// - S the maximum size of a residential key (about 500) // - S the maximum size of a resident key (about 500)
// - C the number of erase cycles (10000) // - C the number of erase cycles (10000)
// - I the minimum number of counter increments // - 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. // 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 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 MAX_PIN_RETRIES: u8 = 8;
const DEFAULT_MIN_PIN_LENGTH: u8 = 4; 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. /// 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> { pub fn get_credential(&self, key: usize) -> Result<PublicKeyCredentialSource, Ctap2StatusCode> {
let min_key = key::CREDENTIALS.start; 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); return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
} }
let credential_entry = self let credential_entry = self
@@ -200,13 +200,11 @@ impl PersistentStore {
let mut old_key = None; let mut old_key = None;
let min_key = key::CREDENTIALS.start; let min_key = key::CREDENTIALS.start;
// Holds whether a key is used (indices are shifted by min_key). // 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 mut iter_result = Ok(());
let iter = self.iter_credentials(&mut iter_result)?; let iter = self.iter_credentials(&mut iter_result)?;
for (key, credential) in iter { for (key, credential) in iter {
if key < min_key if key < min_key || key - min_key >= MAX_SUPPORTED_RESIDENT_KEYS || keys[key - min_key]
|| key - min_key >= MAX_SUPPORTED_RESIDENTIAL_KEYS
|| keys[key - min_key]
{ {
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR); return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
} }
@@ -221,16 +219,14 @@ impl PersistentStore {
} }
} }
iter_result?; iter_result?;
if old_key.is_none() if old_key.is_none() && keys.iter().filter(|&&x| x).count() >= MAX_SUPPORTED_RESIDENT_KEYS {
&& keys.iter().filter(|&&x| x).count() >= MAX_SUPPORTED_RESIDENTIAL_KEYS
{
return Err(Ctap2StatusCode::CTAP2_ERR_KEY_STORE_FULL); return Err(Ctap2StatusCode::CTAP2_ERR_KEY_STORE_FULL);
} }
let key = match old_key { let key = match old_key {
// This is a new credential being added, we need to allocate a free key. We choose the // This is a new credential being added, we need to allocate a free key. We choose the
// first available key. // first available key.
None => key::CREDENTIALS None => key::CREDENTIALS
.take(MAX_SUPPORTED_RESIDENTIAL_KEYS) .take(MAX_SUPPORTED_RESIDENT_KEYS)
.find(|key| !keys[key - min_key]) .find(|key| !keys[key - min_key])
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?, .ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?,
// This is an existing credential being updated, we reuse its key. // 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. /// Returns the estimated number of credentials that can still be stored.
pub fn remaining_credentials(&self) -> Result<usize, Ctap2StatusCode> { pub fn remaining_credentials(&self) -> Result<usize, Ctap2StatusCode> {
MAX_SUPPORTED_RESIDENTIAL_KEYS MAX_SUPPORTED_RESIDENT_KEYS
.checked_sub(self.count_credentials()?) .checked_sub(self.count_credentials()?)
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR) .ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)
} }
@@ -714,7 +710,7 @@ mod test {
assert_eq!(persistent_store.count_credentials().unwrap(), 0); assert_eq!(persistent_store.count_credentials().unwrap(), 0);
let mut credential_ids = vec![]; 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 user_handle = i.to_ne_bytes().to_vec();
let credential_source = create_credential_source(&mut rng, "example.com", user_handle); let credential_source = create_credential_source(&mut rng, "example.com", user_handle);
credential_ids.push(credential_source.credential_id.clone()); credential_ids.push(credential_source.credential_id.clone());
@@ -788,7 +784,7 @@ mod test {
let mut persistent_store = PersistentStore::new(&mut rng); let mut persistent_store = PersistentStore::new(&mut rng);
assert_eq!(persistent_store.count_credentials().unwrap(), 0); 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 user_handle = i.to_ne_bytes().to_vec();
let credential_source = create_credential_source(&mut rng, "example.com", user_handle); let credential_source = create_credential_source(&mut rng, "example.com", user_handle);
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
@@ -797,7 +793,7 @@ mod test {
let credential_source = create_credential_source( let credential_source = create_credential_source(
&mut rng, &mut rng,
"example.com", "example.com",
vec![MAX_SUPPORTED_RESIDENTIAL_KEYS as u8], vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
); );
assert_eq!( assert_eq!(
persistent_store.store_credential(credential_source), persistent_store.store_credential(credential_source),
@@ -805,7 +801,7 @@ mod test {
); );
assert_eq!( assert_eq!(
persistent_store.count_credentials().unwrap(), persistent_store.count_credentials().unwrap(),
MAX_SUPPORTED_RESIDENTIAL_KEYS MAX_SUPPORTED_RESIDENT_KEYS
); );
} }
@@ -837,7 +833,7 @@ mod test {
.is_some()); .is_some());
let mut persistent_store = PersistentStore::new(&mut rng); 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 user_handle = i.to_ne_bytes().to_vec();
let credential_source = create_credential_source(&mut rng, "example.com", user_handle); let credential_source = create_credential_source(&mut rng, "example.com", user_handle);
assert!(persistent_store.store_credential(credential_source).is_ok()); assert!(persistent_store.store_credential(credential_source).is_ok());
@@ -846,7 +842,7 @@ mod test {
let credential_source = create_credential_source( let credential_source = create_credential_source(
&mut rng, &mut rng,
"example.com", "example.com",
vec![MAX_SUPPORTED_RESIDENTIAL_KEYS as u8], vec![MAX_SUPPORTED_RESIDENT_KEYS as u8],
); );
assert_eq!( assert_eq!(
persistent_store.store_credential(credential_source), persistent_store.store_credential(credential_source),
@@ -854,7 +850,7 @@ mod test {
); );
assert_eq!( assert_eq!(
persistent_store.count_credentials().unwrap(), persistent_store.count_credentials().unwrap(),
MAX_SUPPORTED_RESIDENTIAL_KEYS MAX_SUPPORTED_RESIDENT_KEYS
); );
} }

View File

@@ -84,8 +84,8 @@ make_partition! {
/// The credentials. /// The credentials.
/// ///
/// Depending on `MAX_SUPPORTED_RESIDENTIAL_KEYS`, only a prefix of those keys is used. Each /// Depending on `MAX_SUPPORTED_RESIDENT_KEYS`, only a prefix of those keys is used. Each
/// board may configure `MAX_SUPPORTED_RESIDENTIAL_KEYS` depending on the storage size. /// board may configure `MAX_SUPPORTED_RESIDENT_KEYS` depending on the storage size.
CREDENTIALS = 1700..2000; CREDENTIALS = 1700..2000;
/// The secret of the CredRandom feature. /// The secret of the CredRandom feature.
@@ -127,8 +127,8 @@ mod test {
#[test] #[test]
fn enough_credentials() { fn enough_credentials() {
use super::super::MAX_SUPPORTED_RESIDENTIAL_KEYS; use super::super::MAX_SUPPORTED_RESIDENT_KEYS;
assert!(MAX_SUPPORTED_RESIDENTIAL_KEYS <= CREDENTIALS.end - CREDENTIALS.start); assert!(MAX_SUPPORTED_RESIDENT_KEYS <= CREDENTIALS.end - CREDENTIALS.start);
} }
#[test] #[test]