optiga: add async bridge and counter read
What changed, and why it matters
This commit is a routine firmware refactoring: it moves a single secure-chip counter read from a synchronous C function into a new asynchronous Rust wrapper. There is no indication of a security bug being fixed or introduced. The change is architectural groundwork for future async secure-chip operations.
No security action required. Treat as normal code-review item; verify async state-machine invariants (no concurrent callers, safe buffer lifetime across cancellation) during review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch removes optiga_monotonic_increments_remaining() from C and exposes the shared optiga_util_t instance plus async status helpers to Rust. It adds an async bridge (ops.rs) with a single-in-flight state machine, global waker cell, static buffers, and a util_read_data() future. monotonic_increments_remaining() is rewritten as an async Rust function that reads OID_COUNTER via the bridge and computes remaining uses. The change is additive/infrastructural and does not alter access-control, trust-boundary, or cryptographic behavior.
Changed components
src/optiga/optiga.csrc/optiga/optiga.hsrc/optiga/optiga_ops.csrc/optiga/optiga_ops.hsrc/rust/bitbox-securechip/src/optiga.rssrc/rust/bitbox-securechip/src/optiga/ops.rssrc/rust/bitbox02/src/securechip/imp.rssrc/rust/bitbox02/src/hal/securechip.rsInspect captured patch +404 / −28
diff --git a/src/optiga/optiga.c b/src/optiga/optiga.c
index 4d7f209..18e051d 100644
--- a/src/optiga/optiga.c
+++ b/src/optiga/optiga.c
@@ -1845,21 +1845,9 @@ bool optiga_attestation_sign(const uint8_t* challenge, uint8_t* signature_out)
rust_util_bytes(sig_der, sig_der_size), rust_util_bytes_mut(signature_out, 64));
}
-bool optiga_monotonic_increments_remaining(uint32_t* remaining_out)
+optiga_util_t* optiga_util_instance(void)
{
- uint8_t buf[4] = {0};
- uint16_t size = sizeof(buf);
- optiga_lib_status_t res = optiga_ops_util_read_data_sync(_util, OID_COUNTER, 0, buf, &size);
- if (res != OPTIGA_LIB_SUCCESS) {
- return false;
- }
-
- uint32_t counter = optiga_common_get_uint32(buf);
- if (counter > MONOTONIC_COUNTER_MAX_USE) {
- Abort("optiga monotonic counter larget than max");
- }
- *remaining_out = MONOTONIC_COUNTER_MAX_USE - counter;
- return true;
+ return _util;
}
// rand_out must be 32 bytes
diff --git a/src/optiga/optiga.h b/src/optiga/optiga.h
index 6a71afc..5928146 100644
--- a/src/optiga/optiga.h
+++ b/src/optiga/optiga.h
@@ -12,6 +12,8 @@
#include <stddef.h>
#include <stdint.h>
+typedef struct optiga_util optiga_util_t;
+
// Keep in sync with MAX_UNLOCK_ATTEMPTS in keystore.rs.
#ifndef MAX_UNLOCK_ATTEMPTS
#define MAX_UNLOCK_ATTEMPTS 10
@@ -101,7 +103,7 @@ USE_RESULT int optiga_stretch_password(
USE_RESULT bool optiga_reset_keys(void);
USE_RESULT bool optiga_gen_attestation_key(uint8_t* pubkey_out);
USE_RESULT bool optiga_attestation_sign(const uint8_t* challenge, uint8_t* signature_out);
-USE_RESULT bool optiga_monotonic_increments_remaining(uint32_t* remaining_out);
+USE_RESULT optiga_util_t* optiga_util_instance(void);
USE_RESULT int optiga_random(uint8_t* rand_out);
#if APP_U2F == 1 || FACTORYSETUP == 1
USE_RESULT bool optiga_u2f_counter_set(uint32_t counter);
diff --git a/src/optiga/optiga_ops.c b/src/optiga/optiga_ops.c
index 0b8523f..05c43a6 100644
--- a/src/optiga/optiga_ops.c
+++ b/src/optiga/optiga_ops.c
@@ -2,6 +2,7 @@
#include "optiga_ops.h"
+#include <rust/rust.h>
#include <securechip/securechip.h>
#include <util.h>
@@ -13,6 +14,17 @@ static void _optiga_lib_callback(void* callback_ctx, optiga_lib_status_t event)
{
(void)callback_ctx;
_optiga_lib_status = event;
+ rust_optiga_callback_wake();
+}
+
+optiga_lib_status_t optiga_ops_get_status(void)
+{
+ return _optiga_lib_status;
+}
+
+void optiga_ops_set_status_busy(void)
+{
+ _optiga_lib_status = OPTIGA_LIB_BUSY;
}
optiga_lib_status_t optiga_ops_create(optiga_util_t** util_out, optiga_crypt_t** crypt_out)
diff --git a/src/optiga/optiga_ops.h b/src/optiga/optiga_ops.h
index 48aaf37..9f4f467 100644
--- a/src/optiga/optiga_ops.h
+++ b/src/optiga/optiga_ops.h
@@ -8,6 +8,8 @@
#include <stdint.h>
optiga_lib_status_t optiga_ops_create(optiga_util_t** util_out, optiga_crypt_t** crypt_out);
+optiga_lib_status_t optiga_ops_get_status(void);
+void optiga_ops_set_status_busy(void);
optiga_lib_status_t optiga_ops_util_read_data_sync(
optiga_util_t* me,
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 96b9681..da5cba2 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -212,6 +212,8 @@ name = "bitbox-securechip"
version = "0.1.0"
dependencies = [
"bitbox-securechip-sys",
+ "critical-section",
+ "grounded",
"util",
"zeroize",
]
diff --git a/src/rust/bitbox-securechip-sys/build.rs b/src/rust/bitbox-securechip-sys/build.rs
index 965d314..273270c 100644
--- a/src/rust/bitbox-securechip-sys/build.rs
+++ b/src/rust/bitbox-securechip-sys/build.rs
@@ -6,6 +6,8 @@ use std::path::PathBuf;
use std::process::{Command, Output};
const ALLOWLIST_TYPES: &[&str] = &[
+ "optiga_lib_status_t",
+ "optiga_util_t",
"securechip_error_t",
"securechip_interface_functions_t",
"securechip_model_t",
@@ -29,13 +31,25 @@ const ALLOWLIST_FNS: &[&str] = &[
"optiga_gen_attestation_key",
"optiga_init_new_password",
"optiga_kdf_external",
- "optiga_monotonic_increments_remaining",
+ "optiga_ops_get_status",
+ "optiga_ops_set_status_busy",
"optiga_random",
"optiga_reset_keys",
"optiga_setup",
"optiga_stretch_password",
"optiga_u2f_counter_inc",
"optiga_u2f_counter_set",
+ "optiga_util_instance",
+ "optiga_util_read_data",
+];
+
+const ALLOWLIST_VARS: &[&str] = &[
+ "ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE",
+ "MONOTONIC_COUNTER_MAX_USE",
+ "OID_COUNTER",
+ "OPTIGA_LIB_BUSY",
+ "OPTIGA_LIB_SUCCESS",
+ "OPTIGA_UTIL_SUCCESS",
];
const RUSTIFIED_ENUMS: &[&str] = &[
@@ -53,6 +67,8 @@ pub fn main() -> BuildResult<()> {
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
let repo_root = manifest_dir.join("../../..");
let src_dir = repo_root.join("src");
+ let external_dir = repo_root.join("external");
+ let optiga_include_dir = external_dir.join("optiga-trust-m/include");
let wrapper = manifest_dir.join("wrapper.h");
if !wrapper.is_file() {
return Err("wrapper.h not found".into());
@@ -64,14 +80,20 @@ pub fn main() -> BuildResult<()> {
emit_rerun_if_changed(src_dir.join("platform"));
emit_rerun_if_changed(src_dir.join("securechip"));
emit_rerun_if_changed(src_dir.join("compiler_util.h"));
+ emit_rerun_if_changed(external_dir.join("optiga_config.h"));
+ emit_rerun_if_changed(external_dir.join("optiga-trust-m/config"));
+ emit_rerun_if_changed(&optiga_include_dir);
let target = env::var("TARGET").expect("TARGET not set");
let cross_compiling = target == "thumbv7em-none-eabi";
+ let arm_sysroot = env::var("CMAKE_SYSROOT").unwrap_or("/usr/local/arm-none-eabi".to_string());
+ let arm_sysroot = format!("--sysroot={arm_sysroot}");
let mut extra_flags = if cross_compiling {
vec![
// Generate bindings for the firmware target ABI, not the host ABI.
"--target=thumbv7em-none-eabi",
+ &arm_sysroot,
// The firmware C code is compiled with arm-none-eabi-gcc, which uses
// -fshort-enums by default. Bindgen must match those enum sizes.
"-fshort-enums",
@@ -94,6 +116,7 @@ pub fn main() -> BuildResult<()> {
let mut definitions = vec![
// Expose the U2F counter declarations guarded by APP_U2F in atecc.h/optiga.h.
"-DAPP_U2F=1",
+ "-DOPTIGA_LIB_EXTERNAL=\"optiga_config.h\"",
];
definitions.extend(&extra_flags);
@@ -112,6 +135,11 @@ pub fn main() -> BuildResult<()> {
.iter()
.flat_map(|item| ["--allowlist-type", item]),
)
+ .args(
+ ALLOWLIST_VARS
+ .iter()
+ .flat_map(|item| ["--allowlist-var", item]),
+ )
.args(
RUSTIFIED_ENUMS
.iter()
@@ -120,7 +148,41 @@ pub fn main() -> BuildResult<()> {
.arg(&wrapper)
.arg("--")
.args(&definitions)
- .arg(format!("-I{}", src_dir.display())),
+ .arg(format!("-I{}", src_dir.display()))
+ .arg(format!("-I{}", external_dir.display()))
+ .arg(format!(
+ "-I{}",
+ external_dir.join("optiga-trust-m/config").display()
+ ))
+ .arg(format!("-I{}", optiga_include_dir.display()))
+ .arg(format!(
+ "-I{}",
+ external_dir.join("optiga-trust-m/include/cmd").display()
+ ))
+ .arg(format!(
+ "-I{}",
+ external_dir.join("optiga-trust-m/include/common").display()
+ ))
+ .arg(format!(
+ "-I{}",
+ external_dir
+ .join("optiga-trust-m/include/ifx_i2c")
+ .display()
+ ))
+ .arg(format!(
+ "-I{}",
+ external_dir.join("optiga-trust-m/include/pal").display()
+ ))
+ .arg(format!(
+ "-I{}",
+ external_dir.join("optiga-trust-m/include/comms").display()
+ ))
+ .arg(format!(
+ "-I{}",
+ external_dir
+ .join("optiga-trust-m/external/mbedtls/include")
+ .display()
+ )),
"run bindgen",
)?;
diff --git a/src/rust/bitbox-securechip-sys/wrapper.h b/src/rust/bitbox-securechip-sys/wrapper.h
index 9730fc7..da3362e 100644
--- a/src/rust/bitbox-securechip-sys/wrapper.h
+++ b/src/rust/bitbox-securechip-sys/wrapper.h
@@ -2,3 +2,4 @@
#include <atecc/atecc.h>
#include <optiga/optiga.h>
+#include <optiga/optiga_ops.h>
diff --git a/src/rust/bitbox-securechip/Cargo.toml b/src/rust/bitbox-securechip/Cargo.toml
index 1acc9d8..4abe17e 100644
--- a/src/rust/bitbox-securechip/Cargo.toml
+++ b/src/rust/bitbox-securechip/Cargo.toml
@@ -10,6 +10,8 @@ license = "Apache-2.0"
[dependencies]
bitbox-securechip-sys = { path = "../bitbox-securechip-sys" }
+critical-section = { version = "1.2.0", default-features = false, features = [] }
+grounded = { workspace = true }
util = { path = "../util" }
zeroize = { workspace = true }
diff --git a/src/rust/bitbox-securechip/src/optiga.rs b/src/rust/bitbox-securechip/src/optiga.rs
index 1875d57..50a6974 100644
--- a/src/rust/bitbox-securechip/src/optiga.rs
+++ b/src/rust/bitbox-securechip/src/optiga.rs
@@ -4,6 +4,11 @@ use crate::{Error, Model, PasswordStretchAlgo, SecureChipError};
use alloc::{boxed::Box, vec, vec::Vec};
use zeroize::Zeroizing;
+mod ops;
+
+const OID_COUNTER: u16 = bitbox_securechip_sys::OID_COUNTER as u16;
+const MONOTONIC_COUNTER_MAX_USE: u32 = bitbox_securechip_sys::MONOTONIC_COUNTER_MAX_USE;
+
pub fn attestation_sign(challenge: &[u8; 32], signature: &mut [u8; 64]) -> Result<(), ()> {
match unsafe {
bitbox_securechip_sys::optiga_attestation_sign(challenge.as_ptr(), signature.as_mut_ptr())
@@ -22,12 +27,16 @@ pub fn random() -> Result<Box<Zeroizing<[u8; 32]>>, Error> {
Err(Error::from_status(status))
}
}
-pub fn monotonic_increments_remaining() -> Result<u32, ()> {
- let mut result = 0u32;
- match unsafe { bitbox_securechip_sys::optiga_monotonic_increments_remaining(&mut result) } {
- true => Ok(result),
- false => Err(()),
+pub async fn monotonic_increments_remaining() -> Result<u32, ()> {
+ let mut counter_buf = [0; 4];
+ ops::util_read_data(OID_COUNTER, 0, &mut counter_buf)
+ .await
+ .map_err(|_| ())?;
+ let counter = u32::from_be_bytes(counter_buf);
+ if counter > MONOTONIC_COUNTER_MAX_USE {
+ panic!("optiga monotonic counter larger than max");
}
+ Ok(MONOTONIC_COUNTER_MAX_USE - counter)
}
pub fn reset_keys() -> Result<(), ()> {
diff --git a/src/rust/bitbox-securechip/src/optiga/ops.rs b/src/rust/bitbox-securechip/src/optiga/ops.rs
new file mode 100644
index 0000000..6c9e7f1
--- /dev/null
+++ b/src/rust/bitbox-securechip/src/optiga/ops.rs
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::{Error, SecureChipError};
+use core::cell::UnsafeCell;
+use core::future::poll_fn;
+use core::task::{Poll, Waker};
+use grounded::uninit::{GroundedArrayCell, GroundedCell};
+use util::cell::SyncCell;
+use zeroize::Zeroize;
+
+const ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE: usize =
+ bitbox_securechip_sys::ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE as usize;
+
+// This is the biggest buffer we want to move through the async data-object helpers.
+const ASYNC_BUF_MAX_SIZE: usize = ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE;
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+enum AsyncOpState {
+ // No async Rust wrapper owns the shared static buffers or the single global waker.
+ Idle,
+ // One live Rust future launched an Optiga command and still needs to observe the result.
+ Running,
+ // The Rust future was dropped after launching the command, but the C callback has not
+ // completed yet. The old command may still be reading/writing the shared static buffers, so a
+ // new call must not reuse them yet.
+ Detached,
+}
+
+// The Optiga callback exposes only one shared status variable and one wakeup hook, so the Rust
+// wrappers can support only one in-flight async operation at a time. The extra Detached state is
+// needed because cancellation must not free the slot until the callback has really finished using
+// the shared static buffers.
+static STATE: SyncCell<AsyncOpState> = SyncCell::new(AsyncOpState::Idle);
+static WAKER: WakerCell = WakerCell::new();
+
+struct WakerCell {
+ waker: UnsafeCell<Option<Waker>>,
+}
+
+unsafe impl Sync for WakerCell {}
+
+impl WakerCell {
+ const fn new() -> Self {
+ Self {
+ waker: UnsafeCell::new(None),
+ }
+ }
+
+ fn register(&self, waker: &Waker) {
+ critical_section::with(|_| unsafe {
+ *self.waker.get() = Some(waker.clone());
+ });
+ }
+
+ fn take(&self) -> Option<Waker> {
+ critical_section::with(|_| unsafe { (*self.waker.get()).take() })
+ }
+
+ fn clear(&self) {
+ drop(self.take());
+ }
+}
+
+// The Optiga C API retains raw pointers to these statics until its async callback completes,
+// potentially after the Rust future has been dropped. The surrounding async-op state machine
+// ensures only one Rust wrapper owns the buffers at a time, so this wrapper exposes only raw
+// pointers and byte-buffer operations and never hands out Rust references to the static storage.
+struct StaticBytes<const N: usize>(GroundedArrayCell<u8, N>);
+
+impl<const N: usize> StaticBytes<N> {
+ const fn const_init() -> Self {
+ Self(GroundedArrayCell::const_init())
+ }
+
+ fn as_mut_ptr(&self) -> *mut u8 {
+ self.0.as_mut_ptr()
+ }
+
+ fn clear(&self) {
+ unsafe {
+ self.0.initialize_all_copied(0);
+ }
+ }
+
+ fn copy_to_slice(&self, out: &mut [u8]) {
+ unsafe {
+ core::ptr::copy_nonoverlapping(self.as_mut_ptr(), out.as_mut_ptr(), out.len());
+ }
+ }
+
+ fn zeroize(&self) {
+ let (ptr, len) = self.0.get_ptr_len();
+ unsafe {
+ core::slice::from_raw_parts_mut(ptr, len).zeroize();
+ }
+ }
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn rust_optiga_callback_wake() {
+ if let Some(waker) = WAKER.take() {
+ waker.wake();
+ }
+}
+
+struct AsyncOpGuard {
+ armed: bool,
+}
+
+impl AsyncOpGuard {
+ fn new() -> Self {
+ Self { armed: true }
+ }
+
+ fn disarm(&mut self) {
+ self.armed = false;
+ }
+}
+
+impl Drop for AsyncOpGuard {
+ fn drop(&mut self) {
+ if !self.armed {
+ return;
+ }
+
+ WAKER.clear();
+ let status = unsafe { bitbox_securechip_sys::optiga_ops_get_status() };
+ if status == bitbox_securechip_sys::OPTIGA_LIB_BUSY as _ {
+ STATE.write(AsyncOpState::Detached);
+ } else {
+ STATE.write(AsyncOpState::Idle);
+ }
+ }
+}
+
+async fn reclaim_detached_op() {
+ match STATE.read() {
+ AsyncOpState::Idle => {
+ // Another path already observed the callback and released the slot, so there is
+ // nothing left to reclaim here.
+ return;
+ }
+ AsyncOpState::Running => {
+ // Sequential callers are required for this wrapper. Reaching this arm means some
+ // other live future is still using the shared static buffers and the global waker.
+ panic!("concurrent async optiga operation not supported");
+ }
+ AsyncOpState::Detached => {
+ // Detached means the old future is gone. Under the sequential-caller assumption,
+ // this recovery future is now the only one that can wait for the late callback and
+ // then release the shared static buffers for reuse.
+ WAKER.clear();
+ }
+ }
+
+ let mut guard = AsyncOpGuard::new();
+ poll_fn(|cx| {
+ let status = unsafe { bitbox_securechip_sys::optiga_ops_get_status() };
+ if status == bitbox_securechip_sys::OPTIGA_LIB_BUSY as _ {
+ WAKER.register(cx.waker());
+ let status = unsafe { bitbox_securechip_sys::optiga_ops_get_status() };
+ if status == bitbox_securechip_sys::OPTIGA_LIB_BUSY as _ {
+ Poll::Pending
+ } else {
+ WAKER.clear();
+ Poll::Ready(())
+ }
+ } else {
+ WAKER.clear();
+ Poll::Ready(())
+ }
+ })
+ .await;
+ guard.disarm();
+ WAKER.clear();
+ STATE.write(AsyncOpState::Idle);
+}
+
+async fn begin_async_op() -> Result<(), bitbox_securechip_sys::optiga_lib_status_t> {
+ loop {
+ match STATE.read() {
+ AsyncOpState::Idle => {
+ // We are the only Rust future touching the shared static buffers, so it is safe
+ // to hand their addresses to the C library and reuse the global waker slot.
+ STATE.write(AsyncOpState::Running);
+ WAKER.clear();
+ unsafe {
+ bitbox_securechip_sys::optiga_ops_set_status_busy();
+ }
+ return Ok(());
+ }
+ AsyncOpState::Running => {
+ // Sequential callers are required. If we are asked to start another operation
+ // while one live future still owns the shared static buffers, something above this
+ // wrapper broke that invariant.
+ panic!("concurrent async optiga operation not supported");
+ }
+ AsyncOpState::Detached => {
+ // A previous future was cancelled after launching the command. Wait until its
+ // callback has really landed before reusing the shared static buffers.
+ reclaim_detached_op().await;
+ }
+ }
+ }
+}
+
+fn end_async_op() {
+ WAKER.clear();
+ STATE.write(AsyncOpState::Idle);
+}
+
+async fn run_async_op(
+ launch: impl FnOnce() -> bitbox_securechip_sys::optiga_lib_status_t,
+) -> Result<(), bitbox_securechip_sys::optiga_lib_status_t> {
+ begin_async_op().await?;
+ let mut guard = AsyncOpGuard::new();
+ let result = wait(launch()).await;
+ guard.disarm();
+ end_async_op();
+ result
+}
+
+async fn wait(
+ initial_status: bitbox_securechip_sys::optiga_lib_status_t,
+) -> Result<(), bitbox_securechip_sys::optiga_lib_status_t> {
+ if initial_status != bitbox_securechip_sys::OPTIGA_LIB_SUCCESS as _ {
+ return Err(initial_status);
+ }
+
+ poll_fn(|cx| {
+ let status = unsafe { bitbox_securechip_sys::optiga_ops_get_status() };
+ if status == bitbox_securechip_sys::OPTIGA_LIB_BUSY as _ {
+ // Register first, then re-check status to avoid missing a callback that fires between
+ // the initial busy check and storing the waker.
+ WAKER.register(cx.waker());
+ let status = unsafe { bitbox_securechip_sys::optiga_ops_get_status() };
+ if status == bitbox_securechip_sys::OPTIGA_LIB_BUSY as _ {
+ Poll::Pending
+ } else if status == bitbox_securechip_sys::OPTIGA_LIB_SUCCESS as _ {
+ WAKER.clear();
+ Poll::Ready(Ok(()))
+ } else {
+ WAKER.clear();
+ Poll::Ready(Err(status))
+ }
+ } else if status == bitbox_securechip_sys::OPTIGA_LIB_SUCCESS as _ {
+ WAKER.clear();
+ Poll::Ready(Ok(()))
+ } else {
+ WAKER.clear();
+ Poll::Ready(Err(status))
+ }
+ })
+ .await
+}
+
+pub(super) async fn util_read_data(oid: u16, offset: u16, out: &mut [u8]) -> Result<(), Error> {
+ // Static because the Optiga library keeps raw pointers to this buffer and length until the
+ // async callback completes, and the Rust future may be dropped before that happens.
+ static BUF: StaticBytes<ASYNC_BUF_MAX_SIZE> = StaticBytes::const_init();
+ static LEN: GroundedCell<u16> = GroundedCell::const_init();
+ if out.len() > ASYNC_BUF_MAX_SIZE {
+ panic!("optiga async read larger than max supported size");
+ }
+ let requested_len: u16 = out.len().try_into().unwrap();
+
+ let util = unsafe { bitbox_securechip_sys::optiga_util_instance() };
+
+ BUF.clear();
+ unsafe {
+ LEN.get().write(requested_len);
+ }
+ let result = run_async_op(|| unsafe {
+ bitbox_securechip_sys::optiga_util_read_data(util, oid, offset, BUF.as_mut_ptr(), LEN.get())
+ })
+ .await
+ .map_err(|status| Error::from_status(status as i32));
+ if let Err(err) = result {
+ BUF.zeroize();
+ return Err(err);
+ }
+
+ if unsafe { LEN.get().read() } != requested_len {
+ BUF.zeroize();
+ return Err(Error::SecureChip(
+ SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_LEN,
+ ));
+ }
+ BUF.copy_to_slice(out);
+ BUF.zeroize();
+ Ok(())
+}
diff --git a/src/rust/bitbox02-cbindgen.toml b/src/rust/bitbox02-cbindgen.toml
index 0948dda..3b1c7d1 100644
--- a/src/rust/bitbox02-cbindgen.toml
+++ b/src/rust/bitbox02-cbindgen.toml
@@ -18,10 +18,10 @@ header = '''
parse_deps = true
# ... but only parse these crates.
-include = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue", "bitbox-usb-report-queue"]
+include = ["bitbox02", "bitbox02-rust", "bitbox-securechip", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue", "bitbox-usb-report-queue"]
# also generate bindings from these crates.
-extra_bindings = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue", "bitbox-usb-report-queue"]
+extra_bindings = ["bitbox02", "bitbox02-rust", "bitbox-securechip", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue", "bitbox-usb-report-queue"]
[export]
# malloc, free declared in bitbox02-rust-c/src/c_alloc.rs, but does not need to be exported, as it
diff --git a/src/rust/bitbox02/src/hal/securechip.rs b/src/rust/bitbox02/src/hal/securechip.rs
index 35e773e..286e2f3 100644
--- a/src/rust/bitbox02/src/hal/securechip.rs
+++ b/src/rust/bitbox02/src/hal/securechip.rs
@@ -118,7 +118,7 @@ impl SecureChip for BitBox02SecureChip {
}
async fn monotonic_increments_remaining(&mut self) -> Result<u32, ()> {
- crate::securechip::monotonic_increments_remaining()
+ crate::securechip::monotonic_increments_remaining().await
}
fn model(&mut self) -> Result<Model, ()> {
diff --git a/src/rust/bitbox02/src/securechip/imp.rs b/src/rust/bitbox02/src/securechip/imp.rs
index f04c9da..3795d25 100644
--- a/src/rust/bitbox02/src/securechip/imp.rs
+++ b/src/rust/bitbox02/src/securechip/imp.rs
@@ -32,10 +32,10 @@ pub fn random() -> Result<Box<Zeroizing<[u8; 32]>>, Error> {
}
}
-pub fn monotonic_increments_remaining() -> Result<u32, ()> {
+pub async fn monotonic_increments_remaining() -> Result<u32, ()> {
match backend() {
Backend::Atecc => atecc::monotonic_increments_remaining(),
- Backend::Optiga => optiga::monotonic_increments_remaining(),
+ Backend::Optiga => optiga::monotonic_increments_remaining().await,
}
}
diff --git a/src/rust/bitbox02/src/securechip/imp_fake.rs b/src/rust/bitbox02/src/securechip/imp_fake.rs
index 3aa5408..3d3d062 100644
--- a/src/rust/bitbox02/src/securechip/imp_fake.rs
+++ b/src/rust/bitbox02/src/securechip/imp_fake.rs
@@ -32,7 +32,7 @@ pub fn random() -> Result<Box<Zeroizing<[u8; 32]>>, Error> {
Ok(Box::new(Zeroizing::new([0u8; 32])))
}
-pub fn monotonic_increments_remaining() -> Result<u32, ()> {
+pub async fn monotonic_increments_remaining() -> Result<u32, ()> {
Ok(1)
}
diff --git a/test/simulator-graphical-bb03/Cargo.lock b/test/simulator-graphical-bb03/Cargo.lock
index d6e2523..5644d91 100644
--- a/test/simulator-graphical-bb03/Cargo.lock
+++ b/test/simulator-graphical-bb03/Cargo.lock
@@ -416,6 +416,8 @@ name = "bitbox-securechip"
version = "0.1.0"
dependencies = [
"bitbox-securechip-sys",
+ "critical-section",
+ "grounded",
"util",
"zeroize",
]
diff --git a/test/simulator-graphical/Cargo.lock b/test/simulator-graphical/Cargo.lock
index 9a1a49e..ae68daa 100644
--- a/test/simulator-graphical/Cargo.lock
+++ b/test/simulator-graphical/Cargo.lock
@@ -360,6 +360,8 @@ name = "bitbox-securechip"
version = "0.1.0"
dependencies = [
"bitbox-securechip-sys",
+ "critical-section",
+ "grounded",
"util",
"zeroize",
]
Why this scored 11/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.