From ee43932125e8656e999a2e2bface3a694364394c Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Fri, 14 Jun 2024 21:57:33 +0000 Subject: [PATCH] lpc55-rng: Include SN from platform id cert in initial PRNG seed. Platforms assigned a unique serial number can include this string in the initial seed to ensure uniqueness in the bit stream produced by the RNG. We now construct the intial seed as: ``` SEED_0 = sha3_256(DICE_SEED | SN | HRNG(32)) ``` Extracting the Platform Id / serial number from the platform identity cert required exposing the relevant module from the lib-dice crate. We also add additional constants to the template module that are required to know the length of the platform id string at compile time. Finally this feature is gated by the same `dice-seed` feature used for the seed derived by measured boot for simplicity. --- Cargo.lock | 1 + app/lpc55xpresso/app.toml | 4 +-- app/rot-carrier/app.toml | 4 +-- drv/lpc55-rng/Cargo.toml | 3 +- drv/lpc55-rng/build.rs | 37 +++++++++++++------- drv/lpc55-rng/src/main.rs | 53 +++++++++++++++++++++++++---- lib/dice/src/lib.rs | 2 +- lib/dice/src/persistid_cert_tmpl.rs | 5 ++- 8 files changed, 83 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efa5741f3..3f399d893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1255,6 +1255,7 @@ dependencies = [ "hubpack", "idol", "idol-runtime", + "indexmap 1.9.1", "lib-dice", "lib-lpc55-rng", "num-traits", diff --git a/app/lpc55xpresso/app.toml b/app/lpc55xpresso/app.toml index 9100f1529..e1cbcc6bd 100644 --- a/app/lpc55xpresso/app.toml +++ b/app/lpc55xpresso/app.toml @@ -116,9 +116,9 @@ features = ["dice-seed"] priority = 3 uses = ["rng", "pmc"] start = true -stacksize = 2704 +stacksize = 4200 task-slots = ["syscon_driver"] -extern-regions = ["dice_rng"] +extern-regions = ["dice_certs", "dice_rng"] [tasks.pong] name = "task-pong" diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index 016f4cfe8..c22f06be8 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -101,9 +101,9 @@ name = "drv-lpc55-rng" priority = 5 uses = ["rng", "pmc"] start = true -stacksize = 2704 +stacksize = 4200 task-slots = ["syscon_driver"] -extern-regions = ["dice_rng"] +extern-regions = ["dice_certs", "dice_rng"] [tasks.sprot] name = "drv-lpc55-sprot-server" diff --git a/drv/lpc55-rng/Cargo.toml b/drv/lpc55-rng/Cargo.toml index 512e3c3ed..0355c03d4 100644 --- a/drv/lpc55-rng/Cargo.toml +++ b/drv/lpc55-rng/Cargo.toml @@ -28,10 +28,11 @@ anyhow.workspace = true build-util.path = "../../build/util" cfg-if.workspace = true idol.workspace = true +indexmap = { workspace = true, optional = true } serde.workspace = true [features] -dice-seed = ["stage0-handoff"] +dice-seed = ["indexmap", "stage0-handoff"] no-ipc-counters = ["idol/no-counters"] # This section is here to discourage RLS/rust-analyzer from doing test builds, diff --git a/drv/lpc55-rng/build.rs b/drv/lpc55-rng/build.rs index 8fb4688da..1b3cae546 100644 --- a/drv/lpc55-rng/build.rs +++ b/drv/lpc55-rng/build.rs @@ -12,12 +12,35 @@ cfg_if::cfg_if! { } use anyhow::Context; use config::DataRegion; + use indexmap::IndexMap; use std::{fs::File, io::Write}; const CFG_SRC: &str = "rng-config.rs"; } } +#[cfg(feature = "dice-seed")] +fn extern_region_to_cfg( + out: &mut W, + data_regions: &IndexMap, + name: &str, +) -> Result<()> { + let region = data_regions + .get(name) + .ok_or_else(|| anyhow::anyhow!("dice_certs data region not found"))?; + + Ok(writeln!( + out, + r##"pub const {}: DataRegion = DataRegion {{ + address: {:#x}, + size: {:#x}, +}};"##, + name.to_uppercase(), + region.address, + region.size + )?) +} + #[cfg(feature = "dice-seed")] fn extern_regions_to_cfg(path: &str) -> Result<()> { let out_dir = build_util::out_dir(); @@ -32,18 +55,8 @@ fn extern_regions_to_cfg(path: &str) -> Result<()> { writeln!(out, "use crate::config::DataRegion;\n\n")?; - let region = data_regions - .get("dice_rng") - .ok_or_else(|| anyhow::anyhow!("dice_certs data region not found"))?; - - Ok(writeln!( - out, - r##"pub const DICE_RNG: DataRegion = DataRegion {{ - address: {:#x}, - size: {:#x}, -}};"##, - region.address, region.size - )?) + extern_region_to_cfg(&mut out, &data_regions, "dice_certs")?; + extern_region_to_cfg(&mut out, &data_regions, "dice_rng") } fn main() -> Result<()> { diff --git a/drv/lpc55-rng/src/main.rs b/drv/lpc55-rng/src/main.rs index b06d3bf85..f26eae595 100644 --- a/drv/lpc55-rng/src/main.rs +++ b/drv/lpc55-rng/src/main.rs @@ -15,7 +15,7 @@ use core::{cmp, usize}; use drv_lpc55_syscon_api::Syscon; use drv_rng_api::RngError; use idol_runtime::{ClientError, NotificationHandler, RequestError}; -use lib_dice::{RngSeed, SeedBuf}; +use lib_dice::{persistid_cert_tmpl::SUBJECT_CN_LENGTH, RngSeed, SeedBuf}; use lib_lpc55_rng::Lpc55Rng; use rand_chacha::ChaCha20Rng; use rand_core::{impls, Error, RngCore, SeedableRng}; @@ -29,10 +29,10 @@ use userlib::*; use zeroize::Zeroizing; cfg_if::cfg_if! { - if #[cfg(any(feature = "dice-seed"))] { + if #[cfg(feature = "dice-seed")] { use config::DataRegion; use hubpack::SerializedSize; - use lib_dice::RngData; + use lib_dice::{persistid_cert_tmpl::SUBJECT_CN_RANGE, CertData, RngData}; use ringbuf::ringbuf_entry; use serde::Deserialize; use stage0_handoff::{HandoffData, HandoffDataLoadError}; @@ -44,7 +44,7 @@ cfg_if::cfg_if! { include!(concat!(env!("OUT_DIR"), "/rng-config.rs")); } - use build::DICE_RNG; + use build::{DICE_CERTS, DICE_RNG}; } } @@ -56,6 +56,8 @@ enum Trace { NoDiceSeed, #[cfg(feature = "dice-seed")] HandoffError(HandoffDataLoadError), + #[cfg(feature = "dice-seed")] + NoSeedPersonalization, None, } @@ -80,6 +82,7 @@ where fn new( seed: Option<&RngSeed>, mut reseeder: R, + pid: Option<&[u8; SUBJECT_CN_LENGTH]>, threshold: usize, ) -> Result { let threshold = if threshold == 0 { @@ -94,6 +97,11 @@ where Digest::update(&mut mixer, seed.as_bytes()); } + if let Some(pid) = pid { + // mix in unique platform id + Digest::update(&mut mixer, pid); + } + // w/ 32 bytes from HRNG let mut buf = Zeroizing::new(T::Seed::default()); reseeder.try_fill_bytes(buf.as_mut())?; @@ -172,10 +180,11 @@ impl Lpc55RngServer { fn new( seed: Option<&RngSeed>, reseeder: Lpc55Rng, + pid: Option<&[u8; SUBJECT_CN_LENGTH]>, threshold: usize, ) -> Result { Ok(Lpc55RngServer(ReseedingRng::new( - seed, reseeder, threshold, + seed, reseeder, pid, threshold, )?)) } } @@ -266,15 +275,45 @@ pub fn get_dice_seed() -> Option { } } +/// Get the platform identifier / barcode string from the platform identity +/// cert passed to hubris by the lpc55-rot-startup through the stage0-handoff +/// memory region. +/// +/// If use of the platform identifier string is not enabled then this function +/// will return `None`. Otherwise it will try to get the platform identity +/// string from the stage0-handoff region. If it's unable to get this data it +/// will put an entry into the ringbuf and panic. +pub fn get_seed_personalization() -> Option<[u8; SUBJECT_CN_LENGTH]> { + cfg_if::cfg_if! { + if #[cfg(feature = "dice-seed")] { + match load_data_from_region::(&DICE_CERTS) { + Some(cert_data) => Some( + cert_data.persistid_cert.0.as_bytes()[SUBJECT_CN_RANGE] + .try_into() + .unwrap_lite(), + ), + _ => { + ringbuf_entry!(Trace::NoSeedPersonalization); + panic!(); + }, + } + } else { + None + } + } +} + #[export_name = "main"] fn main() -> ! { let seed = get_dice_seed(); + let pid = get_seed_personalization(); let rng = Lpc55Rng::new(&Syscon::from(SYSCON.get_task_id())); let threshold = 0x100000; // 1 MiB - let mut rng = Lpc55RngServer::new(seed.as_ref(), rng, threshold) - .expect("Failed to create Lpc55RngServer"); + let mut rng = + Lpc55RngServer::new(seed.as_ref(), rng, pid.as_ref(), threshold) + .expect("Failed to create Lpc55RngServer"); let mut buffer = [0u8; idl::INCOMING_SIZE]; loop { diff --git a/lib/dice/src/lib.rs b/lib/dice/src/lib.rs index f0d556296..06cfcf2f6 100644 --- a/lib/dice/src/lib.rs +++ b/lib/dice/src/lib.rs @@ -30,7 +30,7 @@ mod alias_cert_tmpl; mod deviceid_cert_tmpl; mod handoff; mod mfg; -mod persistid_cert_tmpl; +pub mod persistid_cert_tmpl; mod persistid_csr_tmpl; pub use crate::mfg::{ DiceMfg, DiceMfgState, PersistIdSeed, SelfMfg, SerialMfg, diff --git a/lib/dice/src/persistid_cert_tmpl.rs b/lib/dice/src/persistid_cert_tmpl.rs index d4c03afb0..68140acfd 100644 --- a/lib/dice/src/persistid_cert_tmpl.rs +++ b/lib/dice/src/persistid_cert_tmpl.rs @@ -12,7 +12,10 @@ use core::ops::Range; pub const SIZE: usize = 441; pub const SERIAL_NUMBER_RANGE: Range = 15..16; pub const ISSUER_CN_RANGE: Range = 82..114; -pub const SUBJECT_CN_RANGE: Range = 207..239; +pub const SUBJECT_CN_START: usize = 207; +pub const SUBJECT_CN_END: usize = 239; +pub const SUBJECT_CN_RANGE: Range = SUBJECT_CN_START..SUBJECT_CN_END; +pub const SUBJECT_CN_LENGTH: usize = SUBJECT_CN_END - SUBJECT_CN_START; pub const PUB_RANGE: Range = 251..283; pub const SIG_RANGE: Range = 377..441; pub const SIGNDATA_RANGE: Range = 4..367;