Skip to content

Commit

Permalink
Merge pull request trussed-dev#12 from Nitrokey/max-credential-count
Browse files Browse the repository at this point in the history
Make maximum resident credential count configurable
  • Loading branch information
robin-nitrokey authored Apr 25, 2023
2 parents d47a7c1 + 9282539 commit 7f6a093
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 13 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
- Add config option for setting a maximum number of resident credentials.

## [0.1.1] - 2022-08-22
- Fix bug that treated U2F payloads as APDU over APDU in NFC transport @conorpp
- Add config option to skip UP when device was just booted,
as insertion is a kind of UP check @robin-nitrokey

## [Unreleased]
## [0.1.0] - 2022-03-17

- use 2021 edition
- use @szszszsz's credential ID shortening
Expand Down
2 changes: 2 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ pub const U2F_UP_TIMEOUT: u32 = 250;

pub const ATTESTATION_CERT_ID: CertId = CertId::from_special(0);
pub const ATTESTATION_KEY_ID: KeyId = KeyId::from_special(0);

pub const MAX_RESIDENT_CREDENTIALS_GUESSTIMATE: u32 = 100;
10 changes: 10 additions & 0 deletions src/ctap2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,16 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
self.delete_resident_key_by_user_id(&rp_id_hash, &credential.user.id)
.ok();

// then check the maximum number of RK credentials
if let Some(max_count) = self.config.max_resident_credential_count {
let mut cm = credential_management::CredentialManagement::new(self);
let metadata = cm.get_creds_metadata()?;
let count = metadata.existing_resident_credentials_count.unwrap_or(max_count);
if count >= max_count {
return Err(Error::KeyStoreFull);
}
}

// then store key, making it resident
let credential_id_hash = self.hash(credential_id.0.as_ref());
try_syscall!(self.trussed.write_file(
Expand Down
14 changes: 7 additions & 7 deletions src/ctap2/credential_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use ctap_types::{
};

use crate::{
constants::MAX_RESIDENT_CREDENTIALS_GUESSTIMATE,
credential::Credential,
state::{CredentialManagementEnumerateCredentials, CredentialManagementEnumerateRps},
Authenticator, Result, TrussedRequirements, UserPresence,
Expand Down Expand Up @@ -65,9 +66,12 @@ where
info!("get metadata");
let mut response: Response = Default::default();

let guesstimate = self.state.persistent.max_resident_credentials_guesstimate();
let max_resident_credentials = self
.config
.max_resident_credential_count
.unwrap_or(MAX_RESIDENT_CREDENTIALS_GUESSTIMATE);
response.existing_resident_credentials_count = Some(0);
response.max_possible_remaining_residential_credentials_count = Some(guesstimate);
response.max_possible_remaining_residential_credentials_count = Some(max_resident_credentials);

let dir = PathBuf::from(b"rk");
let maybe_first_rp =
Expand Down Expand Up @@ -96,11 +100,7 @@ where
None => {
response.existing_resident_credentials_count = Some(num_rks);
response.max_possible_remaining_residential_credentials_count =
Some(if num_rks >= guesstimate {
0
} else {
guesstimate - num_rks
});
Some(max_resident_credentials.saturating_sub(num_rks));
return Ok(response);
}
Some(rp) => {
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub struct Config {
/// If set, the first Get Assertion or Authenticate request within the specified time after
/// boot is accepted without additional user presence verification.
pub skip_up_timeout: Option<Duration>,
/// The maximum number of resident credentials.
pub max_resident_credential_count: Option<u32>,
}

// impl Default for Config {
Expand Down
5 changes: 0 additions & 5 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,6 @@ pub struct PersistentState {
impl PersistentState {
const RESET_RETRIES: u8 = 8;
const FILENAME: &'static [u8] = b"persistent-state.cbor";
const MAX_RESIDENT_CREDENTIALS_GUESSTIMATE: u32 = 100;

pub fn max_resident_credentials_guesstimate(&self) -> u32 {
Self::MAX_RESIDENT_CREDENTIALS_GUESSTIMATE
}

pub fn load<T: client::Client + client::Chacha8Poly1305>(trussed: &mut T) -> Result<Self> {
// TODO: add "exists_file" method instead?
Expand Down

0 comments on commit 7f6a093

Please sign in to comment.