diff --git a/Cargo.lock b/Cargo.lock index 59ac92138..3c7ed3c0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1297,6 +1297,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 1c3e66c5f..b8835edb5 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,13 +29,14 @@ use userlib::task_slot; 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}; + use userlib::UnwrapLite; // This file is generated by the crate build.rs. It contains instances // of config::DataRegion structs describing regions of memory @@ -44,7 +45,7 @@ cfg_if::cfg_if! { include!(concat!(env!("OUT_DIR"), "/rng-config.rs")); } - use build::DICE_RNG; + use build::{DICE_CERTS, DICE_RNG}; } } @@ -57,6 +58,8 @@ enum Trace { NoDiceSeed, #[cfg(feature = "dice-seed")] HandoffError(HandoffDataLoadError), + #[cfg(feature = "dice-seed")] + NoSeedPersonalization, } ringbuf!(Trace, 16, Trace::None); @@ -80,6 +83,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 +98,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 +181,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, )?)) } } @@ -261,15 +271,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;