Skip to content

Commit 44f6260

Browse files
committed
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.
1 parent 95df101 commit 44f6260

File tree

8 files changed

+84
-26
lines changed

8 files changed

+84
-26
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/lpc55xpresso/app.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ features = ["dice-seed"]
116116
priority = 3
117117
uses = ["rng", "pmc"]
118118
start = true
119-
stacksize = 2704
119+
stacksize = 4200
120120
task-slots = ["syscon_driver"]
121-
extern-regions = ["dice_rng"]
121+
extern-regions = ["dice_certs", "dice_rng"]
122122

123123
[tasks.pong]
124124
name = "task-pong"

app/rot-carrier/app.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ name = "drv-lpc55-rng"
101101
priority = 5
102102
uses = ["rng", "pmc"]
103103
start = true
104-
stacksize = 2704
104+
stacksize = 4200
105105
task-slots = ["syscon_driver"]
106-
extern-regions = ["dice_rng"]
106+
extern-regions = ["dice_certs", "dice_rng"]
107107

108108
[tasks.sprot]
109109
name = "drv-lpc55-sprot-server"

drv/lpc55-rng/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ anyhow.workspace = true
2828
build-util.path = "../../build/util"
2929
cfg-if.workspace = true
3030
idol.workspace = true
31+
indexmap = { workspace = true, optional = true }
3132
serde.workspace = true
3233

3334
[features]
34-
dice-seed = ["stage0-handoff"]
35+
dice-seed = ["indexmap", "stage0-handoff"]
3536
no-ipc-counters = ["idol/no-counters"]
3637

3738
# This section is here to discourage RLS/rust-analyzer from doing test builds,

drv/lpc55-rng/build.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,35 @@ cfg_if::cfg_if! {
1212
}
1313
use anyhow::Context;
1414
use config::DataRegion;
15+
use indexmap::IndexMap;
1516
use std::{fs::File, io::Write};
1617

1718
const CFG_SRC: &str = "rng-config.rs";
1819
}
1920
}
2021

22+
#[cfg(feature = "dice-seed")]
23+
fn extern_region_to_cfg<W: Write>(
24+
out: &mut W,
25+
data_regions: &IndexMap<String, DataRegion>,
26+
name: &str,
27+
) -> Result<()> {
28+
let region = data_regions
29+
.get(name)
30+
.ok_or_else(|| anyhow::anyhow!("dice_certs data region not found"))?;
31+
32+
Ok(writeln!(
33+
out,
34+
r##"pub const {}: DataRegion = DataRegion {{
35+
address: {:#x},
36+
size: {:#x},
37+
}};"##,
38+
name.to_uppercase(),
39+
region.address,
40+
region.size
41+
)?)
42+
}
43+
2144
#[cfg(feature = "dice-seed")]
2245
fn extern_regions_to_cfg(path: &str) -> Result<()> {
2346
let out_dir = build_util::out_dir();
@@ -32,18 +55,8 @@ fn extern_regions_to_cfg(path: &str) -> Result<()> {
3255

3356
writeln!(out, "use crate::config::DataRegion;\n\n")?;
3457

35-
let region = data_regions
36-
.get("dice_rng")
37-
.ok_or_else(|| anyhow::anyhow!("dice_certs data region not found"))?;
38-
39-
Ok(writeln!(
40-
out,
41-
r##"pub const DICE_RNG: DataRegion = DataRegion {{
42-
address: {:#x},
43-
size: {:#x},
44-
}};"##,
45-
region.address, region.size
46-
)?)
58+
extern_region_to_cfg(&mut out, &data_regions, "dice_certs")?;
59+
extern_region_to_cfg(&mut out, &data_regions, "dice_rng")
4760
}
4861

4962
fn main() -> Result<()> {

drv/lpc55-rng/src/main.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use core::{cmp, usize};
1515
use drv_lpc55_syscon_api::Syscon;
1616
use drv_rng_api::RngError;
1717
use idol_runtime::{ClientError, NotificationHandler, RequestError};
18-
use lib_dice::{RngSeed, SeedBuf};
18+
use lib_dice::{persistid_cert_tmpl::SUBJECT_CN_LENGTH, RngSeed, SeedBuf};
1919
use lib_lpc55_rng::Lpc55Rng;
2020
use rand_chacha::ChaCha20Rng;
2121
use rand_core::{impls, Error, RngCore, SeedableRng};
@@ -29,13 +29,14 @@ use userlib::task_slot;
2929
use zeroize::Zeroizing;
3030

3131
cfg_if::cfg_if! {
32-
if #[cfg(any(feature = "dice-seed"))] {
32+
if #[cfg(feature = "dice-seed")] {
3333
use config::DataRegion;
3434
use hubpack::SerializedSize;
35-
use lib_dice::RngData;
35+
use lib_dice::{persistid_cert_tmpl::SUBJECT_CN_RANGE, CertData, RngData};
3636
use ringbuf::ringbuf_entry;
3737
use serde::Deserialize;
3838
use stage0_handoff::{HandoffData, HandoffDataLoadError};
39+
use userlib::UnwrapLite;
3940

4041
// This file is generated by the crate build.rs. It contains instances
4142
// of config::DataRegion structs describing regions of memory
@@ -44,7 +45,7 @@ cfg_if::cfg_if! {
4445
include!(concat!(env!("OUT_DIR"), "/rng-config.rs"));
4546
}
4647

47-
use build::DICE_RNG;
48+
use build::{DICE_CERTS, DICE_RNG};
4849
}
4950
}
5051

@@ -56,6 +57,8 @@ enum Trace {
5657
NoDiceSeed,
5758
#[cfg(feature = "dice-seed")]
5859
HandoffError(HandoffDataLoadError),
60+
#[cfg(feature = "dice-seed")]
61+
NoSeedPersonalization,
5962
None,
6063
}
6164

@@ -80,6 +83,7 @@ where
8083
fn new(
8184
seed: Option<&RngSeed>,
8285
mut reseeder: R,
86+
pid: Option<&[u8; SUBJECT_CN_LENGTH]>,
8387
threshold: usize,
8488
) -> Result<Self, Error> {
8589
let threshold = if threshold == 0 {
@@ -94,6 +98,11 @@ where
9498
Digest::update(&mut mixer, seed.as_bytes());
9599
}
96100

101+
if let Some(pid) = pid {
102+
// mix in unique platform id
103+
Digest::update(&mut mixer, pid);
104+
}
105+
97106
// w/ 32 bytes from HRNG
98107
let mut buf = Zeroizing::new(T::Seed::default());
99108
reseeder.try_fill_bytes(buf.as_mut())?;
@@ -172,10 +181,11 @@ impl Lpc55RngServer {
172181
fn new(
173182
seed: Option<&RngSeed>,
174183
reseeder: Lpc55Rng,
184+
pid: Option<&[u8; SUBJECT_CN_LENGTH]>,
175185
threshold: usize,
176186
) -> Result<Self, Error> {
177187
Ok(Lpc55RngServer(ReseedingRng::new(
178-
seed, reseeder, threshold,
188+
seed, reseeder, pid, threshold,
179189
)?))
180190
}
181191
}
@@ -266,15 +276,45 @@ pub fn get_dice_seed() -> Option<RngSeed> {
266276
}
267277
}
268278

279+
/// Get the platform identifier / barcode string from the platform identity
280+
/// cert passed to hubris by the lpc55-rot-startup through the stage0-handoff
281+
/// memory region.
282+
///
283+
/// If use of the platform identifier string is not enabled then this function
284+
/// will return `None`. Otherwise it will try to get the platform identity
285+
/// string from the stage0-handoff region. If it's unable to get this data it
286+
/// will put an entry into the ringbuf and panic.
287+
pub fn get_seed_personalization() -> Option<[u8; SUBJECT_CN_LENGTH]> {
288+
cfg_if::cfg_if! {
289+
if #[cfg(feature = "dice-seed")] {
290+
match load_data_from_region::<CertData>(&DICE_CERTS) {
291+
Some(cert_data) => Some(
292+
cert_data.persistid_cert.0.as_bytes()[SUBJECT_CN_RANGE]
293+
.try_into()
294+
.unwrap_lite(),
295+
),
296+
_ => {
297+
ringbuf_entry!(Trace::NoSeedPersonalization);
298+
panic!();
299+
},
300+
}
301+
} else {
302+
None
303+
}
304+
}
305+
}
306+
269307
#[export_name = "main"]
270308
fn main() -> ! {
271309
let seed = get_dice_seed();
310+
let pid = get_seed_personalization();
272311

273312
let rng = Lpc55Rng::new(&Syscon::from(SYSCON.get_task_id()));
274313

275314
let threshold = 0x100000; // 1 MiB
276-
let mut rng = Lpc55RngServer::new(seed.as_ref(), rng, threshold)
277-
.expect("Failed to create Lpc55RngServer");
315+
let mut rng =
316+
Lpc55RngServer::new(seed.as_ref(), rng, pid.as_ref(), threshold)
317+
.expect("Failed to create Lpc55RngServer");
278318
let mut buffer = [0u8; idl::INCOMING_SIZE];
279319

280320
loop {

lib/dice/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod alias_cert_tmpl;
3030
mod deviceid_cert_tmpl;
3131
mod handoff;
3232
mod mfg;
33-
mod persistid_cert_tmpl;
33+
pub mod persistid_cert_tmpl;
3434
mod persistid_csr_tmpl;
3535
pub use crate::mfg::{
3636
DiceMfg, DiceMfgState, PersistIdSeed, SelfMfg, SerialMfg,

lib/dice/src/persistid_cert_tmpl.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use core::ops::Range;
1212
pub const SIZE: usize = 441;
1313
pub const SERIAL_NUMBER_RANGE: Range<usize> = 15..16;
1414
pub const ISSUER_CN_RANGE: Range<usize> = 82..114;
15-
pub const SUBJECT_CN_RANGE: Range<usize> = 207..239;
15+
pub const SUBJECT_CN_START: usize = 207;
16+
pub const SUBJECT_CN_END: usize = 239;
17+
pub const SUBJECT_CN_RANGE: Range<usize> = SUBJECT_CN_START..SUBJECT_CN_END;
18+
pub const SUBJECT_CN_LENGTH: usize = SUBJECT_CN_END - SUBJECT_CN_START;
1619
pub const PUB_RANGE: Range<usize> = 251..283;
1720
pub const SIG_RANGE: Range<usize> = 377..441;
1821
pub const SIGNDATA_RANGE: Range<usize> = 4..367;

0 commit comments

Comments
 (0)