Removes timer updates from CTAP API (#597)

* Removes timer updates from CTAP API

* helper function for timer check
This commit is contained in:
kaczmarczyck
2023-03-01 14:30:04 +01:00
committed by GitHub
parent 73c60d8740
commit 9a2ef0bf75
4 changed files with 24 additions and 25 deletions

View File

@@ -158,7 +158,7 @@ fn process_enumerate_rps_get_next_rp<E: Env>(
env: &mut E, env: &mut E,
stateful_command_permission: &mut StatefulPermission<E>, stateful_command_permission: &mut StatefulPermission<E>,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
let rp_id_index = stateful_command_permission.next_enumerate_rp()?; let rp_id_index = stateful_command_permission.next_enumerate_rp(env)?;
let rp_set = get_stored_rp_ids(env)?; let rp_set = get_stored_rp_ids(env)?;
// A BTreeSet is already sorted. // A BTreeSet is already sorted.
let rp_id = rp_set let rp_id = rp_set
@@ -213,7 +213,7 @@ fn process_enumerate_credentials_get_next_credential<E: Env>(
env: &mut E, env: &mut E,
stateful_command_permission: &mut StatefulPermission<E>, stateful_command_permission: &mut StatefulPermission<E>,
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> { ) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
let credential_key = stateful_command_permission.next_enumerate_credential()?; let credential_key = stateful_command_permission.next_enumerate_credential(env)?;
let credential = storage::get_credential(env, credential_key)?; let credential = storage::get_credential(env, credential_key)?;
enumerate_credentials_response(env, credential, None) enumerate_credentials_response(env, credential, None)
} }
@@ -264,7 +264,7 @@ pub fn process_credential_management<E: Env>(
pin_uv_auth_param, pin_uv_auth_param,
} = cred_management_params; } = cred_management_params;
match (sub_command, stateful_command_permission.get_command()) { match (sub_command, stateful_command_permission.get_command(env)) {
( (
CredentialManagementSubCommand::EnumerateRpsGetNextRp, CredentialManagementSubCommand::EnumerateRpsGetNextRp,
Ok(StatefulCommand::EnumerateRps(_)), Ok(StatefulCommand::EnumerateRps(_)),

View File

@@ -395,7 +395,7 @@ impl<E: Env> StatefulPermission<E> {
// If we wanted to switch to (B) or (C), we'd have to be very careful that the state does // If we wanted to switch to (B) or (C), we'd have to be very careful that the state does
// not go stale. For example, we keep credential keys that we expect to still exist. // not go stale. For example, we keep credential keys that we expect to still exist.
// However, interleaving (stateless) commands could delete credentials or change the PIN, // However, interleaving (stateless) commands could delete credentials or change the PIN,
// which chould make invalidate our access. Some read-only commands should be okay to run, // which could invalidate our access. Some read-only commands should be okay to run,
// but (A) is the safest and easiest solution. // but (A) is the safest and easiest solution.
if let Some(c) = &self.channel { if let Some(c) = &self.channel {
if c != channel { if c != channel {
@@ -405,14 +405,15 @@ impl<E: Env> StatefulPermission<E> {
} }
/// Clears all state if the permission timed out. /// Clears all state if the permission timed out.
pub fn clear_timer(&mut self, env: &mut E) { fn clear_timer(&mut self, env: &mut E) {
if env.clock().is_elapsed(&self.permission) { if env.clock().is_elapsed(&self.permission) {
self.clear(); self.clear();
} }
} }
/// Gets a reference to the current command state, if any exists. /// Gets a reference to the current command state, if any exists.
pub fn get_command(&self) -> Result<&StatefulCommand, Ctap2StatusCode> { pub fn get_command(&mut self, env: &mut E) -> Result<&StatefulCommand, Ctap2StatusCode> {
self.clear_timer(env);
self.command_type self.command_type
.as_ref() .as_ref()
.ok_or(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED) .ok_or(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)
@@ -442,7 +443,9 @@ impl<E: Env> StatefulPermission<E> {
/// to the next credential that needs to be processed. /// to the next credential that needs to be processed.
pub fn next_assertion_credential( pub fn next_assertion_credential(
&mut self, &mut self,
env: &mut E,
) -> Result<(AssertionInput, usize), Ctap2StatusCode> { ) -> Result<(AssertionInput, usize), Ctap2StatusCode> {
self.clear_timer(env);
if let Some(StatefulCommand::GetAssertion(assertion_state)) = &mut self.command_type { if let Some(StatefulCommand::GetAssertion(assertion_state)) = &mut self.command_type {
let credential_key = assertion_state let credential_key = assertion_state
.next_credential_keys .next_credential_keys
@@ -455,7 +458,8 @@ impl<E: Env> StatefulPermission<E> {
} }
/// Returns the index to the next RP ID for enumeration and advances it. /// Returns the index to the next RP ID for enumeration and advances it.
pub fn next_enumerate_rp(&mut self) -> Result<usize, Ctap2StatusCode> { pub fn next_enumerate_rp(&mut self, env: &mut E) -> Result<usize, Ctap2StatusCode> {
self.clear_timer(env);
if let Some(StatefulCommand::EnumerateRps(rp_id_index)) = &mut self.command_type { if let Some(StatefulCommand::EnumerateRps(rp_id_index)) = &mut self.command_type {
let current_index = *rp_id_index; let current_index = *rp_id_index;
*rp_id_index += 1; *rp_id_index += 1;
@@ -466,7 +470,8 @@ impl<E: Env> StatefulPermission<E> {
} }
/// Returns the next storage credential key for enumeration and advances it. /// Returns the next storage credential key for enumeration and advances it.
pub fn next_enumerate_credential(&mut self) -> Result<usize, Ctap2StatusCode> { pub fn next_enumerate_credential(&mut self, env: &mut E) -> Result<usize, Ctap2StatusCode> {
self.clear_timer(env);
if let Some(StatefulCommand::EnumerateCredentials(rp_credentials)) = &mut self.command_type if let Some(StatefulCommand::EnumerateCredentials(rp_credentials)) = &mut self.command_type
{ {
rp_credentials rp_credentials
@@ -502,11 +507,6 @@ impl<E: Env> CtapState<E> {
} }
} }
pub fn update_timeouts(&mut self, env: &mut E) {
self.stateful_command_permission.clear_timer(env);
self.client_pin.update_timeouts(env);
}
pub fn increment_global_signature_counter( pub fn increment_global_signature_counter(
&mut self, &mut self,
env: &mut E, env: &mut E,
@@ -560,6 +560,9 @@ impl<E: Env> CtapState<E> {
command: Command, command: Command,
channel: Channel, channel: Channel,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
// The auth token timeouts are checked once here, to make error codes consistent. If your
// auth token hasn't timed out now, you can fully use it for this command.
self.client_pin.update_timeouts(env);
// Correct behavior between CTAP1 and CTAP2 isn't defined yet. Just a guess. // Correct behavior between CTAP1 and CTAP2 isn't defined yet. Just a guess.
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
{ {
@@ -569,8 +572,7 @@ impl<E: Env> CtapState<E> {
} }
self.stateful_command_permission self.stateful_command_permission
.clear_old_channels(&channel); .clear_old_channels(&channel);
self.stateful_command_permission.clear_timer(env); match (&command, self.stateful_command_permission.get_command(env)) {
match (&command, self.stateful_command_permission.get_command()) {
(Command::AuthenticatorGetNextAssertion, Ok(StatefulCommand::GetAssertion(_))) (Command::AuthenticatorGetNextAssertion, Ok(StatefulCommand::GetAssertion(_)))
| (Command::AuthenticatorReset, Ok(StatefulCommand::Reset)) | (Command::AuthenticatorReset, Ok(StatefulCommand::Reset))
// AuthenticatorGetInfo still allows Reset. // AuthenticatorGetInfo still allows Reset.
@@ -1213,7 +1215,7 @@ impl<E: Env> CtapState<E> {
fn process_get_next_assertion(&mut self, env: &mut E) -> Result<ResponseData, Ctap2StatusCode> { fn process_get_next_assertion(&mut self, env: &mut E) -> Result<ResponseData, Ctap2StatusCode> {
let (assertion_input, credential_key) = self let (assertion_input, credential_key) = self
.stateful_command_permission .stateful_command_permission
.next_assertion_credential()?; .next_assertion_credential(env)?;
let credential = storage::get_credential(env, credential_key)?; let credential = storage::get_credential(env, credential_key)?;
self.assertion_response(env, credential, assertion_input, None, true) self.assertion_response(env, credential, assertion_input, None, true)
} }
@@ -1295,9 +1297,11 @@ impl<E: Env> CtapState<E> {
env: &mut E, env: &mut E,
channel: Channel, channel: Channel,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
match self.stateful_command_permission.get_command()? { if !matches!(
StatefulCommand::Reset => (), self.stateful_command_permission.get_command(env)?,
_ => return Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED), StatefulCommand::Reset
) {
return Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED);
} }
check_user_presence(env, channel)?; check_user_presence(env, channel)?;

View File

@@ -107,10 +107,6 @@ impl<E: Env> Ctap<E> {
} }
} }
pub fn update_timeouts(&mut self) {
self.state.update_timeouts(&mut self.env);
}
pub fn should_wink(&mut self) -> bool { pub fn should_wink(&mut self) -> bool {
self.hid.should_wink(&mut self.env) self.hid.should_wink(&mut self.env)
} }

View File

@@ -213,9 +213,8 @@ fn main() {
drop(buttons_callback); drop(buttons_callback);
} }
// These calls are making sure that even for long inactivity, wrapping clock values // This call is making sure that even for long inactivity, wrapping clock values
// don't cause problems with timers. // don't cause problems with timers.
ctap.update_timeouts();
ctap.env().clock().tickle(); ctap.env().clock().tickle();
if let Some(endpoint) = usb_endpoint { if let Some(endpoint) = usb_endpoint {