Skip to content

Commit 8358e03

Browse files
committed
security: Fix bug and gate it properly via asserts and warnings. Reported by @mkj, re-reviewed by @ramrunner, thanks and kudos to both
1 parent 3c9dff0 commit 8358e03

1 file changed

Lines changed: 32 additions & 3 deletions

File tree

ssh-stamp-esp32/src/bin/ssh-stamp-esp32.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,31 @@ async fn main(spawner: Spawner) -> ! {
8787
cfg_if::cfg_if! {
8888
if #[cfg(any(feature = "esp32c5", feature = "esp32c61"))] {
8989
// ESP32-C5/C61 have no TRNG peripheral — use the basic Rng directly.
90+
// Until the TODO above is resolved, key material on these chips is
91+
// only as good as the bare RNG register, so say so out loud.
92+
warn!("No TRNG on this chip: RNG is not cryptographically secure until the radio is up");
9093
let rng = esp_hal::rng::Rng::new();
9194
register_custom_rng(rng);
9295
} else {
93-
let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1);
94-
let trng = Trng::try_new().unwrap();
96+
// The TrngSource must outlive every consumer of randomness, not
97+
// just this block. `Trng::downgrade` hands back `Rng`, a
98+
// zero-sized handle that simply reads the RNG register, and
99+
// dropping the TrngSource calls `revert_trng()` which switches the
100+
// ADC entropy source back off. Anything drawn afterwards is no
101+
// longer cryptographically secure.
102+
//
103+
// That matters because none of the key material is generated here:
104+
// the SSH host key, WiFi SSID/PSK and MAC are all minted further
105+
// down in `store::load_or_create`, and sunset draws fresh session
106+
// and key-exchange material for every connection later still.
107+
//
108+
// `main` never returns, so binding it here keeps the entropy
109+
// source enabled for the lifetime of the program.
110+
let _trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1);
111+
let trng = Trng::try_new()
112+
.expect("TrngSource was just created, so the TRNG must be available");
95113
let rng = trng.downgrade();
96114
register_custom_rng(rng);
97-
drop(trng_source);
98115
}
99116
}
100117

@@ -125,6 +142,18 @@ async fn main(spawner: Spawner) -> ! {
125142
tx: tx_num,
126143
};
127144

145+
// On first boot this mints the SSH host key and the WiFi PSK, so the
146+
// entropy source enabled above has to still be running. Guard the
147+
// invariant rather than trusting a comment: `debug-assertions` are on
148+
// even in release for this workspace, so reintroducing an early drop of
149+
// the `TrngSource` fails loudly on the bench instead of silently
150+
// producing predictable keys.
151+
#[cfg(not(any(feature = "esp32c5", feature = "esp32c61")))]
152+
debug_assert!(
153+
TrngSource::is_enabled(),
154+
"entropy source was disabled before host key generation"
155+
);
156+
128157
debug!("Loading config");
129158
let flash_config = {
130159
let Some(flash_storage_guard) = flash::get_flash_n_buffer() else {

0 commit comments

Comments
 (0)