From 788b2b157342ffbd469def78a0ea21d1e0033174 Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Mon, 31 Jul 2023 13:34:12 -0700 Subject: [PATCH 1/2] CODEOWNERS: Replace 'mx-shift' with 'labbott'. --- CODEOWNERS | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 82f6abc5c..c5da8a6b2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,13 +1,13 @@ # Everything in the Oxide RoT v1 startup code path before Platform Identity # private key is secured needs to be reviewed by folks authorized to # production-release sign these images. -/app/oxide-rot-1/ @cbiffle @flihp @mx-shift -/build/util/ @cbiffle @flihp @mx-shift -/lib/armv8-m-mpu/ @cbiffle @flihp @mx-shift -/lib/dice/ @cbiffle @flihp @mx-shift -/lib/lpc55-puf/ @cbiffle @flihp @mx-shift -/lib/lpc55-romapi/ @cbiffle @flihp @mx-shift -/lib/lpc55-rot-startup/ @cbiffle @flihp @mx-shift -/lib/lpc55-usart/ @cbiffle @flihp @mx-shift -/lib/stage0-handoff/ @cbiffle @flihp @mx-shift -/lib/unwrap-lite/ @cbiffle @flihp @mx-shift \ No newline at end of file +/app/oxide-rot-1/ @cbiffle @flihp @labbott +/build/util/ @cbiffle @flihp @labbott +/lib/armv8-m-mpu/ @cbiffle @flihp @labbott +/lib/dice/ @cbiffle @flihp @labbott +/lib/lpc55-puf/ @cbiffle @flihp @labbott +/lib/lpc55-romapi/ @cbiffle @flihp @labbott +/lib/lpc55-rot-startup/ @cbiffle @flihp @labbott +/lib/lpc55-usart/ @cbiffle @flihp @labbott +/lib/stage0-handoff/ @cbiffle @flihp @labbott +/lib/unwrap-lite/ @cbiffle @flihp @labbott From c7b99bfc6ff095d6b516dea62e243a449d67815c Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Tue, 25 Jul 2023 15:42:36 -0700 Subject: [PATCH 2/2] attest: Add function to record a measurement observed by the platform. This function is *not* idempotent: if the 'record' function is called with the same parameters repeatedly the measurement log will eventually fill up resulting in an error. The measurement log is just an array of measurements (aka [u8; 32]) that is managed in an ArrayVec. The 'record' function takes an enum parameter identifying the hash algorithm and a lease holding the digest. We pass the digest as a lease partially because humility / hiffy can't pass arbitrary arrays as parameters, but also because it's possible that in the future we'll need to support digests with varying lengths. --- Cargo.lock | 9 +++++ Cargo.toml | 2 + app/lpc55xpresso/app-sprot.toml | 4 +- app/lpc55xpresso/app.toml | 4 +- app/oxide-rot-1/app-dev.toml | 4 +- app/oxide-rot-1/app.toml | 4 +- app/rot-carrier/app.toml | 4 +- idl/attest.idol | 16 +++++++- task/attest-api/src/lib.rs | 17 +++++++++ task/attest/Cargo.toml | 3 ++ task/attest/src/main.rs | 67 ++++++++++++++++++++++++++++++++- 11 files changed, 121 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af2ff5941..ec5fc35de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,12 @@ dependencies = [ "cortex-m", ] +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "atomic-polyfill" version = "0.1.10" @@ -3873,8 +3879,10 @@ name = "task-attest" version = "0.1.0" dependencies = [ "anyhow", + "arrayvec", "attest-api", "build-util", + "crypto-common", "hubpack", "idol", "idol-runtime", @@ -3882,6 +3890,7 @@ dependencies = [ "num-traits", "ringbuf", "serde", + "sha3", "stage0-handoff", "unwrap-lite", "userlib", diff --git a/Cargo.toml b/Cargo.toml index 73e06faa3..187785ae3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ path = "sys/abi" [workspace.dependencies] anyhow = { version = "1.0.31", default-features = false, features = ["std"] } +arrayvec = { version = "0.7.4", default-features = false } atty = { version = "0.2", default-features = false } bitfield = { version = "0.13", default-features = false } bitflags = { version = "1.2.1", default-features = false } @@ -46,6 +47,7 @@ cortex-m = { version = "0.7", default-features = false, features = ["inline-asm" cortex-m-rt = { version = "0.6.12", default-features = false } cortex-m-semihosting = { version = "0.5.0", default-features = false } crc = { version = "3.0.0", default-features = false } +crypto-common = { version = "0.1.6", default-features = false } ctrlc = { version = "3.1.5", default-features = false } derive_more = { version = "0.99", default-features = false, features = ["from", "into"] } digest = { version = "0.10", default-features = false } diff --git a/app/lpc55xpresso/app-sprot.toml b/app/lpc55xpresso/app-sprot.toml index 9171588d2..0fe6f7f90 100644 --- a/app/lpc55xpresso/app-sprot.toml +++ b/app/lpc55xpresso/app-sprot.toml @@ -211,8 +211,8 @@ pins = [ [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 12512, ram = 16384} -stacksize = 9000 +max-sizes = {flash = 13600, ram = 16384} +stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/lpc55xpresso/app.toml b/app/lpc55xpresso/app.toml index 2a84c180b..be62fa2c1 100644 --- a/app/lpc55xpresso/app.toml +++ b/app/lpc55xpresso/app.toml @@ -141,8 +141,8 @@ extern-regions = ["sram2"] [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 12256, ram = 16384} -stacksize = 9000 +max-sizes = {flash = 13600, ram = 16384} +stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index 3110552d6..4804ca4b2 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -158,8 +158,8 @@ binary_path = "../../target/gimlet-c/dist/default/final.bin" [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 12512, ram = 16384} -stacksize = 9000 +max-sizes = {flash = 13600, ram = 16384} +stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index 74101edaf..cdf9eac5e 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -137,8 +137,8 @@ task-slots = ["swd"] [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 12256, ram = 16384} -stacksize = 9000 +max-sizes = {flash = 13600, ram = 16384} +stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index bfda9eb08..30d583b1c 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -204,8 +204,8 @@ binary_path = "../../target/gemini-bu/dist/final.bin" [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 12256, ram = 16384} -stacksize = 9000 +max-sizes = {flash = 13600, ram = 16384} +stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/idl/attest.idol b/idl/attest.idol index c56d9ef4a..e28216d28 100644 --- a/idl/attest.idol +++ b/idl/attest.idol @@ -40,6 +40,20 @@ Interface( ), encoding: Hubpack, idempotent: true, - ) + ), + "record": ( + doc: "Record a measurment", + args: { + "algorithm": "HashAlgorithm", + }, + leases: { + "data": (type: "[u8]", read: true), + }, + reply: Result( + ok: "()", + err: Complex("AttestError"), + ), + encoding: Hubpack, + ), } ) diff --git a/task/attest-api/src/lib.rs b/task/attest-api/src/lib.rs index 75beb2ad0..309f7e480 100644 --- a/task/attest-api/src/lib.rs +++ b/task/attest-api/src/lib.rs @@ -18,6 +18,23 @@ pub enum AttestError { InvalidCertIndex, NoCerts, OutOfRange, + MeasurementLogFull, + TaskRestarted, + BadLease, + UnsupportedAlgorithm, +} + +impl From for AttestError { + fn from(_: idol_runtime::ServerDeath) -> Self { + AttestError::TaskRestarted + } +} + +#[derive( + Copy, Clone, Debug, Deserialize, Eq, PartialEq, Serialize, SerializedSize, +)] +pub enum HashAlgorithm { + Sha3_256, } include!(concat!(env!("OUT_DIR"), "/client_stub.rs")); diff --git a/task/attest/Cargo.toml b/task/attest/Cargo.toml index b8152536b..59c1348db 100644 --- a/task/attest/Cargo.toml +++ b/task/attest/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] +arrayvec.workspace = true +crypto-common = { workspace = true } lib-dice = { path = "../../lib/dice" } hubpack = { workspace = true } idol-runtime = { workspace = true } @@ -12,6 +14,7 @@ ringbuf = { path = "../../lib/ringbuf" } serde = { workspace = true } stage0-handoff = { path = "../../lib/stage0-handoff" } attest-api = { path = "../attest-api" } +sha3 = { workspace = true } unwrap-lite = { path = "../../lib/unwrap-lite" } userlib = { path = "../../sys/userlib", features = ["panic-messages"] } zerocopy = { workspace = true } diff --git a/task/attest/src/main.rs b/task/attest/src/main.rs index 6a055ed80..09feecb53 100644 --- a/task/attest/src/main.rs +++ b/task/attest/src/main.rs @@ -11,14 +11,17 @@ mod config; -use attest_api::AttestError; +use arrayvec::ArrayVec; +use attest_api::{AttestError, HashAlgorithm}; use config::DataRegion; use core::slice; +use crypto_common::{typenum::Unsigned, OutputSizeUser}; use hubpack::SerializedSize; use idol_runtime::{ClientError, Leased, RequestError, W}; use lib_dice::{AliasData, CertData}; use ringbuf::{ringbuf, ringbuf_entry}; use serde::Deserialize; +use sha3::Sha3_256Core; use stage0_handoff::{HandoffData, HandoffDataLoadError}; use zerocopy::AsBytes; @@ -42,6 +45,8 @@ enum Trace { Index(u32), Offset(u32), Startup, + Record(HashAlgorithm), + BadLease(usize), None, } @@ -70,9 +75,49 @@ fn load_data_from_region< } } +// the size of the measurements we record +// NOTE: the rust crypto digest traits don't expose consts for the lengths +// of various hash functions +const SHA3_256_DIGEST_SIZE: usize = + ::OutputSize::USIZE; + +// the number of Measurements we can record +const CAPACITY: usize = 16; + +#[derive(Clone, Copy, Debug, PartialEq)] +struct Digest([u8; N]); + +#[derive(Clone, Copy, Debug, PartialEq)] +enum Measurement { + Sha3_256(Digest), +} + +impl Measurement { + fn new( + algorithm: HashAlgorithm, + data: idol_runtime::Leased, + ) -> Result> { + Ok(match algorithm { + HashAlgorithm::Sha3_256 => { + if data.len() != SHA3_256_DIGEST_SIZE { + ringbuf_entry!(Trace::BadLease(data.len())); + return Err(AttestError::BadLease.into()); + } + + let mut digest = Digest([0u8; SHA3_256_DIGEST_SIZE]); + data.read_range(0..digest.0.len(), &mut digest.0) + .map_err(|_| RequestError::went_away())?; + + Measurement::Sha3_256(digest) + } + }) + } +} + struct AttestServer { alias_data: Option, cert_data: Option, + measurements: ArrayVec, } impl Default for AttestServer { @@ -80,6 +125,7 @@ impl Default for AttestServer { Self { alias_data: load_data_from_region(&ALIAS_DATA), cert_data: load_data_from_region(&CERT_DATA), + measurements: ArrayVec::::new(), } } } @@ -190,6 +236,23 @@ impl idl::InOrderAttestImpl for AttestServer { Ok(()) } + + fn record( + &mut self, + _: &userlib::RecvMessage, + algorithm: HashAlgorithm, + data: idol_runtime::Leased, + ) -> Result<(), RequestError> { + ringbuf_entry!(Trace::Record(algorithm)); + + if self.measurements.is_full() { + return Err(AttestError::MeasurementLogFull.into()); + } + + self.measurements.push(Measurement::new(algorithm, data)?); + + Ok(()) + } } #[export_name = "main"] @@ -204,7 +267,7 @@ fn main() -> ! { } mod idl { - use super::AttestError; + use super::{AttestError, HashAlgorithm}; include!(concat!(env!("OUT_DIR"), "/server_stub.rs")); }