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

@@ -22,7 +22,7 @@ libtock_drivers = { path = "third_party/libtock-drivers" }
libtock_console = { path = "third_party/libtock-rs/apis/console" }
libtock_leds = { path = "third_party/libtock-rs/apis/leds" }
lang_items = { path = "third_party/lang-items" }
opensk = { path = "libraries/opensk" }
opensk = { path = "libraries/opensk", default-features = false }
sk-cbor = { path = "libraries/cbor" }
crypto = { path = "libraries/crypto" }
persistent_store = { path = "libraries/persistent_store" }
@@ -33,6 +33,7 @@ rand_core = "0.6.4"
ed25519-compact = { version = "1", default-features = false, optional = true }
[features]
config_command = ["opensk/config_command"]
debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap", "opensk/debug_ctap"]
panic_console = ["lang_items/panic_console"]

View File

@@ -1091,6 +1091,13 @@ if __name__ == "__main__":
help=("Compiles the OpenSK application without backward compatible "
"support for U2F/CTAP1 protocol."),
)
main_parser.add_argument(
"--no-config-command",
action=RemoveConstAction,
const="config_command",
dest="features",
help=("Removes the AuthenticatorConfig command."),
)
main_parser.add_argument(
"--rust-crypto",
action="append_const",
@@ -1174,7 +1181,7 @@ if __name__ == "__main__":
help=("Firmware version that is built."),
)
main_parser.set_defaults(features=["with_ctap1"])
main_parser.set_defaults(features=["with_ctap1", "config_command"])
# Start parsing to know if we're going to list things or not.
partial_args, _ = main_parser.parse_known_args()

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)?;

55
tools/authenticator_config.py Executable file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python3
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Lint as: python3
"""Tool that sends a config command to OpenSK."""
from __future__ import absolute_import, division, print_function
import argparse
import colorama
from fido2 import hid
from fido2.ctap2 import Config
import uuid
from tools.configure import fatal, get_opensk_devices, info
def main(args):
colorama.init()
devices = get_opensk_devices(False)
if not devices:
fatal("No devices found.")
for authenticator in devices:
if authenticator.device.capabilities & hid.CAPABILITY.WINK:
authenticator.device.wink()
aaguid = uuid.UUID(bytes=authenticator.get_info().aaguid)
info(f"Config of device AAGUID {aaguid} ({authenticator.device}).")
config = Config(authenticator)
if args.ep:
info("Enable EP...")
config.enable_enterprise_attestation()
if args.always_uv:
info("Toggle AlwaysUv...")
config.toggle_always_uv()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ep", action=argparse.BooleanOptionalAction)
parser.add_argument("--always-uv", action=argparse.BooleanOptionalAction)
main(parser.parse_args())