Skip to content

Commit a92c32a

Browse files
committed
Merge remote-tracking branch 'benma/count-events'
2 parents d46f7a7 + 13d636a commit a92c32a

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)