diff --git a/Cargo.lock b/Cargo.lock index f9ec61f..6576878 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,16 +83,14 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bindgen" -version = "0.69.5" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", "itertools", - "lazy_static", - "lazycell", "proc-macro2", "quote", "regex", @@ -472,16 +470,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - [[package]] name = "embedded-time" version = "0.12.1" @@ -560,6 +548,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "glob" version = "0.3.1" @@ -720,12 +719,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.146" @@ -744,9 +737,9 @@ dependencies = [ [[package]] name = "littlefs2" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6857dedc8aba748ea287177abe2bdfb3bb43464c3003f93cdc0a72e1e542b60f" +checksum = "32a43f3c0c6a7d127e3e1241665dd896d8bf1ca31cf9d826a1dc65239bd59868" dependencies = [ "delog", "generic-array", @@ -757,9 +750,9 @@ dependencies = [ [[package]] name = "littlefs2-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250ec1e3017a4540932dc8b33daca325cb6195cded097e1addd9111d9ea2c48f" +checksum = "9a81a4745d38b288b7583fe8ea3736897628df81f4d0f1d0314fa5a3af570de4" dependencies = [ "bitflags 2.6.0", "heapless-bytes", @@ -768,9 +761,9 @@ dependencies = [ [[package]] name = "littlefs2-sys" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a93267fadc37e91758279342f2055b6c03b1187ec7a6b1419c3710172466e" +checksum = "32f7d54a8325846d818335f6e0a3ce4d4ff1d6a5cea7be989a76913dcb73afdc" dependencies = [ "bindgen", "cc", @@ -826,15 +819,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - [[package]] name = "nb" version = "1.1.0" @@ -1098,6 +1082,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "ref-swap" @@ -1453,7 +1440,7 @@ dependencies = [ [[package]] name = "trussed" version = "0.1.0" -source = "git+https://github.com/trussed-dev/trussed.git?rev=805fe7657e79e06b3220324481cd6325b94877d7#805fe7657e79e06b3220324481cd6325b94877d7" +source = "git+https://github.com/trussed-dev/trussed.git?rev=ac106d63ab5e19021b0e37f0efb4313f8168a110#ac106d63ab5e19021b0e37f0efb4313f8168a110" dependencies = [ "aes", "bitflags 2.6.0", @@ -1465,7 +1452,6 @@ dependencies = [ "cosey", "delog", "des", - "embedded-hal", "flexiber", "generic-array", "heapless", @@ -1475,7 +1461,7 @@ dependencies = [ "interchange", "littlefs2", "littlefs2-core", - "nb 1.1.0", + "nb", "p256-cortex-m4", "postcard", "rand_chacha", @@ -1513,9 +1499,12 @@ dependencies = [ "delog", "heapless-bytes", "interchange", + "littlefs2", "littlefs2-core", "log", "pretty_env_logger", + "rand_chacha", + "rand_core", "trussed", "usb-device", "usbd-ccid", @@ -1612,10 +1601,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "void" -version = "1.0.2" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index e2c2d81..f9f306a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,10 @@ edition = "2021" [dependencies] interchange = "0.3.0" +littlefs2-core = "0.1" log = { version = "0.4.14", default-features = false } +rand_chacha = { version = "0.3", default-features = false } +rand_core = { version = "0.6", features = ["getrandom"] } trussed = { version = "0.1", default-features = false, features = ["log-all", "virt"] } usb-device = { version = "0.2.7", default-features = false } usbip-device = "0.1.5" @@ -24,7 +27,7 @@ clap = { version = "3.0.0", features = ["derive"] } clap-num = "1.0.0" delog = { version = "0.1.6", features = ["std-log"] } heapless-bytes = "0.3" -littlefs2-core = "0.1" +littlefs2 = "0.6" pretty_env_logger = "0.4.0" trussed = "0.1" @@ -34,4 +37,4 @@ ctaphid = ["ctaphid-dispatch", "usbd-ctaphid"] ccid = ["apdu-dispatch", "usbd-ccid"] [patch.crates-io] -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "805fe7657e79e06b3220324481cd6325b94877d7" } +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "ac106d63ab5e19021b0e37f0efb4313f8168a110" } diff --git a/examples/dummy.rs b/examples/dummy.rs index 2267792..92b5d0c 100644 --- a/examples/dummy.rs +++ b/examples/dummy.rs @@ -16,7 +16,11 @@ use ctaphid_dispatch::app::{Command, Error, VendorCommand}; use clap::Parser; use clap_num::maybe_hex; -use littlefs2_core::path; +use littlefs2::{ + const_ram_storage, + fs::{Allocation, Filesystem}, +}; +use littlefs2_core::{path, DynFilesystem}; use trussed::{ backend::{CoreOnly, NoId}, client::Client, @@ -24,9 +28,8 @@ use trussed::{ service::Service, syscall, types::{CoreContext, NoData}, - virt::{self, Platform, StoreProvider}, }; -use trussed_usbip::Syscall; +use trussed_usbip::{Platform, Store, Syscall}; /// USP/IP based virtualization a Trussed device. #[derive(Parser, Debug)] @@ -91,13 +94,11 @@ struct Apps { dummy: DummyApp, } -impl<'a, S: StoreProvider> trussed_usbip::Apps<'a, S, CoreOnly> - for Apps> -{ +impl<'a> trussed_usbip::Apps<'a, CoreOnly> for Apps> { type Data = (); fn new( - _service: &mut Service, CoreOnly>, + _service: &mut Service, endpoints: &mut Vec>, syscall: Syscall, _data: (), @@ -130,12 +131,27 @@ impl<'a, S: StoreProvider> trussed_usbip::Apps<'a, S, CoreOnly> } } +const_ram_storage!(RamStorage, 512 * 128); + +fn ram_filesystem() -> &'static dyn DynFilesystem { + let storage = Box::leak(Box::new(RamStorage::new())); + Filesystem::format(storage).expect("failed to format RAM filesystem"); + let alloc = Box::leak(Box::new(Allocation::new())); + let fs = Filesystem::mount(alloc, storage).expect("failed to mount RAM filesystem"); + Box::leak(Box::new(fs)) +} + fn main() { pretty_env_logger::init(); let args = Args::parse(); - let store = virt::Filesystem::new(args.state_file); + // TODO: use filesystem storage for IFS + let store = Store { + ifs: ram_filesystem(), + efs: ram_filesystem(), + vfs: ram_filesystem(), + }; let options = trussed_usbip::Options { manufacturer: Some(args.manufacturer), product: Some(args.name), @@ -145,7 +161,8 @@ fn main() { }; log::info!("Initializing Trussed"); - trussed_usbip::Builder::new(store, options) + let platform = Platform::new(store); + trussed_usbip::Builder::new(options) .build::>() - .exec(|_| ()); + .exec(platform, ()); } diff --git a/src/lib.rs b/src/lib.rs index 16033ad..3a6708e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,11 +13,16 @@ use std::{ time::{Duration, Instant}, }; +use littlefs2_core::DynFilesystem; +use rand_chacha::ChaCha8Rng; +use rand_core::SeedableRng as _; use trussed::{ backend::{CoreOnly, Dispatch}, pipe::ServiceEndpoint, + platform, service::Service, - virt::{self, Platform, StoreProvider}, + store, + virt::UserInterface, ClientImplementation, }; use usb_device::{ @@ -34,7 +39,7 @@ pub fn set_waiting(waiting: bool) { pub type Client = ClientImplementation<'static, Syscall, D>; -pub type InitPlatform = Box)>; +pub type InitPlatform = Box; pub struct Options { pub manufacturer: Option, @@ -50,11 +55,11 @@ impl Options { } } -pub trait Apps<'interrupt, S: StoreProvider, D: Dispatch> { +pub trait Apps<'interrupt, D: Dispatch> { type Data; fn new( - service: &mut Service, D>, + service: &mut Service, endpoints: &mut Vec>, syscall: Syscall, data: Self::Data, @@ -78,140 +83,173 @@ pub trait Apps<'interrupt, S: StoreProvider, D: Dispatch> { ) -> T; } -pub struct Runner { - store: S, +// virt::Store uses non-static references. To be able to use the usbip runner with apps that +// require direct access to the store, e. g. provisioner-app, we use a custom store implementation +// with static lifetimes here. +#[derive(Copy, Clone)] +pub struct Store { + pub ifs: &'static dyn DynFilesystem, + pub efs: &'static dyn DynFilesystem, + pub vfs: &'static dyn DynFilesystem, +} + +impl store::Store for Store { + fn ifs(&self) -> &'static dyn DynFilesystem { + self.ifs + } + + fn efs(&self) -> &'static dyn DynFilesystem { + self.efs + } + + fn vfs(&self) -> &'static dyn DynFilesystem { + self.vfs + } +} + +pub struct Platform { + rng: ChaCha8Rng, + store: Store, + ui: UserInterface, +} + +impl Platform { + pub fn new(store: Store) -> Self { + Self { + store, + rng: ChaCha8Rng::from_entropy(), + ui: UserInterface::new(), + } + } +} + +unsafe impl platform::Platform for Platform { + type R = ChaCha8Rng; + type S = Store; + type UI = UserInterface; + + fn user_interface(&mut self) -> &mut Self::UI { + &mut self.ui + } + + fn rng(&mut self) -> &mut Self::R { + &mut self.rng + } + + fn store(&self) -> Self::S { + self.store + } +} + +pub struct Runner { options: Options, dispatch: D, - init_platform: Option>, _marker: PhantomData, } -impl<'interrupt, S: StoreProvider, D: Dispatch, A: Apps<'interrupt, S, D>> Runner +impl<'interrupt, D: Dispatch, A: Apps<'interrupt, D>> Runner where D::BackendId: Send + Sync, D::Context: Send + Sync, { - pub fn builder(store: S, options: Options) -> Builder { - Builder::new(store, options) + pub fn builder(options: Options) -> Builder { + Builder::new(options) } - pub fn exec) -> A::Data>(self, make_data: F) { - virt::with_platform(self.store, |mut platform| { - if let Some(init_platform) = &self.init_platform { - init_platform(&mut platform); - } - let data = make_data(&mut platform); + pub fn exec(self, platform: Platform, data: A::Data) { + // To change IP or port see usbip-device-0.1.4/src/handler.rs:26 + let bus_allocator = UsbBusAllocator::new(UsbIpBus::new()); - // To change IP or port see usbip-device-0.1.4/src/handler.rs:26 - let bus_allocator = UsbBusAllocator::new(UsbIpBus::new()); + #[cfg(feature = "ctaphid")] + let ctap_channel = ctaphid_dispatch::Channel::new(); + #[cfg(feature = "ctaphid")] + let (mut ctaphid, mut ctaphid_dispatch) = ctaphid::setup(&bus_allocator, &ctap_channel); - #[cfg(feature = "ctaphid")] - let ctap_channel = ctaphid_dispatch::Channel::new(); - #[cfg(feature = "ctaphid")] - let (mut ctaphid, mut ctaphid_dispatch) = ctaphid::setup(&bus_allocator, &ctap_channel); + #[cfg(feature = "ccid")] + let (contact, contactless) = Default::default(); + #[cfg(feature = "ccid")] + let (mut ccid, mut apdu_dispatch) = ccid::setup(&bus_allocator, &contact, &contactless); - #[cfg(feature = "ccid")] - let (contact, contactless) = Default::default(); - #[cfg(feature = "ccid")] - let (mut ccid, mut apdu_dispatch) = ccid::setup(&bus_allocator, &contact, &contactless); + let mut usb_device = build_device(&bus_allocator, &self.options); + let mut service = Service::with_dispatch(platform, self.dispatch); + let mut endpoints = Vec::new(); + let (syscall_sender, syscall_receiver) = mpsc::channel(); + let syscall = Syscall(syscall_sender); + let mut apps = A::new(&mut service, &mut endpoints, syscall, data); - let mut usb_device = build_device(&bus_allocator, &self.options); - let mut service = Service::with_dispatch(platform, self.dispatch); - let mut endpoints = Vec::new(); - let (syscall_sender, syscall_receiver) = mpsc::channel(); - let syscall = Syscall(syscall_sender); - let mut apps = A::new(&mut service, &mut endpoints, syscall, data); + log::info!("Ready for work"); + thread::scope(|s| { + // usb poll + keepalive task + s.spawn(move || { + let _epoch = Instant::now(); + #[cfg(feature = "ctaphid")] + let mut timeout_ctaphid = Timeout::new(); + #[cfg(feature = "ccid")] + let mut timeout_ccid = Timeout::new(); - log::info!("Ready for work"); - thread::scope(|s| { - // usb poll + keepalive task - s.spawn(move || { - let _epoch = Instant::now(); - #[cfg(feature = "ctaphid")] - let mut timeout_ctaphid = Timeout::new(); - #[cfg(feature = "ccid")] - let mut timeout_ccid = Timeout::new(); - - loop { - thread::sleep(Duration::from_millis(5)); - usb_device.poll(&mut [ - #[cfg(feature = "ctaphid")] - &mut ctaphid, - #[cfg(feature = "ccid")] - &mut ccid, - ]); - - #[cfg(feature = "ctaphid")] - ctaphid::keepalive(&mut ctaphid, &mut timeout_ctaphid, _epoch); - #[cfg(feature = "ccid")] - ccid::keepalive(&mut ccid, &mut timeout_ccid, _epoch); - } - }); - - // trussed task - s.spawn(move || { - for _ in syscall_receiver.iter() { - service.process(&mut endpoints) - } - }); - - // apps task loop { thread::sleep(Duration::from_millis(5)); + usb_device.poll(&mut [ + #[cfg(feature = "ctaphid")] + &mut ctaphid, + #[cfg(feature = "ccid")] + &mut ccid, + ]); + #[cfg(feature = "ctaphid")] - apps.with_ctaphid_apps(|apps| ctaphid_dispatch.poll(apps)); + ctaphid::keepalive(&mut ctaphid, &mut timeout_ctaphid, _epoch); #[cfg(feature = "ccid")] - apps.with_ccid_apps(|apps| apdu_dispatch.poll(apps)); + ccid::keepalive(&mut ccid, &mut timeout_ccid, _epoch); } }); - }) + + // trussed task + s.spawn(move || { + for _ in syscall_receiver.iter() { + service.process(&mut endpoints) + } + }); + + // apps task + loop { + thread::sleep(Duration::from_millis(5)); + #[cfg(feature = "ctaphid")] + apps.with_ctaphid_apps(|apps| ctaphid_dispatch.poll(apps)); + #[cfg(feature = "ccid")] + apps.with_ccid_apps(|apps| apdu_dispatch.poll(apps)); + } + }); } } -pub struct Builder { - store: S, +pub struct Builder { options: Options, dispatch: D, - init_platform: Option>, } -impl Builder { - pub fn new(store: S, options: Options) -> Self { +impl Builder { + pub fn new(options: Options) -> Self { Self { - store, options, dispatch: Default::default(), - init_platform: Default::default(), } } } -impl Builder { - pub fn dispatch(self, dispatch: E) -> Builder { +impl Builder { + pub fn dispatch(self, dispatch: E) -> Builder { Builder { - store: self.store, options: self.options, dispatch, - init_platform: self.init_platform, } } - - pub fn init_platform(mut self, f: F) -> Self - where - F: Fn(&mut Platform) + 'static, - { - self.init_platform = Some(Box::new(f)); - self - } } -impl Builder { - pub fn build<'interrupt, A: Apps<'interrupt, S, D>>(self) -> Runner { +impl Builder { + pub fn build<'interrupt, A: Apps<'interrupt, D>>(self) -> Runner { Runner { - store: self.store, options: self.options, dispatch: self.dispatch, - init_platform: self.init_platform, _marker: Default::default(), } }