1#![cfg_attr(not(test), no_std)]
25#![deny(unsafe_code)]
26#![deny(clippy::all)]
27#![deny(clippy::pedantic)]
28
29#[macro_use]
30pub mod r#macro;
31pub mod data;
32pub mod message;
33
34use crate::data::TpmAlgId;
35use core::{convert::TryFrom, fmt, mem::size_of, ops::Deref, result::Result};
36
37tpm_handle!(
38 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
39 TpmTransient
40);
41tpm_handle!(
42 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
43 TpmSession
44);
45tpm_handle!(
46 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
47 TpmPersistent
48);
49
50pub const TPM_MAX_COMMAND_SIZE: usize = 4096;
52
53#[derive(Debug, PartialEq, Eq)]
54pub enum TpmErrorKind {
55 Boundary,
57 TrailingData,
59 InvalidDiscriminant { type_name: &'static str, value: u64 },
61 InvalidMagic { expected: u32, got: u32 },
63 InvalidTag {
65 type_name: &'static str,
66 expected: u16,
67 got: u16,
68 },
69 InvalidValue,
71 ValueTooLarge,
73 AuthMissing,
75 InternalError,
77}
78
79impl fmt::Display for TpmErrorKind {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 match self {
82 Self::Boundary => write!(f, "Insufficient data in buffer"),
83 Self::TrailingData => write!(f, "Buffer has unexpected trailing data after parsing"),
84 Self::InvalidDiscriminant { type_name, value } => {
85 write!(f, "Invalid discriminant 0x{value:x} for type '{type_name}'")
86 }
87 Self::InvalidMagic { expected, got } => {
88 write!(
89 f,
90 "Invalid magic number: expected 0x{expected:x}, got 0x{got:x}"
91 )
92 }
93 Self::InvalidTag {
94 type_name,
95 expected,
96 got,
97 } => {
98 write!(
99 f,
100 "Invalid tag for {type_name}: expected 0x{expected:x}, got 0x{got:x}"
101 )
102 }
103 Self::InvalidValue => write!(f, "A value is invalid or out of the expected range"),
104 Self::ValueTooLarge => {
105 write!(
106 f,
107 "A size or count is larger than the maximum allowed value"
108 )
109 }
110 Self::AuthMissing => write!(f, "Command requires authorization but none was provided"),
111 Self::InternalError => write!(f, "An unexpected internal error occurred"),
112 }
113 }
114}
115
116impl From<core::num::TryFromIntError> for TpmErrorKind {
117 fn from(_: core::num::TryFromIntError) -> Self {
118 Self::InternalError
119 }
120}
121
122pub type TpmResult<T> = Result<T, TpmErrorKind>;
123
124pub struct TpmWriter<'a> {
126 buffer: &'a mut [u8],
127 cursor: usize,
128}
129
130impl<'a> TpmWriter<'a> {
131 #[must_use]
133 pub fn new(buffer: &'a mut [u8]) -> Self {
134 Self { buffer, cursor: 0 }
135 }
136
137 #[must_use]
139 pub fn len(&self) -> usize {
140 self.cursor
141 }
142
143 #[must_use]
145 pub fn is_empty(&self) -> bool {
146 self.cursor == 0
147 }
148
149 pub fn write_bytes(&mut self, bytes: &[u8]) -> TpmResult<()> {
156 let end = self.cursor + bytes.len();
157 if end > self.buffer.len() {
158 return Err(TpmErrorKind::Boundary);
159 }
160 self.buffer[self.cursor..end].copy_from_slice(bytes);
161 self.cursor = end;
162 Ok(())
163 }
164}
165
166pub trait TpmSized {
169 const SIZE: usize;
172
173 fn len(&self) -> usize;
175
176 fn is_empty(&self) -> bool {
178 self.len() == 0
179 }
180}
181
182pub trait TpmBuild {
183 fn build(&self, writer: &mut TpmWriter) -> TpmResult<()>;
190}
191
192pub trait TpmParse<'a>: Sized {
193 fn parse(buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])>;
202}
203
204pub trait TpmTagged {
206 type Tag: TpmBuild + TpmParse<'static> + Copy;
208 type Value;
210}
211
212pub trait TpmParseTagged<'a>: Sized {
214 fn parse_tagged(tag: <Self as TpmTagged>::Tag, buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])>
222 where
223 Self: TpmTagged,
224 <Self as TpmTagged>::Tag: TpmParse<'a>;
225}
226
227impl TpmSized for u8 {
228 const SIZE: usize = 1;
229 fn len(&self) -> usize {
230 1
231 }
232}
233
234impl TpmBuild for u8 {
235 fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
236 writer.write_bytes(&[*self])
237 }
238}
239
240impl<'a> TpmParse<'a> for u8 {
241 fn parse(buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])> {
242 let (val, buf) = buf.split_first().ok_or(TpmErrorKind::Boundary)?;
243 Ok((*val, buf))
244 }
245}
246
247macro_rules! tpm_integer {
248 ($ty:ty) => {
249 impl<'a> TpmParse<'a> for $ty {
250 fn parse(buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])> {
251 let size = size_of::<$ty>();
252 if buf.len() < size {
253 return Err(TpmErrorKind::Boundary);
254 }
255 let (bytes, buf) = buf.split_at(size);
256 let array = bytes.try_into().map_err(|_| TpmErrorKind::InternalError)?;
257 let val = <$ty>::from_be_bytes(array);
258 Ok((val, buf))
259 }
260 }
261
262 impl TpmBuild for $ty {
263 fn build(&self, writer: &mut TpmWriter) -> TpmResult<()> {
264 writer.write_bytes(&self.to_be_bytes())
265 }
266 }
267
268 impl TpmSized for $ty {
269 const SIZE: usize = size_of::<$ty>();
270 fn len(&self) -> usize {
271 Self::SIZE
272 }
273 }
274 };
275}
276
277tpm_integer!(i32);
278tpm_integer!(u16);
279tpm_integer!(u32);
280tpm_integer!(u64);
281
282pub fn build_tpm2b(writer: &mut TpmWriter, data: &[u8]) -> TpmResult<()> {
288 u16::try_from(data.len())
289 .map_err(|_| TpmErrorKind::ValueTooLarge)?
290 .build(writer)?;
291 writer.write_bytes(data)
292}
293
294pub fn parse_tpm2b(buf: &[u8]) -> TpmResult<(&[u8], &[u8])> {
301 let (size, buf) = u16::parse(buf)?;
302 let size = size as usize;
303
304 if size > TPM_MAX_COMMAND_SIZE {
305 return Err(TpmErrorKind::ValueTooLarge);
306 }
307
308 if buf.len() < size {
309 return Err(TpmErrorKind::Boundary);
310 }
311 Ok(buf.split_at(size))
312}
313
314#[must_use]
316pub const fn tpm_hash_size(alg_id: &TpmAlgId) -> Option<usize> {
317 match alg_id {
318 TpmAlgId::Sha1 => Some(20),
319 TpmAlgId::Sha256 | TpmAlgId::Sm3_256 => Some(32),
320 TpmAlgId::Sha384 => Some(48),
321 TpmAlgId::Sha512 => Some(64),
322 _ => None,
323 }
324}
325
326#[derive(Clone, Copy, PartialEq, Eq)]
327pub struct TpmBuffer<const CAPACITY: usize> {
328 bytes: [u8; CAPACITY],
329 len: u16,
330}
331
332impl<const CAPACITY: usize> TpmBuffer<CAPACITY> {
333 #[must_use]
334 pub const fn new() -> Self {
335 Self {
336 bytes: [0; CAPACITY],
337 len: 0,
338 }
339 }
340
341 #[must_use]
343 pub fn is_empty(&self) -> bool {
344 self.len == 0
345 }
346}
347
348impl<const CAPACITY: usize> Deref for TpmBuffer<CAPACITY> {
349 type Target = [u8];
350
351 fn deref(&self) -> &Self::Target {
352 &self.bytes[..self.len as usize]
353 }
354}
355
356impl<const CAPACITY: usize> Default for TpmBuffer<CAPACITY> {
357 fn default() -> Self {
358 Self::new()
359 }
360}
361
362impl<const CAPACITY: usize> TpmSized for TpmBuffer<CAPACITY> {
363 const SIZE: usize = size_of::<u16>() + CAPACITY;
364 fn len(&self) -> usize {
365 size_of::<u16>() + self.len as usize
366 }
367}
368
369impl<const CAPACITY: usize> TpmBuild for TpmBuffer<CAPACITY> {
370 fn build(&self, writer: &mut crate::TpmWriter) -> TpmResult<()> {
371 build_tpm2b(writer, self)
372 }
373}
374
375impl<'a, const CAPACITY: usize> TpmParse<'a> for TpmBuffer<CAPACITY> {
376 fn parse(buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])> {
377 let (bytes, remainder) = parse_tpm2b(buf)?;
378 if bytes.len() > CAPACITY {
379 return Err(TpmErrorKind::ValueTooLarge);
380 }
381 let mut buffer = Self::new();
382 buffer.bytes[..bytes.len()].copy_from_slice(bytes);
383 buffer.len = u16::try_from(bytes.len()).map_err(|_| TpmErrorKind::InternalError)?;
384 Ok((buffer, remainder))
385 }
386}
387
388impl<const CAPACITY: usize> TryFrom<&[u8]> for TpmBuffer<CAPACITY> {
389 type Error = TpmErrorKind;
390
391 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
392 if slice.len() > CAPACITY {
393 return Err(TpmErrorKind::ValueTooLarge);
394 }
395 let mut buffer = Self::new();
396 buffer.bytes[..slice.len()].copy_from_slice(slice);
397 buffer.len = u16::try_from(slice.len()).map_err(|_| TpmErrorKind::InternalError)?;
398 Ok(buffer)
399 }
400}
401
402impl<const CAPACITY: usize> AsRef<[u8]> for TpmBuffer<CAPACITY> {
403 fn as_ref(&self) -> &[u8] {
404 &self.bytes[..self.len as usize]
405 }
406}
407
408impl<const CAPACITY: usize> core::fmt::Debug for TpmBuffer<CAPACITY> {
409 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
410 write!(f, "TpmBuffer(")?;
411 for byte in &**self {
412 write!(f, "{byte:02x}")?;
413 }
414 write!(f, ")")
415 }
416}
417
418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
419pub struct TpmList<T: Copy + Default, const CAPACITY: usize> {
420 items: [T; CAPACITY],
421 len: u32,
422}
423
424impl<T: Copy + Default, const CAPACITY: usize> TpmList<T, CAPACITY> {
425 #[must_use]
426 pub fn new() -> Self {
427 Self {
428 items: [T::default(); CAPACITY],
429 len: 0,
430 }
431 }
432
433 #[must_use]
435 pub fn is_empty(&self) -> bool {
436 self.len == 0
437 }
438
439 pub fn try_push(&mut self, item: T) -> Result<(), TpmErrorKind> {
446 if self.len as usize >= CAPACITY {
447 return Err(TpmErrorKind::ValueTooLarge);
448 }
449 let index = self.len as usize;
450 self.items[index] = item;
451 self.len += 1;
452 Ok(())
453 }
454}
455
456impl<T: Copy + Default, const CAPACITY: usize> Deref for TpmList<T, CAPACITY> {
457 type Target = [T];
458
459 fn deref(&self) -> &Self::Target {
460 &self.items[..self.len as usize]
461 }
462}
463
464impl<T: Copy + Default, const CAPACITY: usize> Default for TpmList<T, CAPACITY> {
465 fn default() -> Self {
466 Self::new()
467 }
468}
469
470impl<T: TpmSized + Copy + Default, const CAPACITY: usize> TpmSized for TpmList<T, CAPACITY> {
471 const SIZE: usize = size_of::<u32>() + (T::SIZE * CAPACITY);
472 fn len(&self) -> usize {
473 size_of::<u32>() + self.iter().map(TpmSized::len).sum::<usize>()
474 }
475}
476
477impl<T: TpmBuild + Copy + Default, const CAPACITY: usize> TpmBuild for TpmList<T, CAPACITY> {
478 fn build(&self, writer: &mut crate::TpmWriter) -> TpmResult<()> {
479 self.len.build(writer)?;
480 for item in &**self {
481 item.build(writer)?;
482 }
483 Ok(())
484 }
485}
486
487impl<'a, T: TpmParse<'a> + Copy + Default, const CAPACITY: usize> TpmParse<'a>
488 for TpmList<T, CAPACITY>
489{
490 fn parse(buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])> {
491 let (count, mut buf) = u32::parse(buf)?;
492 if count as usize > CAPACITY {
493 return Err(TpmErrorKind::ValueTooLarge);
494 }
495
496 let mut list = Self::new();
497 for i in 0..(count as usize) {
498 let (item, rest) = T::parse(buf)?;
499 list.items[i] = item;
500 list.len += 1;
501 buf = rest;
502 }
503
504 Ok((list, buf))
505 }
506}
507
508pub struct TpmParameters<'a> {
511 buf: &'a [u8],
512}
513
514impl<'a> TpmParameters<'a> {
515 pub fn new(buf: &'a [u8]) -> TpmResult<(Self, &'a [u8])> {
526 let (size, buf) = u32::parse(buf)?;
527 let size = size as usize;
528
529 if size > crate::TPM_MAX_COMMAND_SIZE {
530 return Err(TpmErrorKind::ValueTooLarge);
531 }
532
533 if buf.len() < size {
534 return Err(TpmErrorKind::Boundary);
535 }
536 let (param_data, buf) = buf.split_at(size);
537 Ok((Self { buf: param_data }, buf))
538 }
539
540 pub fn parse<T: TpmParse<'a>>(&mut self) -> TpmResult<T> {
546 let (value, rest) = T::parse(self.buf)?;
547 self.buf = rest;
548 Ok(value)
549 }
550
551 #[must_use]
553 pub fn is_empty(&self) -> bool {
554 self.buf.is_empty()
555 }
556}
557
558#[cfg(test)]
559mod test;