From bd1d737d714ede078a1371c022e396350b74e1ef Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Mon, 25 Mar 2024 16:49:26 +0100 Subject: [PATCH] apps: Derive ExtensionDispatch implementation --- Cargo.lock | 39 ++-- Cargo.toml | 1 + components/apps/Cargo.toml | 1 + components/apps/src/dispatch.rs | 401 ++++++++++---------------------- 4 files changed, 148 insertions(+), 294 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e5ab23ed..052561fd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,6 +176,7 @@ dependencies = [ "trussed", "trussed-auth", "trussed-chunked", + "trussed-derive", "trussed-hkdf", "trussed-manage", "trussed-rsa-alloc", @@ -629,7 +630,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -955,7 +956,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -2740,7 +2741,7 @@ source = "git+https://github.com/nitrokey/serde-indexed.git?tag=v0.1.0-nitrokey. dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -2770,7 +2771,7 @@ checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -2792,7 +2793,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -2991,7 +2992,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3013,9 +3014,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -3071,7 +3072,7 @@ checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3161,7 +3162,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3266,6 +3267,16 @@ dependencies = [ "trussed", ] +[[package]] +name = "trussed-derive" +version = "0.1.0" +source = "git+https://github.com/trussed-dev/trussed.git?rev=refs/pull/153/head#c9a045726da65bbcc8dd8d930ace897cbe1eecf3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "trussed-hkdf" version = "0.1.0" @@ -3404,7 +3415,7 @@ checksum = "563b3b88238ec95680aef36bdece66896eaa7ce3c0f1b4f39d38fb2435261352" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] [[package]] @@ -3634,7 +3645,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -3656,7 +3667,7 @@ checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3896,5 +3907,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.55", ] diff --git a/Cargo.toml b/Cargo.toml index a2d491fb4..9bea7c10d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ webcrypt = { git = "https://github.com/nitrokey/nitrokey-websmartcard-rust", tag opcard = { git = "https://github.com/Nitrokey/opcard-rs", tag = "v1.4.0" } piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator.git", tag = "v0.4.0" } trussed-chunked = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "chunked-v0.1.0" } +trussed-derive = { git = "https://github.com/trussed-dev/trussed.git", rev = "refs/pull/153/head" } trussed-manage = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "manage-v0.1.0" } trussed-wrap-key-to-file = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "wrap-key-to-file-v0.1.0" } trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.2.0" } diff --git a/components/apps/Cargo.toml b/components/apps/Cargo.toml index cd5dbd469..c4f8e159c 100644 --- a/components/apps/Cargo.toml +++ b/components/apps/Cargo.toml @@ -12,6 +12,7 @@ heapless = "0.7" se05x = { version = "0.1.1", optional = true} serde = { version = "1.0.180", default-features = false } trussed = { version = "0.1", features = ["serde-extensions"]} +trussed-derive = { version = "0.1" } trussed-usbip = { version = "0.0.1", default-features = false, features = ["ctaphid"], optional = true } usbd-ctaphid = { version = "0.1", optional = true } utils = { path = "../utils" } diff --git a/components/apps/src/dispatch.rs b/components/apps/src/dispatch.rs index bd40b6146..41e9f6fd5 100644 --- a/components/apps/src/dispatch.rs +++ b/components/apps/src/dispatch.rs @@ -1,22 +1,15 @@ #[cfg(not(feature = "se050"))] use core::marker::PhantomData; +use if_chain::if_chain; +use littlefs2::{path, path::Path}; use trussed::{ api::{Reply, Request}, - error::Error as TrussedError, + platform::Platform, + serde_extensions::ExtensionImpl, service::ServiceResources, - types::{Context, Location}, - Platform, -}; - -use littlefs2::{path, path::Path}; - -use if_chain::if_chain; -use trussed::{ - api::{reply, request}, - backend::Backend as _, - serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl}, - types::NoData, + types::{CoreContext, Location}, + Error, }; #[cfg(feature = "se050")] @@ -24,12 +17,12 @@ use embedded_hal::blocking::delay::DelayUs; #[cfg(feature = "se050")] use se05x::{se05x::Se05X, t1::I2CForT1}; #[cfg(feature = "se050")] -use trussed_se050_backend::{Context as Se050Context, Se050Backend}; +use trussed_se050_backend::Se050Backend; #[cfg(feature = "se050")] use trussed_se050_manage::Se050ManageExtension; #[cfg(feature = "backend-auth")] -use trussed_auth::{AuthBackend, AuthContext, AuthExtension, MAX_HW_KEY_LEN}; +use trussed_auth::{AuthBackend, AuthExtension, MAX_HW_KEY_LEN}; #[cfg(feature = "backend-rsa")] use trussed_rsa_alloc::SoftwareRsa; @@ -37,37 +30,62 @@ use trussed_rsa_alloc::SoftwareRsa; use trussed_chunked::ChunkedExtension; use trussed_hkdf::{HkdfBackend, HkdfExtension}; use trussed_manage::ManageExtension; -use trussed_staging::{StagingBackend, StagingContext}; +use trussed_staging::StagingBackend; use trussed_wrap_key_to_file::WrapKeyToFileExtension; #[cfg(feature = "webcrypt")] -use webcrypt::hmacsha256p256::{ - Backend as HmacSha256P256Backend, BackendContext as HmacSha256P256Context, - HmacSha256P256Extension, -}; - -pub struct Dispatch { +use webcrypt::hmacsha256p256::{Backend as HmacSha256P256Backend, HmacSha256P256Extension}; + +#[derive(trussed_derive::ExtensionDispatch)] +#[dispatch(backend_id = "Backend", extension_id = "Extension")] +#[extensions( + Hkdf = "HkdfExtension", + Chunked = "ChunkedExtension", + Manage = "ManageExtension", + WrapKeyToFile = "WrapKeyToFileExtension" +)] +#[cfg_attr(feature = "backend-auth", extensions(Auth = "AuthExtension"))] +#[cfg_attr(feature = "se050", extensions(Se050Manage = "Se050ManageExtension"))] +#[cfg_attr( + feature = "webcrypt", + extensions(HmacSha256P256 = "HmacSha256P256Extension") +)] +pub struct Dispatch { #[cfg(feature = "backend-auth")] + #[extensions("Auth")] auth: AuthBackend, + + #[dispatch(no_core)] + #[extensions("Hkdf")] hkdf: HkdfBackend, + #[cfg(feature = "webcrypt")] - hmacsha256p256: HmacSha256P256Backend, + #[dispatch(no_core)] + #[extensions("HmacSha256P256")] + hmac_sha256_p256: HmacSha256P256Backend, + + software_rsa: SoftwareRsa, + + #[extensions("Chunked", "WrapKeyToFile")] staging: StagingBackend, + + #[dispatch(delegate_to = "staging", no_core)] + #[extensions("Manage")] + staging_manage: (), + #[cfg(feature = "se050")] - se050: Option>, - #[cfg(not(feature = "se050"))] - __: PhantomData<(T, D)>, -} + #[extensions("WrapKeyToFile")] + #[cfg_attr(feature = "trussed-auth", extensions("Auth"))] + se050: OptionalBackend>, -#[derive(Default)] -pub struct DispatchContext { - #[cfg(feature = "backend-auth")] - auth: AuthContext, - #[cfg(feature = "webcrypt")] - hmacsha256p256: HmacSha256P256Context, - staging: StagingContext, #[cfg(feature = "se050")] - se050: Se050Context, + #[dispatch(delegate_to = "se050", no_core)] + #[extensions("Manage", "Se050Manage")] + se050_manage: (), + + #[cfg(not(feature = "se050"))] + #[dispatch(skip)] + __: PhantomData<(T, D)>, } fn should_preserve_file(file: &Path) -> bool { @@ -126,10 +144,16 @@ impl Dispatch { auth: AuthBackend::new(auth_location), hkdf: HkdfBackend, #[cfg(feature = "webcrypt")] - hmacsha256p256: Default::default(), + hmac_sha256_p256: Default::default(), + software_rsa: SoftwareRsa, staging: build_staging_backend(), + staging_manage: (), + #[cfg(feature = "se050")] + se050: se050 + .map(|driver| Se050Backend::new(driver, auth_location, None, NAMESPACE)) + .into(), #[cfg(feature = "se050")] - se050: se050.map(|driver| Se050Backend::new(driver, auth_location, None, NAMESPACE)), + se050_manage: (), #[cfg(not(feature = "se050"))] __: Default::default(), } @@ -148,12 +172,18 @@ impl Dispatch { auth: AuthBackend::with_hw_key(auth_location, hw_key), hkdf: HkdfBackend, #[cfg(feature = "webcrypt")] - hmacsha256p256: Default::default(), + hmac_sha256_p256: Default::default(), + software_rsa: SoftwareRsa, staging: build_staging_backend(), + staging_manage: (), + #[cfg(feature = "se050")] + se050: se050 + .map(|driver| { + Se050Backend::new(driver, auth_location, Some(hw_key_se050), NAMESPACE) + }) + .into(), #[cfg(feature = "se050")] - se050: se050.map(|driver| { - Se050Backend::new(driver, auth_location, Some(hw_key_se050), NAMESPACE) - }), + se050_manage: (), #[cfg(not(feature = "se050"))] __: Default::default(), } @@ -181,169 +211,6 @@ pub trait Delay {} #[cfg(not(feature = "se050"))] impl Delay for D {} -impl ExtensionDispatch for Dispatch { - type Context = DispatchContext; - type BackendId = Backend; - type ExtensionId = Extension; - - fn core_request( - &mut self, - backend: &Self::BackendId, - ctx: &mut Context, - request: &Request, - resources: &mut ServiceResources

, - ) -> Result { - match backend { - #[cfg(feature = "backend-auth")] - Backend::Auth => { - self.auth - .request(&mut ctx.core, &mut ctx.backends.auth, request, resources) - } - Backend::Hkdf => Err(TrussedError::RequestNotAvailable), - #[cfg(feature = "webcrypt")] - Backend::HmacSha256P256 => Err(TrussedError::RequestNotAvailable), - #[cfg(feature = "backend-rsa")] - Backend::SoftwareRsa => SoftwareRsa.request(&mut ctx.core, &mut (), request, resources), - Backend::Staging => { - self.staging - .request(&mut ctx.core, &mut ctx.backends.staging, request, resources) - } - Backend::StagingManage => Err(TrussedError::RequestNotAvailable), - #[cfg(feature = "se050")] - Backend::Se050 => self - .se050 - .as_mut() - .ok_or(TrussedError::GeneralError)? - .request(&mut ctx.core, &mut ctx.backends.se050, request, resources), - #[cfg(feature = "se050")] - Backend::Se050Manage => Err(TrussedError::RequestNotAvailable), - } - } - - fn extension_request( - &mut self, - backend: &Self::BackendId, - extension: &Self::ExtensionId, - ctx: &mut Context, - request: &request::SerdeExtension, - resources: &mut ServiceResources

, - ) -> Result { - #[allow(unreachable_patterns)] - match backend { - #[cfg(feature = "backend-auth")] - Backend::Auth => match extension { - Extension::Auth => self.auth.extension_request_serialized( - &mut ctx.core, - &mut ctx.backends.auth, - request, - resources, - ), - #[allow(unreachable_patterns)] - _ => Err(TrussedError::RequestNotAvailable), - }, - Backend::Hkdf => match extension { - Extension::Hkdf => self.hkdf.extension_request_serialized( - &mut ctx.core, - &mut NoData, - request, - resources, - ), - _ => Err(TrussedError::RequestNotAvailable), - }, - #[cfg(feature = "webcrypt")] - Backend::HmacSha256P256 => match extension { - Extension::HmacSha256P256 => self.hmacsha256p256.extension_request_serialized( - &mut ctx.core, - &mut ctx.backends.hmacsha256p256, - request, - resources, - ), - _ => Err(TrussedError::RequestNotAvailable), - }, - #[cfg(feature = "backend-rsa")] - Backend::SoftwareRsa => Err(TrussedError::RequestNotAvailable), - Backend::Staging => match extension { - Extension::Chunked => { - ExtensionImpl::::extension_request_serialized( - &mut self.staging, - &mut ctx.core, - &mut ctx.backends.staging, - request, - resources, - ) - } - Extension::WrapKeyToFile => { - ExtensionImpl::::extension_request_serialized( - &mut self.staging, - &mut ctx.core, - &mut ctx.backends.staging, - request, - resources, - ) - } - #[allow(unreachable_patterns)] - _ => Err(TrussedError::RequestNotAvailable), - }, - Backend::StagingManage => match extension { - Extension::Manage => { - ExtensionImpl::::extension_request_serialized( - &mut self.staging, - &mut ctx.core, - &mut ctx.backends.staging, - request, - resources, - ) - } - _ => Err(TrussedError::RequestNotAvailable), - }, - #[cfg(feature = "se050")] - Backend::Se050 => match extension { - #[cfg(feature = "trussed-auth")] - Extension::Auth => ExtensionImpl::::extension_request_serialized( - self.se050.as_mut().ok_or(TrussedError::GeneralError)?, - &mut ctx.core, - &mut ctx.backends.se050, - request, - resources, - ), - Extension::WrapKeyToFile => { - ExtensionImpl::::extension_request_serialized( - self.se050.as_mut().ok_or(TrussedError::GeneralError)?, - &mut ctx.core, - &mut ctx.backends.se050, - request, - resources, - ) - } - _ => Err(TrussedError::RequestNotAvailable), - }, - #[cfg(feature = "se050")] - Backend::Se050Manage => match extension { - Extension::Manage => { - ExtensionImpl::::extension_request_serialized( - self.se050.as_mut().ok_or(TrussedError::GeneralError)?, - &mut ctx.core, - &mut ctx.backends.se050, - request, - resources, - ) - } - Extension::Se050Manage => { - ExtensionImpl::::extension_request_serialized( - self.se050.as_mut().ok_or(TrussedError::GeneralError)?, - &mut ctx.core, - &mut ctx.backends.se050, - request, - resources, - ) - } - _ => Err(TrussedError::RequestNotAvailable), - }, - _ => Err(TrussedError::RequestNotAvailable), - } - } -} - #[derive(Debug, Clone, Copy)] pub enum Backend { #[cfg(feature = "backend-auth")] @@ -363,100 +230,74 @@ pub enum Backend { Se050Manage, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, trussed_derive::ExtensionId)] pub enum Extension { #[cfg(feature = "backend-auth")] - Auth, - Hkdf, - Chunked, - WrapKeyToFile, - Manage, + Auth = 0, + Hkdf = 1, + Chunked = 2, + WrapKeyToFile = 3, + Manage = 4, #[cfg(feature = "webcrypt")] - HmacSha256P256, + HmacSha256P256 = 5, #[cfg(feature = "se050")] - Se050Manage, + Se050Manage = 6, } -impl From for u8 { - fn from(extension: Extension) -> Self { - match extension { - #[cfg(feature = "backend-auth")] - Extension::Auth => 0, - Extension::Chunked => 1, - Extension::WrapKeyToFile => 2, - Extension::Manage => 3, - #[cfg(feature = "webcrypt")] - Extension::HmacSha256P256 => 4, - #[cfg(feature = "se050")] - Extension::Se050Manage => 5, - Extension::Hkdf => 6, - } - } -} +pub struct OptionalBackend(Option); -impl TryFrom for Extension { - type Error = TrussedError; +impl trussed::backend::Backend for OptionalBackend { + type Context = T::Context; - fn try_from(id: u8) -> Result { - match id { - #[cfg(feature = "backend-auth")] - 0 => Ok(Extension::Auth), - 1 => Ok(Extension::Chunked), - 2 => Ok(Extension::WrapKeyToFile), - 3 => Ok(Extension::Manage), - #[cfg(feature = "webcrypt")] - 4 => Ok(Extension::HmacSha256P256), - #[cfg(feature = "se050")] - 5 => Ok(Extension::Se050Manage), - 6 => Ok(Extension::Hkdf), - _ => Err(TrussedError::InternalError), + fn request( + &mut self, + core_ctx: &mut CoreContext, + backend_ctx: &mut Self::Context, + request: &Request, + resources: &mut ServiceResources

, + ) -> Result { + if let Some(backend) = self.0.as_mut() { + backend.request(core_ctx, backend_ctx, request, resources) + } else { + Err(Error::RequestNotAvailable) } } } -#[cfg(feature = "backend-auth")] -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::Auth; -} - -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::Hkdf; -} - -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::Chunked; -} - -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::WrapKeyToFile; +impl, E: trussed::serde_extensions::Extension> ExtensionImpl + for OptionalBackend +{ + fn extension_request( + &mut self, + core_ctx: &mut CoreContext, + backend_ctx: &mut Self::Context, + request: &E::Request, + resources: &mut ServiceResources

, + ) -> Result { + if let Some(backend) = self.0.as_mut() { + backend.extension_request(core_ctx, backend_ctx, request, resources) + } else { + Err(Error::RequestNotAvailable) + } + } } -#[cfg(feature = "webcrypt")] -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::HmacSha256P256; +impl Default for OptionalBackend { + fn default() -> Self { + Self(None) + } } -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::Manage; +impl From for OptionalBackend { + fn from(backend: T) -> Self { + Self(Some(backend)) + } } -#[cfg(feature = "se050")] -impl ExtensionId for Dispatch { - type Id = Extension; - - const ID: Self::Id = Self::Id::Se050Manage; +impl From> for OptionalBackend { + fn from(backend: Option) -> Self { + Self(backend) + } } #[cfg(test)]