reworks command state to its own struct
This commit is contained in:
@@ -22,11 +22,7 @@ use super::pin_protocol_v1::{PinPermission, PinProtocolV1};
|
|||||||
use super::response::{AuthenticatorCredentialManagementResponse, ResponseData};
|
use super::response::{AuthenticatorCredentialManagementResponse, ResponseData};
|
||||||
use super::status_code::Ctap2StatusCode;
|
use super::status_code::Ctap2StatusCode;
|
||||||
use super::storage::PersistentStore;
|
use super::storage::PersistentStore;
|
||||||
use super::timed_permission::TimedPermission;
|
use super::{check_pin_uv_auth_protocol, StatefulCommand, StatefulPermission};
|
||||||
use super::{
|
|
||||||
check_command_permission, check_pin_uv_auth_protocol, StatefulCommand,
|
|
||||||
STATEFUL_COMMAND_TIMEOUT_DURATION,
|
|
||||||
};
|
|
||||||
use alloc::collections::BTreeSet;
|
use alloc::collections::BTreeSet;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
@@ -125,8 +121,7 @@ fn process_get_creds_metadata(
|
|||||||
/// Processes the subcommand enumerateRPsBegin for CredentialManagement.
|
/// Processes the subcommand enumerateRPsBegin for CredentialManagement.
|
||||||
fn process_enumerate_rps_begin(
|
fn process_enumerate_rps_begin(
|
||||||
persistent_store: &PersistentStore,
|
persistent_store: &PersistentStore,
|
||||||
stateful_command_permission: &mut TimedPermission,
|
stateful_command_permission: &mut StatefulPermission,
|
||||||
stateful_command_type: &mut Option<StatefulCommand>,
|
|
||||||
now: ClockValue,
|
now: ClockValue,
|
||||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||||
let rp_set = get_stored_rp_ids(persistent_store)?;
|
let rp_set = get_stored_rp_ids(persistent_store)?;
|
||||||
@@ -134,9 +129,7 @@ fn process_enumerate_rps_begin(
|
|||||||
|
|
||||||
// TODO(kaczmarczyck) should we return CTAP2_ERR_NO_CREDENTIALS if empty?
|
// TODO(kaczmarczyck) should we return CTAP2_ERR_NO_CREDENTIALS if empty?
|
||||||
if total_rps > 1 {
|
if total_rps > 1 {
|
||||||
*stateful_command_permission =
|
stateful_command_permission.set_command(now, StatefulCommand::EnumerateRps(1));
|
||||||
TimedPermission::granted(now, STATEFUL_COMMAND_TIMEOUT_DURATION);
|
|
||||||
*stateful_command_type = Some(StatefulCommand::EnumerateRps(1));
|
|
||||||
}
|
}
|
||||||
// TODO https://github.com/rust-lang/rust/issues/62924 replace with pop_first()
|
// TODO https://github.com/rust-lang/rust/issues/62924 replace with pop_first()
|
||||||
enumerate_rps_response(rp_set.into_iter().next(), Some(total_rps as u64))
|
enumerate_rps_response(rp_set.into_iter().next(), Some(total_rps as u64))
|
||||||
@@ -145,19 +138,16 @@ fn process_enumerate_rps_begin(
|
|||||||
/// Processes the subcommand enumerateRPsGetNextRP for CredentialManagement.
|
/// Processes the subcommand enumerateRPsGetNextRP for CredentialManagement.
|
||||||
fn process_enumerate_rps_get_next_rp(
|
fn process_enumerate_rps_get_next_rp(
|
||||||
persistent_store: &PersistentStore,
|
persistent_store: &PersistentStore,
|
||||||
stateful_command_permission: &mut TimedPermission,
|
stateful_command_permission: &mut StatefulPermission,
|
||||||
stateful_command_type: &mut Option<StatefulCommand>,
|
|
||||||
now: ClockValue,
|
|
||||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||||
check_command_permission(stateful_command_permission, now)?;
|
if let StatefulCommand::EnumerateRps(rp_id_index) = stateful_command_permission.get_command()? {
|
||||||
if let Some(StatefulCommand::EnumerateRps(rp_id_index)) = stateful_command_type {
|
|
||||||
let rp_set = get_stored_rp_ids(persistent_store)?;
|
let rp_set = get_stored_rp_ids(persistent_store)?;
|
||||||
// A BTreeSet is already sorted.
|
// A BTreeSet is already sorted.
|
||||||
let rp_id = rp_set
|
let rp_id = rp_set
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.nth(*rp_id_index)
|
.nth(*rp_id_index)
|
||||||
.ok_or(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)?;
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)?;
|
||||||
*stateful_command_type = Some(StatefulCommand::EnumerateRps(*rp_id_index + 1));
|
*rp_id_index += 1;
|
||||||
enumerate_rps_response(Some(rp_id), None)
|
enumerate_rps_response(Some(rp_id), None)
|
||||||
} else {
|
} else {
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)
|
Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)
|
||||||
@@ -167,8 +157,7 @@ fn process_enumerate_rps_get_next_rp(
|
|||||||
/// Processes the subcommand enumerateCredentialsBegin for CredentialManagement.
|
/// Processes the subcommand enumerateCredentialsBegin for CredentialManagement.
|
||||||
fn process_enumerate_credentials_begin(
|
fn process_enumerate_credentials_begin(
|
||||||
persistent_store: &PersistentStore,
|
persistent_store: &PersistentStore,
|
||||||
stateful_command_permission: &mut TimedPermission,
|
stateful_command_permission: &mut StatefulPermission,
|
||||||
stateful_command_type: &mut Option<StatefulCommand>,
|
|
||||||
sub_command_params: CredentialManagementSubCommandParameters,
|
sub_command_params: CredentialManagementSubCommandParameters,
|
||||||
now: ClockValue,
|
now: ClockValue,
|
||||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||||
@@ -194,9 +183,8 @@ fn process_enumerate_credentials_begin(
|
|||||||
.ok_or(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)?;
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)?;
|
||||||
let credential = persistent_store.get_credential(current_key)?;
|
let credential = persistent_store.get_credential(current_key)?;
|
||||||
if total_credentials > 1 {
|
if total_credentials > 1 {
|
||||||
*stateful_command_permission =
|
stateful_command_permission
|
||||||
TimedPermission::granted(now, STATEFUL_COMMAND_TIMEOUT_DURATION);
|
.set_command(now, StatefulCommand::EnumerateCredentials(rp_credentials));
|
||||||
*stateful_command_type = Some(StatefulCommand::EnumerateCredentials(rp_credentials));
|
|
||||||
}
|
}
|
||||||
enumerate_credentials_response(credential, Some(total_credentials as u64))
|
enumerate_credentials_response(credential, Some(total_credentials as u64))
|
||||||
}
|
}
|
||||||
@@ -204,12 +192,10 @@ fn process_enumerate_credentials_begin(
|
|||||||
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
|
/// Processes the subcommand enumerateCredentialsGetNextCredential for CredentialManagement.
|
||||||
fn process_enumerate_credentials_get_next_credential(
|
fn process_enumerate_credentials_get_next_credential(
|
||||||
persistent_store: &PersistentStore,
|
persistent_store: &PersistentStore,
|
||||||
stateful_command_permission: &mut TimedPermission,
|
stateful_command_permission: &mut StatefulPermission,
|
||||||
mut stateful_command_type: &mut Option<StatefulCommand>,
|
|
||||||
now: ClockValue,
|
|
||||||
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
) -> Result<AuthenticatorCredentialManagementResponse, Ctap2StatusCode> {
|
||||||
check_command_permission(stateful_command_permission, now)?;
|
if let StatefulCommand::EnumerateCredentials(rp_credentials) =
|
||||||
if let Some(StatefulCommand::EnumerateCredentials(rp_credentials)) = &mut stateful_command_type
|
stateful_command_permission.get_command()?
|
||||||
{
|
{
|
||||||
let current_key = rp_credentials
|
let current_key = rp_credentials
|
||||||
.pop()
|
.pop()
|
||||||
@@ -251,8 +237,7 @@ fn process_update_user_information(
|
|||||||
/// Processes the CredentialManagement command and all its subcommands.
|
/// Processes the CredentialManagement command and all its subcommands.
|
||||||
pub fn process_credential_management(
|
pub fn process_credential_management(
|
||||||
persistent_store: &mut PersistentStore,
|
persistent_store: &mut PersistentStore,
|
||||||
stateful_command_permission: &mut TimedPermission,
|
stateful_command_permission: &mut StatefulPermission,
|
||||||
mut stateful_command_type: &mut Option<StatefulCommand>,
|
|
||||||
pin_protocol_v1: &mut PinProtocolV1,
|
pin_protocol_v1: &mut PinProtocolV1,
|
||||||
cred_management_params: AuthenticatorCredentialManagementParameters,
|
cred_management_params: AuthenticatorCredentialManagementParameters,
|
||||||
now: ClockValue,
|
now: ClockValue,
|
||||||
@@ -264,17 +249,17 @@ pub fn process_credential_management(
|
|||||||
pin_auth,
|
pin_auth,
|
||||||
} = cred_management_params;
|
} = cred_management_params;
|
||||||
|
|
||||||
match (sub_command, &mut stateful_command_type) {
|
match (sub_command, stateful_command_permission.get_command()) {
|
||||||
(
|
(
|
||||||
CredentialManagementSubCommand::EnumerateRpsGetNextRp,
|
CredentialManagementSubCommand::EnumerateRpsGetNextRp,
|
||||||
Some(StatefulCommand::EnumerateRps(_)),
|
Ok(StatefulCommand::EnumerateRps(_)),
|
||||||
) => (),
|
)
|
||||||
(
|
| (
|
||||||
CredentialManagementSubCommand::EnumerateCredentialsGetNextCredential,
|
CredentialManagementSubCommand::EnumerateCredentialsGetNextCredential,
|
||||||
Some(StatefulCommand::EnumerateCredentials(_)),
|
Ok(StatefulCommand::EnumerateCredentials(_)),
|
||||||
) => (),
|
) => stateful_command_permission.check_command_permission(now)?,
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
*stateful_command_type = None;
|
stateful_command_permission.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,22 +298,15 @@ pub fn process_credential_management(
|
|||||||
CredentialManagementSubCommand::EnumerateRpsBegin => Some(process_enumerate_rps_begin(
|
CredentialManagementSubCommand::EnumerateRpsBegin => Some(process_enumerate_rps_begin(
|
||||||
persistent_store,
|
persistent_store,
|
||||||
stateful_command_permission,
|
stateful_command_permission,
|
||||||
stateful_command_type,
|
|
||||||
now,
|
now,
|
||||||
)?),
|
)?),
|
||||||
CredentialManagementSubCommand::EnumerateRpsGetNextRp => {
|
CredentialManagementSubCommand::EnumerateRpsGetNextRp => Some(
|
||||||
Some(process_enumerate_rps_get_next_rp(
|
process_enumerate_rps_get_next_rp(persistent_store, stateful_command_permission)?,
|
||||||
persistent_store,
|
),
|
||||||
stateful_command_permission,
|
|
||||||
stateful_command_type,
|
|
||||||
now,
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
CredentialManagementSubCommand::EnumerateCredentialsBegin => {
|
CredentialManagementSubCommand::EnumerateCredentialsBegin => {
|
||||||
Some(process_enumerate_credentials_begin(
|
Some(process_enumerate_credentials_begin(
|
||||||
persistent_store,
|
persistent_store,
|
||||||
stateful_command_permission,
|
stateful_command_permission,
|
||||||
stateful_command_type,
|
|
||||||
sub_command_params.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
sub_command_params.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?,
|
||||||
now,
|
now,
|
||||||
)?)
|
)?)
|
||||||
@@ -337,8 +315,6 @@ pub fn process_credential_management(
|
|||||||
Some(process_enumerate_credentials_get_next_credential(
|
Some(process_enumerate_credentials_get_next_credential(
|
||||||
persistent_store,
|
persistent_store,
|
||||||
stateful_command_permission,
|
stateful_command_permission,
|
||||||
stateful_command_type,
|
|
||||||
now,
|
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
CredentialManagementSubCommand::DeleteCredential => {
|
CredentialManagementSubCommand::DeleteCredential => {
|
||||||
@@ -412,7 +388,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -441,7 +416,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -496,7 +470,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -521,7 +494,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -547,7 +519,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -600,7 +571,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -631,7 +601,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -690,7 +659,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -714,7 +682,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -739,7 +706,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -793,7 +759,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -812,7 +777,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -872,7 +836,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -922,7 +885,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
@@ -950,7 +912,6 @@ mod test {
|
|||||||
let cred_management_response = process_credential_management(
|
let cred_management_response = process_credential_management(
|
||||||
&mut ctap_state.persistent_store,
|
&mut ctap_state.persistent_store,
|
||||||
&mut ctap_state.stateful_command_permission,
|
&mut ctap_state.stateful_command_permission,
|
||||||
&mut ctap_state.stateful_command_type,
|
|
||||||
&mut ctap_state.pin_protocol_v1,
|
&mut ctap_state.pin_protocol_v1,
|
||||||
cred_management_params,
|
cred_management_params,
|
||||||
DUMMY_CLOCK_VALUE,
|
DUMMY_CLOCK_VALUE,
|
||||||
|
|||||||
119
src/ctap/mod.rs
119
src/ctap/mod.rs
@@ -101,8 +101,9 @@ const ED_FLAG: u8 = 0x80;
|
|||||||
pub const TOUCH_TIMEOUT_MS: isize = 30000;
|
pub const TOUCH_TIMEOUT_MS: isize = 30000;
|
||||||
#[cfg(feature = "with_ctap1")]
|
#[cfg(feature = "with_ctap1")]
|
||||||
const U2F_UP_PROMPT_TIMEOUT: Duration<isize> = Duration::from_ms(10000);
|
const U2F_UP_PROMPT_TIMEOUT: Duration<isize> = Duration::from_ms(10000);
|
||||||
|
// TODO(kaczmarczyck) 2.1 allows Reset after Reset and 15 seconds?
|
||||||
const RESET_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(10000);
|
const RESET_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(10000);
|
||||||
pub const STATEFUL_COMMAND_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(30000);
|
const STATEFUL_COMMAND_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(30000);
|
||||||
|
|
||||||
pub const FIDO2_VERSION_STRING: &str = "FIDO_2_0";
|
pub const FIDO2_VERSION_STRING: &str = "FIDO_2_0";
|
||||||
#[cfg(feature = "with_ctap1")]
|
#[cfg(feature = "with_ctap1")]
|
||||||
@@ -169,16 +170,51 @@ pub enum StatefulCommand {
|
|||||||
EnumerateCredentials(Vec<usize>),
|
EnumerateCredentials(Vec<usize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_command_permission(
|
pub struct StatefulPermission {
|
||||||
stateful_command_permission: &mut TimedPermission,
|
permission: TimedPermission,
|
||||||
now: ClockValue,
|
command_type: Option<StatefulCommand>,
|
||||||
) -> Result<(), Ctap2StatusCode> {
|
}
|
||||||
*stateful_command_permission = stateful_command_permission.check_expiration(now);
|
|
||||||
if stateful_command_permission.is_granted(now) {
|
impl StatefulPermission {
|
||||||
|
// Resets are only possible in the first 10 seconds after booting.
|
||||||
|
// Therefore, initialization includes allowing Reset.
|
||||||
|
pub fn new_reset(now: ClockValue) -> StatefulPermission {
|
||||||
|
StatefulPermission {
|
||||||
|
permission: TimedPermission::granted(now, RESET_TIMEOUT_DURATION),
|
||||||
|
command_type: Some(StatefulCommand::Reset),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.permission = TimedPermission::waiting();
|
||||||
|
self.command_type = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_command_permission(&mut self, now: ClockValue) -> Result<(), Ctap2StatusCode> {
|
||||||
|
if self.permission.is_granted(now) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
self.clear();
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)
|
Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_command(&mut self) -> Result<&mut StatefulCommand, Ctap2StatusCode> {
|
||||||
|
self.command_type
|
||||||
|
.as_mut()
|
||||||
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_command(&mut self, now: ClockValue, new_command_type: StatefulCommand) {
|
||||||
|
match &new_command_type {
|
||||||
|
// Reset is only allowed after a power cycle.
|
||||||
|
StatefulCommand::Reset => unreachable!(),
|
||||||
|
_ => {
|
||||||
|
self.permission = TimedPermission::granted(now, STATEFUL_COMMAND_TIMEOUT_DURATION);
|
||||||
|
self.command_type = Some(new_command_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This struct currently holds all state, not only the persistent memory. The persistent members are
|
// This struct currently holds all state, not only the persistent memory. The persistent members are
|
||||||
@@ -194,8 +230,7 @@ pub struct CtapState<'a, R: Rng256, CheckUserPresence: Fn(ChannelID) -> Result<(
|
|||||||
#[cfg(feature = "with_ctap1")]
|
#[cfg(feature = "with_ctap1")]
|
||||||
pub u2f_up_state: U2fUserPresenceState,
|
pub u2f_up_state: U2fUserPresenceState,
|
||||||
// The state initializes to Reset and its timeout, and never goes back to Reset.
|
// The state initializes to Reset and its timeout, and never goes back to Reset.
|
||||||
stateful_command_permission: TimedPermission,
|
stateful_command_permission: StatefulPermission,
|
||||||
stateful_command_type: Option<StatefulCommand>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R, CheckUserPresence> CtapState<'a, R, CheckUserPresence>
|
impl<'a, R, CheckUserPresence> CtapState<'a, R, CheckUserPresence>
|
||||||
@@ -220,13 +255,15 @@ where
|
|||||||
U2F_UP_PROMPT_TIMEOUT,
|
U2F_UP_PROMPT_TIMEOUT,
|
||||||
Duration::from_ms(TOUCH_TIMEOUT_MS),
|
Duration::from_ms(TOUCH_TIMEOUT_MS),
|
||||||
),
|
),
|
||||||
stateful_command_permission: TimedPermission::granted(now, RESET_TIMEOUT_DURATION),
|
stateful_command_permission: StatefulPermission::new_reset(now),
|
||||||
stateful_command_type: Some(StatefulCommand::Reset),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_command_permission(&mut self, now: ClockValue) {
|
pub fn update_command_permission(&mut self, now: ClockValue) {
|
||||||
self.stateful_command_permission = self.stateful_command_permission.check_expiration(now);
|
// Ignore the result, just update.
|
||||||
|
let _ = self
|
||||||
|
.stateful_command_permission
|
||||||
|
.check_command_permission(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment_global_signature_counter(&mut self) -> Result<(), Ctap2StatusCode> {
|
pub fn increment_global_signature_counter(&mut self) -> Result<(), Ctap2StatusCode> {
|
||||||
@@ -345,27 +382,23 @@ where
|
|||||||
Duration::from_ms(TOUCH_TIMEOUT_MS),
|
Duration::from_ms(TOUCH_TIMEOUT_MS),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
match (&command, &self.stateful_command_type) {
|
match (&command, self.stateful_command_permission.get_command()) {
|
||||||
(
|
(Command::AuthenticatorGetNextAssertion, Ok(StatefulCommand::GetAssertion(_)))
|
||||||
Command::AuthenticatorGetNextAssertion,
|
| (Command::AuthenticatorReset, Ok(StatefulCommand::Reset))
|
||||||
Some(StatefulCommand::GetAssertion(_)),
|
// AuthenticatorGetInfo still allows Reset.
|
||||||
) => (),
|
| (Command::AuthenticatorGetInfo, Ok(StatefulCommand::Reset))
|
||||||
(
|
// AuthenticatorSelection still allows Reset.
|
||||||
|
| (Command::AuthenticatorSelection, Ok(StatefulCommand::Reset))
|
||||||
|
// AuthenticatorCredentialManagement handles its subcommands later.
|
||||||
|
| (
|
||||||
Command::AuthenticatorCredentialManagement(_),
|
Command::AuthenticatorCredentialManagement(_),
|
||||||
Some(StatefulCommand::EnumerateRps(_)),
|
Ok(StatefulCommand::EnumerateRps(_)),
|
||||||
) => (),
|
)
|
||||||
(
|
| (
|
||||||
Command::AuthenticatorCredentialManagement(_),
|
Command::AuthenticatorCredentialManagement(_),
|
||||||
Some(StatefulCommand::EnumerateCredentials(_)),
|
Ok(StatefulCommand::EnumerateCredentials(_)),
|
||||||
) => (),
|
) => (),
|
||||||
(Command::AuthenticatorReset, Some(StatefulCommand::Reset)) => (),
|
(_, _) => self.stateful_command_permission.clear(),
|
||||||
// GetInfo does not reset stateful commands.
|
|
||||||
(Command::AuthenticatorGetInfo, _) => (),
|
|
||||||
// AuthenticatorSelection does not reset stateful commands.
|
|
||||||
(Command::AuthenticatorSelection, _) => (),
|
|
||||||
(_, _) => {
|
|
||||||
self.stateful_command_type = None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let response = match command {
|
let response = match command {
|
||||||
Command::AuthenticatorMakeCredential(params) => {
|
Command::AuthenticatorMakeCredential(params) => {
|
||||||
@@ -382,7 +415,6 @@ where
|
|||||||
process_credential_management(
|
process_credential_management(
|
||||||
&mut self.persistent_store,
|
&mut self.persistent_store,
|
||||||
&mut self.stateful_command_permission,
|
&mut self.stateful_command_permission,
|
||||||
&mut self.stateful_command_type,
|
|
||||||
&mut self.pin_protocol_v1,
|
&mut self.pin_protocol_v1,
|
||||||
params,
|
params,
|
||||||
now,
|
now,
|
||||||
@@ -855,12 +887,12 @@ where
|
|||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let number_of_credentials = Some(next_credential_keys.len() + 1);
|
let number_of_credentials = Some(next_credential_keys.len() + 1);
|
||||||
self.stateful_command_permission =
|
let assertion_state = StatefulCommand::GetAssertion(AssertionState {
|
||||||
TimedPermission::granted(now, STATEFUL_COMMAND_TIMEOUT_DURATION);
|
|
||||||
self.stateful_command_type = Some(StatefulCommand::GetAssertion(AssertionState {
|
|
||||||
assertion_input: assertion_input.clone(),
|
assertion_input: assertion_input.clone(),
|
||||||
next_credential_keys,
|
next_credential_keys,
|
||||||
}));
|
});
|
||||||
|
self.stateful_command_permission
|
||||||
|
.set_command(now, assertion_state);
|
||||||
number_of_credentials
|
number_of_credentials
|
||||||
};
|
};
|
||||||
self.assertion_response(credential, assertion_input, number_of_credentials)
|
self.assertion_response(credential, assertion_input, number_of_credentials)
|
||||||
@@ -870,10 +902,10 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
now: ClockValue,
|
now: ClockValue,
|
||||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||||
check_command_permission(&mut self.stateful_command_permission, now)?;
|
self.stateful_command_permission
|
||||||
let (assertion_input, credential) =
|
.check_command_permission(now)?;
|
||||||
if let Some(StatefulCommand::GetAssertion(assertion_state)) =
|
let (assertion_input, credential) = if let StatefulCommand::GetAssertion(assertion_state) =
|
||||||
&mut self.stateful_command_type
|
self.stateful_command_permission.get_command()?
|
||||||
{
|
{
|
||||||
let credential_key = assertion_state
|
let credential_key = assertion_state
|
||||||
.next_credential_keys
|
.next_credential_keys
|
||||||
@@ -949,11 +981,10 @@ where
|
|||||||
cid: ChannelID,
|
cid: ChannelID,
|
||||||
now: ClockValue,
|
now: ClockValue,
|
||||||
) -> Result<ResponseData, Ctap2StatusCode> {
|
) -> Result<ResponseData, Ctap2StatusCode> {
|
||||||
// Resets are only possible in the first 10 seconds after booting.
|
self.stateful_command_permission
|
||||||
// TODO(kaczmarczyck) 2.1 allows Reset after Reset and 15 seconds?
|
.check_command_permission(now)?;
|
||||||
check_command_permission(&mut self.stateful_command_permission, now)?;
|
match self.stateful_command_permission.get_command()? {
|
||||||
match &self.stateful_command_type {
|
StatefulCommand::Reset => (),
|
||||||
Some(StatefulCommand::Reset) => (),
|
|
||||||
_ => return Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED),
|
_ => return Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED),
|
||||||
}
|
}
|
||||||
(self.check_user_presence)(cid)?;
|
(self.check_user_presence)(cid)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user