add attestation_sign to securechip HAL
What changed, and why it matters
This commit is a straightforward internal refactoring: it moves the device attestation signing function behind a hardware-abstraction-layer (HAL) interface so the code can be more easily tested. The actual cryptographic operation and the data it uses remain unchanged. There is no indication this fixes or introduces a security vulnerability.
No security action required; treat as normal code maintenance. Continue standard review and testing of the attestation flow.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change adds attestation_sign to the SecureChip trait in the Rust HAL, implements it for the real BitBox02 secure chip by delegating to the existing bitbox02::securechip::attestation_sign, and updates attestation::perform and the api_attestation handler to receive a &mut impl Hal and call the method through the trait. A test stub is also added. The diff is purely architectural/testability refactoring with no functional change to the attestation protocol or key handling.
Changed components
src/rust/bitbox02-rust/src/attestation.rssrc/rust/bitbox02-rust/src/hal.rssrc/rust/bitbox02-rust/src/hww.rsInspect captured patch +29 / −5
diff --git a/src/rust/bitbox02-rust/src/attestation.rs b/src/rust/bitbox02-rust/src/attestation.rs
index abeb39e..b57d686 100644
--- a/src/rust/bitbox02-rust/src/attestation.rs
+++ b/src/rust/bitbox02-rust/src/attestation.rs
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+use crate::hal::SecureChip;
use sha2::{Digest, Sha256};
pub struct Data {
@@ -22,7 +23,7 @@ pub struct Data {
pub challenge_signature: [u8; 64],
}
-pub fn perform(host_challenge: [u8; 32]) -> Result<Data, ()> {
+pub fn perform(hal: &mut impl crate::hal::Hal, host_challenge: [u8; 32]) -> Result<Data, ()> {
let mut result = Data {
bootloader_hash: [0; 32],
device_pubkey: [0; 64],
@@ -37,6 +38,7 @@ pub fn perform(host_challenge: [u8; 32]) -> Result<Data, ()> {
)?;
let hash: [u8; 32] = Sha256::digest(host_challenge).into();
result.bootloader_hash = bitbox02::memory::get_attestation_bootloader_hash();
- bitbox02::securechip::attestation_sign(&hash, &mut result.challenge_signature)?;
+ hal.securechip()
+ .attestation_sign(&hash, &mut result.challenge_signature)?;
Ok(result)
}
diff --git a/src/rust/bitbox02-rust/src/hal.rs b/src/rust/bitbox02-rust/src/hal.rs
index 52361d5..b7b6ce4 100644
--- a/src/rust/bitbox02-rust/src/hal.rs
+++ b/src/rust/bitbox02-rust/src/hal.rs
@@ -48,6 +48,11 @@ pub trait SecureChip {
&mut self,
msg: &[u8],
) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error>;
+ fn attestation_sign(
+ &mut self,
+ challenge: &[u8; 32],
+ signature: &mut [u8; 64],
+ ) -> Result<(), ()>;
}
/// Hardware abstraction layer for BitBox devices.
@@ -130,6 +135,14 @@ impl SecureChip for BitBox02SecureChip {
) -> Result<zeroize::Zeroizing<Vec<u8>>, bitbox02::securechip::Error> {
bitbox02::securechip::kdf(msg)
}
+
+ fn attestation_sign(
+ &mut self,
+ challenge: &[u8; 32],
+ signature: &mut [u8; 64],
+ ) -> Result<(), ()> {
+ bitbox02::securechip::attestation_sign(challenge, signature)
+ }
}
pub struct BitBox02Hal {
@@ -331,6 +344,15 @@ pub mod testing {
hmac_result.to_byte_array().to_vec(),
))
}
+
+ fn attestation_sign(
+ &mut self,
+ _challenge: &[u8; 32],
+ _signature: &mut [u8; 64],
+ ) -> Result<(), ()> {
+ self.event_counter += 1;
+ todo!()
+ }
}
pub struct TestingHal<'a> {
diff --git a/src/rust/bitbox02-rust/src/hww.rs b/src/rust/bitbox02-rust/src/hww.rs
index ea1497e..e02e42f 100644
--- a/src/rust/bitbox02-rust/src/hww.rs
+++ b/src/rust/bitbox02-rust/src/hww.rs
@@ -86,7 +86,7 @@ async fn api_unlock(hal: &mut impl crate::hal::Hal) -> Vec<u8> {
///
/// On success, returns < 0 | bootloader_hash 32 | device_pubkey 64 |
/// certificate 64 | root_pubkey_identifier 32 | challenge_signature 64>
-fn api_attestation(usb_in: &[u8]) -> Vec<u8> {
+fn api_attestation(hal: &mut impl crate::hal::Hal, usb_in: &[u8]) -> Vec<u8> {
use core::convert::TryInto;
let usb_in: [u8; 32] = match usb_in.try_into() {
@@ -94,7 +94,7 @@ fn api_attestation(usb_in: &[u8]) -> Vec<u8> {
Err(_) => return [OP_STATUS_FAILURE].to_vec(),
};
- let result = match crate::attestation::perform(usb_in) {
+ let result = match crate::attestation::perform(hal, usb_in) {
Ok(result) => result,
Err(()) => return [OP_STATUS_FAILURE].to_vec(),
};
@@ -119,7 +119,7 @@ async fn _process_packet(hal: &mut impl crate::hal::Hal, usb_in: Vec<u8>) -> Vec
match usb_in.split_first() {
Some((&OP_UNLOCK, b"")) => return api_unlock(hal).await,
- Some((&OP_ATTESTATION, rest)) => return api_attestation(rest),
+ Some((&OP_ATTESTATION, rest)) => return api_attestation(hal, rest),
_ => (),
}
Why this scored 15/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.