1use super::{TPM_DISPATCH_TABLE, TPM_HEADER_SIZE};
6use crate::{
7 TpmCast, TpmCastMut, TpmError, TpmResult,
8 constant::MAX_SESSIONS,
9 data::{TpmCc, TpmRc, TpmRcBase, TpmSt},
10};
11use core::{mem::size_of, ops::Range};
12
13const HEADER_SIZE: usize = TPM_HEADER_SIZE as usize;
14const TAG_OFFSET: usize = 0;
15const SIZE_OFFSET: usize = 2;
16const CODE_OFFSET: usize = 6;
17
18#[repr(transparent)]
20pub struct TpmCommand([u8]);
21
22impl TpmCommand {
23 pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
29 Self::validate_envelope(buf)?;
30
31 Ok(unsafe { Self::cast_unchecked(buf) })
34 }
35
36 #[must_use]
43 pub unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
44 let ptr = core::ptr::from_ref(buf) as *const Self;
45
46 unsafe { &*ptr }
49 }
50
51 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
57 Self::validate_envelope(buf)?;
58
59 Ok(unsafe { Self::cast_mut_unchecked(buf) })
63 }
64
65 #[must_use]
73 pub unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
74 let ptr = core::ptr::from_mut(buf) as *mut Self;
75
76 unsafe { &mut *ptr }
79 }
80
81 #[must_use]
83 pub const fn as_bytes(&self) -> &[u8] {
84 &self.0
85 }
86
87 #[must_use]
89 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
90 &mut self.0
91 }
92
93 pub fn tag(&self) -> TpmResult<TpmSt> {
100 let raw = read_u16(&self.0, TAG_OFFSET);
101
102 TpmSt::try_from(raw).map_err(|_| {
103 TpmError::InvalidTag(crate::TpmErrorValue::new(TAG_OFFSET).value(u64::from(raw)))
104 })
105 }
106
107 #[must_use]
109 pub fn size(&self) -> u32 {
110 read_u32(&self.0, SIZE_OFFSET)
111 }
112
113 pub fn cc(&self) -> TpmResult<TpmCc> {
120 command_code(&self.0)
121 }
122
123 pub fn set_tag(&mut self, tag: TpmSt) {
125 write_u16(&mut self.0, TAG_OFFSET, tag.value());
126 }
127
128 pub fn set_cc(&mut self, cc: TpmCc) -> TpmResult<()> {
135 let _ = dispatch_for(cc)?;
136
137 write_u32(&mut self.0, CODE_OFFSET, cc.value());
138 Ok(())
139 }
140
141 pub fn handles(&self) -> TpmResult<&[u8]> {
147 let range = self.handle_area_range()?;
148
149 Ok(&self.0[range])
150 }
151
152 pub fn handles_mut(&mut self) -> TpmResult<&mut [u8]> {
158 let range = self.handle_area_range()?;
159
160 Ok(&mut self.0[range])
161 }
162
163 pub fn auth_area(&self) -> TpmResult<&[u8]> {
170 let (auth_area, _) = self.session_and_parameter_ranges()?;
171
172 Ok(&self.0[auth_area])
173 }
174
175 pub fn auth_area_mut(&mut self) -> TpmResult<&mut [u8]> {
182 let (auth_area, _) = self.session_and_parameter_ranges()?;
183
184 Ok(&mut self.0[auth_area])
185 }
186
187 pub fn parameters(&self) -> TpmResult<&[u8]> {
193 let (_, parameters) = self.session_and_parameter_ranges()?;
194
195 Ok(&self.0[parameters])
196 }
197
198 pub fn parameters_mut(&mut self) -> TpmResult<&mut [u8]> {
204 let (_, parameters) = self.session_and_parameter_ranges()?;
205
206 Ok(&mut self.0[parameters])
207 }
208
209 pub fn validate(&self) -> TpmResult<()> {
215 Self::validate_envelope(&self.0)?;
216 let auth_area = self.auth_area()?;
217
218 validate_auth_commands(&self.0, auth_area)
219 }
220
221 #[must_use]
223 pub const fn is_empty(&self) -> bool {
224 self.0.is_empty()
225 }
226
227 #[must_use]
229 pub const fn len(&self) -> usize {
230 self.0.len()
231 }
232
233 fn handle_area_range(&self) -> TpmResult<Range<usize>> {
234 let dispatch = dispatch_for(self.cc()?)?;
235 let handle_area_size = dispatch.handles * size_of::<u32>();
236
237 Ok(HEADER_SIZE..HEADER_SIZE + handle_area_size)
238 }
239
240 fn session_and_parameter_ranges(&self) -> TpmResult<(Range<usize>, Range<usize>)> {
241 let handle_area = self.handle_area_range()?;
242 let tag = self.tag()?;
243 let after_handles_start = handle_area.end;
244
245 if tag != TpmSt::Sessions {
246 return Ok((
247 after_handles_start..after_handles_start,
248 after_handles_start..self.0.len(),
249 ));
250 }
251
252 let after_handles = &self.0[after_handles_start..];
253
254 if after_handles.len() < size_of::<u32>() {
255 return Err(TpmError::UnexpectedEnd(
256 crate::TpmErrorValue::new(after_handles_start)
257 .size(size_of::<u32>(), after_handles.len()),
258 ));
259 }
260
261 let auth_size = read_u32(after_handles, 0) as usize;
262 let auth_start = size_of::<u32>();
263 let auth_end = auth_start
264 .checked_add(auth_size)
265 .ok_or(TpmError::IntegerTooLarge(
266 crate::TpmErrorValue::new(after_handles_start).value_usize(auth_size),
267 ))?;
268
269 if after_handles.len() < auth_end {
270 return Err(TpmError::UnexpectedEnd(
271 crate::TpmErrorValue::new(after_handles_start + auth_start)
272 .size(auth_size, after_handles.len().saturating_sub(auth_start)),
273 ));
274 }
275
276 let auth_start = after_handles_start + auth_start;
277 let auth_end = after_handles_start + auth_end;
278
279 Ok((auth_start..auth_end, auth_end..self.0.len()))
280 }
281
282 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
283 validate_frame_size(buf)?;
284
285 let raw_tag = read_u16(buf, TAG_OFFSET);
286 let tag = TpmSt::try_from(raw_tag).map_err(|_| {
287 TpmError::InvalidTag(crate::TpmErrorValue::new(TAG_OFFSET).value(u64::from(raw_tag)))
288 })?;
289 if tag != TpmSt::NoSessions && tag != TpmSt::Sessions {
290 return Err(TpmError::InvalidTag(
291 crate::TpmErrorValue::new(TAG_OFFSET).value(u64::from(raw_tag)),
292 ));
293 }
294
295 let dispatch = dispatch_for(command_code(buf)?)?;
296 let body = &buf[HEADER_SIZE..];
297 let handle_area_size = dispatch.handles * size_of::<u32>();
298
299 if body.len() < handle_area_size {
300 return Err(TpmError::UnexpectedEnd(
301 crate::TpmErrorValue::new(HEADER_SIZE).size(handle_area_size, body.len()),
302 ));
303 }
304
305 if tag == TpmSt::Sessions {
306 let after_handles = &body[handle_area_size..];
307 if after_handles.len() < size_of::<u32>() {
308 return Err(TpmError::UnexpectedEnd(
309 crate::TpmErrorValue::new(HEADER_SIZE + handle_area_size)
310 .size(size_of::<u32>(), after_handles.len()),
311 ));
312 }
313
314 let auth_size = read_u32(after_handles, 0) as usize;
315 let auth_end =
316 size_of::<u32>()
317 .checked_add(auth_size)
318 .ok_or(TpmError::IntegerTooLarge(
319 crate::TpmErrorValue::new(HEADER_SIZE + handle_area_size)
320 .value_usize(auth_size),
321 ))?;
322
323 if after_handles.len() < auth_end {
324 return Err(TpmError::UnexpectedEnd(
325 crate::TpmErrorValue::new(HEADER_SIZE + handle_area_size + size_of::<u32>())
326 .size(
327 auth_size,
328 after_handles.len().saturating_sub(size_of::<u32>()),
329 ),
330 ));
331 }
332 }
333
334 Ok(())
335 }
336}
337
338impl TpmCast for TpmCommand {
339 fn cast(buf: &[u8]) -> TpmResult<&Self> {
340 Self::cast(buf)
341 }
342
343 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
344 unsafe { Self::cast_unchecked(buf) }
346 }
347}
348
349impl TpmCastMut for TpmCommand {
350 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
351 Self::cast_mut(buf)
352 }
353
354 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
355 unsafe { Self::cast_mut_unchecked(buf) }
358 }
359}
360
361impl AsRef<[u8]> for TpmCommand {
362 fn as_ref(&self) -> &[u8] {
363 self.as_bytes()
364 }
365}
366
367impl AsMut<[u8]> for TpmCommand {
368 fn as_mut(&mut self) -> &mut [u8] {
369 self.as_bytes_mut()
370 }
371}
372
373#[repr(transparent)]
375pub struct TpmResponse([u8]);
376
377impl TpmResponse {
378 pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
384 Self::validate_envelope(buf)?;
385
386 Ok(unsafe { Self::cast_unchecked(buf) })
389 }
390
391 #[must_use]
398 pub unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
399 let ptr = core::ptr::from_ref(buf) as *const Self;
400
401 unsafe { &*ptr }
404 }
405
406 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
412 Self::validate_envelope(buf)?;
413
414 Ok(unsafe { Self::cast_mut_unchecked(buf) })
418 }
419
420 #[must_use]
428 pub unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
429 let ptr = core::ptr::from_mut(buf) as *mut Self;
430
431 unsafe { &mut *ptr }
434 }
435
436 #[must_use]
438 pub const fn as_bytes(&self) -> &[u8] {
439 &self.0
440 }
441
442 #[must_use]
444 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
445 &mut self.0
446 }
447
448 pub fn tag(&self) -> TpmResult<TpmSt> {
455 let raw = read_u16(&self.0, TAG_OFFSET);
456
457 TpmSt::try_from(raw).map_err(|_| {
458 TpmError::InvalidTag(crate::TpmErrorValue::new(TAG_OFFSET).value(u64::from(raw)))
459 })
460 }
461
462 #[must_use]
464 pub fn size(&self) -> u32 {
465 read_u32(&self.0, SIZE_OFFSET)
466 }
467
468 pub fn rc(&self) -> TpmResult<TpmRc> {
474 let raw = read_u32(&self.0, CODE_OFFSET);
475
476 TpmRc::try_from(raw).map_err(|_| {
477 TpmError::InvalidRc(crate::TpmErrorValue::new(CODE_OFFSET).value(u64::from(raw)))
478 })
479 }
480
481 pub fn set_tag(&mut self, tag: TpmSt) {
483 write_u16(&mut self.0, TAG_OFFSET, tag.value());
484 }
485
486 pub fn set_rc(&mut self, rc: TpmRc) {
488 write_u32(&mut self.0, CODE_OFFSET, rc.value());
489 }
490
491 #[must_use]
493 pub fn body(&self) -> &[u8] {
494 &self.0[HEADER_SIZE..]
495 }
496
497 #[must_use]
499 pub fn body_mut(&mut self) -> &mut [u8] {
500 &mut self.0[HEADER_SIZE..]
501 }
502
503 pub fn validate(&self, cc: TpmCc) -> TpmResult<()> {
510 Self::validate_envelope(&self.0)?;
511 let dispatch = dispatch_for(cc)?;
512
513 if !matches!(self.rc()?, TpmRc::Fmt0(TpmRcBase::Success)) {
514 return Ok(());
515 }
516
517 if self.tag()? != TpmSt::Sessions {
518 return Ok(());
519 }
520
521 let handle_area_size = dispatch.response_handles * size_of::<u32>();
522 let body = self.body();
523 if body.len() < handle_area_size {
524 return Err(TpmError::UnexpectedEnd(
525 crate::TpmErrorValue::new(HEADER_SIZE).size(handle_area_size, body.len()),
526 ));
527 }
528
529 let after_handles = &body[handle_area_size..];
530 if after_handles.len() < size_of::<u32>() {
531 return Err(TpmError::UnexpectedEnd(
532 crate::TpmErrorValue::new(HEADER_SIZE + handle_area_size)
533 .size(size_of::<u32>(), after_handles.len()),
534 ));
535 }
536
537 let params_len = read_u32(after_handles, 0) as usize;
538 let sessions_start =
539 size_of::<u32>()
540 .checked_add(params_len)
541 .ok_or(TpmError::IntegerTooLarge(
542 crate::TpmErrorValue::new(HEADER_SIZE + handle_area_size)
543 .value_usize(params_len),
544 ))?;
545
546 if after_handles.len() < sessions_start {
547 return Err(TpmError::UnexpectedEnd(
548 crate::TpmErrorValue::new(HEADER_SIZE + handle_area_size + size_of::<u32>()).size(
549 params_len,
550 after_handles.len().saturating_sub(size_of::<u32>()),
551 ),
552 ));
553 }
554
555 validate_auth_responses(&self.0, &after_handles[sessions_start..])
556 }
557
558 #[must_use]
560 pub const fn is_empty(&self) -> bool {
561 self.0.is_empty()
562 }
563
564 #[must_use]
566 pub const fn len(&self) -> usize {
567 self.0.len()
568 }
569
570 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
571 validate_frame_size(buf)?;
572 let raw_tag = read_u16(buf, TAG_OFFSET);
573 let _ = TpmSt::try_from(raw_tag).map_err(|_| {
574 TpmError::InvalidTag(crate::TpmErrorValue::new(TAG_OFFSET).value(u64::from(raw_tag)))
575 })?;
576 let raw_rc = read_u32(buf, CODE_OFFSET);
577 let _ = TpmRc::try_from(raw_rc).map_err(|_| {
578 TpmError::InvalidRc(crate::TpmErrorValue::new(CODE_OFFSET).value(u64::from(raw_rc)))
579 })?;
580
581 Ok(())
582 }
583}
584
585impl TpmCast for TpmResponse {
586 fn cast(buf: &[u8]) -> TpmResult<&Self> {
587 Self::cast(buf)
588 }
589
590 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
591 unsafe { Self::cast_unchecked(buf) }
593 }
594}
595
596impl TpmCastMut for TpmResponse {
597 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
598 Self::cast_mut(buf)
599 }
600
601 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
602 unsafe { Self::cast_mut_unchecked(buf) }
605 }
606}
607
608impl AsRef<[u8]> for TpmResponse {
609 fn as_ref(&self) -> &[u8] {
610 self.as_bytes()
611 }
612}
613
614impl AsMut<[u8]> for TpmResponse {
615 fn as_mut(&mut self) -> &mut [u8] {
616 self.as_bytes_mut()
617 }
618}
619
620fn command_code(buf: &[u8]) -> TpmResult<TpmCc> {
621 let raw = read_u32(buf, CODE_OFFSET);
622
623 TpmCc::try_from(raw).map_err(|_| {
624 TpmError::InvalidCc(crate::TpmErrorValue::new(CODE_OFFSET).value(u64::from(raw)))
625 })
626}
627
628fn dispatch_for(cc: TpmCc) -> TpmResult<&'static super::TpmDispatch> {
629 TPM_DISPATCH_TABLE
630 .binary_search_by_key(&cc, |d| d.cc)
631 .map(|index| &TPM_DISPATCH_TABLE[index])
632 .map_err(|_| TpmError::InvalidCc(crate::TpmErrorValue::new(0).value(u64::from(cc.value()))))
633}
634
635fn validate_frame_size(buf: &[u8]) -> TpmResult<()> {
636 if buf.len() < HEADER_SIZE {
637 return Err(TpmError::UnexpectedEnd(
638 crate::TpmErrorValue::new(0).size(HEADER_SIZE, buf.len()),
639 ));
640 }
641
642 let size = read_u32(buf, SIZE_OFFSET) as usize;
643 if buf.len() < size {
644 return Err(TpmError::UnexpectedEnd(
645 crate::TpmErrorValue::new(buf.len()).size(size - buf.len(), 0),
646 ));
647 }
648
649 if buf.len() > size {
650 return Err(TpmError::TrailingData(
651 crate::TpmErrorValue::new(size).actual(buf.len() - size),
652 ));
653 }
654
655 Ok(())
656}
657
658fn read_u16(buf: &[u8], offset: usize) -> u16 {
659 u16::from_be_bytes([buf[offset], buf[offset + 1]])
660}
661
662fn read_u32(buf: &[u8], offset: usize) -> u32 {
663 u32::from_be_bytes([
664 buf[offset],
665 buf[offset + 1],
666 buf[offset + 2],
667 buf[offset + 3],
668 ])
669}
670
671fn write_u16(buf: &mut [u8], offset: usize, value: u16) {
672 buf[offset..offset + size_of::<u16>()].copy_from_slice(&value.to_be_bytes());
673}
674
675fn write_u32(buf: &mut [u8], offset: usize, value: u32) {
676 buf[offset..offset + size_of::<u32>()].copy_from_slice(&value.to_be_bytes());
677}
678
679fn validate_auth_commands(base: &[u8], mut buf: &[u8]) -> TpmResult<()> {
680 let mut count = 0;
681
682 while !buf.is_empty() {
683 if count >= MAX_SESSIONS {
684 return Err(TpmError::TooManyItems(
685 crate::TpmErrorValue::at(base, buf).limit(MAX_SESSIONS, count + 1),
686 ));
687 }
688
689 if buf.len() < size_of::<u32>() {
690 return Err(TpmError::UnexpectedEnd(
691 crate::TpmErrorValue::at(base, buf).size(size_of::<u32>(), buf.len()),
692 ));
693 }
694
695 buf = &buf[size_of::<u32>()..];
696 buf = skip_tpm2b(base, buf)?;
697
698 if buf.is_empty() {
699 return Err(TpmError::UnexpectedEnd(
700 crate::TpmErrorValue::at(base, buf).size(1, 0),
701 ));
702 }
703
704 buf = &buf[1..];
705 buf = skip_tpm2b(base, buf)?;
706 count += 1;
707 }
708
709 Ok(())
710}
711
712fn validate_auth_responses(base: &[u8], mut buf: &[u8]) -> TpmResult<()> {
713 let mut count = 0;
714
715 while !buf.is_empty() {
716 if count >= MAX_SESSIONS {
717 return Err(TpmError::TooManyItems(
718 crate::TpmErrorValue::at(base, buf).limit(MAX_SESSIONS, count + 1),
719 ));
720 }
721
722 buf = skip_tpm2b(base, buf)?;
723
724 if buf.is_empty() {
725 return Err(TpmError::UnexpectedEnd(
726 crate::TpmErrorValue::at(base, buf).size(1, 0),
727 ));
728 }
729
730 buf = &buf[1..];
731 buf = skip_tpm2b(base, buf)?;
732 count += 1;
733 }
734
735 Ok(())
736}
737
738fn skip_tpm2b<'a>(base: &[u8], buf: &'a [u8]) -> TpmResult<&'a [u8]> {
739 if buf.len() < size_of::<u16>() {
740 return Err(TpmError::UnexpectedEnd(
741 crate::TpmErrorValue::at(base, buf).size(size_of::<u16>(), buf.len()),
742 ));
743 }
744
745 let size = read_u16(buf, 0) as usize;
746 let end = size_of::<u16>()
747 .checked_add(size)
748 .ok_or(TpmError::IntegerTooLarge(
749 crate::TpmErrorValue::at(base, buf).value_usize(size),
750 ))?;
751
752 if buf.len() < end {
753 return Err(TpmError::UnexpectedEnd(
754 crate::TpmErrorValue::at(base, buf).size(end, buf.len()),
755 ));
756 }
757
758 Ok(&buf[end..])
759}