Expand description
Client interface for applications.
The API methods (such as GenerateKey
, Sign
, Verify
,…) are implemented by a variety
of mechanisms (such as Ed255
, X255
, Chacha8Poly1305
, HmacSha256
,…).
The ClientImplementation
structure in this module offers only one general request
method:
pub fn request<'c, T: From<Reply>>(&'c mut self, req: impl Into<Request>)
-> ClientResult<'c, T, Self>
For convenience, the Client
trait expands the API methods, keeping the mechanism general,
e.g.:
// use trussed::Client as _;
fn sign<'c>(&'c mut self,
mechanism: Mechanism,
key: KeyId,
data: &[u8],
format: SignatureSerialization
) -> ClientResult<'c, reply::Sign, Self>;
For further convenience, each mechanism has a corresponding trait of the same name, e.g.,
Ed255
, which also specializes the mechanism, e.g.
// use trussed::client::Ed255 as _;
fn sign_ed255<'c>(&'c mut self, key: &KeyId, message: &[u8])
-> ClientResult<'c, reply::Sign, Self>
Pick your poison :)
Details
The lower-level workings of ClientResult
are currently a hand-rolled / semi-horrible
pseudo-Future
implementation; this will likely be replaced by a proper core::future::Future
with something like the direct-executor.
The lifetimes indicate that the ClientResult
takes ownership of the unique reference
to the client itself for the length of its own lifetime. That is, once the call to Trussed
completes (success or failure), there is no use for the ClientResult
anymore, so due to
lexical lifetimes, the ClientImplementation
can be used again.
What does always happen is that each client has an Interchange with the service, in which
it places the api::Request
(a Rust enum), and then uses the Syscall
implementation, to
trigger processing by the Trussed service.
In practice, in embedded Syscall is implemented by pending a hardware interrupt for the service, which runs at a higher interrupt priority. For PC testing, the service itself has a Syscall implementation (“call thyself”). In both cases, the caller is blocked until processing completes.
All the same, to unpack the “result” it is suggested to use the syscall!
macro, which
returns the Reply
corresponding to the Request
. Example:
let secret_key = syscall!(client.generate_x255_secret_key(Internal)).key;
This syscall!
can fail (by panicking) in two ways:
- logic error: clients are only allowed to make one syscall to the Trussed service at once, then they must wait for a response. By the above, this case cannot happen in practice.
- processing error: some methods are naturally fallible; for example, a public key that is
to be imported via
Deserialize
may be invalid for the mechanism (such things are always checked).
In this second case (probably in all cases when programming defensively, e.g. one possible
trussed::error::Error
is HostMemory
, which means out of RAM), the try_syscall!
macro
should be used instead, which does not unwrap the inner Result type.
In terms of the Result<FutureResult<'c, T, C>, ClientError>
return type of the Client::request
method, the outer Result
corresponds to the logic error (see trussed::client::ClientError
)
for possible causes.
The processing error corresponds to the Result<From<Reply, trussed::error::Error>>
which is
the Ready
variant of the core::task::Poll
struct returns by the FutureResult
’s poll
method.
Possible causes are listed in trussed::error::Error
.
Re-exports
pub use crate::platform::Syscall;
pub use mechanisms::*;
Modules
Structs
The client implementation client applications actually receive.
Enums
Traits
Read/Write + Delete certificates
All-in-one trait bounding on the sub-traits.
Create counters, increment existing counters.
Trussed Client interface that Trussed apps can rely on.
Read/Write/Delete files, iterate over directories.
All the other methods that are fit to expose.
Lowest level interface, use one of the higher level ones.
User-interfacing functionality.