diff --git a/fuzz/fuzz_helper/src/lib.rs b/fuzz/fuzz_helper/src/lib.rs index fb484ce..7c4ca1c 100644 --- a/fuzz/fuzz_helper/src/lib.rs +++ b/fuzz/fuzz_helper/src/lib.rs @@ -28,7 +28,7 @@ use ctap2::ctap::hid::{ ChannelID, CtapHidCommand, HidPacket, HidPacketIterator, Message, MessageAssembler, }; use ctap2::env::test::TestEnv; -use ctap2::Ctap; +use ctap2::{Ctap, Transport}; const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF]; @@ -72,7 +72,9 @@ fn initialize(ctap: &mut Ctap) -> ChannelID { let mut assembler_reply = MessageAssembler::new(); let mut result_cid: ChannelID = Default::default(); for pkt_request in HidPacketIterator::new(message).unwrap() { - for pkt_reply in ctap.process_hid_packet(&pkt_request, CtapInstant::new(0)) { + 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)) { result_cid.copy_from_slice(&result.payload[8..12]); @@ -111,7 +113,9 @@ fn process_message(data: &[u8], ctap: &mut Ctap) { if let Some(hid_packet_iterator) = HidPacketIterator::new(message) { let mut assembler_reply = MessageAssembler::new(); for pkt_request in hid_packet_iterator { - for pkt_reply in ctap.process_hid_packet(&pkt_request, CtapInstant::new(0)) { + for pkt_reply in + 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)); } diff --git a/src/ctap/main_hid.rs b/src/ctap/main_hid.rs index 992fde2..ae11587 100644 --- a/src/ctap/main_hid.rs +++ b/src/ctap/main_hid.rs @@ -21,7 +21,7 @@ use crate::ctap::hid::ChannelID; use crate::ctap::hid::{ CtapHid, CtapHidCommand, CtapHidError, HidPacket, HidPacketIterator, Message, }; -use crate::ctap::TimedPermission; +use crate::ctap::{Channel, TimedPermission}; use crate::env::Env; use embedded_time::duration::Milliseconds; @@ -91,7 +91,8 @@ impl MainHid { // Each transaction is atomic, so we process the command directly here and // don't handle any other packet in the meantime. // TODO: Send "Processing" type keep-alive packets in the meantime. - let response = ctap_state.process_command(env, &message.payload, cid, now); + let response = + ctap_state.process_command(env, &message.payload, Channel::MainHid(cid), now); Message { cid, cmd: CtapHidCommand::Cbor, diff --git a/src/ctap/mod.rs b/src/ctap/mod.rs index 97d7a3c..53fedaf 100644 --- a/src/ctap/mod.rs +++ b/src/ctap/mod.rs @@ -125,6 +125,36 @@ pub const ES256_CRED_PARAM: PublicKeyCredentialParameter = PublicKeyCredentialPa alg: SignatureAlgorithm::ES256, }; +/// Transports supported by OpenSK. +/// +/// An OpenSK library user annotates incoming data with this data type. +/// +/// The difference between this data type and `AuthenticatorTransport` is that the latter +/// corresponds to the communication defined in the CTAP specification. This data type describes +/// the hardware path a packet took. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Transport { + /// Corresponds to CTAP's USB transport. + MainHid, + /// No equivalent in CTAP, used for communication outside the specification. + VendorHid, +} + +/// Communication channels between authenticator and client. +/// +/// From OpenSK's perspective, a channel represents a client. When we receive data from a new +/// channel, we have to assume it's a new client. +/// +/// For HID, communication channels coincide with the channel ID. NFC and HID transports are unique +/// channels themselves. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Channel { + /// Corresponds to CTAP's USB transport. + MainHid(ChannelID), + /// No equivalent in CTAP, used for communication outside the specification. + VendorHid(ChannelID), +} + // Helpers to perform CBOR read/write while respecting CTAP2 nesting limits. pub fn cbor_read(encoded_cbor: &[u8]) -> Result { cbor::reader::read_nested(encoded_cbor, Some(MAX_CBOR_NESTING_DEPTH)) @@ -448,7 +478,7 @@ impl CtapState { &mut self, env: &mut impl Env, command_cbor: &[u8], - cid: ChannelID, + channel: Channel, now: CtapInstant, ) -> Vec { let cmd = Command::deserialize(command_cbor); @@ -481,10 +511,10 @@ impl CtapState { } let response = match command { Command::AuthenticatorMakeCredential(params) => { - self.process_make_credential(env, params, cid) + self.process_make_credential(env, params, channel) } Command::AuthenticatorGetAssertion(params) => { - self.process_get_assertion(env, params, cid, now) + self.process_get_assertion(env, params, channel, now) } Command::AuthenticatorGetNextAssertion => { self.process_get_next_assertion(env, now) @@ -493,7 +523,7 @@ impl CtapState { Command::AuthenticatorClientPin(params) => { self.client_pin.process_command(env, params, now) } - Command::AuthenticatorReset => self.process_reset(env, cid, now), + Command::AuthenticatorReset => self.process_reset(env, channel, now), Command::AuthenticatorCredentialManagement(params) => { process_credential_management( env, @@ -503,7 +533,7 @@ impl CtapState { now, ) } - Command::AuthenticatorSelection => self.process_selection(env, cid), + Command::AuthenticatorSelection => self.process_selection(env, channel), Command::AuthenticatorLargeBlobs(params) => { self.large_blobs .process_command(env, &mut self.client_pin, params) @@ -513,7 +543,7 @@ impl CtapState { } // Vendor specific commands Command::AuthenticatorVendorConfigure(params) => { - self.process_vendor_configure(env, params, cid) + self.process_vendor_configure(env, params, channel) } Command::AuthenticatorVendorUpgrade(params) => { self.process_vendor_upgrade(env, params) @@ -546,12 +576,12 @@ impl CtapState { env: &mut impl Env, pin_uv_auth_param: &Option>, pin_uv_auth_protocol: Option, - cid: ChannelID, + channel: Channel, ) -> Result<(), Ctap2StatusCode> { if let Some(auth_param) = &pin_uv_auth_param { // This case was added in FIDO 2.1. if auth_param.is_empty() { - env.user_presence().check(cid)?; + env.user_presence().check(channel)?; if storage::pin_hash(env)?.is_none() { return Err(Ctap2StatusCode::CTAP2_ERR_PIN_NOT_SET); } else { @@ -567,7 +597,7 @@ impl CtapState { &mut self, env: &mut impl Env, make_credential_params: AuthenticatorMakeCredentialParameters, - cid: ChannelID, + channel: Channel, ) -> Result { let AuthenticatorMakeCredentialParameters { client_data_hash, @@ -582,7 +612,7 @@ impl CtapState { enterprise_attestation, } = make_credential_params; - self.pin_uv_auth_precheck(env, &pin_uv_auth_param, pin_uv_auth_protocol, cid)?; + self.pin_uv_auth_precheck(env, &pin_uv_auth_param, pin_uv_auth_protocol, channel)?; if !pub_key_cred_params.contains(&ES256_CRED_PARAM) { return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM); @@ -659,13 +689,13 @@ impl CtapState { { // Perform this check, so bad actors can't brute force exclude_list // without user interaction. - let _ = env.user_presence().check(cid); + let _ = env.user_presence().check(channel); return Err(Ctap2StatusCode::CTAP2_ERR_CREDENTIAL_EXCLUDED); } } } - env.user_presence().check(cid)?; + env.user_presence().check(channel)?; self.client_pin.clear_token_flags(); let mut cred_protect_policy = extensions.cred_protect; @@ -923,7 +953,7 @@ impl CtapState { &mut self, env: &mut impl Env, get_assertion_params: AuthenticatorGetAssertionParameters, - cid: ChannelID, + channel: Channel, now: CtapInstant, ) -> Result { let AuthenticatorGetAssertionParameters { @@ -936,7 +966,7 @@ impl CtapState { pin_uv_auth_protocol, } = get_assertion_params; - self.pin_uv_auth_precheck(env, &pin_uv_auth_param, pin_uv_auth_protocol, cid)?; + self.pin_uv_auth_precheck(env, &pin_uv_auth_param, pin_uv_auth_protocol, channel)?; if extensions.hmac_secret.is_some() && !options.up { // The extension is actually supported, but we need user presence. @@ -1024,7 +1054,7 @@ impl CtapState { // This check comes before CTAP2_ERR_NO_CREDENTIALS in CTAP 2.0. if options.up { - env.user_presence().check(cid)?; + env.user_presence().check(channel)?; self.client_pin.clear_token_flags(); } @@ -1134,7 +1164,7 @@ impl CtapState { fn process_reset( &mut self, env: &mut impl Env, - cid: ChannelID, + channel: Channel, now: CtapInstant, ) -> Result { self.stateful_command_permission @@ -1143,7 +1173,7 @@ impl CtapState { StatefulCommand::Reset => (), _ => return Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED), } - env.user_presence().check(cid)?; + env.user_presence().check(channel)?; storage::reset(env)?; self.client_pin.reset(env.rng()); @@ -1157,9 +1187,9 @@ impl CtapState { fn process_selection( &self, env: &mut impl Env, - cid: ChannelID, + channel: Channel, ) -> Result { - env.user_presence().check(cid)?; + env.user_presence().check(channel)?; Ok(ResponseData::AuthenticatorSelection) } @@ -1167,10 +1197,10 @@ impl CtapState { &mut self, env: &mut impl Env, params: AuthenticatorVendorConfigureParameters, - cid: ChannelID, + channel: Channel, ) -> Result { if params.attestation_material.is_some() || params.lockdown { - env.user_presence().check(cid)?; + env.user_presence().check(channel)?; } // Sanity checks @@ -1336,7 +1366,7 @@ mod test { // keep-alive packets to. // In tests where we define a dummy user-presence check that immediately returns, the channel // ID is irrelevant, so we pass this (dummy but valid) value. - const DUMMY_CHANNEL_ID: ChannelID = [0x12, 0x34, 0x56, 0x78]; + const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]); fn check_make_response( make_credential_response: Result, @@ -1385,7 +1415,7 @@ mod test { let mut env = TestEnv::new(); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); let info_reponse = - ctap_state.process_command(&mut env, &[0x04], DUMMY_CHANNEL_ID, CtapInstant::new(0)); + ctap_state.process_command(&mut env, &[0x04], DUMMY_CHANNEL, CtapInstant::new(0)); let expected_cbor = cbor_map_options! { 0x01 => cbor_array_vec![vec![ @@ -1499,7 +1529,7 @@ mod test { let make_credential_params = create_minimal_make_credential_parameters(); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); check_make_response( make_credential_response, @@ -1518,7 +1548,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.options.rk = false; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); check_make_response( make_credential_response, @@ -1537,7 +1567,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.pub_key_cred_params = vec![]; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, @@ -1571,7 +1601,7 @@ mod test { assert!(storage::store_credential(&mut env, excluded_credential_source).is_ok()); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, Err(Ctap2StatusCode::CTAP2_ERR_CREDENTIAL_EXCLUDED) @@ -1587,7 +1617,7 @@ mod test { let make_credential_params = create_make_credential_parameters_with_cred_protect_policy(test_policy); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert!(make_credential_response.is_ok()); let mut iter_result = Ok(()); @@ -1601,7 +1631,7 @@ mod test { let make_credential_params = create_make_credential_parameters_with_exclude_list(&credential_id); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, Err(Ctap2StatusCode::CTAP2_ERR_CREDENTIAL_EXCLUDED) @@ -1611,7 +1641,7 @@ mod test { let make_credential_params = create_make_credential_parameters_with_cred_protect_policy(test_policy); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert!(make_credential_response.is_ok()); let mut iter_result = Ok(()); @@ -1625,7 +1655,7 @@ mod test { let make_credential_params = create_make_credential_parameters_with_exclude_list(&credential_id); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert!(make_credential_response.is_ok()); } @@ -1642,7 +1672,7 @@ mod test { make_credential_params.options.rk = false; make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); let expected_extension_cbor = [ 0xA1, 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xF5, @@ -1668,7 +1698,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); let expected_extension_cbor = [ 0xA1, 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0xF5, @@ -1695,7 +1725,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); check_make_response( make_credential_response, 0x41, @@ -1717,7 +1747,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); let expected_extension_cbor = [ 0xA1, 0x6C, 0x6D, 0x69, 0x6E, 0x50, 0x69, 0x6E, 0x4C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x04, @@ -1743,7 +1773,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); let expected_extension_cbor = [ 0xA1, 0x68, 0x63, 0x72, 0x65, 0x64, 0x42, 0x6C, 0x6F, 0x62, 0xF5, ]; @@ -1775,7 +1805,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); let expected_extension_cbor = [ 0xA1, 0x68, 0x63, 0x72, 0x65, 0x64, 0x42, 0x6C, 0x6F, 0x62, 0xF4, ]; @@ -1807,7 +1837,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); let large_blob_key = match make_credential_response.unwrap() { ResponseData::AuthenticatorMakeCredential(make_credential_response) => { make_credential_response.large_blob_key.unwrap() @@ -1850,7 +1880,7 @@ mod test { let make_credential_response = ctap_state.process_make_credential( &mut env, make_credential_params.clone(), - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, ); check_make_response( @@ -1862,7 +1892,7 @@ mod test { ); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID) @@ -1888,7 +1918,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.options.rk = false; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); check_make_response( make_credential_response, @@ -1907,7 +1937,7 @@ mod test { let make_credential_params = create_minimal_make_credential_parameters(); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, Err(Ctap2StatusCode::CTAP2_ERR_PUAT_REQUIRED) @@ -1922,7 +1952,7 @@ mod test { storage::toggle_always_uv(&mut env).unwrap(); let make_credential_params = create_minimal_make_credential_parameters(); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, Err(Ctap2StatusCode::CTAP2_ERR_PUAT_REQUIRED) @@ -1933,7 +1963,7 @@ mod test { make_credential_params.pin_uv_auth_param = Some(vec![0xA4; 16]); make_credential_params.pin_uv_auth_protocol = Some(PinUvAuthProtocol::V1); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID) @@ -1949,7 +1979,7 @@ mod test { let make_credential_params = create_minimal_make_credential_parameters(); let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert_eq!( make_credential_response, @@ -2044,7 +2074,7 @@ mod test { let make_credential_params = create_minimal_make_credential_parameters(); assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let get_assertion_params = AuthenticatorGetAssertionParameters { @@ -2062,7 +2092,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); @@ -2135,7 +2165,7 @@ mod test { make_credential_params.options.rk = false; make_credential_params.extensions = make_extensions; let make_credential_response = - ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID); + ctap_state.process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL); assert!(make_credential_response.is_ok()); let credential_id = match make_credential_response.unwrap() { ResponseData::AuthenticatorMakeCredential(make_credential_response) => { @@ -2171,7 +2201,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); assert!(get_assertion_response.is_ok()); @@ -2201,7 +2231,7 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.extensions = make_extensions; assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let client_pin_params = AuthenticatorClientPinParameters { @@ -2227,7 +2257,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); assert!(get_assertion_response.is_ok()); @@ -2288,7 +2318,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); assert_eq!( @@ -2311,7 +2341,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); @@ -2348,7 +2378,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); assert_eq!( @@ -2399,7 +2429,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); @@ -2457,7 +2487,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let large_blob_key = match get_assertion_response.unwrap() { @@ -2489,7 +2519,7 @@ mod test { }; make_credential_params.user = user1.clone(); assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let mut make_credential_params = create_minimal_make_credential_parameters(); let user2 = PublicKeyCredentialUserEntity { @@ -2500,7 +2530,7 @@ mod test { }; make_credential_params.user = user2.clone(); assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); ctap_state.client_pin = client_pin; @@ -2528,7 +2558,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); @@ -2581,7 +2611,7 @@ mod test { make_credential_params.user.user_display_name = Some("removed".to_string()); make_credential_params.user.user_icon = Some("removed".to_string()); assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.user.user_id = vec![0x02]; @@ -2589,7 +2619,7 @@ mod test { make_credential_params.user.user_display_name = Some("removed".to_string()); make_credential_params.user.user_icon = Some("removed".to_string()); assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.user.user_id = vec![0x03]; @@ -2597,7 +2627,7 @@ mod test { make_credential_params.user.user_display_name = Some("removed".to_string()); make_credential_params.user.user_icon = Some("removed".to_string()); assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let get_assertion_params = AuthenticatorGetAssertionParameters { @@ -2615,7 +2645,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let signature_counter = storage::global_signature_counter(&mut env).unwrap(); @@ -2657,12 +2687,12 @@ mod test { let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.user.user_id = vec![0x01]; assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let mut make_credential_params = create_minimal_make_credential_parameters(); make_credential_params.user.user_id = vec![0x02]; assert!(ctap_state - .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL_ID) + .process_make_credential(&mut env, make_credential_params, DUMMY_CHANNEL) .is_ok()); let get_assertion_params = AuthenticatorGetAssertionParameters { @@ -2680,7 +2710,7 @@ mod test { let get_assertion_response = ctap_state.process_get_assertion( &mut env, get_assertion_params, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); assert!(get_assertion_response.is_ok()); @@ -2698,12 +2728,7 @@ mod test { 4 => cbor_array![ES256_CRED_PARAM], }; assert!(cbor_write(cbor_value, &mut command_cbor).is_ok()); - ctap_state.process_command( - &mut env, - &command_cbor, - DUMMY_CHANNEL_ID, - CtapInstant::new(0), - ); + ctap_state.process_command(&mut env, &command_cbor, DUMMY_CHANNEL, CtapInstant::new(0)); let get_assertion_response = ctap_state.process_get_next_assertion(&mut env, CtapInstant::new(0)); @@ -2738,7 +2763,7 @@ mod test { assert!(storage::count_credentials(&mut env).unwrap() > 0); let reset_reponse = - ctap_state.process_command(&mut env, &[0x07], DUMMY_CHANNEL_ID, CtapInstant::new(0)); + ctap_state.process_command(&mut env, &[0x07], DUMMY_CHANNEL, CtapInstant::new(0)); let expected_response = vec![0x00]; assert_eq!(reset_reponse, expected_response); assert!(storage::count_credentials(&mut env).unwrap() == 0); @@ -2751,8 +2776,7 @@ mod test { .set(|_| Err(Ctap2StatusCode::CTAP2_ERR_KEEPALIVE_CANCEL)); let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); - let reset_reponse = - ctap_state.process_reset(&mut env, DUMMY_CHANNEL_ID, CtapInstant::new(0)); + let reset_reponse = ctap_state.process_reset(&mut env, DUMMY_CHANNEL, CtapInstant::new(0)); assert_eq!( reset_reponse, @@ -2766,10 +2790,9 @@ mod test { let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0)); // This is a GetNextAssertion command. - ctap_state.process_command(&mut env, &[0x08], DUMMY_CHANNEL_ID, CtapInstant::new(0)); + ctap_state.process_command(&mut env, &[0x08], DUMMY_CHANNEL, CtapInstant::new(0)); - let reset_reponse = - ctap_state.process_reset(&mut env, DUMMY_CHANNEL_ID, CtapInstant::new(0)); + let reset_reponse = ctap_state.process_reset(&mut env, DUMMY_CHANNEL, CtapInstant::new(0)); assert_eq!(reset_reponse, Err(Ctap2StatusCode::CTAP2_ERR_NOT_ALLOWED)); } @@ -2782,7 +2805,7 @@ mod test { let reponse = ctap_state.process_command( &mut env, &[0x0A, 0xA1, 0x01, 0x18, 0xEE], - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, CtapInstant::new(0), ); let expected_response = vec![Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND as u8]; @@ -2796,7 +2819,7 @@ mod test { // This command does not exist. let reponse = - ctap_state.process_command(&mut env, &[0xDF], DUMMY_CHANNEL_ID, CtapInstant::new(0)); + ctap_state.process_command(&mut env, &[0xDF], DUMMY_CHANNEL, CtapInstant::new(0)); let expected_response = vec![Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND as u8]; assert_eq!(reponse, expected_response); } @@ -2871,7 +2894,7 @@ mod test { lockdown: false, attestation_material: None, }, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, ); assert_eq!( response, @@ -2895,7 +2918,7 @@ mod test { private_key: dummy_key, }), }, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, ); assert_eq!( response, @@ -2926,7 +2949,7 @@ mod test { private_key: other_dummy_key, }), }, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, ); assert_eq!( response, @@ -2953,7 +2976,7 @@ mod test { lockdown: true, attestation_material: None, }, - DUMMY_CHANNEL_ID, + DUMMY_CHANNEL, ); assert_eq!( response, diff --git a/src/env/mod.rs b/src/env/mod.rs index 03d6f92..77f232d 100644 --- a/src/env/mod.rs +++ b/src/env/mod.rs @@ -1,7 +1,7 @@ use crate::api::firmware_protection::FirmwareProtection; use crate::api::upgrade_storage::UpgradeStorage; -use crate::ctap::hid::ChannelID; use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::Channel; use crypto::rng256::Rng256; use persistent_store::{Storage, Store}; @@ -13,7 +13,7 @@ pub trait UserPresence { /// Blocks for user presence. /// /// Returns an error in case of timeout or keepalive error. - fn check(&mut self, cid: ChannelID) -> Result<(), Ctap2StatusCode>; + fn check(&mut self, channel: Channel) -> Result<(), Ctap2StatusCode>; } /// Describes what CTAP needs to function. diff --git a/src/env/test/mod.rs b/src/env/test/mod.rs index b169a34..c7e15a1 100644 --- a/src/env/test/mod.rs +++ b/src/env/test/mod.rs @@ -1,7 +1,7 @@ use self::upgrade_storage::BufferUpgradeStorage; use crate::api::firmware_protection::FirmwareProtection; -use crate::ctap::hid::ChannelID; use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::Channel; use crate::env::{Env, UserPresence}; use crypto::rng256::ThreadRng256; use persistent_store::{BufferOptions, BufferStorage, Store}; @@ -16,7 +16,7 @@ pub struct TestEnv { } pub struct TestUserPresence { - check: Box Result<(), Ctap2StatusCode>>, + check: Box Result<(), Ctap2StatusCode>>, } pub struct TestWrite; @@ -65,14 +65,14 @@ impl TestEnv { } impl TestUserPresence { - pub fn set(&mut self, check: impl Fn(ChannelID) -> Result<(), Ctap2StatusCode> + 'static) { + pub fn set(&mut self, check: impl Fn(Channel) -> Result<(), Ctap2StatusCode> + 'static) { self.check = Box::new(check); } } impl UserPresence for TestUserPresence { - fn check(&mut self, cid: ChannelID) -> Result<(), Ctap2StatusCode> { - (self.check)(cid) + fn check(&mut self, channel: Channel) -> Result<(), Ctap2StatusCode> { + (self.check)(channel) } } diff --git a/src/env/tock/mod.rs b/src/env/tock/mod.rs index 3f3933c..b7de1b0 100644 --- a/src/env/tock/mod.rs +++ b/src/env/tock/mod.rs @@ -2,6 +2,7 @@ pub use self::storage::{TockStorage, TockUpgradeStorage}; use crate::api::firmware_protection::FirmwareProtection; use crate::ctap::hid::{ChannelID, CtapHid, CtapHidCommand, KeepaliveStatus, ProcessedPacket}; use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::Channel; use crate::env::{Env, UserPresence}; use core::cell::Cell; use core::sync::atomic::{AtomicBool, Ordering}; @@ -54,8 +55,11 @@ pub fn take_storage() -> StorageResult { } impl UserPresence for TockEnv { - fn check(&mut self, cid: ChannelID) -> Result<(), Ctap2StatusCode> { - check_user_presence(self, cid) + fn check(&mut self, channel: Channel) -> Result<(), Ctap2StatusCode> { + match channel { + Channel::MainHid(cid) => check_user_presence(self, cid), + Channel::VendorHid(cid) => check_user_presence(self, cid), + } } } diff --git a/src/lib.rs b/src/lib.rs index 3f9379c..055c422 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ extern crate arrayref; use crate::ctap::hid::{HidPacket, HidPacketIterator}; use crate::ctap::main_hid::MainHid; use crate::ctap::CtapState; +pub use crate::ctap::Transport; use crate::env::Env; use clock::CtapInstant; @@ -78,10 +79,16 @@ impl Ctap { pub fn process_hid_packet( &mut self, packet: &HidPacket, + transport: Transport, now: CtapInstant, ) -> HidPacketIterator { - self.hid - .process_hid_packet(&mut self.env, packet, now, &mut self.state) + match transport { + Transport::MainHid => { + self.hid + .process_hid_packet(&mut self.env, packet, now, &mut self.state) + } + Transport::VendorHid => HidPacketIterator::none(), + } } pub fn update_timeouts(&mut self, now: CtapInstant) { diff --git a/src/main.rs b/src/main.rs index a3db262..fd59a11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ use ctap2::clock::{new_clock, Clock, ClockInt, KEEPALIVE_DELAY}; #[cfg(feature = "with_ctap1")] use ctap2::env::tock::blink_leds; use ctap2::env::tock::{switch_off_leds, wink_leds, TockEnv, KEEPALIVE_DELAY_TOCK}; +use ctap2::Transport; #[cfg(feature = "debug_ctap")] use embedded_time::duration::Microseconds; use embedded_time::duration::Milliseconds; @@ -120,7 +121,7 @@ fn main() { ctap.update_timeouts(now); if has_packet { - let reply = ctap.process_hid_packet(&pkt_request, now); + let reply = ctap.process_hid_packet(&pkt_request, Transport::MainHid, now); // This block handles sending packets. for mut pkt_reply in reply { let status = usb_ctap_hid::send_or_recv_with_timeout(&mut pkt_reply, SEND_TIMEOUT);