blob: b6f397e3601b932e7699b11e7e3c793e1a74358e [file] [log] [blame]
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2025 Opinsys Oy
// Copyright (c) 2024-2025 Jarkko Sakkinen
use crate::{
constant::TPM_HEADER_SIZE,
data::{TpmRc, TpmRcBase, TpmSt, TpmsAuthCommand, TpmsAuthResponse},
message::{TpmBodyBuild, TpmHeader},
TpmBuild, TpmError, TpmResult, TpmSized,
};
use core::{convert::TryFrom, mem::size_of};
/// Builds a TPM command into a writer and returns the total bytes written.
///
/// # Errors
///
/// Returns `Err(TpmError)` on a build failure.
pub fn tpm_build_command<C>(
command: &C,
tag: TpmSt,
sessions: &[TpmsAuthCommand],
writer: &mut crate::TpmWriter,
) -> TpmResult<()>
where
C: TpmHeader + TpmBodyBuild,
{
if tag != TpmSt::NoSessions && tag != TpmSt::Sessions {
return Err(TpmError::Malformed);
}
let handle_area_size = C::HANDLES * size_of::<u32>();
let param_area_size = command.len() - handle_area_size;
let auth_area_size = if tag == TpmSt::Sessions {
let sessions_len: usize = sessions.iter().map(TpmSized::len).sum();
size_of::<u32>() + sessions_len
} else {
0
};
let total_body_len = handle_area_size + auth_area_size + param_area_size;
let command_size =
u32::try_from(TPM_HEADER_SIZE + total_body_len).map_err(|_| TpmError::CapacityExceeded)?;
(tag as u16).build(writer)?;
command_size.build(writer)?;
(C::CC as u32).build(writer)?;
command.build_handles(writer)?;
if tag == TpmSt::Sessions {
let sessions_len = u32::try_from(auth_area_size - size_of::<u32>())
.map_err(|_| TpmError::CapacityExceeded)?;
sessions_len.build(writer)?;
for s in sessions {
s.build(writer)?;
}
}
command.build_parameters(writer)
}
/// Builds a TPM response.
///
/// # Errors
///
/// Returns `Err(TpmError)` on a build failure.
pub fn tpm_build_response<R>(
response: &R,
sessions: &[TpmsAuthResponse],
rc: TpmRc,
writer: &mut crate::TpmWriter,
) -> TpmResult<()>
where
R: TpmHeader + TpmBodyBuild,
{
if !matches!(rc, TpmRc::Fmt0(TpmRcBase::Success)) {
(TpmSt::NoSessions as u16).build(writer)?;
u32::try_from(TPM_HEADER_SIZE)?.build(writer)?;
rc.value().build(writer)?;
return Ok(());
}
let tag = if sessions.is_empty() {
TpmSt::NoSessions
} else {
TpmSt::Sessions
};
let handle_area_size = R::HANDLES * size_of::<u32>();
let param_area_size = response.len() - handle_area_size;
let sessions_len: usize = sessions.iter().map(TpmSized::len).sum();
let parameter_area_size_field_len = if tag == TpmSt::Sessions {
size_of::<u32>()
} else {
0
};
let total_body_len =
handle_area_size + parameter_area_size_field_len + param_area_size + sessions_len;
let response_size =
u32::try_from(TPM_HEADER_SIZE + total_body_len).map_err(|_| TpmError::CapacityExceeded)?;
(tag as u16).build(writer)?;
response_size.build(writer)?;
rc.value().build(writer)?;
response.build_handles(writer)?;
if tag == TpmSt::Sessions {
let params_len = u32::try_from(param_area_size).map_err(|_| TpmError::CapacityExceeded)?;
params_len.build(writer)?;
}
response.build_parameters(writer)?;
if tag == TpmSt::Sessions {
for s in sessions {
s.build(writer)?;
}
}
Ok(())
}