Skip to content

Commit

Permalink
lpc55-rng: Include SN from platform id cert in initial PRNG seed.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
flihp committed Sep 17, 2024
1 parent 39767db commit a51a583
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/lpc55xpresso/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions app/rot-carrier/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 2 additions & 1 deletion drv/lpc55-rng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
37 changes: 25 additions & 12 deletions drv/lpc55-rng/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<W: Write>(
out: &mut W,
data_regions: &IndexMap<String, DataRegion>,
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();
Expand All @@ -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<()> {
Expand Down
54 changes: 47 additions & 7 deletions drv/lpc55-rng/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand All @@ -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};
}
}

Expand All @@ -57,6 +58,8 @@ enum Trace {
NoDiceSeed,
#[cfg(feature = "dice-seed")]
HandoffError(HandoffDataLoadError),
#[cfg(feature = "dice-seed")]
NoSeedPersonalization,
}

ringbuf!(Trace, 16, Trace::None);
Expand All @@ -80,6 +83,7 @@ where
fn new(
seed: Option<&RngSeed>,
mut reseeder: R,
pid: Option<&[u8; SUBJECT_CN_LENGTH]>,
threshold: usize,
) -> Result<Self, Error> {
let threshold = if threshold == 0 {
Expand All @@ -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())?;
Expand Down Expand Up @@ -172,10 +181,11 @@ impl Lpc55RngServer {
fn new(
seed: Option<&RngSeed>,
reseeder: Lpc55Rng,
pid: Option<&[u8; SUBJECT_CN_LENGTH]>,
threshold: usize,
) -> Result<Self, Error> {
Ok(Lpc55RngServer(ReseedingRng::new(
seed, reseeder, threshold,
seed, reseeder, pid, threshold,
)?))
}
}
Expand Down Expand Up @@ -261,15 +271,45 @@ pub fn get_dice_seed() -> Option<RngSeed> {
}
}

/// 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::<CertData>(&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 {
Expand Down
2 changes: 1 addition & 1 deletion lib/dice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 4 additions & 1 deletion lib/dice/src/persistid_cert_tmpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use core::ops::Range;
pub const SIZE: usize = 441;
pub const SERIAL_NUMBER_RANGE: Range<usize> = 15..16;
pub const ISSUER_CN_RANGE: Range<usize> = 82..114;
pub const SUBJECT_CN_RANGE: Range<usize> = 207..239;
pub const SUBJECT_CN_START: usize = 207;
pub const SUBJECT_CN_END: usize = 239;
pub const SUBJECT_CN_RANGE: Range<usize> = SUBJECT_CN_START..SUBJECT_CN_END;
pub const SUBJECT_CN_LENGTH: usize = SUBJECT_CN_END - SUBJECT_CN_START;
pub const PUB_RANGE: Range<usize> = 251..283;
pub const SIG_RANGE: Range<usize> = 377..441;
pub const SIGNDATA_RANGE: Range<usize> = 4..367;
Expand Down

0 comments on commit a51a583

Please sign in to comment.