From a89e0a954a7ab0a7e571707e480789432dfa149a Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Wed, 10 Jan 2024 06:40:41 -0800 Subject: [PATCH] sprot: plumbing for attest & attest_len 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. --- app/lpc55xpresso/app-sprot.toml | 2 +- app/oxide-rot-1/app-dev.toml | 2 +- app/oxide-rot-1/app.toml | 2 +- app/rot-carrier/app.toml | 2 +- drv/lpc55-sprot-server/src/handler.rs | 46 +++++++++++++-- drv/sprot-api/src/lib.rs | 4 ++ drv/stm32h7-sprot-server/src/main.rs | 85 ++++++++++++++++++++++++++- idl/sprot.idol | 22 +++++++ 8 files changed, 156 insertions(+), 9 deletions(-) diff --git a/app/lpc55xpresso/app-sprot.toml b/app/lpc55xpresso/app-sprot.toml index 936714a1d..98ce9ce2c 100644 --- a/app/lpc55xpresso/app-sprot.toml +++ b/app/lpc55xpresso/app-sprot.toml @@ -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 diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index 6cd5377b6..285eee892 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -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 diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index f5d92e53e..878c1f9a9 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -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 diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index 768770c74..56666b518 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -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 diff --git a/drv/lpc55-sprot-server/src/handler.rs b/drv/lpc55-sprot-server/src/handler.rs index 4526ab112..8921054fc 100644 --- a/drv/lpc55-sprot-server/src/handler.rs +++ b/drv/lpc55-sprot-server/src/handler.rs @@ -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 }, } @@ -57,7 +58,7 @@ pub struct Handler { attest: Attest, } -impl Handler { +impl<'a> Handler { pub fn new() -> Handler { Handler { sprocket: crate::handler::sprockets::init(), @@ -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), SprotError> { + ) -> Result<(RspBody, Option>), SprotError> { match req.body { ReqBody::Status => { let status = RotStatus { @@ -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)) + } } } } diff --git a/drv/sprot-api/src/lib.rs b/drv/sprot-api/src/lib.rs index 70ea696b0..f9726eaed 100644 --- a/drv/sprot-api/src/lib.rs +++ b/drv/sprot-api/src/lib.rs @@ -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 @@ -414,6 +416,8 @@ pub enum AttestRsp { Record, Log, LogLen(u32), + Attest, + AttestLen(u32), } /// The body of a sprot response. diff --git a/drv/stm32h7-sprot-server/src/main.rs b/drv/stm32h7-sprot-server/src/main.rs index b32452391..f7633fc8a 100644 --- a/drv/stm32h7-sprot-server/src/main.rs +++ b/drv/stm32h7-sprot-server/src/main.rs @@ -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, @@ -1010,6 +1010,89 @@ impl idl::InOrderSpRotImpl for ServerImpl { Err(e) => Err(AttestOrSprotError::Sprot(e).into()), } } + + fn attest( + &mut self, + _msg: &userlib::RecvMessage, + nonce: idol_runtime::LenLimit< + idol_runtime::Leased, + NONCE_MAX_SIZE, + >, + dest: idol_runtime::Leased, + ) -> Result<(), idol_runtime::RequestError> + where + AttestOrSprotError: From, + { + 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::>( + 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> { + 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 { diff --git a/idl/sprot.idol b/idl/sprot.idol index 2e2ae8f8d..5315b786b 100644 --- a/idl/sprot.idol +++ b/idl/sprot.idol @@ -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, + ), } )