From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../authenticator/src/transport/mock/device.rs | 328 +++++++++++++++++++++ .../rust/authenticator/src/transport/mock/mod.rs | 6 + .../src/transport/mock/transaction.rs | 35 +++ 3 files changed, 369 insertions(+) create mode 100644 third_party/rust/authenticator/src/transport/mock/device.rs create mode 100644 third_party/rust/authenticator/src/transport/mock/mod.rs create mode 100644 third_party/rust/authenticator/src/transport/mock/transaction.rs (limited to 'third_party/rust/authenticator/src/transport/mock') diff --git a/third_party/rust/authenticator/src/transport/mock/device.rs b/third_party/rust/authenticator/src/transport/mock/device.rs new file mode 100644 index 0000000000..ac4e156d8a --- /dev/null +++ b/third_party/rust/authenticator/src/transport/mock/device.rs @@ -0,0 +1,328 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use crate::consts::{Capability, HIDCmd, CID_BROADCAST}; +use crate::crypto::SharedSecret; +use crate::ctap2::commands::get_info::AuthenticatorInfo; +use crate::ctap2::commands::{CtapResponse, RequestCtap1, RequestCtap2}; +use crate::transport::device_selector::DeviceCommand; +use crate::transport::TestDevice; +use crate::transport::{hid::HIDDevice, FidoDevice, FidoProtocol, HIDError}; +use crate::u2ftypes::{U2FDeviceInfo, U2FHIDInitResp}; +use std::any::Any; +use std::collections::VecDeque; +use std::hash::{Hash, Hasher}; +use std::io::{self, Read, Write}; +use std::sync::mpsc::{channel, Receiver, Sender}; + +pub(crate) const IN_HID_RPT_SIZE: usize = 64; +const OUT_HID_RPT_SIZE: usize = 64; + +#[derive(Debug)] +pub struct Device { + pub id: String, + pub cid: [u8; 4], + pub reads: Vec<[u8; IN_HID_RPT_SIZE]>, + pub writes: Vec<[u8; OUT_HID_RPT_SIZE + 1]>, + pub dev_info: Option, + pub authenticator_info: Option, + pub sender: Option>, + pub receiver: Option>, + pub protocol: FidoProtocol, + skip_serialization: bool, + pub upcoming_requests: VecDeque>, + pub upcoming_responses: VecDeque, HIDError>>, +} + +impl Device { + pub fn add_write(&mut self, packet: &[u8], fill_value: u8) { + // Add one to deal with record index check + let mut write = [fill_value; OUT_HID_RPT_SIZE + 1]; + // Make sure we start with a 0, for HID record index + write[0] = 0; + // Clone packet data in at 1, since front is padded with HID record index + write[1..=packet.len()].clone_from_slice(packet); + self.writes.push(write); + } + + pub fn add_read(&mut self, packet: &[u8], fill_value: u8) { + let mut read = [fill_value; IN_HID_RPT_SIZE]; + read[..packet.len()].clone_from_slice(packet); + self.reads.push(read); + } + + pub fn add_upcoming_ctap2_request(&mut self, msg: &impl RequestCtap2) { + self.upcoming_requests + .push_back(msg.wire_format().expect("Failed to serialize CTAP request")); + } + + pub fn add_upcoming_ctap1_request(&mut self, msg: &impl RequestCtap1) { + let (upcoming, _) = msg + .ctap1_format() + .expect("Failed to serialize CTAP request"); + self.upcoming_requests.push_back(upcoming); + } + + pub fn add_upcoming_ctap_response(&mut self, msg: impl CtapResponse) { + self.upcoming_responses.push_back(Ok(Box::new(msg))); + } + + pub fn add_upcoming_ctap_error(&mut self, msg: HIDError) { + self.upcoming_responses.push_back(Err(msg)); + } + + pub fn create_channel(&mut self) { + let (tx, rx) = channel(); + self.sender = Some(tx); + self.receiver = Some(rx); + } + + pub fn new_skipping_serialization(id: &str) -> Result { + Ok(Device { + id: id.to_string(), + cid: CID_BROADCAST, + reads: vec![], + writes: vec![], + dev_info: None, + authenticator_info: None, + sender: None, + receiver: None, + protocol: FidoProtocol::CTAP2, + skip_serialization: true, + upcoming_requests: VecDeque::new(), + upcoming_responses: VecDeque::new(), + }) + } +} + +impl Write for Device { + fn write(&mut self, bytes: &[u8]) -> io::Result { + // Pop a vector from the expected writes, check for quality + // against bytes array. + assert!( + !self.writes.is_empty(), + "Ran out of expected write values! Wanted to write {:?}", + bytes + ); + let check = self.writes.remove(0); + assert_eq!(check.len(), bytes.len()); + assert_eq!(&check, bytes); + Ok(bytes.len()) + } + + // nop + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Read for Device { + fn read(&mut self, bytes: &mut [u8]) -> io::Result { + assert!(!self.reads.is_empty(), "Ran out of read values!"); + let check = self.reads.remove(0); + assert_eq!(check.len(), bytes.len()); + bytes.clone_from_slice(&check); + Ok(check.len()) + } +} + +impl Drop for Device { + fn drop(&mut self) { + if !std::thread::panicking() { + assert!(self.reads.is_empty()); + assert!(self.writes.is_empty()); + } + } +} + +impl PartialEq for Device { + fn eq(&self, other: &Device) -> bool { + self.id == other.id + } +} + +impl Eq for Device {} + +impl Hash for Device { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl HIDDevice for Device { + type Id = String; + type BuildParameters = &'static str; // None used + + fn id(&self) -> Self::Id { + self.id.clone() + } + + fn new(id: Self::BuildParameters) -> Result { + Ok(Device { + id: id.to_string(), + cid: CID_BROADCAST, + reads: vec![], + writes: vec![], + dev_info: None, + authenticator_info: None, + sender: None, + receiver: None, + protocol: FidoProtocol::CTAP2, + skip_serialization: false, + upcoming_requests: VecDeque::new(), + upcoming_responses: VecDeque::new(), + }) + } + + fn get_cid(&self) -> &[u8; 4] { + &self.cid + } + + fn set_cid(&mut self, cid: [u8; 4]) { + self.cid = cid; + } + + fn in_rpt_size(&self) -> usize { + IN_HID_RPT_SIZE + } + + fn out_rpt_size(&self) -> usize { + OUT_HID_RPT_SIZE + } + + fn get_property(&self, prop_name: &str) -> io::Result { + Ok(format!("{prop_name} not implemented")) + } + + fn get_device_info(&self) -> U2FDeviceInfo { + self.dev_info.clone().unwrap() + } + + fn set_device_info(&mut self, dev_info: U2FDeviceInfo) { + self.dev_info = Some(dev_info); + } + + fn pre_init(&mut self) -> Result<(), HIDError> { + if self.initialized() { + return Ok(()); + } + + let nonce = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]; + + // Send Init to broadcast address to create a new channel + self.set_cid(CID_BROADCAST); + let (cmd, raw) = HIDDevice::sendrecv(self, HIDCmd::Init, &nonce, &|| true)?; + if cmd != HIDCmd::Init { + return Err(HIDError::DeviceError); + } + + let rsp = U2FHIDInitResp::read(&raw, &nonce)?; + + // Set the new Channel ID + self.set_cid(rsp.cid); + + let info = U2FDeviceInfo { + vendor_name: "Test vendor".as_bytes().to_vec(), + device_name: "Test device".as_bytes().to_vec(), + version_interface: rsp.version_interface, + version_major: rsp.version_major, + version_minor: rsp.version_minor, + version_build: rsp.version_build, + cap_flags: rsp.cap_flags, + }; + debug!("{:?}: {:?}", self.id(), info); + self.set_device_info(info); + + Ok(()) + } +} + +impl TestDevice for Device { + fn skip_serialization(&self) -> bool { + self.skip_serialization + } + + fn send_ctap1_unserialized( + &mut self, + msg: &Req, + ) -> Result { + let expected = self + .upcoming_requests + .pop_front() + .expect("No expected CTAP1 command left"); + let (incoming, _) = msg.ctap1_format().expect("Can't serialize CTAP1 request"); + assert_eq!(expected, incoming); + let response = self + .upcoming_responses + .pop_front() + .expect("No response given!"); + response.map(|x| { + *x.downcast() + .expect("Failed to downcast given CTAP response") + }) + } + + fn send_ctap2_unserialized( + &mut self, + msg: &Req, + ) -> Result { + let expected = self + .upcoming_requests + .pop_front() + .expect("No expected CTAP2 command left"); + let incoming = msg.wire_format().expect("Can't serialize CTAP2 request"); + assert_eq!(expected, incoming); + let response = self + .upcoming_responses + .pop_front() + .expect("No response given!"); + response.map(|x| { + *x.downcast() + .expect("Failed to downcast given CTAP response") + }) + } +} + +impl FidoDevice for Device { + fn pre_init(&mut self) -> Result<(), HIDError> { + HIDDevice::pre_init(self) + } + + fn should_try_ctap2(&self) -> bool { + HIDDevice::get_device_info(self) + .cap_flags + .contains(Capability::CBOR) + } + + fn initialized(&self) -> bool { + self.get_cid() != &CID_BROADCAST + } + + fn is_u2f(&mut self) -> bool { + self.sender.is_some() + } + + fn get_shared_secret(&self) -> std::option::Option<&SharedSecret> { + None + } + + fn set_shared_secret(&mut self, _: SharedSecret) { + // Nothing + } + + fn get_authenticator_info(&self) -> Option<&AuthenticatorInfo> { + self.authenticator_info.as_ref() + } + + fn set_authenticator_info(&mut self, authenticator_info: AuthenticatorInfo) { + self.authenticator_info = Some(authenticator_info); + } + + fn get_protocol(&self) -> FidoProtocol { + self.protocol + } + + fn downgrade_to_ctap1(&mut self) { + self.protocol = FidoProtocol::CTAP1; + } +} diff --git a/third_party/rust/authenticator/src/transport/mock/mod.rs b/third_party/rust/authenticator/src/transport/mock/mod.rs new file mode 100644 index 0000000000..d0e200a7ef --- /dev/null +++ b/third_party/rust/authenticator/src/transport/mock/mod.rs @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub mod device; +pub mod transaction; diff --git a/third_party/rust/authenticator/src/transport/mock/transaction.rs b/third_party/rust/authenticator/src/transport/mock/transaction.rs new file mode 100644 index 0000000000..e19b1cb56f --- /dev/null +++ b/third_party/rust/authenticator/src/transport/mock/transaction.rs @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::statecallback::StateCallback; +use crate::transport::device_selector::{DeviceBuildParameters, DeviceSelectorEvent}; +use std::sync::mpsc::Sender; + +pub struct Transaction {} + +impl Transaction { + pub fn new( + _timeout: u64, + _callback: StateCallback>, + _status: Sender, + _new_device_cb: F, + ) -> crate::Result + where + F: Fn( + DeviceBuildParameters, + Sender, + Sender, + &dyn Fn() -> bool, + ) + Sync + + Send + + 'static, + T: 'static, + { + Ok(Self {}) + } + + pub fn cancel(&mut self) { + info!("Transaction was cancelled."); + } +} -- cgit v1.2.3