Skip to content

Commit b7826c2

Browse files
committed
flesh out backup register interfaces
- adds API for retrieving & setting the ephemeral key. This is a key that is erased by a power-on reset, but is preserved between deep-sleep sleep/wake cycles. It is intended for securing a lock PIN, and can be up to 192 bits long. - adds API for checking the warm boot flags, which are also stored in the backup registers.
1 parent 8ac6e17 commit b7826c2

File tree

5 files changed

+165
-9
lines changed

5 files changed

+165
-9
lines changed

libs/bao1x-api/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub mod signatures;
1818
pub use offsets::*;
1919
pub mod clocks;
2020
pub mod pubkeys;
21-
use arbitrary_int::u31;
21+
use arbitrary_int::u30;
2222
use bitbybit::bitfield;
2323
pub use clocks::*;
2424
pub mod bio;
@@ -65,8 +65,13 @@ pub const AUTO_AUDIT_LIMIT: u32 = 3;
6565
#[bitfield(u32)]
6666
#[derive(PartialEq, Eq, Debug)]
6767
pub struct BackupFlags {
68-
#[bits(1..=31, rw)]
69-
reserved: u31,
68+
#[bits(2..=31, rw)]
69+
reserved: u30,
70+
/// When true, the system has previously booted. This is reserved for OS-level management. It is
71+
/// not automatically managed by the bootloader. However, after an AORST_N, the flag should be `false`
72+
/// by hardware design.
73+
#[bit(1, rw)]
74+
warm_boot: bool,
7075
/// When `false`, indicates that the time in the RTC register is not synchronized to the offset
7176
/// that is read from disk. Upon first encounter with an external time source, the offset should
7277
/// be captured and recorded to disk.

libs/bao1x-hal/src/buram.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::ops::Range;
22

33
const KEY_RANGE: Range<usize> = 2..8;
4-
const KEY_LEN: usize = range_len(KEY_RANGE) * size_of::<u32>();
4+
pub const KEY_LEN: usize = range_len(KEY_RANGE) * size_of::<u32>();
55
const HASH_LOC: usize = 0;
66
const FLAGS_LOC: usize = 1;
77

libs/keystore-api/src/gen2_api.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ pub enum Opcode {
1515
AesOracle = 4,
1616
/// initiate key wrapper operation
1717
AesKwp = 5,
18-
/// Ephemeral secret operations
19-
EphemeralOp = 256,
18+
/// Ephemeral secret operations. Split into MSB/LSB pairs, because we want to strictly use
19+
/// scalar messages only for this. This helps to ensure to leakage of secrets to memory pages
20+
/// (there is some risk of stack spillage, but this at least reduces the attack surface).
21+
/// The ephemeral secret is 192 bits long - so the `Scalar` operation is split into 1x control
22+
/// word, and 3x 32 bit words that transmit the secret.
23+
Ephemeral = 256,
24+
/// Flag operations
25+
GetFlags = 512,
26+
SetFlags = 513,
2027

2128
// ----- below are non-cryptographic opcodes but used to manipulate sensitive state -----
2229
/// Set bootwait parameters
@@ -26,3 +33,11 @@ pub enum Opcode {
2633
/// Used to map unknown opcodes
2734
InvalidCall = 65535,
2835
}
36+
37+
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)]
38+
pub enum EphemeralOp {
39+
GetLsb,
40+
SetLsb,
41+
GetMsb,
42+
SetMsb,
43+
}

services/keystore/src/lib.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bao1x_api::BackupFlags;
12
pub use cipher::{
23
BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, BlockSizeUser, ParBlocksSizeUser,
34
consts::U16, generic_array::GenericArray, inout::InOut,
@@ -208,6 +209,99 @@ impl Keystore {
208209
_ => unimplemented!(),
209210
}
210211
}
212+
213+
pub fn set_flags(&self, flags: BackupFlags) -> Result<(), xous::Error> {
214+
xous::send_message(
215+
self.conn,
216+
xous::Message::new_blocking_scalar(
217+
Opcode::SetFlags.to_usize().unwrap(),
218+
flags.raw_value() as usize,
219+
0,
220+
0,
221+
0,
222+
),
223+
)
224+
.map(|_| ())
225+
}
226+
227+
pub fn get_flags(&self) -> Result<BackupFlags, xous::Error> {
228+
match xous::send_message(
229+
self.conn,
230+
xous::Message::new_blocking_scalar(Opcode::GetFlags.to_usize().unwrap(), 0, 0, 0, 0),
231+
)? {
232+
xous::Result::Scalar5(_, flags, _, _, _) => Ok(BackupFlags::new_with_raw_value(flags as u32)),
233+
_ => unimplemented!(),
234+
}
235+
}
236+
237+
pub fn set_ephemeral_key(&self, key: &[u8; bao1x_hal::buram::KEY_LEN]) -> Result<(), xous::Error> {
238+
let offset = 0;
239+
xous::send_message(
240+
self.conn,
241+
xous::Message::new_blocking_scalar(
242+
Opcode::Ephemeral.to_usize().unwrap(),
243+
EphemeralOp::SetLsb.to_usize().unwrap(),
244+
u32::from_le_bytes(key[offset..offset + 4].try_into().unwrap()) as usize,
245+
u32::from_le_bytes(key[offset + 4..offset + 8].try_into().unwrap()) as usize,
246+
u32::from_le_bytes(key[offset + 8..offset + 12].try_into().unwrap()) as usize,
247+
),
248+
)
249+
.map(|_| ())?;
250+
251+
let offset = bao1x_hal::buram::KEY_LEN / 2;
252+
xous::send_message(
253+
self.conn,
254+
xous::Message::new_blocking_scalar(
255+
Opcode::Ephemeral.to_usize().unwrap(),
256+
EphemeralOp::SetMsb.to_usize().unwrap(),
257+
u32::from_le_bytes(key[offset..offset + 4].try_into().unwrap()) as usize,
258+
u32::from_le_bytes(key[offset + 4..offset + 8].try_into().unwrap()) as usize,
259+
u32::from_le_bytes(key[offset + 8..offset + 12].try_into().unwrap()) as usize,
260+
),
261+
)
262+
.map(|_| ())
263+
}
264+
265+
pub fn get_ephemeral_key(&self) -> Result<[u8; bao1x_hal::buram::KEY_LEN], xous::Error> {
266+
let mut key = [0u8; bao1x_hal::buram::KEY_LEN];
267+
let offset = 0;
268+
match xous::send_message(
269+
self.conn,
270+
xous::Message::new_blocking_scalar(
271+
Opcode::Ephemeral.to_usize().unwrap(),
272+
EphemeralOp::GetLsb.to_usize().unwrap(),
273+
0,
274+
0,
275+
0,
276+
),
277+
)? {
278+
xous::Result::Scalar5(_, _, arg2, arg3, arg4) => {
279+
key[offset..offset + 4].copy_from_slice(&arg2.to_le_bytes());
280+
key[offset + 4..offset + 8].copy_from_slice(&arg3.to_le_bytes());
281+
key[offset + 8..offset + 12].copy_from_slice(&arg4.to_le_bytes());
282+
}
283+
_ => unimplemented!(),
284+
}
285+
let offset = bao1x_hal::buram::KEY_LEN / 2;
286+
match xous::send_message(
287+
self.conn,
288+
xous::Message::new_blocking_scalar(
289+
Opcode::Ephemeral.to_usize().unwrap(),
290+
EphemeralOp::GetMsb.to_usize().unwrap(),
291+
0,
292+
0,
293+
0,
294+
),
295+
)? {
296+
xous::Result::Scalar5(_, _, arg2, arg3, arg4) => {
297+
key[offset..offset + 4].copy_from_slice(&arg2.to_le_bytes());
298+
key[offset + 4..offset + 8].copy_from_slice(&arg3.to_le_bytes());
299+
key[offset + 8..offset + 12].copy_from_slice(&arg4.to_le_bytes());
300+
}
301+
_ => unimplemented!(),
302+
}
303+
Ok(key)
304+
}
211305
}
212306

213307
use core::sync::atomic::{AtomicU32, Ordering};

services/keystore/src/platform/baosec/server.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bao1x_api::BackupFlags;
12
use bao1x_hal::board::{BOOKEND_END, BOOKEND_START};
23
use bao1x_hal::rram::Reram;
34
use keystore_api::*;
@@ -52,9 +53,50 @@ pub fn keystore(sid: SID) -> ! {
5253
store.aes_kwp(&mut kwp).expect("couldn't wrap key");
5354
buffer.replace(kwp).unwrap();
5455
}
55-
Opcode::EphemeralOp => {
56-
// this will use the backup_mgr to store ephemeral secrets
57-
todo!()
56+
Opcode::Ephemeral => {
57+
if let Some(scalar) = msg.body.scalar_message_mut() {
58+
let ephemeral_op: EphemeralOp =
59+
num_traits::FromPrimitive::from_usize(scalar.arg1).expect("invalid ephemeral op");
60+
let offset = match ephemeral_op {
61+
EphemeralOp::GetLsb | EphemeralOp::SetLsb => 0,
62+
EphemeralOp::GetMsb | EphemeralOp::SetMsb => bao1x_hal::buram::KEY_LEN / 2,
63+
};
64+
match ephemeral_op {
65+
EphemeralOp::SetLsb | EphemeralOp::SetMsb => {
66+
let mut key = backup_mgr.get_backup_key();
67+
key[offset..offset + 4].copy_from_slice(&scalar.arg2.to_le_bytes());
68+
key[offset + 4..offset + 8].copy_from_slice(&scalar.arg3.to_le_bytes());
69+
key[offset + 8..offset + 12].copy_from_slice(&scalar.arg4.to_le_bytes());
70+
// zeroize
71+
scalar.arg1 = 0;
72+
scalar.arg2 = 0;
73+
scalar.arg3 = 0;
74+
scalar.arg4 = 0;
75+
backup_mgr.set_backup_key(key);
76+
}
77+
EphemeralOp::GetLsb | EphemeralOp::GetMsb => {
78+
let key = backup_mgr.get_backup_key();
79+
scalar.arg2 =
80+
u32::from_le_bytes(key[offset..offset + 4].try_into().unwrap()) as usize;
81+
scalar.arg3 =
82+
u32::from_le_bytes(key[offset + 4..offset + 8].try_into().unwrap()) as usize;
83+
scalar.arg4 =
84+
u32::from_le_bytes(key[offset + 8..offset + 12].try_into().unwrap()) as usize;
85+
}
86+
}
87+
}
88+
}
89+
Opcode::GetFlags => {
90+
if let Some(scalar) = msg.body.scalar_message_mut() {
91+
let flags = backup_mgr.get_flags();
92+
scalar.arg1 = flags.raw_value() as usize;
93+
}
94+
}
95+
Opcode::SetFlags => {
96+
if let Some(scalar) = msg.body.scalar_message_mut() {
97+
let flag = BackupFlags::new_with_raw_value(scalar.arg1 as u32);
98+
backup_mgr.set_flags(flag);
99+
}
58100
}
59101
Opcode::Bootwait => {
60102
if let Some(scalar) = msg.body.scalar_message_mut() {

0 commit comments

Comments
 (0)