hal: add local memory/securechip types
What changed, and why it matters
This commit is a software-architecture cleanup, not a security fix. It moves data types such as device platform, secure chip model, and password-stretching algorithm out of a low-level BitBox02-specific module into a new hardware-abstraction layer (HAL). The real hardware behavior is unchanged; only the internal Rust type names and error-conversion paths are different. A few error mappings were made slightly more precise (for example, a duplicate name now returns a clearer 'duplicate' error instead of a generic memory error), but these are minor refinements rather than vulnerability fixes.
No security action required. Treat as normal code-quality/architecture review. If auditing, verify that the new error mappings do not accidentally expose more information to callers than intended (e.g., the more specific Duplicate/InvalidInput responses in hww/api/error.rs).
Security signals we found
Refactoring of memory/securechip error types into HAL abstraction layer
Slight improvement in error mapping for duplicate-name and invalid-input memory errors
Addition of SC_ERR_MEMORY to securechip status-code lookup table
No changes to input validation, access control, or cryptographic operations
Evidence from the diff
The change introduces local HAL enums (memory::Platform, memory::SecurechipType, memory::PasswordStretchAlgo, memory::Error, securechip::Model, securechip::Error, securechip::SecureChipError) so that the HAL trait no longer depends on bitbox02_sys-generated types. BitBox02Memory and BitBox02SecureChip now translate between the C FFI types and the new HAL types. TestingMemory/TestingSecureChip were updated to use the HAL types. Call sites in communication_mode, bluetooth, device_info, keystore, reset, workflow/password, and bitcoin/registration were adjusted. Notable behavior changes: bitbox02::memory::set_device_name now returns MemoryError instead of a private Error; hww/api/error.rs maps hal::memory::Error to more specific API errors (InvalidInput, Duplicate, Generic, Memory); and securechip.rs adds SC_ERR_MEMORY to the status-to-enum lookup table. The diff shows no new input validation, no bounds-check changes, and no cryptographic changes.
Changed components
src/rust/bitbox02-rust/src/hal/memory.rssrc/rust/bitbox02-rust/src/hal/securechip.rssrc/rust/bitbox02-rust/src/hal/bitbox02/memory.rssrc/rust/bitbox02-rust/src/hal/bitbox02/securechip.rssrc/rust/bitbox02-rust/src/hal/testing/memory.rssrc/rust/bitbox02-rust/src/hal/testing/securechip.rssrc/rust/bitbox02-rust/src/hww/api/error.rssrc/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rssrc/rust/bitbox02/src/memory.rssrc/rust/bitbox02/src/securechip.rsInspect captured patch +533 / −172
diff --git a/src/rust/bitbox02-rust/src/communication_mode.rs b/src/rust/bitbox02-rust/src/communication_mode.rs
index ea789d0..b024829 100644
--- a/src/rust/bitbox02-rust/src/communication_mode.rs
+++ b/src/rust/bitbox02-rust/src/communication_mode.rs
@@ -3,7 +3,7 @@
//! The BitBox02 Nova has two communication modes: USB and Bluetooth.
//! Bluetooth is active until the first USB request is seen, at which point USB takes priority.
-use crate::hal::Memory;
+use crate::hal::{Memory, memory};
use util::cell::SyncCell;
static USB_HWW_REQUEST_SEEN: SyncCell<bool> = SyncCell::new(false);
@@ -28,7 +28,7 @@ fn has_ble(hal: &mut impl crate::hal::Hal) -> bool {
let has_ble = matches!(
hal.memory().get_platform(),
- Ok(bitbox02::memory::Platform::BitBox02Plus),
+ Ok(memory::Platform::BitBox02Plus),
);
HAS_BLE.write(Some(has_ble));
has_ble
@@ -61,8 +61,7 @@ mod tests {
fn test_ble_disabled_on_non_plus() {
reset_for_testing();
let mut hal = TestingHal::new();
- hal.memory
- .set_platform(bitbox02::memory::Platform::BitBox02);
+ hal.memory.set_platform(memory::Platform::BitBox02);
assert!(!ble_enabled(&mut hal));
@@ -74,8 +73,7 @@ mod tests {
fn test_ble_enabled_until_usb_request_seen() {
reset_for_testing();
let mut hal = TestingHal::new();
- hal.memory
- .set_platform(bitbox02::memory::Platform::BitBox02Plus);
+ hal.memory.set_platform(memory::Platform::BitBox02Plus);
assert!(ble_enabled(&mut hal));
diff --git a/src/rust/bitbox02-rust/src/hal/bitbox02/memory.rs b/src/rust/bitbox02-rust/src/hal/bitbox02/memory.rs
index a128ff7..69442a5 100644
--- a/src/rust/bitbox02-rust/src/hal/bitbox02/memory.rs
+++ b/src/rust/bitbox02-rust/src/hal/bitbox02/memory.rs
@@ -4,24 +4,77 @@ use alloc::string::String;
use alloc::vec::Vec;
use crate::hal::Memory;
+use crate::hal::memory::{Error, PasswordStretchAlgo, Platform, SecurechipType};
pub(crate) struct BitBox02Memory;
+fn to_hal_securechip_type(securechip_type: bitbox02::memory::SecurechipType) -> SecurechipType {
+ match securechip_type {
+ bitbox02::memory::SecurechipType::Atecc => SecurechipType::Atecc,
+ bitbox02::memory::SecurechipType::Optiga => SecurechipType::Optiga,
+ }
+}
+
+fn to_hal_platform(platform: bitbox02::memory::Platform) -> Platform {
+ match platform {
+ bitbox02::memory::Platform::BitBox02 => Platform::BitBox02,
+ bitbox02::memory::Platform::BitBox02Plus => Platform::BitBox02Plus,
+ }
+}
+
+fn to_hal_password_stretch_algo(
+ algo: bitbox02::memory::PasswordStretchAlgo,
+) -> PasswordStretchAlgo {
+ match algo {
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0 => {
+ PasswordStretchAlgo::V0
+ }
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1 => {
+ PasswordStretchAlgo::V1
+ }
+ }
+}
+
+fn to_hal_error(error: bitbox02::memory::MemoryError) -> Error {
+ match error {
+ bitbox02::memory::MemoryError::MEMORY_OK => {
+ unreachable!("MEMORY_OK must not be converted to hal::memory::Error")
+ }
+ bitbox02::memory::MemoryError::MEMORY_ERR_INVALID_INPUT => Error::InvalidInput,
+ bitbox02::memory::MemoryError::MEMORY_ERR_FULL => Error::Full,
+ bitbox02::memory::MemoryError::MEMORY_ERR_DUPLICATE_NAME => Error::DuplicateName,
+ bitbox02::memory::MemoryError::MEMORY_ERR_UNKNOWN => Error::Unknown,
+ }
+}
+
+pub(super) fn to_bitbox02_password_stretch_algo(
+ algo: PasswordStretchAlgo,
+) -> bitbox02::memory::PasswordStretchAlgo {
+ match algo {
+ PasswordStretchAlgo::V0 => {
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0
+ }
+ PasswordStretchAlgo::V1 => {
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1
+ }
+ }
+}
+
impl Memory for BitBox02Memory {
- fn get_securechip_type(&mut self) -> Result<bitbox02::memory::SecurechipType, ()> {
- bitbox02::memory::get_securechip_type()
+ fn get_securechip_type(&mut self) -> Result<SecurechipType, ()> {
+ bitbox02::memory::get_securechip_type().map(to_hal_securechip_type)
}
- fn get_platform(&mut self) -> Result<bitbox02::memory::Platform, ()> {
- bitbox02::memory::get_platform()
+ fn get_platform(&mut self) -> Result<Platform, ()> {
+ bitbox02::memory::get_platform().map(to_hal_platform)
}
fn get_device_name(&mut self) -> String {
bitbox02::memory::get_device_name()
}
- fn set_device_name(&mut self, name: &str) -> Result<(), bitbox02::memory::Error> {
- bitbox02::memory::set_device_name(name)
+ fn set_device_name(&mut self, name: &str) -> Result<(), Error> {
+ bitbox02::memory::set_device_name(name).map_err(to_hal_error)
}
fn is_mnemonic_passphrase_enabled(&mut self) -> bool {
@@ -52,18 +105,20 @@ impl Memory for BitBox02Memory {
bitbox02::memory::set_initialized()
}
- fn get_encrypted_seed_and_hmac(
- &mut self,
- ) -> Result<(Vec<u8>, bitbox02::memory::PasswordStretchAlgo), ()> {
+ fn get_encrypted_seed_and_hmac(&mut self) -> Result<(Vec<u8>, PasswordStretchAlgo), ()> {
bitbox02::memory::get_encrypted_seed_and_hmac()
+ .map(|(seed, algo)| (seed, to_hal_password_stretch_algo(algo)))
}
fn set_encrypted_seed_and_hmac(
&mut self,
data: &[u8],
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
+ password_stretch_algo: PasswordStretchAlgo,
) -> Result<(), ()> {
- bitbox02::memory::set_encrypted_seed_and_hmac(data, password_stretch_algo)
+ bitbox02::memory::set_encrypted_seed_and_hmac(
+ data,
+ to_bitbox02_password_stretch_algo(password_stretch_algo),
+ )
}
fn reset_hww(&mut self) -> Result<(), ()> {
@@ -103,15 +158,92 @@ impl Memory for BitBox02Memory {
bitbox02::memory::get_attestation_bootloader_hash()
}
- fn multisig_set_by_hash(
- &mut self,
- hash: &[u8; 32],
- name: &str,
- ) -> Result<(), bitbox02::memory::MemoryError> {
- bitbox02::memory::multisig_set_by_hash(hash, name)
+ fn multisig_set_by_hash(&mut self, hash: &[u8; 32], name: &str) -> Result<(), Error> {
+ bitbox02::memory::multisig_set_by_hash(hash, name).map_err(to_hal_error)
}
fn multisig_get_by_hash(&self, hash: &[u8; 32]) -> Option<String> {
bitbox02::memory::multisig_get_by_hash(hash)
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_to_hal_securechip_type() {
+ assert_eq!(
+ to_hal_securechip_type(bitbox02::memory::SecurechipType::Atecc),
+ SecurechipType::Atecc,
+ );
+ assert_eq!(
+ to_hal_securechip_type(bitbox02::memory::SecurechipType::Optiga),
+ SecurechipType::Optiga,
+ );
+ }
+
+ #[test]
+ fn test_to_hal_platform() {
+ assert_eq!(
+ to_hal_platform(bitbox02::memory::Platform::BitBox02),
+ Platform::BitBox02,
+ );
+ assert_eq!(
+ to_hal_platform(bitbox02::memory::Platform::BitBox02Plus),
+ Platform::BitBox02Plus,
+ );
+ }
+
+ #[test]
+ fn test_to_hal_error() {
+ let cases = [
+ (
+ bitbox02::memory::MemoryError::MEMORY_ERR_INVALID_INPUT,
+ Error::InvalidInput,
+ ),
+ (bitbox02::memory::MemoryError::MEMORY_ERR_FULL, Error::Full),
+ (
+ bitbox02::memory::MemoryError::MEMORY_ERR_DUPLICATE_NAME,
+ Error::DuplicateName,
+ ),
+ (
+ bitbox02::memory::MemoryError::MEMORY_ERR_UNKNOWN,
+ Error::Unknown,
+ ),
+ ];
+ for (input, expected) in cases {
+ assert_eq!(to_hal_error(input), expected);
+ }
+ }
+
+ #[test]
+ #[should_panic(expected = "MEMORY_OK must not be converted to hal::memory::Error")]
+ fn test_to_hal_error_memory_ok_panics() {
+ let _ = to_hal_error(bitbox02::memory::MemoryError::MEMORY_OK);
+ }
+
+ #[test]
+ fn test_password_stretch_algo_mappings() {
+ assert_eq!(
+ to_hal_password_stretch_algo(
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0,
+ ),
+ PasswordStretchAlgo::V0,
+ );
+ assert_eq!(
+ to_hal_password_stretch_algo(
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1,
+ ),
+ PasswordStretchAlgo::V1,
+ );
+ assert_eq!(
+ to_bitbox02_password_stretch_algo(PasswordStretchAlgo::V0) as i32,
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0 as i32,
+ );
+ assert_eq!(
+ to_bitbox02_password_stretch_algo(PasswordStretchAlgo::V1) as i32,
+ bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1 as i32,
+ );
+ }
+}
diff --git a/src/rust/bitbox02-rust/src/hal/bitbox02/securechip.rs b/src/rust/bitbox02-rust/src/hal/bitbox02/securechip.rs
index 73eea74..cbc26f3 100644
--- a/src/rust/bitbox02-rust/src/hal/bitbox02/securechip.rs
+++ b/src/rust/bitbox02-rust/src/hal/bitbox02/securechip.rs
@@ -3,31 +3,97 @@
use alloc::vec::Vec;
use crate::hal::SecureChip;
+use crate::hal::memory::PasswordStretchAlgo;
+use crate::hal::securechip::{Error, Model, SecureChipError};
pub(crate) struct BitBox02SecureChip;
+fn to_hal_model(model: bitbox02::securechip::Model) -> Model {
+ match model {
+ bitbox02::securechip::Model::ATECC_ATECC608A => Model::Atecc608A,
+ bitbox02::securechip::Model::ATECC_ATECC608B => Model::Atecc608B,
+ bitbox02::securechip::Model::OPTIGA_TRUST_M_V3 => Model::OptigaTrustM3,
+ }
+}
+
+fn to_hal_error(error: bitbox02::securechip::Error) -> Error {
+ match error {
+ bitbox02::securechip::Error::SecureChip(sc_err) => Error::SecureChip(match sc_err {
+ bitbox02::securechip::SecureChipError::SC_ERR_IFS => SecureChipError::Ifs,
+ bitbox02::securechip::SecureChipError::SC_ERR_INVALID_ARGS => {
+ SecureChipError::InvalidArgs
+ }
+ bitbox02::securechip::SecureChipError::SC_ERR_CONFIG_MISMATCH => {
+ SecureChipError::ConfigMismatch
+ }
+ bitbox02::securechip::SecureChipError::SC_ERR_SALT => SecureChipError::Salt,
+ bitbox02::securechip::SecureChipError::SC_ERR_INCORRECT_PASSWORD => {
+ SecureChipError::IncorrectPassword
+ }
+ bitbox02::securechip::SecureChipError::SC_ERR_INVALID_PASSWORD_STRETCH_ALGO => {
+ SecureChipError::InvalidPasswordStretchAlgo
+ }
+ bitbox02::securechip::SecureChipError::SC_ERR_MEMORY => SecureChipError::Memory,
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_CONFIG => {
+ SecureChipError::AteccZoneUnlockedConfig
+ }
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_DATA => {
+ SecureChipError::AteccZoneUnlockedData
+ }
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_IO => {
+ SecureChipError::AteccSlotUnlockedIo
+ }
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_AUTH => {
+ SecureChipError::AteccSlotUnlockedAuth
+ }
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_ENC => {
+ SecureChipError::AteccSlotUnlockedEnc
+ }
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_RESET_KEYS => {
+ SecureChipError::AteccResetKeys
+ }
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_CREATE => {
+ SecureChipError::OptigaCreate
+ }
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_METADATA => {
+ SecureChipError::OptigaUnexpectedMetadata
+ }
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_PAL => SecureChipError::OptigaPal,
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_LEN => {
+ SecureChipError::OptigaUnexpectedLen
+ }
+ }),
+ bitbox02::securechip::Error::Status(status) => Error::Status(status),
+ }
+}
+
impl SecureChip for BitBox02SecureChip {
fn init_new_password(
&mut self,
password: &str,
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
- bitbox02::securechip::init_new_password(password, password_stretch_algo)
+ password_stretch_algo: PasswordStretchAlgo,
+ ) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
+ bitbox02::securechip::init_new_password(
+ password,
+ super::memory::to_bitbox02_password_stretch_algo(password_stretch_algo),
+ )
+ .map_err(to_hal_error)
}
fn stretch_password(
&mut self,
password: &str,
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
- bitbox02::securechip::stretch_password(password, password_stretch_algo)
+ password_stretch_algo: PasswordStretchAlgo,
+ ) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
+ bitbox02::securechip::stretch_password(
+ password,
+ super::memory::to_bitbox02_password_stretch_algo(password_stretch_algo),
+ )
+ .map_err(to_hal_error)
}
- fn kdf(
- &mut self,
- msg: &[u8],
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
- bitbox02::securechip::kdf(msg)
+ fn kdf(&mut self, msg: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
+ bitbox02::securechip::kdf(msg).map_err(to_hal_error)
}
fn attestation_sign(
@@ -42,8 +108,8 @@ impl SecureChip for BitBox02SecureChip {
bitbox02::securechip::monotonic_increments_remaining()
}
- fn model(&mut self) -> Result<bitbox02::securechip::Model, ()> {
- bitbox02::securechip::model()
+ fn model(&mut self) -> Result<Model, ()> {
+ bitbox02::securechip::model().map(to_hal_model)
}
fn reset_keys(&mut self) -> Result<(), ()> {
@@ -55,3 +121,112 @@ impl SecureChip for BitBox02SecureChip {
bitbox02::securechip::u2f_counter_set(counter)
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_to_hal_model() {
+ assert_eq!(
+ to_hal_model(bitbox02::securechip::Model::ATECC_ATECC608A),
+ Model::Atecc608A,
+ );
+ assert_eq!(
+ to_hal_model(bitbox02::securechip::Model::ATECC_ATECC608B),
+ Model::Atecc608B,
+ );
+ assert_eq!(
+ to_hal_model(bitbox02::securechip::Model::OPTIGA_TRUST_M_V3),
+ Model::OptigaTrustM3,
+ );
+ }
+
+ #[test]
+ fn test_to_hal_error_securechip() {
+ let cases = [
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_IFS,
+ SecureChipError::Ifs,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_INVALID_ARGS,
+ SecureChipError::InvalidArgs,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_CONFIG_MISMATCH,
+ SecureChipError::ConfigMismatch,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_SALT,
+ SecureChipError::Salt,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_INCORRECT_PASSWORD,
+ SecureChipError::IncorrectPassword,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_INVALID_PASSWORD_STRETCH_ALGO,
+ SecureChipError::InvalidPasswordStretchAlgo,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ERR_MEMORY,
+ SecureChipError::Memory,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_CONFIG,
+ SecureChipError::AteccZoneUnlockedConfig,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_DATA,
+ SecureChipError::AteccZoneUnlockedData,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_IO,
+ SecureChipError::AteccSlotUnlockedIo,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_AUTH,
+ SecureChipError::AteccSlotUnlockedAuth,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_ENC,
+ SecureChipError::AteccSlotUnlockedEnc,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_ATECC_ERR_RESET_KEYS,
+ SecureChipError::AteccResetKeys,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_CREATE,
+ SecureChipError::OptigaCreate,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_METADATA,
+ SecureChipError::OptigaUnexpectedMetadata,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_PAL,
+ SecureChipError::OptigaPal,
+ ),
+ (
+ bitbox02::securechip::SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_LEN,
+ SecureChipError::OptigaUnexpectedLen,
+ ),
+ ];
+ for (input, expected) in cases {
+ assert_eq!(
+ to_hal_error(bitbox02::securechip::Error::SecureChip(input)),
+ Error::SecureChip(expected),
+ );
+ }
+ }
+
+ #[test]
+ fn test_to_hal_error_status() {
+ assert_eq!(
+ to_hal_error(bitbox02::securechip::Error::Status(7)),
+ Error::Status(7)
+ );
+ }
+}
diff --git a/src/rust/bitbox02-rust/src/hal/memory.rs b/src/rust/bitbox02-rust/src/hal/memory.rs
index 759af70..632e67c 100644
--- a/src/rust/bitbox02-rust/src/hal/memory.rs
+++ b/src/rust/bitbox02-rust/src/hal/memory.rs
@@ -3,11 +3,37 @@
use alloc::string::String;
use alloc::vec::Vec;
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum PasswordStretchAlgo {
+ V0,
+ V1,
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum SecurechipType {
+ Atecc,
+ Optiga,
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Platform {
+ BitBox02,
+ BitBox02Plus,
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Error {
+ InvalidInput,
+ Full,
+ DuplicateName,
+ Unknown,
+}
+
pub trait Memory {
- fn get_securechip_type(&mut self) -> Result<bitbox02::memory::SecurechipType, ()>;
- fn get_platform(&mut self) -> Result<bitbox02::memory::Platform, ()>;
+ fn get_securechip_type(&mut self) -> Result<SecurechipType, ()>;
+ fn get_platform(&mut self) -> Result<Platform, ()>;
fn get_device_name(&mut self) -> String;
- fn set_device_name(&mut self, name: &str) -> Result<(), bitbox02::memory::Error>;
+ fn set_device_name(&mut self, name: &str) -> Result<(), Error>;
fn is_mnemonic_passphrase_enabled(&mut self) -> bool;
fn set_mnemonic_passphrase_enabled(&mut self, enabled: bool) -> Result<(), ()>;
fn set_seed_birthdate(&mut self, timestamp: u32) -> Result<(), ()>;
@@ -15,13 +41,11 @@ pub trait Memory {
fn is_seeded(&mut self) -> bool;
fn is_initialized(&mut self) -> bool;
fn set_initialized(&mut self) -> Result<(), ()>;
- fn get_encrypted_seed_and_hmac(
- &mut self,
- ) -> Result<(Vec<u8>, bitbox02::memory::PasswordStretchAlgo), ()>;
+ fn get_encrypted_seed_and_hmac(&mut self) -> Result<(Vec<u8>, PasswordStretchAlgo), ()>;
fn set_encrypted_seed_and_hmac(
&mut self,
data: &[u8],
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
+ password_stretch_algo: PasswordStretchAlgo,
) -> Result<(), ()>;
fn reset_hww(&mut self) -> Result<(), ()>;
fn get_unlock_attempts(&mut self) -> u8;
@@ -35,10 +59,6 @@ pub trait Memory {
root_pubkey_identifier_out: &mut [u8; 32],
) -> Result<(), ()>;
fn get_attestation_bootloader_hash(&mut self) -> [u8; 32];
- fn multisig_set_by_hash(
- &mut self,
- hash: &[u8; 32],
- name: &str,
- ) -> Result<(), bitbox02::memory::MemoryError>;
+ fn multisig_set_by_hash(&mut self, hash: &[u8; 32], name: &str) -> Result<(), Error>;
fn multisig_get_by_hash(&self, hash: &[u8; 32]) -> Option<String>;
}
diff --git a/src/rust/bitbox02-rust/src/hal/securechip.rs b/src/rust/bitbox02-rust/src/hal/securechip.rs
index 8f30596..ed64b1c 100644
--- a/src/rust/bitbox02-rust/src/hal/securechip.rs
+++ b/src/rust/bitbox02-rust/src/hal/securechip.rs
@@ -2,28 +2,70 @@
use alloc::vec::Vec;
+use super::memory::PasswordStretchAlgo;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Model {
+ Atecc608A,
+ Atecc608B,
+ OptigaTrustM3,
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Error {
+ SecureChip(SecureChipError),
+ Status(i32),
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(i32)]
+// Keep in sync with securechip.h's securechip_error_t.
+pub enum SecureChipError {
+ // Errors common to any securechip implementation
+ Ifs = -1,
+ InvalidArgs = -2,
+ ConfigMismatch = -3,
+ Salt = -4,
+ // Currently only used by Optiga, but it is in the common errors so that the API of the
+ // securechip is consistent and the caller does not need to distinguish between the chips at
+ // the callsite.
+ IncorrectPassword = -6,
+ // The password stretch algo is not supported
+ InvalidPasswordStretchAlgo = -7,
+ Memory = -8,
+ // Errors specific to the ATECC
+ AteccZoneUnlockedConfig = -100,
+ AteccZoneUnlockedData = -101,
+ AteccSlotUnlockedIo = -103,
+ AteccSlotUnlockedAuth = -104,
+ AteccSlotUnlockedEnc = -105,
+ AteccResetKeys = -106,
+ // Errors specific to the Optiga
+ OptigaCreate = -201,
+ OptigaUnexpectedMetadata = -204,
+ OptigaPal = -205,
+ OptigaUnexpectedLen = -206,
+}
+
pub trait SecureChip {
fn init_new_password(
&mut self,
password: &str,
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error>;
+ password_stretch_algo: PasswordStretchAlgo,
+ ) -> Result<zeroize::Zeroizing<Vec<u8>>, Error>;
fn stretch_password(
&mut self,
password: &str,
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error>;
- fn kdf(
- &mut self,
- msg: &[u8],
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error>;
+ password_stretch_algo: PasswordStretchAlgo,
+ ) -> Result<zeroize::Zeroizing<Vec<u8>>, Error>;
+ fn kdf(&mut self, msg: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error>;
fn attestation_sign(
&mut self,
challenge: &[u8; 32],
signature: &mut [u8; 64],
) -> Result<(), ()>;
fn monotonic_increments_remaining(&mut self) -> Result<u32, ()>;
- fn model(&mut self) -> Result<bitbox02::securechip::Model, ()>;
+ fn model(&mut self) -> Result<Model, ()>;
fn reset_keys(&mut self) -> Result<(), ()>;
#[cfg(feature = "app-u2f")]
fn u2f_counter_set(&mut self, counter: u32) -> Result<(), ()>;
diff --git a/src/rust/bitbox02-rust/src/hal/testing/memory.rs b/src/rust/bitbox02-rust/src/hal/testing/memory.rs
index 4e788eb..d09abb6 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/memory.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/memory.rs
@@ -3,16 +3,16 @@
use alloc::string::String;
use alloc::vec::Vec;
-use bitbox02::memory::SecurechipType;
+use crate::hal::memory::{Error, PasswordStretchAlgo, Platform, SecurechipType};
pub struct TestingMemory {
securechip_type: SecurechipType,
- platform: bitbox02::memory::Platform,
+ platform: Platform,
initialized: bool,
is_seeded: bool,
mnemonic_passphrase_enabled: bool,
seed_birthdate: u32,
- encrypted_seed_and_hmac: Option<(Vec<u8>, bitbox02::memory::PasswordStretchAlgo)>,
+ encrypted_seed_and_hmac: Option<(Vec<u8>, PasswordStretchAlgo)>,
device_name: Option<String>,
unlock_attempts: u8,
salt_root: [u8; 32],
@@ -30,7 +30,7 @@ impl TestingMemory {
pub fn new() -> Self {
Self {
securechip_type: SecurechipType::Optiga,
- platform: bitbox02::memory::Platform::BitBox02,
+ platform: Platform::BitBox02,
initialized: false,
is_seeded: false,
mnemonic_passphrase_enabled: false,
@@ -51,7 +51,7 @@ impl TestingMemory {
self.securechip_type = securechip_type;
}
- pub fn set_platform(&mut self, platform: bitbox02::memory::Platform) {
+ pub fn set_platform(&mut self, platform: Platform) {
self.platform = platform;
}
@@ -84,7 +84,7 @@ impl crate::hal::Memory for TestingMemory {
Ok(self.securechip_type)
}
- fn get_platform(&mut self) -> Result<bitbox02::memory::Platform, ()> {
+ fn get_platform(&mut self) -> Result<Platform, ()> {
Ok(self.platform)
}
@@ -94,7 +94,7 @@ impl crate::hal::Memory for TestingMemory {
.unwrap_or_else(|| "My BitBox".into())
}
- fn set_device_name(&mut self, name: &str) -> Result<(), bitbox02::memory::Error> {
+ fn set_device_name(&mut self, name: &str) -> Result<(), Error> {
self.device_name = Some(name.into());
Ok(())
}
@@ -132,14 +132,14 @@ impl crate::hal::Memory for TestingMemory {
fn get_encrypted_seed_and_hmac(
&mut self,
- ) -> Result<(alloc::vec::Vec<u8>, bitbox02::memory::PasswordStretchAlgo), ()> {
+ ) -> Result<(alloc::vec::Vec<u8>, PasswordStretchAlgo), ()> {
self.encrypted_seed_and_hmac.clone().ok_or(())
}
fn set_encrypted_seed_and_hmac(
&mut self,
data: &[u8],
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
+ password_stretch_algo: PasswordStretchAlgo,
) -> Result<(), ()> {
// 96 is the max space allocated in BitBox02's memory for this.
if data.len() > 96 {
@@ -206,14 +206,10 @@ impl crate::hal::Memory for TestingMemory {
self.attestation_bootloader_hash
}
- fn multisig_set_by_hash(
- &mut self,
- hash: &[u8; 32],
- name: &str,
- ) -> Result<(), bitbox02::memory::MemoryError> {
+ fn multisig_set_by_hash(&mut self, hash: &[u8; 32], name: &str) -> Result<(), Error> {
// Validate input
if name.is_empty() {
- return Err(bitbox02::memory::MemoryError::MEMORY_ERR_INVALID_INPUT);
+ return Err(Error::InvalidInput);
}
// Check for duplicate name with different hash
for (existing_hash, existing_name) in &self.multisig_entries {
@@ -221,7 +217,7 @@ impl crate::hal::Memory for TestingMemory {
if existing_hash != hash {
// Mirror bitbox02::memory multisig_set_by_hash semantics (duplicate-name / full-table),
// even if these branches are not currently exercised in bitbox02-rust tests.
- return Err(bitbox02::memory::MemoryError::MEMORY_ERR_DUPLICATE_NAME);
+ return Err(Error::DuplicateName);
}
// same name, same hash (already stored)
return Ok(());
@@ -239,7 +235,7 @@ impl crate::hal::Memory for TestingMemory {
}
if self.multisig_entries.len() >= MULTISIG_LIMIT {
// See comment above about mirroring bitbox02::memory semantics.
- return Err(bitbox02::memory::MemoryError::MEMORY_ERR_FULL);
+ return Err(Error::Full);
}
// Insert new entry
self.multisig_entries.push((*hash, String::from(name)));
diff --git a/src/rust/bitbox02-rust/src/hal/testing/securechip.rs b/src/rust/bitbox02-rust/src/hal/testing/securechip.rs
index a7c9510..219d86c 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/securechip.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/securechip.rs
@@ -5,6 +5,9 @@ use alloc::vec::Vec;
use bitcoin::hashes::Hash;
use hex_lit::hex;
+use crate::hal::memory::PasswordStretchAlgo;
+use crate::hal::securechip::{Error, Model};
+
pub struct TestingSecureChip {
// Count how many security events happen. The numbers were obtained by reading the security
// event counter slot (0xE0C5) on a real device. We can use this to assert how many events
@@ -62,15 +65,13 @@ impl crate::hal::SecureChip for TestingSecureChip {
fn init_new_password(
&mut self,
password: &str,
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
+ password_stretch_algo: PasswordStretchAlgo,
+ ) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
self.event_counter += 3;
let key: &'static [u8] = match password_stretch_algo {
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0 => {
- b"unit-test-v0"
- }
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1 => b"unit-test",
+ PasswordStretchAlgo::V0 => b"unit-test-v0",
+ PasswordStretchAlgo::V1 => b"unit-test",
};
use bitcoin::hashes::{HashEngine, Hmac, HmacEngine, sha256};
let mut engine = HmacEngine::<sha256::Hash>::new(key);
@@ -84,18 +85,16 @@ impl crate::hal::SecureChip for TestingSecureChip {
fn stretch_password(
&mut self,
password: &str,
- password_stretch_algo: bitbox02::memory::PasswordStretchAlgo,
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
+ password_stretch_algo: PasswordStretchAlgo,
+ ) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
self.event_counter += match password_stretch_algo {
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0 => 5,
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1 => 4,
+ PasswordStretchAlgo::V0 => 5,
+ PasswordStretchAlgo::V1 => 4,
};
let key: &'static [u8] = match password_stretch_algo {
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0 => {
- b"unit-test-v0"
- }
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1 => b"unit-test",
+ PasswordStretchAlgo::V0 => b"unit-test-v0",
+ PasswordStretchAlgo::V1 => b"unit-test",
};
use bitcoin::hashes::{HashEngine, Hmac, HmacEngine, sha256};
@@ -107,10 +106,7 @@ impl crate::hal::SecureChip for TestingSecureChip {
))
}
- fn kdf(
- &mut self,
- msg: &[u8],
- ) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
+ fn kdf(&mut self, msg: &[u8]) -> Result<zeroize::Zeroizing<Vec<u8>>, Error> {
self.event_counter += 1;
use bitcoin::hashes::{HashEngine, Hmac, HmacEngine, sha256};
@@ -139,8 +135,8 @@ impl crate::hal::SecureChip for TestingSecureChip {
Ok(1)
}
- fn model(&mut self) -> Result<bitbox02::securechip::Model, ()> {
- Ok(bitbox02::securechip::Model::ATECC_ATECC608B)
+ fn model(&mut self) -> Result<Model, ()> {
+ Ok(Model::Atecc608B)
}
fn reset_keys(&mut self) -> Result<(), ()> {
diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs
index 7433cc6..af75115 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/registration.rs
@@ -126,16 +126,9 @@ pub async fn process_register_script_config(
)
.await?;
let hash = super::multisig::get_hash(coin, multisig, SortXpubs::Yes, keypath)?;
- match hal.memory().multisig_set_by_hash(&hash, &name) {
- Ok(()) => {
- hal.ui().status("Multisig account\nregistered", true).await;
- Ok(Response::Success(pb::BtcSuccess {}))
- }
- Err(bitbox02::memory::MemoryError::MEMORY_ERR_DUPLICATE_NAME) => {
- Err(Error::Duplicate)
- }
- Err(_) => Err(Error::Generic),
- }
+ hal.memory().multisig_set_by_hash(&hash, &name)?;
+ hal.ui().status("Multisig account\nregistered", true).await;
+ Ok(Response::Success(pb::BtcSuccess {}))
}
Some(pb::BtcScriptConfigRegistration {
coin,
@@ -159,16 +152,9 @@ pub async fn process_register_script_config(
)
.await?;
let hash = super::policies::get_hash(coin, policy)?;
- match hal.memory().multisig_set_by_hash(&hash, &name) {
- Ok(()) => {
- hal.ui().status("Policy\nregistered", true).await;
- Ok(Response::Success(pb::BtcSuccess {}))
- }
- Err(bitbox02::memory::MemoryError::MEMORY_ERR_DUPLICATE_NAME) => {
- Err(Error::Duplicate)
- }
- Err(_) => Err(Error::Generic),
- }
+ hal.memory().multisig_set_by_hash(&hash, &name)?;
+ hal.ui().status("Policy\nregistered", true).await;
+ Ok(Response::Success(pb::BtcSuccess {}))
}
// Only multisig and policy registration supported for now.
_ => Err(Error::InvalidInput),
diff --git a/src/rust/bitbox02-rust/src/hww/api/bluetooth.rs b/src/rust/bitbox02-rust/src/hww/api/bluetooth.rs
index 917e08e..96e32e7 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bluetooth.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bluetooth.rs
@@ -10,7 +10,7 @@ use pb::bluetooth_response::Response;
use sha2::{Digest, Sha256};
-use crate::hal::{Memory, Ui};
+use crate::hal::{Memory, Ui, memory as hal_memory};
use crate::workflow::confirm;
use alloc::vec::Vec;
@@ -205,7 +205,7 @@ pub async fn process_api(
) -> Result<Response, Error> {
if !matches!(
hal.memory().get_platform().map_err(|_| Error::Memory)?,
- memory::Platform::BitBox02Plus
+ hal_memory::Platform::BitBox02Plus
) {
return Err(Error::Disabled);
}
diff --git a/src/rust/bitbox02-rust/src/hww/api/device_info.rs b/src/rust/bitbox02-rust/src/hww/api/device_info.rs
index 5874f83..936f46f 100644
--- a/src/rust/bitbox02-rust/src/hww/api/device_info.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/device_info.rs
@@ -1,15 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
use super::Error;
-use crate::hal::{Memory, SecureChip};
+use crate::hal::{Memory, SecureChip, memory as hal_memory, securechip};
use crate::pb;
-use bitbox02::{memory, securechip, spi_mem};
+use bitbox02::{memory, spi_mem};
use pb::response::Response;
pub fn process(hal: &mut impl crate::hal::Hal) -> Result<Response, Error> {
let bluetooth = match hal.memory().get_platform().map_err(|_| Error::Memory)? {
- memory::Platform::BitBox02Plus => {
+ hal_memory::Platform::BitBox02Plus => {
let ble_metadata = memory::get_ble_metadata();
Some(pb::device_info_response::Bluetooth {
firmware_hash: ble_metadata.allowed_firmware_hash.to_vec(),
@@ -18,7 +18,7 @@ pub fn process(hal: &mut impl crate::hal::Hal) -> Result<Response, Error> {
enabled: memory::ble_enabled(),
})
}
- memory::Platform::BitBox02 => None,
+ hal_memory::Platform::BitBox02 => None,
};
// We display the stretching algo that is used on a seeded device, or the algo that would be
// used for a new seed on an unseeded device.
@@ -41,14 +41,14 @@ pub fn process(hal: &mut impl crate::hal::Hal) -> Result<Response, Error> {
mnemonic_passphrase_enabled: hal.memory().is_mnemonic_passphrase_enabled(),
monotonic_increments_remaining: hal.securechip().monotonic_increments_remaining()?,
securechip_model: match hal.securechip().model()? {
- securechip::Model::ATECC_ATECC608A => "ATECC608A".into(),
- securechip::Model::ATECC_ATECC608B => "ATECC608B".into(),
- securechip::Model::OPTIGA_TRUST_M_V3 => "OPTIGA_TRUST_M_V3".into(),
+ securechip::Model::Atecc608A => "ATECC608A".into(),
+ securechip::Model::Atecc608B => "ATECC608B".into(),
+ securechip::Model::OptigaTrustM3 => "OPTIGA_TRUST_M_V3".into(),
},
bluetooth,
password_stretching_algo: match password_stretching_algo {
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0 => "V1".into(),
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1 => "V2".into(),
+ hal_memory::PasswordStretchAlgo::V0 => "V1".into(),
+ hal_memory::PasswordStretchAlgo::V1 => "V2".into(),
},
}))
}
diff --git a/src/rust/bitbox02-rust/src/hww/api/error.rs b/src/rust/bitbox02-rust/src/hww/api/error.rs
index 0c05342..4beecba 100644
--- a/src/rust/bitbox02-rust/src/hww/api/error.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/error.rs
@@ -24,9 +24,14 @@ impl core::convert::From<()> for Error {
}
}
-impl core::convert::From<bitbox02::memory::Error> for Error {
- fn from(_error: bitbox02::memory::Error) -> Self {
- Error::Memory
+impl core::convert::From<crate::hal::memory::Error> for Error {
+ fn from(error: crate::hal::memory::Error) -> Self {
+ match error {
+ crate::hal::memory::Error::InvalidInput => Error::InvalidInput,
+ crate::hal::memory::Error::DuplicateName => Error::Duplicate,
+ crate::hal::memory::Error::Unknown => Error::Memory,
+ crate::hal::memory::Error::Full => Error::Generic,
+ }
}
}
diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs
index 0dba157..75a00eb 100644
--- a/src/rust/bitbox02-rust/src/keystore.rs
+++ b/src/rust/bitbox02-rust/src/keystore.rs
@@ -7,7 +7,7 @@ use alloc::string::String;
use alloc::vec::Vec;
use crate::bip32;
-use crate::hal::{Memory, Random, SecureChip};
+use crate::hal::{Memory, Random, SecureChip, memory, securechip};
use util::bip32::HARDENED;
use util::cell::SyncCell;
@@ -41,14 +41,14 @@ pub enum Error {
Decrypt,
}
-impl core::convert::From<bitbox02::securechip::Error> for Error {
- fn from(error: bitbox02::securechip::Error) -> Self {
+impl core::convert::From<securechip::Error> for Error {
+ fn from(error: securechip::Error) -> Self {
match error {
- bitbox02::securechip::Error::SecureChip(
- bitbox02::securechip::SecureChipError::SC_ERR_INCORRECT_PASSWORD,
- ) => Error::IncorrectPassword,
- bitbox02::securechip::Error::SecureChip(sc_err) => Error::SecureChip(sc_err as i32),
- bitbox02::securechip::Error::Status(status) => Error::SecureChip(status),
+ securechip::Error::SecureChip(securechip::SecureChipError::IncorrectPassword) => {
+ Error::IncorrectPassword
+ }
+ securechip::Error::SecureChip(sc_err) => Error::SecureChip(sc_err as i32),
+ securechip::Error::Status(status) => Error::SecureChip(status),
}
}
}
@@ -157,7 +157,7 @@ fn verify_seed(
hal: &mut impl crate::hal::Hal,
encryption_key: &[u8],
expected_seed: &[u8],
- expected_password_stretch_also: bitbox02::memory::PasswordStretchAlgo,
+ expected_password_stretch_also: memory::PasswordStretchAlgo,
) -> bool {
if encryption_key.len() != 32 {
return false;
@@ -209,18 +209,14 @@ fn retain_bip39_seed(hal: &mut impl crate::hal::Hal, bip39_seed: &[u8]) -> Resul
/// Returns the stretching algo that will be used when setting new passwords.
pub fn default_password_stretch_algo(
hal: &mut impl crate::hal::Hal,
-) -> Result<bitbox02::memory::PasswordStretchAlgo, Error> {
+) -> Result<memory::PasswordStretchAlgo, Error> {
match hal
.memory()
.get_securechip_type()
.map_err(|_| Error::Memory)?
{
- bitbox02::memory::SecurechipType::Atecc => {
- Ok(bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0)
- }
- bitbox02::memory::SecurechipType::Optiga => {
- Ok(bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1)
- }
+ memory::SecurechipType::Atecc => Ok(memory::PasswordStretchAlgo::V0),
+ memory::SecurechipType::Optiga => Ok(memory::PasswordStretchAlgo::V1),
}
}
@@ -894,10 +890,7 @@ mod tests {
// Decrypt and check seed.
let (cipher, password_stretch_algo) = hal.memory.get_encrypted_seed_and_hmac().unwrap();
- assert_eq!(
- password_stretch_algo,
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1
- );
+ assert_eq!(password_stretch_algo, memory::PasswordStretchAlgo::V1);
// Same as Python:
// import hmac, hashlib; hmac.digest(b"unit-test", b"password", hashlib.sha256).hex()
// See also: mock_securechip.c
@@ -1375,7 +1368,7 @@ mod tests {
assert!(matches!(
mock_hal.memory.get_securechip_type().unwrap(),
- bitbox02::memory::SecurechipType::Optiga
+ memory::SecurechipType::Optiga
));
// Setup a seed encrypted with algo V0.
@@ -1383,10 +1376,7 @@ mod tests {
let encrypted = {
let secret = mock_hal
.securechip
- .stretch_password(
- password,
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0,
- )
+ .stretch_password(password, memory::PasswordStretchAlgo::V0)
.unwrap();
let iv: &[u8; 16] = &[0xaau8; 16];
@@ -1395,10 +1385,7 @@ mod tests {
mock_hal
.memory
- .set_encrypted_seed_and_hmac(
- &encrypted,
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V0,
- )
+ .set_encrypted_seed_and_hmac(&encrypted, memory::PasswordStretchAlgo::V0)
.unwrap();
}
@@ -1416,10 +1403,7 @@ mod tests {
assert_eq!(copy_seed(&mut mock_hal).unwrap().as_slice(), seed);
// Check the seed now uses the new algo.
let (_, stored_algo) = mock_hal.memory.get_encrypted_seed_and_hmac().unwrap();
- assert_eq!(
- stored_algo,
- bitbox02::memory::PasswordStretchAlgo::MEMORY_PASSWORD_STRETCH_ALGO_V1
- );
+ assert_eq!(stored_algo, memory::PasswordStretchAlgo::V1);
// Password check still works
assert_eq!(
diff --git a/src/rust/bitbox02-rust/src/reset.rs b/src/rust/bitbox02-rust/src/reset.rs
index 7337e61..04ad1cc 100644
--- a/src/rust/bitbox02-rust/src/reset.rs
+++ b/src/rust/bitbox02-rust/src/reset.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::general::abort;
-use crate::hal::{Memory, SecureChip, Ui};
+use crate::hal::{Memory, SecureChip, Ui, memory};
/// Resets the device:
/// - Updates secure chip KDF keys.
@@ -59,7 +59,7 @@ pub(crate) async fn reset(hal: &mut impl crate::hal::Hal, status: bool) {
// The ble chip needs to be restarted to load the new secrets.
if matches!(
hal.memory().get_platform(),
- Ok(bitbox02::memory::Platform::BitBox02Plus)
+ Ok(memory::Platform::BitBox02Plus)
) {
bitbox02::reset_ble();
}
diff --git a/src/rust/bitbox02-rust/src/workflow/password.rs b/src/rust/bitbox02-rust/src/workflow/password.rs
index 0b2a64b..ebf8a82 100644
--- a/src/rust/bitbox02-rust/src/workflow/password.rs
+++ b/src/rust/bitbox02-rust/src/workflow/password.rs
@@ -3,8 +3,7 @@
use super::{confirm, trinary_input_string};
use crate::hal::Ui;
-use crate::hal::Memory;
-use bitbox02::memory::SecurechipType;
+use crate::hal::{Memory, memory::SecurechipType};
pub use trinary_input_string::{CanCancel, Error};
diff --git a/src/rust/bitbox02/src/memory.rs b/src/rust/bitbox02/src/memory.rs
index ceee314..764503a 100644
--- a/src/rust/bitbox02/src/memory.rs
+++ b/src/rust/bitbox02/src/memory.rs
@@ -16,9 +16,6 @@ pub use bitbox02_sys::memory_optiga_config_version_t as OptigaConfigVersion;
pub use bitbox02_sys::memory_password_stretch_algo_t as PasswordStretchAlgo;
pub use bitbox02_sys::memory_result_t as MemoryError;
-#[derive(Debug)]
-pub struct Error;
-
pub fn get_device_name() -> String {
let mut name = [0u8; DEVICE_NAME_MAX_LEN + 1];
unsafe { bitbox02_sys::memory_get_device_name(name.as_mut_ptr().cast()) }
@@ -27,17 +24,17 @@ pub fn get_device_name() -> String {
.into()
}
-pub fn set_device_name(name: &str) -> Result<(), Error> {
+pub fn set_device_name(name: &str) -> Result<(), MemoryError> {
match unsafe {
bitbox02_sys::memory_set_device_name(
util::strings::str_to_cstr_vec(name)
- .or(Err(Error))?
+ .or(Err(MemoryError::MEMORY_ERR_UNKNOWN))?
.as_ptr()
.cast(),
)
} {
true => Ok(()),
- false => Err(Error),
+ false => Err(MemoryError::MEMORY_ERR_UNKNOWN),
}
}
diff --git a/src/rust/bitbox02/src/securechip.rs b/src/rust/bitbox02/src/securechip.rs
index f8d025d..a2cd1db 100644
--- a/src/rust/bitbox02/src/securechip.rs
+++ b/src/rust/bitbox02/src/securechip.rs
@@ -17,7 +17,7 @@ pub enum Error {
}
// Keep in sync with securechip.h's securechip_error_t.
-const SECURECHIP_ERRORS: [SecureChipError; 16] = [
+const SECURECHIP_ERRORS: [SecureChipError; 17] = [
// Errors common to any securechip implementation
SecureChipError::SC_ERR_IFS,
SecureChipError::SC_ERR_INVALID_ARGS,
@@ -25,6 +25,7 @@ const SECURECHIP_ERRORS: [SecureChipError; 16] = [
SecureChipError::SC_ERR_SALT,
SecureChipError::SC_ERR_INCORRECT_PASSWORD,
SecureChipError::SC_ERR_INVALID_PASSWORD_STRETCH_ALGO,
+ SecureChipError::SC_ERR_MEMORY,
// Errors specific to the ATECC
SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_CONFIG,
SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_DATA,
@@ -166,6 +167,36 @@ mod tests {
use hex_lit::hex;
+ #[test]
+ fn test_error_from_status() {
+ let cases = [
+ SecureChipError::SC_ERR_IFS,
+ SecureChipError::SC_ERR_INVALID_ARGS,
+ SecureChipError::SC_ERR_CONFIG_MISMATCH,
+ SecureChipError::SC_ERR_SALT,
+ SecureChipError::SC_ERR_INCORRECT_PASSWORD,
+ SecureChipError::SC_ERR_INVALID_PASSWORD_STRETCH_ALGO,
+ SecureChipError::SC_ERR_MEMORY,
+ SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_CONFIG,
+ SecureChipError::SC_ATECC_ERR_ZONE_UNLOCKED_DATA,
+ SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_IO,
+ SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_AUTH,
+ SecureChipError::SC_ATECC_ERR_SLOT_UNLOCKED_ENC,
+ SecureChipError::SC_ATECC_ERR_RESET_KEYS,
+ SecureChipError::SC_OPTIGA_ERR_CREATE,
+ SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_METADATA,
+ SecureChipError::SC_OPTIGA_ERR_PAL,
+ SecureChipError::SC_OPTIGA_ERR_UNEXPECTED_LEN,
+ ];
+
+ for error in cases {
+ assert_eq!(Error::from_status(error as i32), Error::SecureChip(error),);
+ }
+
+ assert_eq!(Error::from_status(7), Error::Status(7));
+ assert_eq!(Error::from_status(-9999), Error::Status(-9999));
+ }
+
#[test]
fn test_kdf() {
// Matches the deterministic HMAC result returned by test/hardware-fakes/src/fake_securechip.c.
Why this scored 19/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.