Skip to content

Commit

Permalink
sprot: plumbing for attest & attest_len
Browse files Browse the repository at this point in the history
This is the first op supported by sprot that takes both a read and a
write lease. Following the existing structure of `handle_request` we add
a new `Attest` variant to the TrailingData enum where we store the
appropriately sized slice that holds the read lease. As a result we must
be more explicit about the lifetimes in the `handle_request` method
because it's return value no longer has the same lifetime as the `self`
param (3rd lifetime elision rule).

The rest is pretty straight forward with the call to `Attest::attest`
happending in the match arm for this new `TrailingData` variant.
  • Loading branch information
flihp committed Jan 23, 2024
1 parent d7c49c9 commit 1bca9d5
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 9 deletions.
2 changes: 1 addition & 1 deletion app/lpc55xpresso/app-sprot.toml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ task-slots = ["swd"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 46592, ram = 32768}
max-sizes = {flash = 47328, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
2 changes: 1 addition & 1 deletion app/oxide-rot-1/app-dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ task-slots = ["syscon_driver"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 46592, ram = 32768}
max-sizes = {flash = 47328, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
2 changes: 1 addition & 1 deletion app/oxide-rot-1/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ task-slots = ["syscon_driver"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 46592, ram = 32768}
max-sizes = {flash = 47328, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
2 changes: 1 addition & 1 deletion app/rot-carrier/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ task-slots = ["syscon_driver"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 46592, ram = 32768}
max-sizes = {flash = 47328, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
46 changes: 42 additions & 4 deletions drv/lpc55-sprot-server/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ pub struct StartupState {
}

/// Marker for data which should be copied after the packet is encoded
pub enum TrailingData {
pub enum TrailingData<'a> {
Caboose { slot: SlotId, start: u32, size: u32 },
AttestCert { index: u32, offset: u32, size: u32 },
AttestLog { offset: u32, size: u32 },
Attest { nonce: &'a [u8], write_size: u32 },
RotPage { page: RotPage },
}

Expand All @@ -57,7 +58,7 @@ pub struct Handler {
attest: Attest,
}

impl Handler {
impl<'a> Handler {
pub fn new() -> Handler {
Handler {
sprocket: crate::handler::sprockets::init(),
Expand Down Expand Up @@ -198,15 +199,35 @@ impl Handler {
}
}
}
Some(TrailingData::Attest { nonce, write_size }) => {
if write_size as usize > drv_sprot_api::MAX_BLOB_SIZE {
Response::pack(
&Err(SprotError::Protocol(
SprotProtocolError::BadMessageLength,
)),
tx_buf,
)
} else {
match Response::pack_with_cb(&rsp_body, tx_buf, |buf| {
self.attest
.attest(nonce, &mut buf[..write_size as usize])
.map_err(|e| RspBody::Attest(Err(e)))?;
Ok(write_size as usize)
}) {
Ok(size) => size,
Err(e) => Response::pack(&Ok(e), tx_buf),
}
}
}
_ => Response::pack(&rsp_body, tx_buf),
}
}

pub fn handle_request(
&mut self,
req: Request<'_>,
req: Request<'a>,
stats: &mut RotIoStats,
) -> Result<(RspBody, Option<TrailingData>), SprotError> {
) -> Result<(RspBody, Option<TrailingData<'a>>), SprotError> {
match req.body {
ReqBody::Status => {
let status = RotStatus {
Expand Down Expand Up @@ -367,6 +388,23 @@ impl Handler {
};
Ok((RspBody::Attest(rsp), None))
}
ReqBody::Attest(AttestReq::Attest {
nonce_size,
write_size,
}) => Ok((
RspBody::Attest(Ok(AttestRsp::Attest)),
Some(TrailingData::Attest {
nonce: &req.blob[..nonce_size as usize],
write_size,
}),
)),
ReqBody::Attest(AttestReq::AttestLen) => {
let rsp = match self.attest.attest_len() {
Ok(l) => Ok(AttestRsp::AttestLen(l)),
Err(e) => Err(e),
};
Ok((RspBody::Attest(rsp), None))
}
}
}
}
4 changes: 4 additions & 0 deletions drv/sprot-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ pub enum AttestReq {
Record { algorithm: HashAlgorithm },
Log { offset: u32, size: u32 },
LogLen,
Attest { nonce_size: u32, write_size: u32 },
AttestLen,
}

/// A response used for RoT updates
Expand Down Expand Up @@ -414,6 +416,8 @@ pub enum AttestRsp {
Record,
Log,
LogLen(u32),
Attest,
AttestLen(u32),
}

/// The body of a sprot response.
Expand Down
85 changes: 84 additions & 1 deletion drv/stm32h7-sprot-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#![no_main]
#![deny(elided_lifetimes_in_paths)]

use attest_api::HashAlgorithm;
use attest_api::{AttestError, HashAlgorithm, NONCE_MAX_SIZE, NONCE_MIN_SIZE};
use core::convert::Into;
use drv_lpc55_update_api::{
RotBootInfo, RotPage, SlotId, SwitchDuration, UpdateTarget,
Expand Down Expand Up @@ -1009,6 +1009,89 @@ impl<S: SpiServer> idl::InOrderSpRotImpl for ServerImpl<S> {
Err(e) => Err(AttestOrSprotError::Sprot(e).into()),
}
}

fn attest(
&mut self,
_msg: &userlib::RecvMessage,
nonce: idol_runtime::LenLimit<
idol_runtime::Leased<idol_runtime::R, [u8]>,
NONCE_MAX_SIZE,
>,
dest: idol_runtime::Leased<idol_runtime::W, [u8]>,
) -> Result<(), idol_runtime::RequestError<AttestOrSprotError>>
where
AttestOrSprotError: From<idol_runtime::ServerDeath>,
{
if nonce.len() < NONCE_MIN_SIZE {
return Err(
AttestOrSprotError::Attest(AttestError::BadLease).into()
);
}

let nonce_size = u32::try_from(nonce.len()).unwrap_lite();
let write_size = u32::try_from(dest.len()).unwrap_lite();

let body = ReqBody::Attest(AttestReq::Attest {
nonce_size,
write_size,
});
let tx_size = Request::pack_with_cb(&body, self.tx_buf, |buf| {
nonce
.read_range(0..nonce.len(), buf)
.map_err(|_| SprotProtocolError::TaskRestarted)?;
Ok::<usize, idol_runtime::RequestError<AttestOrSprotError>>(
nonce.len(),
)
})?;

let rsp = self.do_send_recv_retries(tx_size, TIMEOUT_MEDIUM, 1)?;

match rsp.body {
Ok(RspBody::Attest(Ok(AttestRsp::Attest))) => {
// Copy response data into the lease
if rsp.blob.len() < dest.len() {
return Err(idol_runtime::RequestError::Fail(
idol_runtime::ClientError::BadLease,
));
}
dest.write_range(0..dest.len(), &rsp.blob[..dest.len()])
.map_err(|()| {
idol_runtime::RequestError::Fail(
idol_runtime::ClientError::WentAway,
)
})?;
Ok(())
}
Ok(RspBody::Attest(Err(e))) => {
Err(AttestOrSprotError::Attest(e).into())
}
Ok(RspBody::Attest(_)) | Ok(_) => Err(AttestOrSprotError::Sprot(
SprotError::Protocol(SprotProtocolError::UnexpectedResponse),
)
.into()),
Err(e) => Err(AttestOrSprotError::Sprot(e).into()),
}
}

fn attest_len(
&mut self,
_msg: &userlib::RecvMessage,
) -> Result<u32, idol_runtime::RequestError<AttestOrSprotError>> {
let body = ReqBody::Attest(AttestReq::AttestLen);
let tx_size = Request::pack(&body, self.tx_buf);
let rsp = self.do_send_recv_retries(tx_size, TIMEOUT_QUICK, 1)?;
match rsp.body {
Ok(RspBody::Attest(Ok(AttestRsp::AttestLen(s)))) => Ok(s),
Ok(RspBody::Attest(Err(e))) => {
Err(AttestOrSprotError::Attest(e).into())
}
Ok(RspBody::Attest(_)) | Ok(_) => Err(AttestOrSprotError::Sprot(
SprotError::Protocol(SprotProtocolError::UnexpectedResponse),
)
.into()),
Err(e) => Err(AttestOrSprotError::Sprot(e).into()),
}
}
}

mod idl {
Expand Down
22 changes: 22 additions & 0 deletions idl/sprot.idol
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,27 @@ Interface(
encoding: Hubpack,
idempotent: true,
),
"attest": (
doc: "Get an attestation",
args: {},
leases: {
"nonce": (type: "[u8]", read: true, max_len: Some(128)),
"dest": (type: "[u8]", write: true),
},
reply: Result(
ok: "()",
err: Complex("AttestOrSprotError"),
),
encoding: Hubpack,
),
"attest_len": (
doc: "Get length of a serialized attestation",
reply: Result(
ok: "u32",
err: Complex("AttestOrSprotError"),
),
encoding: Hubpack,
idempotent: true,
),
}
)

0 comments on commit 1bca9d5

Please sign in to comment.