Skip to content

Commit cea3967

Browse files
committed
lpc55-rng: Include DICE derived seed in initial PRNG seed.
Previously we constructed the initial seed as 32 bytes from the hardware RNG: ``` SEED_0 = HRNG(32) ``` This commit includes a seed value constructed by the measured boot implementation from the DICE CDI. This is passed through to the RNG task using the `stage0-handoff` mechanism. This 32 byte value is now extracted and mixed with 32 bytes from the HRNG to construct SEED_0: ``` SEED_0 = sha3_256(DICE_SEED | HRNG(32)) ```
1 parent c39cea0 commit cea3967

File tree

8 files changed

+172
-16
lines changed

8 files changed

+172
-16
lines changed

Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/lpc55xpresso/app.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ name = "drv-lpc55-rng"
115115
priority = 3
116116
uses = ["rng", "pmc"]
117117
start = true
118-
stacksize = 2600
118+
stacksize = 3000
119119
task-slots = ["syscon_driver"]
120+
extern-regions = ["dice_rng"]
120121

121122
[tasks.pong]
122123
name = "task-pong"

app/rot-carrier/app.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ name = "drv-lpc55-rng"
101101
priority = 5
102102
uses = ["rng", "pmc"]
103103
start = true
104-
stacksize = 2600
104+
stacksize = 3000
105105
task-slots = ["syscon_driver"]
106+
extern-regions = ["dice_rng"]
106107

107108
[tasks.sprot]
108109
name = "drv-lpc55-sprot-server"

chips/lpc55/memory.toml

+16
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,19 @@ size = 0x800
156156
read = true
157157
write = true
158158
execute = false
159+
160+
[[dice_rng]]
161+
name = "a"
162+
address =0x40101a00
163+
size = 0x100
164+
read = true
165+
write = true
166+
execute = false
167+
168+
[[dice_rng]]
169+
name = "b"
170+
address =0x40101a00
171+
size = 0x100
172+
read = true
173+
write = true
174+
execute = false

drv/lpc55-rng/Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,29 @@ edition = "2021"
55

66
[dependencies]
77
cfg-if = { workspace = true }
8+
hubpack.workspace = true
89
idol-runtime = { workspace = true }
910
num-traits = { workspace = true }
1011
rand_chacha = { workspace = true }
1112
rand_core = { workspace = true }
13+
serde.workspace = true
1214
sha3.workspace = true
1315
zerocopy = { workspace = true }
1416
zeroize.workspace = true
1517

1618
drv-lpc55-syscon-api = { path = "../lpc55-syscon-api" }
1719
drv-rng-api = { path = "../rng-api" }
20+
lib-dice.path = "../../lib/dice"
1821
lib-lpc55-rng.path = "../../lib/lpc55-rng"
22+
ringbuf.path = "../../lib/ringbuf"
23+
stage0-handoff.path = "../../lib/stage0-handoff"
1924
userlib = { path = "../../sys/userlib", features = ["panic-messages"] }
2025

2126
[build-dependencies]
22-
idol = { workspace = true }
27+
anyhow.workspace = true
28+
build-util.path = "../../build/util"
29+
idol.workspace = true
30+
serde.workspace = true
2331

2432
[features]
2533
no-ipc-counters = ["idol/no-counters"]

drv/lpc55-rng/build.rs

+41-6
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,50 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
5+
use anyhow::{anyhow, Context, Result};
6+
use idol::{server::ServerStyle, CounterSettings};
7+
use std::{fs::File, io::Write};
8+
9+
mod config {
10+
include!("src/config.rs");
11+
}
12+
13+
use config::DataRegion;
14+
15+
const CFG_SRC: &str = "rng-config.rs";
16+
17+
fn main() -> Result<()> {
618
idol::Generator::new()
7-
.with_counters(
8-
idol::CounterSettings::default().with_server_counters(false),
9-
)
19+
.with_counters(CounterSettings::default().with_server_counters(false))
1020
.build_server_support(
1121
"../../idl/rng.idol",
1222
"server_stub.rs",
13-
idol::server::ServerStyle::InOrder,
14-
)?;
23+
ServerStyle::InOrder,
24+
)
25+
.map_err(|e| anyhow!(e))?;
26+
27+
let out_dir = build_util::out_dir();
28+
let dest_path = out_dir.join(CFG_SRC);
29+
let mut out =
30+
File::create(dest_path).context(format!("creating {}", CFG_SRC))?;
31+
32+
let data_regions = build_util::task_extern_regions::<DataRegion>()?;
33+
if data_regions.is_empty() {
34+
return Err(anyhow!("no data regions found"));
35+
}
36+
37+
let region = data_regions
38+
.get("dice_rng")
39+
.ok_or_else(|| anyhow!("dice_rng data region not found"))?;
40+
writeln!(
41+
out,
42+
r##"use crate::config::DataRegion;
43+
pub const RNG_DATA: DataRegion = DataRegion {{
44+
address: {:#x},
45+
size: {:#x},
46+
}};"##,
47+
region.address, region.size
48+
)?;
49+
1550
Ok(())
1651
}

drv/lpc55-rng/src/config.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use serde::Deserialize;
6+
7+
#[derive(Deserialize, Default, Debug)]
8+
#[serde(rename_all = "kebab-case")]
9+
pub struct DataRegion {
10+
pub address: u32,
11+
pub size: u32,
12+
}

drv/lpc55-rng/src/main.rs

+83-7
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,48 @@
99
#![no_std]
1010
#![no_main]
1111

12-
use core::{cmp, usize};
12+
mod config;
13+
14+
use config::DataRegion;
15+
use core::{cmp, slice, usize};
1316
use drv_lpc55_syscon_api::Syscon;
1417
use drv_rng_api::RngError;
18+
use hubpack::SerializedSize;
1519
use idol_runtime::{ClientError, NotificationHandler, RequestError};
20+
use lib_dice::{RngData, RngSeed, SeedBuf};
1621
use lib_lpc55_rng::Lpc55Rng;
1722
use rand_chacha::ChaCha20Rng;
1823
use rand_core::{impls, Error, RngCore, SeedableRng};
24+
use ringbuf::{ringbuf, ringbuf_entry};
25+
use serde::Deserialize;
1926
use sha3::{
2027
digest::crypto_common::{generic_array::GenericArray, OutputSizeUser},
2128
digest::FixedOutputReset,
2229
Digest, Sha3_256,
2330
};
31+
use stage0_handoff::{HandoffData, HandoffDataLoadError};
2432
use userlib::*;
2533
use zeroize::Zeroizing;
2634

35+
// This file is generated by the crate build.rs. It contains instances of
36+
// config::DataRegion structs describing regions of memory configured &
37+
// exposed to this task by the hubris build.
38+
mod build {
39+
include!(concat!(env!("OUT_DIR"), "/rng-config.rs"));
40+
}
41+
42+
use build::RNG_DATA;
43+
2744
task_slot!(SYSCON, syscon_driver);
2845

46+
#[derive(Copy, Clone, PartialEq)]
47+
enum Trace {
48+
HandoffError(HandoffDataLoadError),
49+
None,
50+
}
51+
52+
ringbuf!(Trace, 16, Trace::None);
53+
2954
// low-budget rand::rngs::adapter::ReseedingRng w/o fork stuff
3055
struct ReseedingRng<T: SeedableRng, R: RngCore, H: Digest> {
3156
inner: T,
@@ -42,19 +67,35 @@ where
4267
H: FixedOutputReset + Default + Digest,
4368
[u8; 32]: From<GenericArray<u8, <H as OutputSizeUser>::OutputSize>>,
4469
{
45-
fn new(mut reseeder: R, threshold: usize) -> Result<Self, Error> {
70+
fn new(
71+
seed: RngSeed,
72+
mut reseeder: R,
73+
threshold: usize,
74+
) -> Result<Self, Error> {
4675
let threshold = if threshold == 0 {
4776
usize::MAX
4877
} else {
4978
threshold
5079
};
5180

81+
let mut mixer = H::default();
82+
// mix platform unique seed drived by measured boot
83+
Digest::update(&mut mixer, seed.as_bytes());
84+
85+
// w/ 32 bytes from HRNG
86+
let mut buf = Zeroizing::new(T::Seed::default());
87+
reseeder.try_fill_bytes(buf.as_mut())?;
88+
Digest::update(&mut mixer, buf.as_ref());
89+
90+
// create initial instance of the SeedableRng from the seed
91+
let inner = T::from_seed(mixer.finalize_fixed_reset().into());
92+
5293
Ok(ReseedingRng {
53-
inner: T::from_rng(&mut reseeder)?,
94+
inner,
5495
reseeder,
5596
threshold,
5697
bytes_until_reseed: threshold,
57-
mixer: H::default(),
98+
mixer,
5899
})
59100
}
60101
}
@@ -116,8 +157,14 @@ where
116157
struct Lpc55RngServer(ReseedingRng<ChaCha20Rng, Lpc55Rng, Sha3_256>);
117158

118159
impl Lpc55RngServer {
119-
fn new(reseeder: Lpc55Rng, threshold: usize) -> Result<Self, Error> {
120-
Ok(Lpc55RngServer(ReseedingRng::new(reseeder, threshold)?))
160+
fn new(
161+
seed: RngSeed,
162+
reseeder: Lpc55Rng,
163+
threshold: usize,
164+
) -> Result<Self, Error> {
165+
Ok(Lpc55RngServer(ReseedingRng::new(
166+
seed, reseeder, threshold,
167+
)?))
121168
}
122169
}
123170

@@ -156,12 +203,41 @@ impl NotificationHandler for Lpc55RngServer {
156203
}
157204
}
158205

206+
/// Load a type implementing HandoffData (and others) from a config::DataRegion.
207+
/// Errors will be reported in the ringbuf and will return in None.
208+
fn load_data_from_region<
209+
T: for<'a> Deserialize<'a> + HandoffData + SerializedSize,
210+
>(
211+
region: &DataRegion,
212+
) -> Option<T> {
213+
// Safety: This memory is setup by code executed before hubris and
214+
// exposed using the kernel `extern-regions` mechanism. The safety of
215+
// this code is an extension of our trust in the hubris kernel / build.
216+
let data = unsafe {
217+
slice::from_raw_parts(region.address as *mut u8, region.size as usize)
218+
};
219+
220+
// this can be replaced w/ .ok() if we get rid of the ringbuf entry
221+
match T::load_from_addr(data) {
222+
Ok(d) => Some(d),
223+
Err(e) => {
224+
ringbuf_entry!(Trace::HandoffError(e));
225+
None
226+
}
227+
}
228+
}
229+
159230
#[export_name = "main"]
160231
fn main() -> ! {
232+
let seed = {
233+
load_data_from_region::<RngData>(&RNG_DATA)
234+
.unwrap_lite()
235+
.seed
236+
};
161237
let rng = Lpc55Rng::new(&Syscon::from(SYSCON.get_task_id()));
162238

163239
let threshold = 0x100000; // 1 MiB
164-
let mut rng = Lpc55RngServer::new(rng, threshold)
240+
let mut rng = Lpc55RngServer::new(seed, rng, threshold)
165241
.expect("Failed to create Lpc55RngServer");
166242
let mut buffer = [0u8; idl::INCOMING_SIZE];
167243

0 commit comments

Comments
 (0)