What changed, and why it matters
This commit moves the U2F counter read/write logic out of C code and into Rust code for the BitBox02 firmware. It is a refactoring/porting change: the same secure-chip storage object is still used, and the same operations (set counter, increment counter) are preserved. There is no obvious new security vulnerability in the diff, but the change touches sensitive secure-chip code and is only a partial port (some platforms still have placeholder 'todo!' implementations).
Review the new Rust Optiga implementation for atomicity and error-handling parity with the removed C code. Ensure that the `todo!()` placeholders in BitBox03 are completed before release, because unimplemented secure-chip methods would panic. Verify that the `factory-setup` feature does not expose U2F counter manipulation inappropriately in production builds.
Security signals we found
Refactoring of secure-chip U2F counter storage
New async Rust trait methods for U2F counter set/increment
Removal of C-based Optiga U2F counter functions
Addition of factory-setup feature gate for counter initialization
BitBox03 implementation left as unimplemented todo!() placeholders
Evidence from the diff
The patch ports U2F counter operations from src/optiga/optiga.c into the Rust bitbox-securechip crate. The C functions optiga_u2f_counter_set and optiga_u2f_counter_inc are removed; equivalent Rust async functions are added in src/rust/bitbox-securechip/src/optiga.rs and src/rust/bitbox-securechip/src/atecc.rs. The Rust implementation for Optiga reads/writes the OID_ARBITRARY_DATA object, interpreting the first four bytes as a little-endian U2F counter, matching the prior C behavior. The trait SecureChip::u2f_counter_set becomes async, and a new async u2f_counter_inc method is added. Call sites in restore and reset are updated to .await. A factory-setup feature is introduced so u2f_counter_set can be used in factory builds without enabling the full app-u2f feature. The BitBox03 implementation is left as todo!() placeholders.
Changed components
src/optiga/optiga.csrc/optiga/optiga.hsrc/rust/bitbox-hal/src/securechip.rssrc/rust/bitbox-platform-host/src/securechip.rssrc/rust/bitbox-securechip/src/atecc.rssrc/rust/bitbox-securechip/src/optiga.rssrc/rust/bitbox-securechip/src/optiga/ops_fake.rssrc/rust/bitbox02-rust/src/hww/api/restore.rssrc/rust/bitbox02-rust/src/reset.rssrc/rust/bitbox02/src/hal/securechip.rssrc/rust/bitbox02/src/securechip/imp.rssrc/rust/bitbox02/src/securechip/imp_fake.rssrc/rust/bitbox03/src/securechip.rsInspect captured patch +192 / −93
diff --git a/src/optiga/optiga.c b/src/optiga/optiga.c
index b6cbf73..6fb7842 100644
--- a/src/optiga/optiga.c
+++ b/src/optiga/optiga.c
@@ -468,30 +468,7 @@ static int _reset_counter(uint16_t oid, uint32_t limit)
}
#endif
-#if APP_U2F == 1 || FACTORYSETUP == 1
-static bool _read_arbitrary_data(arbitrary_data_t* data_out)
-{
- memset(data_out->bytes, 0x00, sizeof(data_out->bytes));
- uint16_t len = sizeof(data_out->bytes);
- optiga_lib_status_t res =
- optiga_ops_util_read_data_sync(_util, OID_ARBITRARY_DATA, 0, data_out->bytes, &len);
- if (res != OPTIGA_UTIL_SUCCESS) {
- util_log("could not read arbitrary data: %x", res);
- return false;
- }
- if (len != sizeof(data_out->bytes)) {
- util_log(
- "arbitrary data: expected to read size %d, but read %d. Data read: %s",
- (int)sizeof(data_out->bytes),
- (int)len,
- util_dbg_hex(data_out->bytes, len));
- return false;
- }
- return true;
-}
-#endif
-
-#if APP_U2F == 1 || FACTORYSETUP == 1 || FACTORY_DURING_PROD == 1
+#if FACTORYSETUP == 1 || FACTORY_DURING_PROD == 1
static int _write_arbitrary_data(const arbitrary_data_t* data)
{
optiga_lib_status_t res = optiga_ops_util_write_data_sync(
@@ -1304,29 +1281,3 @@ optiga_crypt_t* optiga_crypt_instance(void)
{
return _crypt;
}
-
-#if APP_U2F == 1 || FACTORYSETUP == 1
-bool optiga_u2f_counter_set(uint32_t counter)
-{
- arbitrary_data_t data = {0};
- if (!_read_arbitrary_data(&data)) {
- return false;
- }
- data.fields.u2f_counter = counter;
- return _write_arbitrary_data(&data) == OPTIGA_LIB_SUCCESS;
-}
-#endif
-
-#if APP_U2F == 1
-bool optiga_u2f_counter_inc(uint32_t* counter)
-{
- arbitrary_data_t data = {0};
- if (!_read_arbitrary_data(&data)) {
- return false;
- }
- data.fields.u2f_counter += 1;
- *counter = data.fields.u2f_counter;
-
- return _write_arbitrary_data(&data) == OPTIGA_LIB_SUCCESS;
-}
-#endif
diff --git a/src/optiga/optiga.h b/src/optiga/optiga.h
index 39d71cb..078ac7f 100644
--- a/src/optiga/optiga.h
+++ b/src/optiga/optiga.h
@@ -94,11 +94,5 @@ USE_RESULT int optiga_setup(const securechip_interface_functions_t* ifs);
USE_RESULT bool optiga_gen_attestation_key(uint8_t* pubkey_out);
USE_RESULT optiga_util_t* optiga_util_instance(void);
USE_RESULT optiga_crypt_t* optiga_crypt_instance(void);
-#if APP_U2F == 1 || FACTORYSETUP == 1
-USE_RESULT bool optiga_u2f_counter_set(uint32_t counter);
-#endif
-#if APP_U2F == 1
-USE_RESULT bool optiga_u2f_counter_inc(uint32_t* counter);
-#endif
#endif // _OPTIGA_H_
diff --git a/src/rust/bitbox-hal/src/securechip.rs b/src/rust/bitbox-hal/src/securechip.rs
index d23aa30..d87684b 100644
--- a/src/rust/bitbox-hal/src/securechip.rs
+++ b/src/rust/bitbox-hal/src/securechip.rs
@@ -112,5 +112,9 @@ pub trait SecureChip {
/// Sets the U2F counter to `counter`.
///
/// This is intended for initialization only.
- fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()>;
+ async fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()>;
+
+ #[cfg(feature = "app-u2f")]
+ /// Increments the U2F counter and returns the new value.
+ async fn u2f_counter_inc(&mut self) -> Result<u32, ()>;
}
diff --git a/src/rust/bitbox-platform-host/src/securechip.rs b/src/rust/bitbox-platform-host/src/securechip.rs
index f8fac3d..11c445c 100644
--- a/src/rust/bitbox-platform-host/src/securechip.rs
+++ b/src/rust/bitbox-platform-host/src/securechip.rs
@@ -179,10 +179,16 @@ impl bitbox_hal::SecureChip for FakeSecureChip {
}
#[cfg(feature = "app-u2f")]
- fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()> {
+ async fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()> {
self.u2f_counter = counter;
Ok(())
}
+
+ #[cfg(feature = "app-u2f")]
+ async fn u2f_counter_inc(&mut self) -> Result<u32, ()> {
+ self.u2f_counter = self.u2f_counter.wrapping_add(1);
+ Ok(self.u2f_counter)
+ }
}
#[cfg(test)]
@@ -201,4 +207,15 @@ mod tests {
assert_eq!(first.as_slice(), &expected);
assert_eq!(second.as_slice(), &[0u8; 32]);
}
+
+ #[cfg(feature = "app-u2f")]
+ #[async_test::test]
+ async fn test_u2f_counter_inc() {
+ let mut securechip = FakeSecureChip::new();
+ assert_eq!(securechip.get_u2f_counter(), 0);
+ assert_eq!(securechip.u2f_counter_inc().await.unwrap(), 1);
+ assert_eq!(securechip.get_u2f_counter(), 1);
+ assert_eq!(securechip.u2f_counter_inc().await.unwrap(), 2);
+ assert_eq!(securechip.get_u2f_counter(), 2);
+ }
}
diff --git a/src/rust/bitbox-securechip-sys/build.rs b/src/rust/bitbox-securechip-sys/build.rs
index 0931c4d..cd77f2c 100644
--- a/src/rust/bitbox-securechip-sys/build.rs
+++ b/src/rust/bitbox-securechip-sys/build.rs
@@ -48,8 +48,6 @@ const ALLOWLIST_FNS: &[&str] = &[
"optiga_ops_get_status",
"optiga_ops_set_status_busy",
"optiga_setup",
- "optiga_u2f_counter_inc",
- "optiga_u2f_counter_set",
"optiga_util_instance",
"optiga_util_read_data",
"optiga_util_write_data",
@@ -59,6 +57,7 @@ const ALLOWLIST_VARS: &[&str] = &[
"ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE",
"MONOTONIC_COUNTER_MAX_USE",
"OID_AES_SYMKEY",
+ "OID_ARBITRARY_DATA",
"OID_COUNTER",
"OID_COUNTER_HMAC_WRITEPROTECTED",
"OID_COUNTER_PASSWORD",
diff --git a/src/rust/bitbox-securechip/Cargo.toml b/src/rust/bitbox-securechip/Cargo.toml
index efba376..d5589be 100644
--- a/src/rust/bitbox-securechip/Cargo.toml
+++ b/src/rust/bitbox-securechip/Cargo.toml
@@ -20,6 +20,7 @@ zeroize = { workspace = true }
[features]
app-u2f = []
+factory-setup = []
[dev-dependencies]
async_test = { path = "../async_test" }
diff --git a/src/rust/bitbox-securechip/src/atecc.rs b/src/rust/bitbox-securechip/src/atecc.rs
index 2b7e069..f6935c1 100644
--- a/src/rust/bitbox-securechip/src/atecc.rs
+++ b/src/rust/bitbox-securechip/src/atecc.rs
@@ -93,7 +93,7 @@ pub fn kdf(msg: &[u8; 32]) -> Result<Box<Zeroizing<[u8; 32]>>, Error> {
}
}
-#[cfg(feature = "app-u2f")]
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
pub fn u2f_counter_set(counter: u32) -> Result<(), ()> {
match unsafe { bitbox_securechip_sys::atecc_u2f_counter_set(counter) } {
true => Ok(()),
@@ -101,6 +101,15 @@ pub fn u2f_counter_set(counter: u32) -> Result<(), ()> {
}
}
+#[cfg(feature = "app-u2f")]
+pub fn u2f_counter_inc() -> Result<u32, ()> {
+ let mut counter = 0;
+ match unsafe { bitbox_securechip_sys::atecc_u2f_counter_inc(&mut counter) } {
+ true => Ok(counter),
+ false => Err(()),
+ }
+}
+
pub fn model() -> Result<Model, ()> {
let mut model = core::mem::MaybeUninit::uninit();
match unsafe { bitbox_securechip_sys::atecc_model(model.as_mut_ptr()) } {
diff --git a/src/rust/bitbox-securechip/src/optiga.rs b/src/rust/bitbox-securechip/src/optiga.rs
index 9c6ccd5..9d599d6 100644
--- a/src/rust/bitbox-securechip/src/optiga.rs
+++ b/src/rust/bitbox-securechip/src/optiga.rs
@@ -16,6 +16,8 @@ mod ops;
mod ops;
const OID_AES_SYMKEY: u16 = bitbox_securechip_sys::OID_AES_SYMKEY as u16;
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+const OID_ARBITRARY_DATA: u16 = bitbox_securechip_sys::OID_ARBITRARY_DATA as u16;
const OID_COUNTER: u16 = bitbox_securechip_sys::OID_COUNTER as u16;
const OID_COUNTER_HMAC_WRITEPROTECTED: u16 =
bitbox_securechip_sys::OID_COUNTER_HMAC_WRITEPROTECTED as u16;
@@ -26,6 +28,9 @@ const OID_PASSWORD: u16 = bitbox_securechip_sys::OID_PASSWORD as u16;
const OID_PASSWORD_SECRET: u16 = bitbox_securechip_sys::OID_PASSWORD_SECRET as u16;
const MONOTONIC_COUNTER_MAX_USE: u32 = bitbox_securechip_sys::MONOTONIC_COUNTER_MAX_USE;
const SMALL_MONOTONIC_COUNTER_MAX_USE: u32 = bitbox_securechip_sys::SMALL_MONOTONIC_COUNTER_MAX_USE;
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+const ARBITRARY_DATA_LEN: usize =
+ bitbox_securechip_sys::ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE as usize;
const KDF_LEN: usize = 32;
const OPTIGA_HMAC_SHA_256: bitbox_securechip_sys::optiga_hmac_type_t =
bitbox_securechip_sys::optiga_hmac_type::OPTIGA_HMAC_SHA_256;
@@ -46,6 +51,47 @@ fn zeroed_secret<const N: usize>() -> Box<Zeroizing<[u8; N]>> {
Box::new(Zeroizing::new([0; N]))
}
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+struct ArbitraryData {
+ bytes: [u8; ARBITRARY_DATA_LEN],
+}
+
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+impl ArbitraryData {
+ fn new() -> Self {
+ Self {
+ bytes: [0; ARBITRARY_DATA_LEN],
+ }
+ }
+
+ #[cfg(feature = "app-u2f")]
+ fn u2f_counter(&self) -> u32 {
+ u32::from_le_bytes(self.bytes[..4].try_into().unwrap())
+ }
+
+ fn set_u2f_counter(&mut self, counter: u32) {
+ self.bytes[..4].copy_from_slice(&counter.to_le_bytes());
+ }
+}
+
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+async fn read_arbitrary_data() -> Result<ArbitraryData, Error> {
+ let mut data = ArbitraryData::new();
+ ops::util_read_data(OID_ARBITRARY_DATA, 0, &mut data.bytes).await?;
+ Ok(data)
+}
+
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+async fn write_arbitary_data(data: &ArbitraryData) -> Result<(), Error> {
+ ops::util_write_data(
+ OID_ARBITRARY_DATA,
+ bitbox_securechip_sys::OPTIGA_UTIL_ERASE_AND_WRITE as u8,
+ 0,
+ &data.bytes,
+ )
+ .await
+}
+
fn key_id_from_oid(oid: u16) -> bitbox_securechip_sys::optiga_key_id_t {
match oid {
OID_AES_SYMKEY => bitbox_securechip_sys::optiga_key_id::OPTIGA_KEY_ID_SECRET_BASED,
@@ -473,12 +519,20 @@ pub async fn kdf(msg: &[u8; KDF_LEN]) -> Result<Box<Zeroizing<[u8; 32]>>, Error>
Ok(result)
}
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+pub async fn u2f_counter_set(counter: u32) -> Result<(), ()> {
+ let mut data = read_arbitrary_data().await.map_err(|_| ())?;
+ data.set_u2f_counter(counter);
+ write_arbitary_data(&data).await.map_err(|_| ())
+}
+
#[cfg(feature = "app-u2f")]
-pub fn u2f_counter_set(counter: u32) -> Result<(), ()> {
- match unsafe { bitbox_securechip_sys::optiga_u2f_counter_set(counter) } {
- true => Ok(()),
- false => Err(()),
- }
+pub async fn u2f_counter_inc() -> Result<u32, ()> {
+ let mut data = read_arbitrary_data().await.map_err(|_| ())?;
+ let counter = data.u2f_counter().wrapping_add(1);
+ data.set_u2f_counter(counter);
+ write_arbitary_data(&data).await.map_err(|_| ())?;
+ Ok(counter)
}
pub fn model() -> Result<Model, ()> {
@@ -534,6 +588,25 @@ mod tests {
);
}
+ #[cfg(feature = "app-u2f")]
+ #[async_test::test]
+ #[allow(clippy::await_holding_lock)]
+ async fn test_u2f_counter_set() {
+ let (_guard, _memory) = setup_test();
+ u2f_counter_set(42).await.unwrap();
+ assert_eq!(read_arbitrary_data().await.unwrap().u2f_counter(), 42);
+ }
+
+ #[cfg(feature = "app-u2f")]
+ #[async_test::test]
+ #[allow(clippy::await_holding_lock)]
+ async fn test_u2f_counter_inc() {
+ let (_guard, _memory) = setup_test();
+ u2f_counter_set(42).await.unwrap();
+ assert_eq!(u2f_counter_inc().await.unwrap(), 43);
+ assert_eq!(read_arbitrary_data().await.unwrap().u2f_counter(), 43);
+ }
+
// Expected stretched_out for password "pw" for the V0 algorithm given the deterministic fake
// constants in ops_fake.rs.
//
diff --git a/src/rust/bitbox-securechip/src/optiga/ops_fake.rs b/src/rust/bitbox-securechip/src/optiga/ops_fake.rs
index 53dbdbd..7371e5b 100644
--- a/src/rust/bitbox-securechip/src/optiga/ops_fake.rs
+++ b/src/rust/bitbox-securechip/src/optiga/ops_fake.rs
@@ -27,6 +27,7 @@ const OPTIGA_UTIL_ERROR_MEMORY_INSUFFICIENT: i32 =
struct FakeState {
oid_password: [u8; super::KDF_LEN],
oid_password_set: bool,
+ oid_arbitrary_data: [u8; super::ARBITRARY_DATA_LEN],
oid_counter_password_buf: [u8; 8],
oid_counter_hmac_writeprotected_buf: [u8; 8],
authorized_password: bool,
@@ -39,6 +40,7 @@ impl Default for FakeState {
Self {
oid_password: [0; super::KDF_LEN],
oid_password_set: false,
+ oid_arbitrary_data: [0; super::ARBITRARY_DATA_LEN],
oid_counter_password_buf: [0; 8],
oid_counter_hmac_writeprotected_buf: [0; 8],
authorized_password: false,
@@ -151,6 +153,13 @@ pub(super) async fn util_read_data(oid: u16, offset: u16, out: &mut [u8]) -> Res
out.fill(0);
Ok(())
}
+ super::OID_ARBITRARY_DATA => {
+ if out.len() != super::ARBITRARY_DATA_LEN {
+ return Err(Error::from_status(OPTIGA_UTIL_ERROR_MEMORY_INSUFFICIENT));
+ }
+ out.copy_from_slice(&state.oid_arbitrary_data);
+ Ok(())
+ }
_ => Err(Error::from_status(OPTIGA_UTIL_ERROR_INVALID_INPUT)),
}
}
@@ -301,6 +310,13 @@ pub(super) fn util_write_data_sync(
assert_eq!(buffer, PASSWORD_SECRET_FIXED.as_slice());
Ok(())
}
+ super::OID_ARBITRARY_DATA => {
+ if buffer.len() != super::ARBITRARY_DATA_LEN {
+ return Err(Error::from_status(OPTIGA_UTIL_ERROR_INVALID_INPUT));
+ }
+ state.oid_arbitrary_data.copy_from_slice(buffer);
+ Ok(())
+ }
// Accept other writes without emulating full semantics (counter reset, hmac key, etc.).
_ => Ok(()),
}
diff --git a/src/rust/bitbox02-rust-c/Cargo.toml b/src/rust/bitbox02-rust-c/Cargo.toml
index 1ce843c..16491f7 100644
--- a/src/rust/bitbox02-rust-c/Cargo.toml
+++ b/src/rust/bitbox02-rust-c/Cargo.toml
@@ -118,6 +118,6 @@ app-cardano = [
"bitbox02-rust/app-cardano",
]
-factory-setup = []
+factory-setup = ["bitbox02/factory-setup"]
rtt = ["util/rtt"]
diff --git a/src/rust/bitbox02-rust/src/hww/api/restore.rs b/src/rust/bitbox02-rust/src/hww/api/restore.rs
index d58ad51..05b291d 100644
--- a/src/rust/bitbox02-rust/src/hww/api/restore.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/restore.rs
@@ -73,7 +73,7 @@ pub async fn from_file(
{
// Ignore error - the U2f counter not being set can lead to problems with U2F, but it should
// not fail the recovery, so the user can access their coins.
- let _ = hal.securechip().u2f_counter_set(request.timestamp);
+ let _ = hal.securechip().u2f_counter_set(request.timestamp).await;
}
hal.memory().set_initialized().or(Err(Error::Memory))?;
@@ -148,7 +148,7 @@ pub async fn from_mnemonic(
{
// Ignore error - the U2f counter not being set can lead to problems with U2F, but it should
// not fail the recovery, so the user can access their coins.
- let _ = hal.securechip().u2f_counter_set(timestamp);
+ let _ = hal.securechip().u2f_counter_set(timestamp).await;
}
hal.memory().set_initialized().or(Err(Error::Memory))?;
diff --git a/src/rust/bitbox02-rust/src/reset.rs b/src/rust/bitbox02-rust/src/reset.rs
index 41eb804..0746034 100644
--- a/src/rust/bitbox02-rust/src/reset.rs
+++ b/src/rust/bitbox02-rust/src/reset.rs
@@ -43,7 +43,7 @@ pub(crate) async fn reset(hal: &mut impl crate::hal::Hal, status: bool) {
{
let mut u2f_ok = false;
for _ in 0..5 {
- if hal.securechip().u2f_counter_set(0).is_ok() {
+ if hal.securechip().u2f_counter_set(0).await.is_ok() {
u2f_ok = true;
break;
}
@@ -98,7 +98,7 @@ mod tests {
hal.securechip.mock_reset_keys_fails();
// Simulate a non-zero U2F counter before reset.
- hal.securechip.u2f_counter_set(42).unwrap();
+ hal.securechip.u2f_counter_set(42).await.unwrap();
hal.securechip.event_counter_reset();
reset(&mut hal, true).await;
diff --git a/src/rust/bitbox02/Cargo.toml b/src/rust/bitbox02/Cargo.toml
index 2b9d74c..a55c005 100644
--- a/src/rust/bitbox02/Cargo.toml
+++ b/src/rust/bitbox02/Cargo.toml
@@ -46,3 +46,4 @@ app-ethereum = []
app-bitcoin = []
app-litecoin = []
app-u2f = ["bitbox-hal/app-u2f", "bitbox-securechip/app-u2f"]
+factory-setup = ["bitbox-securechip/factory-setup"]
diff --git a/src/rust/bitbox02/src/hal/securechip.rs b/src/rust/bitbox02/src/hal/securechip.rs
index a2d30a3..8fa5b3e 100644
--- a/src/rust/bitbox02/src/hal/securechip.rs
+++ b/src/rust/bitbox02/src/hal/securechip.rs
@@ -142,8 +142,13 @@ impl SecureChip for BitBox02SecureChip {
}
#[cfg(feature = "app-u2f")]
- fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()> {
- crate::securechip::u2f_counter_set(counter)
+ async fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()> {
+ crate::securechip::u2f_counter_set(counter).await
+ }
+
+ #[cfg(feature = "app-u2f")]
+ async fn u2f_counter_inc(&mut self) -> Result<u32, ()> {
+ crate::securechip::u2f_counter_inc().await
}
}
diff --git a/src/rust/bitbox02/src/securechip/imp.rs b/src/rust/bitbox02/src/securechip/imp.rs
index 507db6a..1b043cb 100644
--- a/src/rust/bitbox02/src/securechip/imp.rs
+++ b/src/rust/bitbox02/src/securechip/imp.rs
@@ -81,11 +81,19 @@ pub async fn kdf(msg: &[u8; 32]) -> Result<Box<Zeroizing<[u8; 32]>>, Error> {
}
}
-#[cfg(feature = "app-u2f")]
-pub fn u2f_counter_set(counter: u32) -> Result<(), ()> {
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+pub async fn u2f_counter_set(counter: u32) -> Result<(), ()> {
match backend() {
Backend::Atecc => atecc::u2f_counter_set(counter),
- Backend::Optiga => optiga::u2f_counter_set(counter),
+ Backend::Optiga => optiga::u2f_counter_set(counter).await,
+ }
+}
+
+#[cfg(feature = "app-u2f")]
+pub async fn u2f_counter_inc() -> Result<u32, ()> {
+ match backend() {
+ Backend::Atecc => atecc::u2f_counter_inc(),
+ Backend::Optiga => optiga::u2f_counter_inc().await,
}
}
@@ -160,20 +168,24 @@ pub unsafe extern "C" fn rust_securechip_random(rand_out: *mut u8) -> bool {
/// Sets the U2F counter to `counter`.
///
/// This is intended for initialization only.
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
#[unsafe(no_mangle)]
pub extern "C" fn rust_securechip_u2f_counter_set(counter: u32) -> bool {
- match backend() {
- Backend::Atecc => unsafe { bitbox_securechip_sys::atecc_u2f_counter_set(counter) },
- Backend::Optiga => unsafe { bitbox_securechip_sys::optiga_u2f_counter_set(counter) },
- }
+ util::bb02_async::block_on(u2f_counter_set(counter)).is_ok()
}
#[cfg(feature = "app-u2f")]
-/// Increments the U2F counter and writes the current value to `counter`.
+/// Increments the U2F counter and writes the new value to `counter`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_securechip_u2f_counter_inc(counter: *mut u32) -> bool {
- match backend() {
- Backend::Atecc => unsafe { bitbox_securechip_sys::atecc_u2f_counter_inc(counter) },
- Backend::Optiga => unsafe { bitbox_securechip_sys::optiga_u2f_counter_inc(counter) },
+ assert!(!counter.is_null());
+ match util::bb02_async::block_on(u2f_counter_inc()) {
+ Ok(current) => {
+ unsafe {
+ *counter = current;
+ }
+ true
+ }
+ Err(()) => false,
}
}
diff --git a/src/rust/bitbox02/src/securechip/imp_fake.rs b/src/rust/bitbox02/src/securechip/imp_fake.rs
index 110ca1a..d921679 100644
--- a/src/rust/bitbox02/src/securechip/imp_fake.rs
+++ b/src/rust/bitbox02/src/securechip/imp_fake.rs
@@ -10,7 +10,7 @@ use zeroize::Zeroizing;
const PASSWORD_STRETCH_KEY: &[u8] = b"unit-test";
const KDF_KEY: [u8; 32] = hex!("d2e1e6b18b6c6b08433edbc1d168c1a0043774a4221877e79ed56684be5ac01b");
-#[cfg(feature = "app-u2f")]
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
static U2F_COUNTER: util::cell::SyncCell<u32> = util::cell::SyncCell::new(0);
type HmacSha256 = Hmac<Sha256>;
@@ -77,23 +77,35 @@ pub async fn kdf(msg: &[u8; 32]) -> Result<Box<Zeroizing<[u8; 32]>>, Error> {
Ok(Box::new(Zeroizing::new(hmac_sha256(&KDF_KEY, msg))))
}
-#[cfg(feature = "app-u2f")]
-pub fn u2f_counter_set(counter: u32) -> Result<(), ()> {
+#[cfg(any(feature = "app-u2f", feature = "factory-setup"))]
+pub async fn u2f_counter_set(counter: u32) -> Result<(), ()> {
U2F_COUNTER.write(counter);
Ok(())
}
+#[cfg(feature = "app-u2f")]
+pub async fn u2f_counter_inc() -> Result<u32, ()> {
+ let current = U2F_COUNTER.read().wrapping_add(1);
+ U2F_COUNTER.write(current);
+ Ok(current)
+}
+
pub fn model() -> Result<Model, ()> {
Ok(Model::ATECC_ATECC608B)
}
#[cfg(feature = "app-u2f")]
-/// Increments the fake host-side U2F counter and writes the current value to `counter`.
+/// Increments the fake host-side U2F counter and writes the new value to `counter`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_securechip_u2f_counter_inc(counter: *mut u32) -> bool {
assert!(!counter.is_null());
- let current = U2F_COUNTER.read();
- U2F_COUNTER.write(current.wrapping_add(1));
- unsafe { *counter = current };
- true
+ match util::bb02_async::block_on(u2f_counter_inc()) {
+ Ok(current) => {
+ unsafe {
+ *counter = current;
+ }
+ true
+ }
+ Err(()) => false,
+ }
}
diff --git a/src/rust/bitbox03/src/securechip.rs b/src/rust/bitbox03/src/securechip.rs
index 0f49fe8..6ef88f0 100644
--- a/src/rust/bitbox03/src/securechip.rs
+++ b/src/rust/bitbox03/src/securechip.rs
@@ -64,7 +64,12 @@ impl hal::securechip::SecureChip for BitBox03SecureChip {
}
#[cfg(feature = "app-u2f")]
- fn u2f_counter_set(&mut self, _counter: u32) -> Result<(), ()> {
+ async fn u2f_counter_set(&mut self, _counter: u32) -> Result<(), ()> {
+ todo!()
+ }
+
+ #[cfg(feature = "app-u2f")]
+ async fn u2f_counter_inc(&mut self) -> Result<u32, ()> {
todo!()
}
}
Why this scored 27/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.