Skip to content

Commit

Permalink
Move serde_extensions module into trussed-core
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-nitrokey committed Oct 31, 2024
1 parent 0975eb4 commit d095a53
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 95 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ license = "Apache-2.0 OR MIT"
heapless = "0.7"
heapless-bytes = "0.3"
littlefs2-core = { version = "0.1", features = ["serde"] }
postcard = "0.7.0"
rand_core = "0.6"
serde = { version = "1.0", default-features = false, features = ["derive"] }

Expand Down Expand Up @@ -39,7 +40,7 @@ generic-array = "0.14.4"
heapless = { workspace = true, features = ["serde"] }
hex-literal = "0.4.1"
nb = "1"
postcard = "0.7.0"
postcard.workspace = true
rand_core.workspace = true
serde.workspace = true
zeroize = { version = "1.2", default-features = false, features = ["zeroize_derive"] }
Expand Down Expand Up @@ -82,7 +83,7 @@ trussed-derive = { path = "derive" }

[features]
default = ["default-mechanisms", "default-syscalls", "clients-5"]
serde-extensions = []
serde-extensions = ["trussed-core/serde-extensions"]
std = []
verbose-tests = ["littlefs2/ll-assertions"]
verbose-lfs = ["littlefs2/ll-assertions", "littlefs2/ll-trace"]
Expand Down
2 changes: 2 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ license.workspace = true
heapless.workspace = true
heapless-bytes.workspace = true
littlefs2-core.workspace = true
postcard.workspace = true
rand_core.workspace = true
serde.workspace = true

Expand All @@ -19,3 +20,4 @@ serde-indexed = "0.1"
[features]
crypto-client-attest = []
counter-client = []
serde-extensions = []
3 changes: 1 addition & 2 deletions core/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ pub struct FutureResult<'c, T, C: ?Sized>
where
C: PollClient,
{
// TODO: make private
pub client: &'c mut C,
pub(crate) client: &'c mut C,
__: PhantomData<T>,
}

Expand Down
2 changes: 2 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ pub mod client;
pub mod config;
pub mod error;
pub mod interrupt;
#[cfg(feature = "serde-extensions")]
pub mod serde_extensions;
pub mod types;
122 changes: 122 additions & 0 deletions core/src/serde_extensions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//! Extensions to the core Trussed syscalls.
//!
//! *Requires the `serde-extensions` feature.*
//!
//! This module makes it possible to add additional syscalls to Trussed by implementing the
//! [`Extension`][] trait. Extension requests and replies are serialized to
//! [`Request::SerdeExtension`][] and [`Reply::SerdeExtension`][].
//!
//! [`Request::SerdeExtension`]: `crate::api::Request::SerdeExtension`
//! [`Reply::SerdeExtension`]: `crate::api::Reply::SerdeExtension`
use core::{marker::PhantomData, task::Poll};

use serde::{de::DeserializeOwned, Serialize};

use crate::{
api::{reply, request},
client::{ClientError, FutureResult, PollClient},
error::Error,
types::Bytes,
};

/// A Trussed API extension.
pub trait Extension {
/// The requests supported by this extension.
type Request: DeserializeOwned + Serialize;
/// The replies supported by this extension.
type Reply: DeserializeOwned + Serialize;

/// Deserialize an extension request.
///
/// This function can be used to deserialize requests that have been serialized by
/// [`ExtensionClient`][]. The format is not guaranteed to be stable.
fn deserialize_request(request: &request::SerdeExtension) -> Result<Self::Request, Error> {
postcard::from_bytes(&request.request).map_err(|_| Error::InvalidSerializedRequest)
}

/// Serialize an extension reply.
///
/// Replies that are serialized with this function can be deserialized by
/// [`ExtensionClient`][]. The format is not guaranteed to be stable.
fn serialize_reply(reply: &Self::Reply) -> Result<reply::SerdeExtension, Error> {
postcard::to_vec(reply)
.map(Bytes::from)
.map(|reply| reply::SerdeExtension { reply })
.map_err(|_| Error::ReplySerializationFailure)
}
}

/// Executes extension requests.
///
/// Instead of using this trait directly, extensions should define their own traits that extend
/// this trait and use the `extension` function to execute extension requests.
pub trait ExtensionClient<E: Extension>: PollClient {
/// Returns the ID for the `E` extension as defined by the runner.
fn id() -> u8;

/// Executes an extension request.
///
/// Applications should not call this method directly and instead use a trait provided by the
/// extension.
fn extension<Rq, Rp>(&mut self, request: Rq) -> ExtensionResult<'_, E, Rp, Self>
where
Rq: Into<E::Request>,
Rp: TryFrom<E::Reply, Error = Error>,
{
self.request(request::SerdeExtension {
id: Self::id(),
request: postcard::to_vec(&request.into())
.map(Bytes::from)
.map_err(|_| ClientError::SerializationFailed)?,
})
.map(From::from)
}
}

/// A result returned by [`ExtensionClient`][] and clients using it.
pub type ExtensionResult<'a, E, T, C> = Result<ExtensionFutureResult<'a, E, T, C>, ClientError>;

#[must_use = "Syscalls must be polled with the `syscall` macro"]
/// A future of an [`ExtensionResult`][].
pub struct ExtensionFutureResult<'c, E, T, C: ?Sized> {
client: &'c mut C,
__: PhantomData<(E, T)>,
}

impl<'c, E, T, C: ?Sized> ExtensionFutureResult<'c, E, T, C> {
fn new(client: &'c mut C) -> Self {
Self {
client,
__: PhantomData,
}
}
}

impl<'c, E, T, C> ExtensionFutureResult<'c, E, T, C>
where
E: Extension,
T: TryFrom<E::Reply, Error = Error>,
C: PollClient,
{
pub fn poll(&mut self) -> Poll<Result<T, Error>> {
self.client.poll().map(|result| {
result.and_then(|reply| {
let reply = reply::SerdeExtension::try_from(reply)?;
let reply: E::Reply = postcard::from_bytes(&reply.reply)
.map_err(|_| Error::InvalidSerializedReply)?;
reply.try_into()
})
})
}
}

impl<'c, E, T, C> From<FutureResult<'c, reply::SerdeExtension, C>>
for ExtensionFutureResult<'c, E, T, C>
where
C: PollClient + ?Sized,
{
fn from(result: FutureResult<'c, reply::SerdeExtension, C>) -> Self {
Self::new(result.client)
}
}
97 changes: 6 additions & 91 deletions src/serde_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,19 @@
//!
//! See `tests/serde_extensions.rs` for an example.
use core::{marker::PhantomData, task::Poll};

use crate::{
api::{reply, request, Reply, Request},
backend::{Backend, CoreOnly, Dispatch, NoId, OptionalBackend},
client::{ClientError, ClientImplementation, FutureResult, PollClient},
client::ClientImplementation,
error::Error,
platform::{Platform, Syscall},
postcard_deserialize, postcard_serialize_bytes,
service::ServiceResources,
types::{self, Context, CoreContext},
};

use serde::{de::DeserializeOwned, Serialize};

/// A Trussed API extension.
pub trait Extension {
/// The requests supported by this extension.
type Request: DeserializeOwned + Serialize;
/// The replies supported by this extension.
type Reply: DeserializeOwned + Serialize;
}
pub use trussed_core::serde_extensions::{
Extension, ExtensionClient, ExtensionFutureResult, ExtensionResult,
};

/// Dispatches extension requests to custom backends.
pub trait ExtensionDispatch {
Expand Down Expand Up @@ -122,12 +113,9 @@ pub trait ExtensionImpl<E: Extension>: Backend {
request: &request::SerdeExtension,
resources: &mut ServiceResources<P>,
) -> Result<reply::SerdeExtension, Error> {
let request =
postcard_deserialize(&request.request).map_err(|_| Error::InvalidSerializedRequest)?;
let request = E::deserialize_request(request)?;
let reply = self.extension_request(core_ctx, backend_ctx, &request, resources)?;
postcard_serialize_bytes(&reply)
.map(|reply| reply::SerdeExtension { reply })
.map_err(|_| Error::ReplySerializationFailure)
E::serialize_reply(&reply)
}
}

Expand All @@ -153,32 +141,6 @@ pub trait ExtensionId<E> {
const ID: Self::Id;
}

/// Executes extension requests.
///
/// Instead of using this trait directly, extensions should define their own traits that extend
/// this trait and use the `extension` function to execute extension requests.
pub trait ExtensionClient<E: Extension>: PollClient {
/// Returns the ID for the `E` extension as defined by the runner, see [`ExtensionId`][].
fn id() -> u8;

/// Executes an extension request.
///
/// Applications should not call this method directly and instead use a trait provided by the
/// extension.
fn extension<Rq, Rp>(&mut self, request: Rq) -> ExtensionResult<'_, E, Rp, Self>
where
Rq: Into<E::Request>,
Rp: TryFrom<E::Reply, Error = Error>,
{
self.request(request::SerdeExtension {
id: Self::id(),
request: postcard_serialize_bytes(&request.into())
.map_err(|_| ClientError::SerializationFailed)?,
})
.map(From::from)
}
}

impl<E, S, I> ExtensionClient<E> for ClientImplementation<S, I>
where
E: Extension,
Expand All @@ -189,50 +151,3 @@ where
I::ID.into()
}
}

/// A result returned by [`ExtensionClient`][] and clients using it.
pub type ExtensionResult<'a, E, T, C> = Result<ExtensionFutureResult<'a, E, T, C>, ClientError>;

#[must_use = "Syscalls must be polled with the `syscall` macro"]
/// A future of an [`ExtensionResult`][].
pub struct ExtensionFutureResult<'c, E, T, C: ?Sized> {
client: &'c mut C,
__: PhantomData<(E, T)>,
}

impl<'c, E, T, C: ?Sized> ExtensionFutureResult<'c, E, T, C> {
fn new(client: &'c mut C) -> Self {
Self {
client,
__: PhantomData,
}
}
}

impl<'c, E, T, C> ExtensionFutureResult<'c, E, T, C>
where
E: Extension,
T: TryFrom<E::Reply, Error = Error>,
C: PollClient,
{
pub fn poll(&mut self) -> Poll<Result<T, Error>> {
self.client.poll().map(|result| {
result.and_then(|reply| {
let reply = reply::SerdeExtension::try_from(reply)?;
let reply: E::Reply = postcard_deserialize(&reply.reply)
.map_err(|_| Error::InvalidSerializedReply)?;
reply.try_into()
})
})
}
}

impl<'c, E, T, C> From<FutureResult<'c, reply::SerdeExtension, C>>
for ExtensionFutureResult<'c, E, T, C>
where
C: PollClient + ?Sized,
{
fn from(result: FutureResult<'c, reply::SerdeExtension, C>) -> Self {
Self::new(result.client)
}
}

0 comments on commit d095a53

Please sign in to comment.