#![cfg_attr(not(test), no_std)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(clippy::all)]
#![deny(clippy::undocumented_unsafe_blocks)]
#![deny(clippy::pedantic)]
#![recursion_limit = "256"]
pub mod basic;
pub mod constant;
pub mod data;
#[macro_use]
pub mod r#macro;
pub mod frame;
#[repr(transparent)]
pub struct TpmWire([u8]);
impl TpmWire {
#[must_use]
pub fn cast(buf: &[u8]) -> &Self {
unsafe { Self::cast_unchecked(buf) }
}
#[must_use]
pub unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
let ptr = core::ptr::from_ref(buf) as *const Self;
unsafe { &*ptr }
}
#[must_use]
pub fn cast_mut(buf: &mut [u8]) -> &mut Self {
unsafe { Self::cast_mut_unchecked(buf) }
}
#[must_use]
pub unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
let ptr = core::ptr::from_mut(buf) as *mut Self;
unsafe { &mut *ptr }
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
#[must_use]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}
#[must_use]
pub const fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl AsRef<[u8]> for TpmWire {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsMut<[u8]> for TpmWire {
fn as_mut(&mut self) -> &mut [u8] {
self.as_bytes_mut()
}
}
#[repr(transparent)]
pub struct TpmWireBytes<const N: usize>([u8; N]);
impl<const N: usize> TpmWireBytes<N> {
pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
if buf.len() < N {
return Err(TpmProtocolError::UnexpectedEnd);
}
if buf.len() > N {
return Err(TpmProtocolError::TrailingData);
}
Ok(unsafe { Self::cast_unchecked(buf) })
}
#[must_use]
pub unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
let ptr = buf.as_ptr().cast::<Self>();
unsafe { &*ptr }
}
pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
if buf.len() < N {
return Err(TpmProtocolError::UnexpectedEnd);
}
if buf.len() > N {
return Err(TpmProtocolError::TrailingData);
}
Ok(unsafe { Self::cast_mut_unchecked(buf) })
}
#[must_use]
pub unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
let ptr = buf.as_mut_ptr().cast::<Self>();
unsafe { &mut *ptr }
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; N] {
&self.0
}
#[must_use]
pub fn as_bytes_mut(&mut self) -> &mut [u8; N] {
&mut self.0
}
#[must_use]
pub const fn len(&self) -> usize {
N
}
#[must_use]
pub const fn is_empty(&self) -> bool {
N == 0
}
}
impl<const N: usize> AsRef<[u8]> for TpmWireBytes<N> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N: usize> AsMut<[u8]> for TpmWireBytes<N> {
fn as_mut(&mut self) -> &mut [u8] {
self.as_bytes_mut()
}
}
pub trait TpmCast {
fn cast(buf: &[u8]) -> TpmResult<&Self>;
unsafe fn cast_unchecked(buf: &[u8]) -> &Self;
}
pub trait TpmCastMut: TpmCast {
fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self>;
unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self;
}
impl TpmCast for TpmWire {
fn cast(buf: &[u8]) -> TpmResult<&Self> {
Ok(Self::cast(buf))
}
unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
unsafe { Self::cast_unchecked(buf) }
}
}
impl TpmCastMut for TpmWire {
fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
Ok(Self::cast_mut(buf))
}
unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
unsafe { Self::cast_mut_unchecked(buf) }
}
}
impl<const N: usize> TpmCast for TpmWireBytes<N> {
fn cast(buf: &[u8]) -> TpmResult<&Self> {
Self::cast(buf)
}
unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
unsafe { Self::cast_unchecked(buf) }
}
}
impl<const N: usize> TpmCastMut for TpmWireBytes<N> {
fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
Self::cast_mut(buf)
}
unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
unsafe { Self::cast_mut_unchecked(buf) }
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TpmProtocolError {
BufferOverflow,
IntegerTooLarge,
InvalidBoolean,
InvalidCc,
InvalidMagicNumber,
InvalidTag,
TooManyBytes,
TooManyItems,
TrailingData,
UnexpectedEnd,
VariantNotAvailable,
}
impl core::fmt::Display for TpmProtocolError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::BufferOverflow => write!(f, "buffer overflow"),
Self::InvalidBoolean => write!(f, "invalid boolean value"),
Self::InvalidCc => write!(f, "invalid command code"),
Self::InvalidMagicNumber => write!(f, "invalid magic number"),
Self::InvalidTag => write!(f, "invalid tag"),
Self::IntegerTooLarge => write!(f, "integer overflow"),
Self::TooManyBytes => write!(f, "buffer capacity surpassed"),
Self::TooManyItems => write!(f, "list capaacity surpassed"),
Self::TrailingData => write!(f, "trailing data"),
Self::UnexpectedEnd => write!(f, "unexpected end"),
Self::VariantNotAvailable => write!(f, "enum variant is not available"),
}
}
}
impl core::error::Error for TpmProtocolError {}
pub type TpmResult<T> = Result<T, TpmProtocolError>;
pub struct TpmWriter<'a> {
buffer: &'a mut [u8],
cursor: usize,
}
impl<'a> TpmWriter<'a> {
#[must_use]
pub fn new(buffer: &'a mut [u8]) -> Self {
Self { buffer, cursor: 0 }
}
#[must_use]
pub fn len(&self) -> usize {
self.cursor
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.cursor == 0
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.buffer[..self.cursor]
}
pub fn write_bytes(&mut self, bytes: &[u8]) -> TpmResult<()> {
let end = self
.cursor
.checked_add(bytes.len())
.ok_or(TpmProtocolError::BufferOverflow)?;
if end > self.buffer.len() {
return Err(TpmProtocolError::BufferOverflow);
}
self.buffer[self.cursor..end].copy_from_slice(bytes);
self.cursor = end;
Ok(())
}
}
pub trait TpmSized {
const SIZE: usize;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub trait TpmMarshal {
fn marshal(&self, writer: &mut TpmWriter) -> TpmResult<()>;
}
pub(crate) trait TpmUnmarshal: Sized + TpmSized {
fn unmarshal(buf: &[u8]) -> TpmResult<(Self, &[u8])>;
}
pub(crate) trait TpmTagged {
type Tag: TpmUnmarshal + TpmMarshal + Copy;
type Value;
}
pub(crate) trait TpmUnmarshalTagged: Sized {
fn unmarshal_tagged(tag: <Self as TpmTagged>::Tag, buf: &[u8]) -> TpmResult<(Self, &[u8])>
where
Self: TpmTagged,
<Self as TpmTagged>::Tag: TpmUnmarshal + TpmMarshal;
}