diff --git a/fuzz/fuzz_helper/src/lib.rs b/fuzz/fuzz_helper/src/lib.rs index a4b5dc0..c14f4b7 100644 --- a/fuzz/fuzz_helper/src/lib.rs +++ b/fuzz/fuzz_helper/src/lib.rs @@ -76,7 +76,8 @@ fn initialize(ctap: &mut Ctap) -> ChannelID { for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid, CtapInstant::new(0)) { - if let Ok(Some(result)) = assembler_reply.parse_packet(&pkt_reply, CtapInstant::new(0)) + if let Ok(Some(result)) = + assembler_reply.parse_packet(ctap.env(), &pkt_reply, CtapInstant::new(0)) { result_cid.copy_from_slice(&result.payload[8..12]); } @@ -118,7 +119,7 @@ fn process_message(data: &[u8], ctap: &mut Ctap) { ctap.process_hid_packet(&pkt_request, Transport::MainHid, CtapInstant::new(0)) { // Only checks for assembling crashes, not for semantics. - let _ = assembler_reply.parse_packet(&pkt_reply, CtapInstant::new(0)); + let _ = assembler_reply.parse_packet(ctap.env(), &pkt_reply, CtapInstant::new(0)); } } } @@ -202,6 +203,7 @@ pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> arbitrary: // Splits the given data as HID packets and reassembles it, verifying that the original input message is reconstructed. pub fn split_assemble_hid_packets(data: &[u8]) { + let mut env = TestEnv::new(); let message = raw_to_message(data); if let Some(hid_packet_iterator) = HidPacketIterator::new(message.clone()) { let mut assembler = MessageAssembler::new(); @@ -209,12 +211,12 @@ pub fn split_assemble_hid_packets(data: &[u8]) { if let Some((last_packet, first_packets)) = packets.split_last() { for packet in first_packets { assert_eq!( - assembler.parse_packet(packet, CtapInstant::new(0)), + assembler.parse_packet(&mut env, packet, CtapInstant::new(0)), Ok(None) ); } assert_eq!( - assembler.parse_packet(last_packet, CtapInstant::new(0)), + assembler.parse_packet(&mut env, last_packet, CtapInstant::new(0)), Ok(Some(message)) ); } diff --git a/src/api/customization.rs b/src/api/customization.rs new file mode 100644 index 0000000..acc5bec --- /dev/null +++ b/src/api/customization.rs @@ -0,0 +1,62 @@ +// Copyright 2022 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. + +//! This file contains all customizable constants. +//! +//! If you adapt them, make sure to run the tests before flashing the firmware. +//! Our deploy script enforces the invariants. + +pub trait Customization { + /// Maximum message size send for CTAP commands. + /// + /// The maximum value is 7609, as HID packets can not encode longer messages. + /// 1024 is the default mentioned in the authenticatorLargeBlobs commands. + /// Larger values are preferred, as that allows more parameters in commands. + /// If long commands are too unreliable on your hardware, consider decreasing + /// this value. + fn max_msg_size(&self) -> usize; +} + +#[derive(Clone)] +pub struct CustomizationImpl { + pub max_msg_size: usize, +} + +pub const DEFAULT_CUSTOMIZATION: CustomizationImpl = CustomizationImpl { max_msg_size: 7609 }; + +impl Customization for CustomizationImpl { + fn max_msg_size(&self) -> usize { + self.max_msg_size + } +} + +#[cfg(feature = "std")] +pub fn is_valid(customization: &impl Customization) -> bool { + // Max message size must be between 1024 and 7609. + if customization.max_msg_size() < 1024 || customization.max_msg_size() > 7609 { + return false; + } + true +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + #[allow(clippy::assertions_on_constants)] + fn test_invariants() { + assert!(is_valid(&DEFAULT_CUSTOMIZATION)); + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index 6738124..d848bfe 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -3,5 +3,6 @@ //! The [environment](crate::env::Env) is split into components. Each component has an API described //! by a trait. This module gathers the API of those components. +pub mod customization; pub mod firmware_protection; pub mod upgrade_storage; diff --git a/src/ctap/customization.rs b/src/ctap/customization.rs index 6314728..8b418ae 100644 --- a/src/ctap/customization.rs +++ b/src/ctap/customization.rs @@ -119,15 +119,6 @@ pub const ENTERPRISE_ATTESTATION_MODE: Option = None; /// VendorFacilitated. pub const ENTERPRISE_RP_ID_LIST: &[&str] = &[]; -/// Maximum message size send for CTAP commands. -/// -/// The maximum value is 7609, as HID packets can not encode longer messages. -/// 1024 is the default mentioned in the authenticatorLargeBlobs commands. -/// Larger values are preferred, as that allows more parameters in commands. -/// If long commands are too unreliable on your hardware, consider decreasing -/// this value. -pub const MAX_MSG_SIZE: usize = 7609; - /// Sets the number of consecutive failed PINs before blocking interaction. /// /// # Invariant @@ -252,8 +243,6 @@ mod test { } else { assert!(ENTERPRISE_RP_ID_LIST.is_empty()); } - assert!(MAX_MSG_SIZE >= 1024); - assert!(MAX_MSG_SIZE <= 7609); assert!(MAX_PIN_RETRIES <= 8); assert!(MAX_CRED_BLOB_LENGTH >= 32); if let Some(count) = MAX_CREDENTIAL_COUNT_IN_LIST { diff --git a/src/ctap/hid/mod.rs b/src/ctap/hid/mod.rs index 2f75ce8..5436900 100644 --- a/src/ctap/hid/mod.rs +++ b/src/ctap/hid/mod.rs @@ -235,7 +235,7 @@ impl CtapHid { packet: &HidPacket, clock_value: CtapInstant, ) -> Option { - match self.assembler.parse_packet(packet, clock_value) { + match self.assembler.parse_packet(env, packet, clock_value) { Ok(Some(message)) => { debug_ctap!(env, "Received message: {:02x?}", message); self.preprocess_message(message) @@ -420,6 +420,7 @@ mod test { #[test] fn test_split_assemble() { + let mut env = TestEnv::new(); for payload_len in 0..7609 { let message = Message { cid: [0x12, 0x34, 0x56, 0x78], @@ -430,7 +431,7 @@ mod test { let mut messages = Vec::new(); let mut assembler = MessageAssembler::new(); for packet in HidPacketIterator::new(message.clone()).unwrap() { - match assembler.parse_packet(&packet, CtapInstant::new(0)) { + match assembler.parse_packet(&mut env, &packet, CtapInstant::new(0)) { Ok(Some(msg)) => messages.push(msg), Ok(None) => (), Err(_) => panic!("Couldn't assemble packet: {:02x?}", &packet as &[u8]), diff --git a/src/ctap/hid/receive.rs b/src/ctap/hid/receive.rs index bd4e9a0..2b88648 100644 --- a/src/ctap/hid/receive.rs +++ b/src/ctap/hid/receive.rs @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::clock::CtapInstant; - -use super::super::customization::MAX_MSG_SIZE; use super::{ ChannelID, CtapHid, CtapHidCommand, CtapHidError, HidPacket, Message, ProcessedPacket, }; +use crate::api::customization::Customization; +use crate::clock::CtapInstant; +use crate::env::Env; use alloc::vec::Vec; use core::mem::swap; @@ -73,6 +73,7 @@ impl MessageAssembler { // packet was received. pub fn parse_packet( &mut self, + env: &mut impl Env, packet: &HidPacket, timestamp: CtapInstant, ) -> Result, (ChannelID, CtapHidError)> { @@ -97,7 +98,7 @@ impl MessageAssembler { // Expecting an initialization packet. match processed_packet { ProcessedPacket::InitPacket { cmd, len, data } => { - self.parse_init_packet(*cid, cmd, len, data, timestamp) + self.parse_init_packet(env, *cid, cmd, len, data, timestamp) } ProcessedPacket::ContinuationPacket { .. } => { // CTAP specification (version 20190130) section 8.1.5.4 @@ -119,7 +120,7 @@ impl MessageAssembler { ProcessedPacket::InitPacket { cmd, len, data } => { self.reset(); if cmd == CtapHidCommand::Init as u8 { - self.parse_init_packet(*cid, cmd, len, data, timestamp) + self.parse_init_packet(env, *cid, cmd, len, data, timestamp) } else { Err((*cid, CtapHidError::InvalidSeq)) } @@ -143,6 +144,7 @@ impl MessageAssembler { fn parse_init_packet( &mut self, + env: &mut impl Env, cid: ChannelID, cmd: u8, len: usize, @@ -151,7 +153,7 @@ impl MessageAssembler { ) -> Result, (ChannelID, CtapHidError)> { // Reject invalid lengths early to reduce the risk of running out of memory. // TODO: also reject invalid commands early? - if len > MAX_MSG_SIZE { + if len > env.customization().max_msg_size() { return Err((cid, CtapHidError::InvalidLen)); } self.cid = cid; @@ -186,6 +188,7 @@ impl MessageAssembler { #[cfg(test)] mod test { use crate::ctap::hid::CtapHid; + use crate::env::test::TestEnv; use embedded_time::duration::Milliseconds; use super::*; @@ -207,11 +210,13 @@ mod test { #[test] fn test_empty_payload() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); // Except for tests that exercise timeouts, all packets are synchronized at the same dummy // timestamp. assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90]), CtapInstant::new(0) ), @@ -225,9 +230,11 @@ mod test { #[test] fn test_one_packet() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10]), CtapInstant::new(0) ), @@ -241,12 +248,14 @@ mod test { #[test] fn test_nonzero_padding() { + let mut env = TestEnv::new(); // CTAP specification (version 20190130) section 8.1.4 // It is written that "Unused bytes SHOULD be set to zero", so we test that non-zero // padding is accepted as well. let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10], 0xFF), CtapInstant::new(0) ), @@ -260,9 +269,11 @@ mod test { #[test] fn test_two_packets() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), CtapInstant::new(0) ), @@ -270,6 +281,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), CtapInstant::new(0) ), @@ -283,9 +295,11 @@ mod test { #[test] fn test_three_packets() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x80]), CtapInstant::new(0) ), @@ -293,6 +307,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), CtapInstant::new(0) ), @@ -300,6 +315,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]), CtapInstant::new(0) ), @@ -313,9 +329,11 @@ mod test { #[test] fn test_max_packets() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x1D, 0xB9]), CtapInstant::new(0) ), @@ -324,6 +342,7 @@ mod test { for seq in 0..0x7F { assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), CtapInstant::new(0) ), @@ -332,6 +351,7 @@ mod test { } assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]), CtapInstant::new(0) ), @@ -345,6 +365,7 @@ mod test { #[test] fn test_multiple_messages() { + let mut env = TestEnv::new(); // Check that after yielding a message, the assembler is ready to process new messages. let mut assembler = MessageAssembler::new(); for i in 0..10 { @@ -354,6 +375,7 @@ mod test { assert_eq!( assembler.parse_packet( + &mut env, &byte_extend( &[0x12, 0x34, 0x56, 0x78, 0x80 | cmd as u8, 0x00, 0x80], byte @@ -364,6 +386,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x00], byte), CtapInstant::new(0) ), @@ -371,6 +394,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x01], byte), CtapInstant::new(0) ), @@ -385,6 +409,7 @@ mod test { #[test] fn test_channel_switch() { + let mut env = TestEnv::new(); // Check that the assembler can process messages from multiple channels, sequentially. let mut assembler = MessageAssembler::new(); for i in 0..10 { @@ -395,6 +420,7 @@ mod test { assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, cid, 0x80 | cmd as u8, 0x00, 0x80], byte), CtapInstant::new(0) ), @@ -402,6 +428,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, cid, 0x00], byte), CtapInstant::new(0) ), @@ -409,6 +436,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, cid, 0x01], byte), CtapInstant::new(0) ), @@ -423,9 +451,11 @@ mod test { #[test] fn test_unexpected_channel() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), CtapInstant::new(0) ), @@ -438,6 +468,7 @@ mod test { for byte in 0..=0xFF { assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, 0x9A, cmd as u8, 0x00], byte), CtapInstant::new(0) ), @@ -448,6 +479,7 @@ mod test { assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), CtapInstant::new(0) ), @@ -461,6 +493,7 @@ mod test { #[test] fn test_spurious_continuation_packets() { + let mut env = TestEnv::new(); // CTAP specification (version 20190130) section 8.1.5.4 // Spurious continuation packets appearing without a prior initialization packet will be // ignored. @@ -470,6 +503,7 @@ mod test { let byte = 2 * i; assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x10], byte), CtapInstant::new(0) ), @@ -484,6 +518,7 @@ mod test { let seq = i; assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), CtapInstant::new(0) ), @@ -497,9 +532,11 @@ mod test { #[test] fn test_unexpected_init() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), CtapInstant::new(0) ), @@ -507,6 +544,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x80]), CtapInstant::new(0) ), @@ -516,9 +554,11 @@ mod test { #[test] fn test_unexpected_seq() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), CtapInstant::new(0) ), @@ -526,6 +566,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]), CtapInstant::new(0) ), @@ -535,9 +576,11 @@ mod test { #[test] fn test_timed_out_packet() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]), CtapInstant::new(0) ), @@ -545,6 +588,7 @@ mod test { ); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]), CtapInstant::new(0) + CtapHid::TIMEOUT_DURATION ), @@ -554,6 +598,7 @@ mod test { #[test] fn test_just_in_time_packets() { + let mut env = TestEnv::new(); let mut timestamp: CtapInstant = CtapInstant::new(0); // Delay between each packet is just below the threshold. let delay = CtapHid::TIMEOUT_DURATION - Milliseconds(1_u32); @@ -561,6 +606,7 @@ mod test { let mut assembler = MessageAssembler::new(); assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x1D, 0xB9]), timestamp ), @@ -569,13 +615,21 @@ mod test { for seq in 0..0x7F { timestamp = timestamp + delay; assert_eq!( - assembler.parse_packet(&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), timestamp), + assembler.parse_packet( + &mut env, + &zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), + timestamp + ), Ok(None) ); } timestamp = timestamp + delay; assert_eq!( - assembler.parse_packet(&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]), timestamp), + assembler.parse_packet( + &mut env, + &zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]), + timestamp + ), Ok(Some(Message { cid: [0x12, 0x34, 0x56, 0x78], cmd: CtapHidCommand::Ping, @@ -586,10 +640,12 @@ mod test { #[test] fn test_init_sync() { + let mut env = TestEnv::new(); let mut assembler = MessageAssembler::new(); // Ping packet with a length longer than one packet. assert_eq!( assembler.parse_packet( + &mut env, &byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x02, 0x00], 0x51), CtapInstant::new(0) ), @@ -598,6 +654,7 @@ mod test { // Init packet on the same channel. assert_eq!( assembler.parse_packet( + &mut env, &zero_extend(&[ 0x12, 0x34, 0x56, 0x78, 0x86, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 diff --git a/src/ctap/large_blobs.rs b/src/ctap/large_blobs.rs index 3a0eb62..38a797d 100644 --- a/src/ctap/large_blobs.rs +++ b/src/ctap/large_blobs.rs @@ -14,9 +14,9 @@ use super::client_pin::{ClientPin, PinPermission}; use super::command::AuthenticatorLargeBlobsParameters; -use super::customization::MAX_MSG_SIZE; use super::response::{AuthenticatorLargeBlobsResponse, ResponseData}; use super::status_code::Ctap2StatusCode; +use crate::api::customization::Customization; use crate::ctap::storage; use crate::env::Env; use alloc::vec; @@ -60,10 +60,10 @@ impl LargeBlobs { pin_uv_auth_protocol, } = large_blobs_params; - const MAX_FRAGMENT_LENGTH: usize = MAX_MSG_SIZE - 64; + let max_fragment_size = env.customization().max_msg_size() - 64; if let Some(get) = get { - if get > MAX_FRAGMENT_LENGTH || offset.checked_add(get).is_none() { + if get > max_fragment_size || offset.checked_add(get).is_none() { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_LENGTH); } let config = storage::get_large_blob_array(env, offset, get)?; @@ -73,7 +73,7 @@ impl LargeBlobs { } if let Some(mut set) = set { - if set.len() > MAX_FRAGMENT_LENGTH { + if set.len() > max_fragment_size { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_LENGTH); } if offset == 0 { diff --git a/src/ctap/mod.rs b/src/ctap/mod.rs index 2511ce5..f523f46 100644 --- a/src/ctap/mod.rs +++ b/src/ctap/mod.rs @@ -20,7 +20,7 @@ mod credential_management; mod crypto_wrapper; #[cfg(feature = "with_ctap1")] mod ctap1; -mod customization; +pub mod customization; pub mod data_formats; pub mod hid; mod key_material; @@ -45,7 +45,7 @@ use self::credential_management::process_credential_management; use self::crypto_wrapper::{aes256_cbc_decrypt, aes256_cbc_encrypt}; use self::customization::{ DEFAULT_CRED_PROTECT, ENTERPRISE_ATTESTATION_MODE, ENTERPRISE_RP_ID_LIST, - MAX_CREDENTIAL_COUNT_IN_LIST, MAX_CRED_BLOB_LENGTH, MAX_LARGE_BLOB_ARRAY_SIZE, MAX_MSG_SIZE, + MAX_CREDENTIAL_COUNT_IN_LIST, MAX_CRED_BLOB_LENGTH, MAX_LARGE_BLOB_ARRAY_SIZE, MAX_RP_IDS_LENGTH, USE_BATCH_ATTESTATION, USE_SIGNATURE_COUNTER, }; use self::data_formats::{ @@ -66,6 +66,7 @@ use self::status_code::Ctap2StatusCode; use self::timed_permission::TimedPermission; #[cfg(feature = "with_ctap1")] use self::timed_permission::U2fUserPresenceState; +use crate::api::customization::Customization; use crate::api::firmware_protection::FirmwareProtection; use crate::api::upgrade_storage::UpgradeStorage; use crate::clock::{ClockInt, CtapInstant}; @@ -1207,7 +1208,7 @@ impl CtapState { ]), aaguid: storage::aaguid(env)?, options: Some(options), - max_msg_size: Some(MAX_MSG_SIZE as u64), + max_msg_size: Some(env.customization().max_msg_size() as u64), // The order implies preference. We favor the new V2. pin_protocols: Some(vec![ PinUvAuthProtocol::V2 as u64, @@ -1519,7 +1520,7 @@ mod test { "setMinPINLength" => true, "makeCredUvNotRqd" => true, }, - 0x05 => MAX_MSG_SIZE as u64, + 0x05 => env.customization().max_msg_size() as u64, 0x06 => cbor_array![2, 1], 0x07 => MAX_CREDENTIAL_COUNT_IN_LIST.map(|c| c as u64), 0x08 => CREDENTIAL_ID_SIZE as u64, diff --git a/src/env/mod.rs b/src/env/mod.rs index 77f232d..f222817 100644 --- a/src/env/mod.rs +++ b/src/env/mod.rs @@ -1,3 +1,4 @@ +use crate::api::customization::Customization; use crate::api::firmware_protection::FirmwareProtection; use crate::api::upgrade_storage::UpgradeStorage; use crate::ctap::status_code::Ctap2StatusCode; @@ -24,6 +25,7 @@ pub trait Env { type UpgradeStorage: UpgradeStorage; type FirmwareProtection: FirmwareProtection; type Write: core::fmt::Write; + type Customization: Customization; fn rng(&mut self) -> &mut Self::Rng; fn user_presence(&mut self) -> &mut Self::UserPresence; @@ -44,4 +46,6 @@ pub trait Env { /// using the defmt crate) and ignore this API. Non-embedded environments may either use this /// API or use the log feature (to be implemented using the log crate). fn write(&mut self) -> Self::Write; + + fn customization(&self) -> &Self::Customization; } diff --git a/src/env/test/mod.rs b/src/env/test/mod.rs index c7e15a1..b5f1459 100644 --- a/src/env/test/mod.rs +++ b/src/env/test/mod.rs @@ -1,4 +1,5 @@ use self::upgrade_storage::BufferUpgradeStorage; +use crate::api::customization::{CustomizationImpl, DEFAULT_CUSTOMIZATION}; use crate::api::firmware_protection::FirmwareProtection; use crate::ctap::status_code::Ctap2StatusCode; use crate::ctap::Channel; @@ -13,6 +14,7 @@ pub struct TestEnv { user_presence: TestUserPresence, store: Store, upgrade_storage: Option, + customization: CustomizationImpl, } pub struct TestUserPresence { @@ -51,17 +53,23 @@ impl TestEnv { let storage = new_storage(); let store = Store::new(storage).ok().unwrap(); let upgrade_storage = Some(BufferUpgradeStorage::new().unwrap()); + let customization = DEFAULT_CUSTOMIZATION.clone(); TestEnv { rng, user_presence, store, upgrade_storage, + customization, } } pub fn disable_upgrade_storage(&mut self) { self.upgrade_storage = None; } + + pub fn customization_mut(&mut self) -> &mut CustomizationImpl { + &mut self.customization + } } impl TestUserPresence { @@ -89,6 +97,7 @@ impl Env for TestEnv { type UpgradeStorage = BufferUpgradeStorage; type FirmwareProtection = Self; type Write = TestWrite; + type Customization = CustomizationImpl; fn rng(&mut self) -> &mut Self::Rng { &mut self.rng @@ -113,4 +122,8 @@ impl Env for TestEnv { fn write(&mut self) -> Self::Write { TestWrite } + + fn customization(&self) -> &Self::Customization { + &self.customization + } } diff --git a/src/env/tock/mod.rs b/src/env/tock/mod.rs index 8c46b0d..700fcb1 100644 --- a/src/env/tock/mod.rs +++ b/src/env/tock/mod.rs @@ -1,4 +1,5 @@ pub use self::storage::{TockStorage, TockUpgradeStorage}; +use crate::api::customization::{CustomizationImpl, DEFAULT_CUSTOMIZATION}; use crate::api::firmware_protection::FirmwareProtection; use crate::ctap::hid::{CtapHid, CtapHidCommand, KeepaliveStatus, ProcessedPacket}; use crate::ctap::status_code::Ctap2StatusCode; @@ -80,6 +81,7 @@ impl Env for TockEnv { type UpgradeStorage = TockUpgradeStorage; type FirmwareProtection = Self; type Write = Console; + type Customization = CustomizationImpl; fn rng(&mut self) -> &mut Self::Rng { &mut self.rng @@ -104,6 +106,10 @@ impl Env for TockEnv { fn write(&mut self) -> Self::Write { Console::new() } + + fn customization(&self) -> &Self::Customization { + &DEFAULT_CUSTOMIZATION + } } // Returns whether the keepalive was sent, or false if cancelled. diff --git a/src/lib.rs b/src/lib.rs index 38e3387..840bbfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,11 @@ impl Ctap { &mut self.hid } + #[cfg(feature = "std")] + pub fn env(&mut self) -> &mut E { + &mut self.env + } + pub fn process_hid_packet( &mut self, packet: &HidPacket,