//! Interface library for communicating with the hwbcc service. //! //! Where these interfaces require user-supplied buffers, it is //! important for the buffers supplied to be large enough to //! contain the entirety of the hwbcc service response. All services //! provided are subject to tipc failures; the corresponding error //! codes will be returned in these cases.
#![feature(allocator_api)]
#[cfg(test)] mod test; #[cfg(test)] mod test_serializer;
use core::ffi::CStr; use core::mem; use coset::iana; use num_derive::FromPrimitive; use sys::*; use tipc::Serializer; use tipc::{Deserialize, Handle, Serialize}; use trusty_std::alloc::{TryAllocFrom, Vec}; use trusty_sys::{c_long, Error}; use zerocopy::IntoBytes;
// Constant defined in trusty/user/base/interface/hwbcc/include/interface/hwbcc pubconst HWBCC_MAX_RESP_PAYLOAD_LENGTH: usize = HWBCC_MAX_RESP_PAYLOAD_SIZE as usize;
/// The request message for the hwbcc service. /// Note that the Serialize trait implementation ensures compatibility with /// C clients and servers. We do not depend on the representation of this /// struct for that compatibility. #[derive(Debug, PartialEq)] struct BccMsg<'a> {
header: BccMsgHeader,
sign_req: Option<SignDataMsg<'a>>,
}
impl<'s> Serialize<'s> for SignDataMsg<'s> { fn serialize<'a: 's, S: Serializer<'s>>(
&'a self,
serializer: &mut S,
) -> Result<S::Ok, S::Error> { // SAFETY: // All serialized attributes are trivial types with // corresponding C representations unsafe {
serializer.serialize_as_bytes(&self.algorithm)?;
serializer.serialize_as_bytes(&self.data_size)?;
serializer.serialize_as_bytes(&self.aad_size)?;
}
serializer.serialize_bytes(self.data)?;
serializer.serialize_bytes(self.aad)
}
}
/// Response type for all hwbcc services. #[derive(Debug, PartialEq)] struct HwBccResponse { /// Status of command result.
status: i32, /// Sent command, acknowledged by service if successful.
cmd: u32, /// The payload size in bytes. We store this separately because /// to serialize a response we need a size guaranteed to live as /// long as the input serializer and calling payload.len() won't /// satisfy that constraint. There are no current use cases where /// payload is mutable. If they arise, this field needs to be kept /// in sync with the length of the payload.
payload_size: u32, /// Response data.
payload: Vec<u8>,
}
Ok(HwBccResponse {
status: status as i32,
cmd: hwbcc_cmd_HWBCC_CMD_RESP_BIT | cmd as u32,
payload_size: payload.len().try_into()?,
payload: payload,
})
}
fn new_without_payload(status: Error, cmd: BccCmd) -> HwBccResponse {
HwBccResponse {
status: status as i32,
cmd: hwbcc_cmd_HWBCC_CMD_RESP_BIT | cmd as u32,
payload_size: 0,
payload: Vec::new(),
}
}
}
impl<'s> Serialize<'s> for HwBccResponse { /// We serialize for compatibility /// with hwbcc_resp_hdr as defined in hwbcc.h fn serialize<'a: 's, S: Serializer<'s>>(
&'a self,
serializer: &mut S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_bytes(self.cmd.as_bytes())?;
serializer.serialize_bytes(self.status.as_bytes())?;
serializer.serialize_bytes(self.payload_size.as_bytes())?;
serializer.serialize_bytes(&self.payload)
}
}
impl Deserialize for HwBccResponse { type Error = HwBccError; const MAX_SERIALIZED_SIZE: usize = HWBCC_MAX_RESP_PAYLOAD_LENGTH;
fn deserialize(bytes: &[u8], handles: &mut [Option<Handle>]) -> Result<Self, Self::Error> { if handles.len() != 0 { for handle in handles {
log::error!("unexpected handle: {:?}", handle);
} return Err(HwBccError::InvalidCmdResponse);
}
let header_size = mem::size_of::<hwbcc_resp_hdr>(); if bytes.len() < header_size {
log::error!("response too small"); return Err(HwBccError::BadLen);
} // SAFETY: We have validated that the buffer contains enough data to // represent a hwbcc_resp_hdr. The constructed lifetime here does not // outlive the function and thus cannot outlive the lifetime of the // buffer. let (header, payload) = bytes.split_at(header_size); let (prefix, header_body, _) = unsafe { header.align_to::<hwbcc_resp_hdr>() }; if !prefix.is_empty() {
log::error!("buffer too short or misaligned"); return Err(HwBccError::BadLen);
} let msg: &hwbcc_resp_hdr = &header_body[0]; let response_payload = Vec::try_alloc_from(payload)?;
if msg.payload_size as usize != response_payload.len() {
log::error!("response payload size is not as advertised"); return Err(HwBccError::BadLen);
}
/// Specifies test or release request types. /// /// `Test` mode derives key seed bytes with a secure RNG, /// and should differ with each invocation, intra-test. /// `Release` mode relies on the hwkey service to derive /// its key seed. #[derive(Copy, Clone, Debug, PartialEq, FromPrimitive)] #[repr(u32)] pubenum HwBccMode {
Release = 0,
Test = 1,
}
if response.status != 0 {
log::error!("Status is not SUCCESS. Actual: {:?}", response.status); return Err(HwBccError::System(Error::from(response.status as c_long)));
}
Ok(response)
}
fn read_payload(resp: HwBccResponse, buf: &mut [u8]) -> Result<&[u8], HwBccError> { let payload_size = resp.payload.len(); if payload_size > buf.len() {
log::error!("response payload is too large to fit into buffer"); return Err(HwBccError::BadLen);
}
/// DICE artifacts for a child node in the DICE chain/tree. pubstruct DiceArtifacts<'a> { pub artifacts: &'a [u8],
}
/// Retrieves DICE artifacts for a child node in the DICE chain/tree. /// /// The user supplies device-specific `context` as well as an /// `artifacts` buffer, in which the service will write a portion /// of its response payload. /// /// # Returns /// /// A [`DiceArtifacts`] result containing truncated prefixes of the populated /// `artifacts` buffer. A [`HwBccError`] will be /// returned if the user supplies an empty `artifacts` buffer. /// /// # Examples /// /// ``` /// let dice_artifacts_buf = &mut [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; /// let DiceArtifacts { artifacts } = /// get_dice_artifacts(0, dice_artifacts_buf).expect("could not get protected data"); /// ``` /// pubfn get_dice_artifacts<'a>(
context: u64,
artifacts: &'a mut [u8],
) -> Result<DiceArtifacts<'a>, HwBccError> { if artifacts.is_empty() {
log::error!("DICE artifacts buffer must not be empty"); return Err(HwBccError::BadLen);
}
let port = CStr::from_bytes_with_nul(HWBCC_PORT).expect("HWBCC_PORT was not null terminated"); let session = Handle::connect(port)?;
let cmd = BccCmd::GetDiceArtifacts;
session.send(&BccMsg::new(cmd, HwBccMode::Release, context))?;
let res_buf = &mut [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; let response = recv_resp(&session, cmd, res_buf)?; let artifacts = read_payload(response, artifacts)?;
Ok(DiceArtifacts { artifacts })
}
/// Deprivileges hwbcc from serving calls to non-secure clients. /// /// # Returns /// /// Err(HwBccError) on failure. /// /// # Examples /// /// ``` /// ns_deprivilege().expect("could not execute ns deprivilege"); /// /// // assuming non-secure client /// let dice_artifacts_buf = &mut [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; /// let err = /// get_dice_artifacts(0, dice_artifacts_buf).expect_err("non-secure client has access to hwbcc services"); /// ``` /// pubfn ns_deprivilege() -> Result<(), HwBccError> { let port = CStr::from_bytes_with_nul(HWBCC_PORT).expect("HWBCC_PORT was not null terminated"); let session = Handle::connect(port)?;
let cmd = BccCmd::NsDeprivilege;
session.send(&BccMsg::new(cmd, HwBccMode::Release, 0))?;
let res_buf = &mut [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH];
recv_resp(&session, cmd, res_buf)?;
Ok(())
}
/// Retrieves Boot certificate chain (BCC). /// Clients may request test values using `test_mode`. /// /// # Examples /// /// ``` /// let mut cose_sign1_buf = [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; /// /// let bcc = get_bcc ( /// HwBccMode::Test, /// &mut bcc_buf, /// ) /// .expect("could not get bcc"); /// ``` pubfn get_bcc<'a>(test_mode: HwBccMode, bcc: &'a mut [u8]) -> Result<&'a [u8], HwBccError> { if bcc.is_empty() {
log::error!("bcc buffer must not be empty"); return Err(HwBccError::BadLen);
}
let port = CStr::from_bytes_with_nul(HWBCC_PORT).expect("HWBCC_PORT was not null terminated"); let session = Handle::connect(port)?;
let cmd = BccCmd::GetBcc;
session.send(&BccMsg::new(cmd, test_mode, 0))?;
let res_buf = &mut [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; let response = recv_resp(&session, cmd, res_buf)?; let bcc = read_payload(response, bcc)?;
Ok(bcc)
}
/// Retrieves the signed data in a COSE-Sign1 message. Data signed using the CDI leaf private key. /// Clients may request to sign using a test key via test_mode. /// /// # Examples /// /// ``` /// let mut cose_sign1_buf = [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; /// /// let cose_sign1 = sign_data( /// HwBccMode::Test, /// SigningAlgorithm::ED25519, /// TEST_MAC_KEY, /// TEST_AAD, /// &mut cose_sign1_buf, /// ) /// .expect("could not get signed data"); /// ``` pubfn sign_data<'a>(
test_mode: HwBccMode,
cose_algorithm: SigningAlgorithm,
data: &[u8],
aad: &[u8],
cose_sign1: &'a mut [u8],
) -> Result<&'a [u8], HwBccError> { if cose_sign1.is_empty() {
log::error!("cose_sign1 buffer must not be empty"); return Err(HwBccError::BadLen);
}
if aad.len() > HWBCC_MAX_AAD_SIZE as usize {
log::error!("AAD exceeds HWCC_MAX_AAD_SIZE limit"); return Err(HwBccError::BadLen);
}
let port = CStr::from_bytes_with_nul(HWBCC_PORT).expect("HWBCC_PORT was not null terminated"); let session = Handle::connect(port)?;
let res_buf = &mut [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH]; let response = recv_resp(&session, cmd, res_buf)?; let cose_sign1 = read_payload(response, cose_sign1)?;
Ok(cose_sign1)
}
#[cfg(test)] mod tests { usecrate::test_serializer::TestSerializer; usecrate::{BccCmd, HwBccResponse}; use test::expect_eq; use tipc::{Deserialize, Serialize};
#[test] fn test_hwbcc_resp_serde() { let test_payload = "i am an expected response payload".as_bytes();
letmut serializer = TestSerializer::default(); let hwbcc_resp =
HwBccResponse::try_new_with_payload(0.into(), BccCmd::GetBcc, test_payload.to_vec())
.expect("Failed to create HwBccResponse for test"); let _ =
hwbcc_resp.serialize(&mut serializer).expect("serialization of HwBccResponse failed");
let deserialized =
HwBccResponse::deserialize(&mut serializer.buffers, &le='color:red'>mut serializer.handles)
.expect("deserialization failed");
expect_eq!(deserialized, hwbcc_resp);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.