Skip to content

Commit 13d636a

Browse files
committed
securechip: count optiga security events and integrate into tests
We count the number of security events the securechip functions take, and then assert in the keystore unit tests how many events the functions take there. This is a basis for trying to reduce the count, so we can measure the changes properly. Too many events induce throttling.
1 parent d46f7a7 commit 13d636a

File tree

7 files changed

+85
-10
lines changed

7 files changed

+85
-10
lines changed

src/rust/bitbox02-rust/src/hww/api/set_password.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ mod tests {
7272
}
7373
Ok("password".into())
7474
}));
75+
76+
bitbox02::securechip::fake_event_counter_reset();
7577
assert_eq!(
7678
block_on(process(
7779
&mut mock_hal,
@@ -81,6 +83,7 @@ mod tests {
8183
)),
8284
Ok(Response::Success(pb::Success {}))
8385
);
86+
assert_eq!(bitbox02::securechip::fake_event_counter(), 19);
8487
drop(mock_hal); // to remove mutable borrow of counter
8588
assert_eq!(counter, 2);
8689
assert!(!keystore::is_locked());

src/rust/bitbox02-rust/src/keystore.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,12 @@ mod tests {
205205
"",
206206
);
207207

208+
bitbox02::securechip::fake_event_counter_reset();
208209
assert_eq!(
209210
hex::encode(secp256k1_get_private_key(keypath).unwrap()),
210211
"4604b4b710fe91f584fff084e1a9159fe4f8408fff380596a604948474ce4fa3"
211212
);
213+
assert_eq!(bitbox02::securechip::fake_event_counter(), 1);
212214
}
213215

214216
#[test]
@@ -222,10 +224,12 @@ mod tests {
222224
"",
223225
);
224226

227+
bitbox02::securechip::fake_event_counter_reset();
225228
assert_eq!(
226229
hex::encode(secp256k1_get_private_key_twice(keypath).unwrap()),
227230
"4604b4b710fe91f584fff084e1a9159fe4f8408fff380596a604948474ce4fa3"
228231
);
232+
assert_eq!(bitbox02::securechip::fake_event_counter(), 2);
229233
}
230234

231235
#[test]
@@ -252,13 +256,19 @@ mod tests {
252256
"sleep own lobster state clean thrive tail exist cactus bitter pass soccer clinic riot dream turkey before sport action praise tunnel hood donate man",
253257
"",
254258
);
259+
260+
bitbox02::securechip::fake_event_counter_reset();
261+
255262
assert_eq!(
256263
get_xpub_twice(&[])
257264
.unwrap()
258265
.serialize_str(bip32::XPubType::Xpub)
259266
.unwrap(),
260267
"xpub661MyMwAqRbcEhX8d9WJh78SZrxusAzWFoykz4n5CF75uYRzixw5FZPUSoWyhaaJ1bpiPFdzdHSQqJN38PcTkyrLmxT4J2JDYfoGJQ4ioE2",
261268
);
269+
270+
assert_eq!(bitbox02::securechip::fake_event_counter(), 2);
271+
262272
assert_eq!(
263273
get_xpub_twice(keypath)
264274
.unwrap()
@@ -310,7 +320,10 @@ mod tests {
310320
"purity concert above invest pigeon category peace tuition hazard vivid latin since legal speak nation session onion library travel spell region blast estate stay",
311321
"",
312322
);
323+
324+
bitbox02::securechip::fake_event_counter_reset();
313325
assert_eq!(root_fingerprint(), Ok(vec![0x02, 0x40, 0xe9, 0x2a]));
326+
assert_eq!(bitbox02::securechip::fake_event_counter(), 2);
314327

315328
mock_unlocked_using_mnemonic(
316329
"small agent wife animal marine cloth exit thank stool idea steel frame",
@@ -439,20 +452,37 @@ mod tests {
439452
mock_memory();
440453
keystore::lock();
441454
let seed = &seed[..test.seed_len];
455+
442456
assert!(keystore::unlock_bip39(test.mnemonic_passphrase).is_err());
457+
458+
bitbox02::securechip::fake_event_counter_reset();
443459
assert!(keystore::encrypt_and_store_seed(seed, "foo").is_ok());
460+
assert_eq!(bitbox02::securechip::fake_event_counter(), 11);
461+
444462
assert!(keystore::unlock_bip39(test.mnemonic_passphrase).is_err());
445463
assert!(keystore::is_locked());
464+
465+
bitbox02::securechip::fake_event_counter_reset();
446466
assert!(keystore::unlock("foo").is_ok());
467+
assert_eq!(bitbox02::securechip::fake_event_counter(), 6);
468+
447469
assert!(keystore::is_locked());
470+
471+
bitbox02::securechip::fake_event_counter_reset();
448472
assert!(keystore::unlock_bip39(test.mnemonic_passphrase).is_ok());
473+
assert_eq!(bitbox02::securechip::fake_event_counter(), 2);
474+
449475
assert!(!keystore::is_locked());
450476
assert_eq!(
451477
get_bip39_mnemonic().unwrap().as_str(),
452478
test.expected_mnemonic,
453479
);
454480
let keypath = &[44 + HARDENED, 0 + HARDENED, 0 + HARDENED];
481+
482+
bitbox02::securechip::fake_event_counter_reset();
455483
let xpub = get_xpub_once(keypath).unwrap();
484+
assert_eq!(bitbox02::securechip::fake_event_counter(), 1);
485+
456486
assert_eq!(
457487
xpub.serialize_str(crate::bip32::XPubType::Xpub).unwrap(),
458488
test.expected_xpub,
@@ -482,7 +512,11 @@ mod tests {
482512

483513
// Test without tweak
484514
bitbox02::random::fake_reset();
515+
516+
bitbox02::securechip::fake_event_counter_reset();
485517
let sig = secp256k1_schnorr_sign(&keypath, &msg, None).unwrap();
518+
assert_eq!(bitbox02::securechip::fake_event_counter(), 1);
519+
486520
assert!(
487521
SECP256K1
488522
.verify_schnorr(

src/rust/bitbox02-sys/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ const ALLOWLIST_FNS: &[&str] = &[
144144
"securechip_model",
145145
"securechip_monotonic_increments_remaining",
146146
"securechip_u2f_counter_set",
147+
"fake_securechip_event_counter",
148+
"fake_securechip_event_counter_reset",
147149
"smarteeprom_is_enabled",
148150
"smarteeprom_disable",
149151
"smarteeprom_bb02_config",

src/rust/bitbox02/src/keystore.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,16 @@ mod tests {
422422
crate::memory::set_salt_root(mock_salt_root.as_slice().try_into().unwrap()).unwrap();
423423

424424
assert!(encrypt_and_store_seed(&seed, "password").is_ok());
425+
425426
// Loop to check that unlocking works while unlocked.
426427
for _ in 0..3 {
428+
// First call: unlock Further calls perform a password check. The first onedoes a seed
429+
// rentention (1 securechip event). The password check does not do the rentention but a
430+
// copy_seed() instead to check the seed, so they end up hacing the same number of
431+
// events.crate::securechip::fake_event_counter_reset();
432+
crate::securechip::fake_event_counter_reset();
427433
assert!(unlock("password").is_ok());
434+
assert_eq!(crate::securechip::fake_event_counter(), 6);
428435
}
429436

430437
// Also check that the retained seed was encrypted with the expected encryption key.

src/rust/bitbox02/src/securechip.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ pub fn u2f_counter_set(_counter: u32) -> Result<(), ()> {
4646
Ok(())
4747
}
4848

49+
#[cfg(feature = "testing")]
50+
pub fn fake_event_counter() -> u32 {
51+
unsafe { bitbox02_sys::fake_securechip_event_counter() }
52+
}
53+
54+
#[cfg(feature = "testing")]
55+
pub fn fake_event_counter_reset() {
56+
unsafe { bitbox02_sys::fake_securechip_event_counter_reset() }
57+
}
58+
4959
pub fn model() -> Result<Model, ()> {
5060
let mut ver = core::mem::MaybeUninit::uninit();
5161
match unsafe { bitbox02_sys::securechip_model(ver.as_mut_ptr()) } {

src/securechip/securechip.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,11 @@ typedef enum {
177177
*/
178178
USE_RESULT bool securechip_model(securechip_model_t* model_out);
179179

180+
#ifdef TESTING
181+
// Resets the event counter.
182+
void fake_securechip_event_counter_reset(void);
183+
// Retrieves the event counter.
184+
uint32_t fake_securechip_event_counter(void);
185+
#endif
186+
180187
#endif

test/hardware-fakes/src/fake_securechip.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,53 @@
2020

2121
static uint32_t _u2f_counter;
2222

23-
// Mocked contents of the secure chip rollkey slot.
24-
static const uint8_t _rollkey[32] =
25-
"\x9d\xd1\x34\x1f\x6b\x4b\x26\xb1\x72\x89\xa1\xa3\x92\x71\x5c\xf0\xd0\x57\x8c\x84\xdb\x9a\x51"
26-
"\xeb\xde\x14\x24\x06\x69\xd1\xd0\x5e";
27-
2823
// Mocked contents of the securechip kdf slot.
2924
static const uint8_t _kdfkey[32] =
3025
"\xd2\xe1\xe6\xb1\x8b\x6c\x6b\x08\x43\x3e\xdb\xc1\xd1\x68\xc1\xa0\x04\x37\x74\xa4\x22\x18\x77"
3126
"\xe7\x9e\xd5\x66\x84\xbe\x5a\xc0\x1b";
3227

28+
// Count how man seceurity events happen. The numbers were obtained by reading the security event
29+
// counter slot (0xE0C5) on a real device. We can use this to assert how many events were used in
30+
// unit tests. The number is relevant due to Optiga's throttling mechanism.
31+
static uint32_t _event_counter = 0;
32+
3333
int securechip_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out)
3434
{
35+
_event_counter += 1;
3536
rust_hmac_sha256(_kdfkey, 32, msg, len, kdf_out);
3637
return 0;
3738
}
38-
int securechip_kdf_rollkey(const uint8_t* msg, size_t len, uint8_t* kdf_out)
39-
{
40-
rust_hmac_sha256(_rollkey, 32, msg, len, kdf_out);
41-
return 0;
42-
}
39+
4340
int securechip_init_new_password(const char* password)
4441
{
42+
_event_counter += 1;
4543
(void)password;
4644
return 0;
4745
}
4846
int securechip_stretch_password(const char* password, uint8_t* stretched_out)
4947
{
48+
_event_counter += 5;
5049
uint8_t key[9] = "unit-test";
5150
rust_hmac_sha256(key, sizeof(key), (const uint8_t*)password, strlen(password), stretched_out);
5251
return 0;
5352
}
5453
bool securechip_u2f_counter_set(uint32_t counter)
5554
{
55+
_event_counter += 0;
5656
_u2f_counter = counter;
5757
return true;
5858
}
5959

6060
bool securechip_u2f_counter_inc(uint32_t* counter)
6161
{
62+
_event_counter += 0;
6263
*counter = _u2f_counter++;
6364
return true;
6465
}
6566

6667
bool securechip_attestation_sign(const uint8_t* msg, uint8_t* signature_out)
6768
{
69+
_event_counter += 1;
6870
return false;
6971
}
7072

@@ -79,3 +81,13 @@ bool securechip_model(securechip_model_t* model_out)
7981
*model_out = ATECC_ATECC608B;
8082
return true;
8183
}
84+
85+
void fake_securechip_event_counter_reset(void)
86+
{
87+
_event_counter = 0;
88+
}
89+
90+
uint32_t fake_securechip_event_counter(void)
91+
{
92+
return _event_counter;
93+
}

0 commit comments

Comments
 (0)