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 pub fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
43 let frame_len = frame_prefix_size(buf)?;
44 let (frame, tail) = buf.split_at(frame_len);
45
46 Self::validate_envelope(frame)?;
47
48 Ok((unsafe { Self::cast_unchecked(frame) }, tail))
50 }
51
52 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
58 Self::validate_envelope(buf)?;
59
60 Ok(unsafe { Self::cast_mut_unchecked(buf) })
64 }
65
66 pub fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
73 let frame_len = frame_prefix_size(buf)?;
74 let (frame, tail) = buf.split_at_mut(frame_len);
75
76 Self::validate_envelope(frame)?;
77
78 Ok((unsafe { Self::cast_mut_unchecked(frame) }, tail))
80 }
81
82 #[must_use]
84 pub const fn as_bytes(&self) -> &[u8] {
85 &self.0
86 }
87
88 #[must_use]
90 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
91 &mut self.0
92 }
93
94 pub fn tag(&self) -> TpmResult<TpmSt> {
101 let raw = read_u16(&self.0, TAG_OFFSET);
102
103 TpmSt::try_from(raw).map_err(|_| TpmError::InvalidTag {
104 offset: TAG_OFFSET,
105 value: u64::from(raw),
106 })
107 }
108
109 #[must_use]
111 pub fn size(&self) -> u32 {
112 read_u32(&self.0, SIZE_OFFSET)
113 }
114
115 pub fn cc(&self) -> TpmResult<TpmCc> {
122 command_code(&self.0)
123 }
124
125 pub fn set_tag(&mut self, tag: TpmSt) {
127 write_u16(&mut self.0, TAG_OFFSET, tag.value());
128 }
129
130 pub fn set_cc(&mut self, cc: TpmCc) -> TpmResult<()> {
137 let _ = dispatch_for(cc)?;
138
139 write_u32(&mut self.0, CODE_OFFSET, cc.value());
140 Ok(())
141 }
142
143 pub fn handles(&self) -> TpmResult<&[u8]> {
149 let range = self.handle_area_range()?;
150
151 Ok(&self.0[range])
152 }
153
154 pub fn handles_mut(&mut self) -> TpmResult<&mut [u8]> {
160 let range = self.handle_area_range()?;
161
162 Ok(&mut self.0[range])
163 }
164
165 pub fn auth_area(&self) -> TpmResult<&[u8]> {
172 let (auth_area, _) = self.session_and_parameter_ranges()?;
173
174 Ok(&self.0[auth_area])
175 }
176
177 pub fn auth_area_mut(&mut self) -> TpmResult<&mut [u8]> {
184 let (auth_area, _) = self.session_and_parameter_ranges()?;
185
186 Ok(&mut self.0[auth_area])
187 }
188
189 pub fn parameters(&self) -> TpmResult<&[u8]> {
195 let (_, parameters) = self.session_and_parameter_ranges()?;
196
197 Ok(&self.0[parameters])
198 }
199
200 pub fn parameters_mut(&mut self) -> TpmResult<&mut [u8]> {
206 let (_, parameters) = self.session_and_parameter_ranges()?;
207
208 Ok(&mut self.0[parameters])
209 }
210
211 pub fn validate(&self) -> TpmResult<()> {
217 Self::validate_envelope(&self.0)?;
218 let auth_area = self.auth_area()?;
219
220 validate_auth_commands(&self.0, auth_area)
221 }
222
223 #[must_use]
225 pub const fn is_empty(&self) -> bool {
226 self.0.is_empty()
227 }
228
229 #[must_use]
231 pub const fn len(&self) -> usize {
232 self.0.len()
233 }
234
235 fn handle_area_range(&self) -> TpmResult<Range<usize>> {
236 let dispatch = dispatch_for(self.cc()?)?;
237 let handle_area_size = handle_area_size(dispatch.handles, HEADER_SIZE)?;
238 let handle_area_end =
239 HEADER_SIZE
240 .checked_add(handle_area_size)
241 .ok_or(TpmError::IntegerTooLarge {
242 offset: HEADER_SIZE,
243 value: crate::tpm_value(handle_area_size),
244 })?;
245
246 if self.0.len() < handle_area_end {
247 return Err(TpmError::UnexpectedEnd {
248 offset: HEADER_SIZE,
249 needed: handle_area_size,
250 available: self.0.len().saturating_sub(HEADER_SIZE),
251 });
252 }
253
254 Ok(HEADER_SIZE..handle_area_end)
255 }
256
257 fn session_and_parameter_ranges(&self) -> TpmResult<(Range<usize>, Range<usize>)> {
258 let handle_area = self.handle_area_range()?;
259 let tag = self.tag()?;
260 let after_handles_start = handle_area.end;
261
262 if tag != TpmSt::Sessions {
263 return Ok((
264 after_handles_start..after_handles_start,
265 after_handles_start..self.0.len(),
266 ));
267 }
268
269 let after_handles = &self.0[after_handles_start..];
270
271 if after_handles.len() < size_of::<u32>() {
272 return Err(TpmError::UnexpectedEnd {
273 offset: after_handles_start,
274 needed: size_of::<u32>(),
275 available: after_handles.len(),
276 });
277 }
278
279 let auth_size = read_u32(after_handles, 0) as usize;
280 let auth_start = size_of::<u32>();
281 let auth_end = auth_start
282 .checked_add(auth_size)
283 .ok_or(TpmError::IntegerTooLarge {
284 offset: after_handles_start,
285 value: crate::tpm_value(auth_size),
286 })?;
287
288 if after_handles.len() < auth_end {
289 return Err(TpmError::UnexpectedEnd {
290 offset: after_handles_start + auth_start,
291 needed: auth_size,
292 available: after_handles.len().saturating_sub(auth_start),
293 });
294 }
295
296 let auth_start = after_handles_start + auth_start;
297 let auth_end = after_handles_start + auth_end;
298
299 Ok((auth_start..auth_end, auth_end..self.0.len()))
300 }
301
302 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
303 validate_frame_size(buf)?;
304
305 let raw_tag = read_u16(buf, TAG_OFFSET);
306 let tag = TpmSt::try_from(raw_tag).map_err(|_| TpmError::InvalidTag {
307 offset: TAG_OFFSET,
308 value: u64::from(raw_tag),
309 })?;
310 if tag != TpmSt::NoSessions && tag != TpmSt::Sessions {
311 return Err(TpmError::InvalidTag {
312 offset: TAG_OFFSET,
313 value: u64::from(raw_tag),
314 });
315 }
316
317 let dispatch = dispatch_for(command_code(buf)?)?;
318 let body = &buf[HEADER_SIZE..];
319 let handle_area_size = handle_area_size(dispatch.handles, HEADER_SIZE)?;
320
321 if body.len() < handle_area_size {
322 return Err(TpmError::UnexpectedEnd {
323 offset: HEADER_SIZE,
324 needed: handle_area_size,
325 available: body.len(),
326 });
327 }
328
329 if tag == TpmSt::Sessions {
330 let after_handles = &body[handle_area_size..];
331 if after_handles.len() < size_of::<u32>() {
332 return Err(TpmError::UnexpectedEnd {
333 offset: HEADER_SIZE + handle_area_size,
334 needed: size_of::<u32>(),
335 available: after_handles.len(),
336 });
337 }
338
339 let auth_size = read_u32(after_handles, 0) as usize;
340 let auth_end =
341 size_of::<u32>()
342 .checked_add(auth_size)
343 .ok_or(TpmError::IntegerTooLarge {
344 offset: HEADER_SIZE + handle_area_size,
345 value: crate::tpm_value(auth_size),
346 })?;
347
348 if after_handles.len() < auth_end {
349 return Err(TpmError::UnexpectedEnd {
350 offset: HEADER_SIZE + handle_area_size + size_of::<u32>(),
351 needed: auth_size,
352 available: after_handles.len().saturating_sub(size_of::<u32>()),
353 });
354 }
355 }
356
357 Ok(())
358 }
359}
360
361impl TpmCast for TpmCommand {
362 fn cast(buf: &[u8]) -> TpmResult<&Self> {
363 Self::cast(buf)
364 }
365
366 fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
367 Self::cast_prefix(buf)
368 }
369
370 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
371 unsafe { Self::cast_unchecked(buf) }
373 }
374}
375
376impl TpmCastMut for TpmCommand {
377 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
378 Self::cast_mut(buf)
379 }
380
381 fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
382 Self::cast_prefix_mut(buf)
383 }
384
385 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
386 unsafe { Self::cast_mut_unchecked(buf) }
389 }
390}
391
392crate::tpm_byte_view!(TpmCommand);
393
394#[repr(transparent)]
396pub struct TpmResponse([u8]);
397
398impl TpmResponse {
399 pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
405 Self::validate_envelope(buf)?;
406
407 Ok(unsafe { Self::cast_unchecked(buf) })
410 }
411
412 pub fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
419 let frame_len = frame_prefix_size(buf)?;
420 let (frame, tail) = buf.split_at(frame_len);
421
422 Self::validate_envelope(frame)?;
423
424 Ok((unsafe { Self::cast_unchecked(frame) }, tail))
426 }
427
428 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
434 Self::validate_envelope(buf)?;
435
436 Ok(unsafe { Self::cast_mut_unchecked(buf) })
440 }
441
442 pub fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
449 let frame_len = frame_prefix_size(buf)?;
450 let (frame, tail) = buf.split_at_mut(frame_len);
451
452 Self::validate_envelope(frame)?;
453
454 Ok((unsafe { Self::cast_mut_unchecked(frame) }, tail))
456 }
457
458 #[must_use]
460 pub const fn as_bytes(&self) -> &[u8] {
461 &self.0
462 }
463
464 #[must_use]
466 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
467 &mut self.0
468 }
469
470 pub fn tag(&self) -> TpmResult<TpmSt> {
477 let raw = read_u16(&self.0, TAG_OFFSET);
478
479 TpmSt::try_from(raw).map_err(|_| TpmError::InvalidTag {
480 offset: TAG_OFFSET,
481 value: u64::from(raw),
482 })
483 }
484
485 #[must_use]
487 pub fn size(&self) -> u32 {
488 read_u32(&self.0, SIZE_OFFSET)
489 }
490
491 pub fn rc(&self) -> TpmResult<TpmRc> {
497 let raw = read_u32(&self.0, CODE_OFFSET);
498
499 TpmRc::try_from(raw).map_err(|_| TpmError::InvalidRc {
500 offset: CODE_OFFSET,
501 value: u64::from(raw),
502 })
503 }
504
505 pub fn set_tag(&mut self, tag: TpmSt) {
507 write_u16(&mut self.0, TAG_OFFSET, tag.value());
508 }
509
510 pub fn set_rc(&mut self, rc: TpmRc) {
512 write_u32(&mut self.0, CODE_OFFSET, rc.value());
513 }
514
515 #[must_use]
517 pub fn body(&self) -> &[u8] {
518 &self.0[HEADER_SIZE..]
519 }
520
521 #[must_use]
523 pub fn body_mut(&mut self) -> &mut [u8] {
524 &mut self.0[HEADER_SIZE..]
525 }
526
527 pub fn validate(&self, cc: TpmCc) -> TpmResult<()> {
534 Self::validate_envelope(&self.0)?;
535 let dispatch = dispatch_for(cc)?;
536
537 if !matches!(self.rc()?, TpmRc::Fmt0(TpmRcBase::Success)) {
538 return Ok(());
539 }
540
541 if self.tag()? != TpmSt::Sessions {
542 return Ok(());
543 }
544
545 let handle_area_size = handle_area_size(dispatch.response_handles, HEADER_SIZE)?;
546 let body = self.body();
547 if body.len() < handle_area_size {
548 return Err(TpmError::UnexpectedEnd {
549 offset: HEADER_SIZE,
550 needed: handle_area_size,
551 available: body.len(),
552 });
553 }
554
555 let after_handles = &body[handle_area_size..];
556 if after_handles.len() < size_of::<u32>() {
557 return Err(TpmError::UnexpectedEnd {
558 offset: HEADER_SIZE + handle_area_size,
559 needed: size_of::<u32>(),
560 available: after_handles.len(),
561 });
562 }
563
564 let params_len = read_u32(after_handles, 0) as usize;
565 let sessions_start =
566 size_of::<u32>()
567 .checked_add(params_len)
568 .ok_or(TpmError::IntegerTooLarge {
569 offset: HEADER_SIZE + handle_area_size,
570 value: crate::tpm_value(params_len),
571 })?;
572
573 if after_handles.len() < sessions_start {
574 return Err(TpmError::UnexpectedEnd {
575 offset: HEADER_SIZE + handle_area_size + size_of::<u32>(),
576 needed: params_len,
577 available: after_handles.len().saturating_sub(size_of::<u32>()),
578 });
579 }
580
581 validate_auth_responses(&self.0, &after_handles[sessions_start..])
582 }
583
584 #[must_use]
586 pub const fn is_empty(&self) -> bool {
587 self.0.is_empty()
588 }
589
590 #[must_use]
592 pub const fn len(&self) -> usize {
593 self.0.len()
594 }
595
596 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
597 validate_frame_size(buf)?;
598 let raw_tag = read_u16(buf, TAG_OFFSET);
599 let _ = TpmSt::try_from(raw_tag).map_err(|_| TpmError::InvalidTag {
600 offset: TAG_OFFSET,
601 value: u64::from(raw_tag),
602 })?;
603 let raw_rc = read_u32(buf, CODE_OFFSET);
604 let _ = TpmRc::try_from(raw_rc).map_err(|_| TpmError::InvalidRc {
605 offset: CODE_OFFSET,
606 value: u64::from(raw_rc),
607 })?;
608
609 Ok(())
610 }
611}
612
613impl TpmCast for TpmResponse {
614 fn cast(buf: &[u8]) -> TpmResult<&Self> {
615 Self::cast(buf)
616 }
617
618 fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
619 Self::cast_prefix(buf)
620 }
621
622 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
623 unsafe { Self::cast_unchecked(buf) }
625 }
626}
627
628impl TpmCastMut for TpmResponse {
629 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
630 Self::cast_mut(buf)
631 }
632
633 fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
634 Self::cast_prefix_mut(buf)
635 }
636
637 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
638 unsafe { Self::cast_mut_unchecked(buf) }
641 }
642}
643
644crate::tpm_byte_view!(TpmResponse);
645
646fn command_code(buf: &[u8]) -> TpmResult<TpmCc> {
647 let raw = read_u32(buf, CODE_OFFSET);
648
649 TpmCc::try_from(raw).map_err(|_| TpmError::InvalidCc {
650 offset: CODE_OFFSET,
651 value: u64::from(raw),
652 })
653}
654
655fn dispatch_for(cc: TpmCc) -> TpmResult<&'static super::TpmDispatch> {
656 TPM_DISPATCH_TABLE
657 .binary_search_by_key(&cc, |d| d.cc)
658 .map(|index| &TPM_DISPATCH_TABLE[index])
659 .map_err(|_| TpmError::InvalidCc {
660 offset: 0,
661 value: u64::from(cc.value()),
662 })
663}
664
665fn validate_frame_size(buf: &[u8]) -> TpmResult<()> {
666 let size = frame_prefix_size(buf)?;
667
668 if buf.len() > size {
669 return Err(TpmError::TrailingData {
670 offset: size,
671 actual: buf.len() - size,
672 });
673 }
674
675 Ok(())
676}
677
678fn handle_area_size(handles: usize, offset: usize) -> TpmResult<usize> {
679 handles
680 .checked_mul(size_of::<u32>())
681 .ok_or(TpmError::IntegerTooLarge {
682 offset,
683 value: crate::tpm_value(handles),
684 })
685}
686
687fn frame_prefix_size(buf: &[u8]) -> TpmResult<usize> {
688 if buf.len() < HEADER_SIZE {
689 return Err(TpmError::UnexpectedEnd {
690 offset: 0,
691 needed: HEADER_SIZE,
692 available: buf.len(),
693 });
694 }
695
696 let size = read_u32(buf, SIZE_OFFSET) as usize;
697 if buf.len() < size {
698 return Err(TpmError::UnexpectedEnd {
699 offset: buf.len(),
700 needed: size - buf.len(),
701 available: 0,
702 });
703 }
704
705 Ok(size)
706}
707
708fn read_u16(buf: &[u8], offset: usize) -> u16 {
709 u16::from_be_bytes([buf[offset], buf[offset + 1]])
710}
711
712fn read_u32(buf: &[u8], offset: usize) -> u32 {
713 u32::from_be_bytes([
714 buf[offset],
715 buf[offset + 1],
716 buf[offset + 2],
717 buf[offset + 3],
718 ])
719}
720
721fn write_u16(buf: &mut [u8], offset: usize, value: u16) {
722 buf[offset..offset + size_of::<u16>()].copy_from_slice(&value.to_be_bytes());
723}
724
725fn write_u32(buf: &mut [u8], offset: usize, value: u32) {
726 buf[offset..offset + size_of::<u32>()].copy_from_slice(&value.to_be_bytes());
727}
728
729fn validate_auth_commands(base: &[u8], mut buf: &[u8]) -> TpmResult<()> {
730 let mut count = 0;
731
732 while !buf.is_empty() {
733 if count >= MAX_SESSIONS {
734 return Err(TpmError::TooManyItems {
735 offset: crate::tpm_offset(base, buf),
736 limit: MAX_SESSIONS,
737 actual: count + 1,
738 });
739 }
740
741 if buf.len() < size_of::<u32>() {
742 return Err(TpmError::UnexpectedEnd {
743 offset: crate::tpm_offset(base, buf),
744 needed: size_of::<u32>(),
745 available: buf.len(),
746 });
747 }
748
749 buf = &buf[size_of::<u32>()..];
750 buf = skip_tpm2b(base, buf)?;
751
752 if buf.is_empty() {
753 return Err(TpmError::UnexpectedEnd {
754 offset: crate::tpm_offset(base, buf),
755 needed: 1,
756 available: 0,
757 });
758 }
759
760 buf = &buf[1..];
761 buf = skip_tpm2b(base, buf)?;
762 count += 1;
763 }
764
765 Ok(())
766}
767
768fn validate_auth_responses(base: &[u8], mut buf: &[u8]) -> TpmResult<()> {
769 let mut count = 0;
770
771 while !buf.is_empty() {
772 if count >= MAX_SESSIONS {
773 return Err(TpmError::TooManyItems {
774 offset: crate::tpm_offset(base, buf),
775 limit: MAX_SESSIONS,
776 actual: count + 1,
777 });
778 }
779
780 buf = skip_tpm2b(base, buf)?;
781
782 if buf.is_empty() {
783 return Err(TpmError::UnexpectedEnd {
784 offset: crate::tpm_offset(base, buf),
785 needed: 1,
786 available: 0,
787 });
788 }
789
790 buf = &buf[1..];
791 buf = skip_tpm2b(base, buf)?;
792 count += 1;
793 }
794
795 Ok(())
796}
797
798fn skip_tpm2b<'a>(base: &[u8], buf: &'a [u8]) -> TpmResult<&'a [u8]> {
799 if buf.len() < size_of::<u16>() {
800 return Err(TpmError::UnexpectedEnd {
801 offset: crate::tpm_offset(base, buf),
802 needed: size_of::<u16>(),
803 available: buf.len(),
804 });
805 }
806
807 let size = read_u16(buf, 0) as usize;
808 let end = size_of::<u16>()
809 .checked_add(size)
810 .ok_or(TpmError::IntegerTooLarge {
811 offset: crate::tpm_offset(base, buf),
812 value: crate::tpm_value(size),
813 })?;
814
815 if buf.len() < end {
816 return Err(TpmError::UnexpectedEnd {
817 offset: crate::tpm_offset(base, buf),
818 needed: end,
819 available: buf.len(),
820 });
821 }
822
823 Ok(&buf[end..])
824}