Compile flag for AuthenticatorConfig (#628)

* Adds a compile flag for AuthenticatorConfig

The command can be disabled for authenticators that don't want users to
change their configuration.

* adds tool for calling Config

* std now implies config_command

* removes obsolete comment
This commit is contained in:
kaczmarczyck
2023-05-08 15:45:32 +02:00
committed by GitHub
parent 94b0beed4b
commit 6fb7e194eb
9 changed files with 98 additions and 8 deletions

View File

@@ -36,8 +36,10 @@ features = ["alloc", "ecdh", "ecdsa"]
optional = true
[features]
default = ["config_command", "with_ctap1"]
config_command = []
debug_ctap = []
std = ["crypto/std", "persistent_store/std", "rand/std_rng"]
std = ["crypto/std", "persistent_store/std", "rand/std_rng", "config_command"]
with_ctap1 = ["crypto/with_ctap1"]
vendor_hid = []
fuzz = ["arbitrary", "std"]

View File

@@ -119,6 +119,7 @@ pub enum PinPermission {
CredentialManagement = 0x04,
_BioEnrollment = 0x08,
LargeBlobWrite = 0x10,
#[cfg(feature = "config_command")]
AuthenticatorConfiguration = 0x20,
}

View File

@@ -15,12 +15,14 @@
use super::cbor_read;
use super::data_formats::{
extract_array, extract_byte_string, extract_map, extract_text_string, extract_unsigned,
ok_or_missing, ClientPinSubCommand, ConfigSubCommand, ConfigSubCommandParams, CoseKey,
CredentialManagementSubCommand, CredentialManagementSubCommandParameters,
GetAssertionExtensions, GetAssertionOptions, MakeCredentialExtensions, MakeCredentialOptions,
PinUvAuthProtocol, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, SetMinPinLengthParams,
ok_or_missing, ClientPinSubCommand, CoseKey, CredentialManagementSubCommand,
CredentialManagementSubCommandParameters, GetAssertionExtensions, GetAssertionOptions,
MakeCredentialExtensions, MakeCredentialOptions, PinUvAuthProtocol,
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialRpEntity,
PublicKeyCredentialUserEntity,
};
#[cfg(feature = "config_command")]
use super::data_formats::{ConfigSubCommand, ConfigSubCommandParams, SetMinPinLengthParams};
use super::status_code::Ctap2StatusCode;
use alloc::string::String;
use alloc::vec::Vec;
@@ -46,6 +48,7 @@ pub enum Command {
AuthenticatorCredentialManagement(AuthenticatorCredentialManagementParameters),
AuthenticatorSelection,
AuthenticatorLargeBlobs(AuthenticatorLargeBlobsParameters),
#[cfg(feature = "config_command")]
AuthenticatorConfig(AuthenticatorConfigParameters),
}
@@ -61,6 +64,7 @@ impl Command {
const AUTHENTICATOR_CREDENTIAL_MANAGEMENT: u8 = 0x0A;
const AUTHENTICATOR_SELECTION: u8 = 0x0B;
const AUTHENTICATOR_LARGE_BLOBS: u8 = 0x0C;
#[cfg(feature = "config_command")]
const AUTHENTICATOR_CONFIG: u8 = 0x0D;
const _AUTHENTICATOR_VENDOR_FIRST: u8 = 0x40;
// This commands is the same as AUTHENTICATOR_CREDENTIAL_MANAGEMENT but is duplicated as a
@@ -124,6 +128,7 @@ impl Command {
AuthenticatorLargeBlobsParameters::try_from(decoded_cbor)?,
))
}
#[cfg(feature = "config_command")]
Command::AUTHENTICATOR_CONFIG => {
let decoded_cbor = cbor_read(&bytes[1..])?;
Ok(Command::AuthenticatorConfig(
@@ -429,6 +434,7 @@ impl TryFrom<cbor::Value> for AuthenticatorLargeBlobsParameters {
}
}
#[cfg(feature = "config_command")]
#[derive(Debug, PartialEq, Eq)]
pub struct AuthenticatorConfigParameters {
pub sub_command: ConfigSubCommand,
@@ -437,6 +443,7 @@ pub struct AuthenticatorConfigParameters {
pub pin_uv_auth_param: Option<Vec<u8>>,
}
#[cfg(feature = "config_command")]
impl TryFrom<cbor::Value> for AuthenticatorConfigParameters {
type Error = Ctap2StatusCode;
@@ -684,6 +691,7 @@ mod test {
}
#[test]
#[cfg(feature = "config_command")]
fn test_from_cbor_config_parameters() {
let cbor_value = cbor_map! {
0x01 => ConfigSubCommand::SetMinPinLength as u64,

View File

@@ -15,6 +15,7 @@
pub mod apdu;
mod client_pin;
pub mod command;
#[cfg(feature = "config_command")]
mod config_command;
mod credential_management;
pub mod crypto_wrapper;
@@ -39,6 +40,7 @@ use self::client_pin::{ClientPin, PinPermission};
use self::command::{
AuthenticatorGetAssertionParameters, AuthenticatorMakeCredentialParameters, Command,
};
#[cfg(feature = "config_command")]
use self::config_command::process_config;
use self::credential_management::process_credential_management;
use self::data_formats::{
@@ -655,6 +657,7 @@ impl<E: Env> CtapState<E> {
self.large_blobs
.process_command(env, &mut self.client_pin, params)
}
#[cfg(feature = "config_command")]
Command::AuthenticatorConfig(params) => {
process_config(env, &mut self.client_pin, params)
}

View File

@@ -36,6 +36,7 @@ pub enum ResponseData {
AuthenticatorCredentialManagement(Option<AuthenticatorCredentialManagementResponse>),
AuthenticatorSelection,
AuthenticatorLargeBlobs(Option<AuthenticatorLargeBlobsResponse>),
#[cfg(feature = "config_command")]
AuthenticatorConfig,
}
@@ -51,6 +52,7 @@ impl From<ResponseData> for Option<cbor::Value> {
ResponseData::AuthenticatorCredentialManagement(data) => data.map(|d| d.into()),
ResponseData::AuthenticatorSelection => None,
ResponseData::AuthenticatorLargeBlobs(data) => data.map(|d| d.into()),
#[cfg(feature = "config_command")]
ResponseData::AuthenticatorConfig => None,
}
}
@@ -586,6 +588,7 @@ mod test {
}
#[test]
#[cfg(feature = "config_command")]
fn test_config_into_cbor() {
let response_cbor: Option<cbor::Value> = ResponseData::AuthenticatorConfig.into();
assert_eq!(response_cbor, None);

View File

@@ -14,6 +14,7 @@
mod key;
#[cfg(feature = "config_command")]
use crate::api::attestation_store::{self, AttestationStore};
use crate::api::customization::Customization;
use crate::api::key_store::KeyStore;
@@ -31,6 +32,7 @@ use arrayref::array_ref;
use core::cmp;
use core::convert::TryInto;
use persistent_store::{fragment, StoreUpdate};
#[cfg(feature = "config_command")]
use sk_cbor::cbor_array_vec;
/// Wrapper for PIN properties.
@@ -39,6 +41,7 @@ struct PinProperties {
hash: [u8; PIN_AUTH_LENGTH],
/// Length of the current PIN in code points.
#[cfg_attr(not(feature = "config_command"), allow(dead_code))]
code_point_length: u8,
}
@@ -268,6 +271,7 @@ pub fn pin_hash(env: &mut impl Env) -> Result<Option<[u8; PIN_AUTH_LENGTH]>, Cta
}
/// Returns the length of the currently set PIN if defined.
#[cfg(feature = "config_command")]
pub fn pin_code_point_length(env: &mut impl Env) -> Result<Option<u8>, Ctap2StatusCode> {
Ok(pin_properties(env)?.map(|p| p.code_point_length))
}
@@ -328,6 +332,7 @@ pub fn min_pin_length(env: &mut impl Env) -> Result<u8, Ctap2StatusCode> {
}
/// Sets the minimum PIN length.
#[cfg(feature = "config_command")]
pub fn set_min_pin_length(env: &mut impl Env, min_pin_length: u8) -> Result<(), Ctap2StatusCode> {
Ok(env.store().insert(key::MIN_PIN_LENGTH, &[min_pin_length])?)
}
@@ -344,6 +349,7 @@ pub fn min_pin_length_rp_ids(env: &mut impl Env) -> Result<Vec<String>, Ctap2Sta
}
/// Sets the list of RP IDs that are used to check if reading the minimum PIN length is allowed.
#[cfg(feature = "config_command")]
pub fn set_min_pin_length_rp_ids(
env: &mut impl Env,
min_pin_length_rp_ids: Vec<String>,
@@ -428,6 +434,7 @@ pub fn has_force_pin_change(env: &mut impl Env) -> Result<bool, Ctap2StatusCode>
}
/// Marks the PIN as outdated with respect to the new PIN policy.
#[cfg(feature = "config_command")]
pub fn force_pin_change(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
Ok(env.store().insert(key::FORCE_PIN_CHANGE, &[])?)
}
@@ -442,6 +449,7 @@ pub fn enterprise_attestation(env: &mut impl Env) -> Result<bool, Ctap2StatusCod
}
/// Marks enterprise attestation as enabled.
#[cfg(feature = "config_command")]
pub fn enable_enterprise_attestation(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
if env
.attestation_store()
@@ -469,6 +477,7 @@ pub fn has_always_uv(env: &mut impl Env) -> Result<bool, Ctap2StatusCode> {
}
/// Enables alwaysUv, when disabled, and vice versa.
#[cfg(feature = "config_command")]
pub fn toggle_always_uv(env: &mut impl Env) -> Result<(), Ctap2StatusCode> {
if env.customization().enforce_always_uv() {
return Err(Ctap2StatusCode::CTAP2_ERR_OPERATION_DENIED);
@@ -588,6 +597,7 @@ fn deserialize_min_pin_length_rp_ids(data: &[u8]) -> Option<Vec<String>> {
}
/// Serializes a list of RP IDs to storage representation.
#[cfg(feature = "config_command")]
fn serialize_min_pin_length_rp_ids(rp_ids: Vec<String>) -> Result<Vec<u8>, Ctap2StatusCode> {
let mut data = Vec::new();
super::cbor_write(cbor_array_vec!(rp_ids), &mut data)?;