1use super::{TPM_DISPATCH_TABLE, TPM_HEADER_SIZE};
6use crate::{
7 TpmCast, TpmCastMut, TpmError, TpmResult, TpmUnmarshal,
8 basic::TpmUint32,
9 constant::MAX_SESSIONS,
10 data::{TpmCc, TpmRc, TpmRcBase, TpmSt},
11};
12use core::{mem::size_of, ops::Range};
13
14const HEADER_SIZE: usize = TPM_HEADER_SIZE as usize;
15const TAG_OFFSET: usize = 0;
16const SIZE_OFFSET: usize = 2;
17const CODE_OFFSET: usize = 6;
18
19#[repr(transparent)]
21pub struct TpmCommand([u8]);
22
23impl TpmCommand {
24 pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
30 Self::validate_envelope(buf)?;
31
32 Ok(unsafe { Self::cast_unchecked(buf) })
35 }
36
37 pub fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
44 let frame_len = frame_prefix_size(buf)?;
45 let (frame, tail) = buf.split_at(frame_len);
46
47 Self::validate_envelope(frame)?;
48
49 Ok((unsafe { Self::cast_unchecked(frame) }, tail))
51 }
52
53 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
59 Self::validate_envelope(buf)?;
60
61 Ok(unsafe { Self::cast_mut_unchecked(buf) })
65 }
66
67 pub fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
74 let frame_len = frame_prefix_size(buf)?;
75 let (frame, tail) = buf.split_at_mut(frame_len);
76
77 Self::validate_envelope(frame)?;
78
79 Ok((unsafe { Self::cast_mut_unchecked(frame) }, tail))
81 }
82
83 #[must_use]
85 pub const fn as_bytes(&self) -> &[u8] {
86 &self.0
87 }
88
89 #[must_use]
91 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
92 &mut self.0
93 }
94
95 pub fn tag(&self) -> TpmResult<TpmSt> {
102 let raw = read_u16(&self.0, TAG_OFFSET);
103
104 TpmSt::try_from(raw).map_err(|_| TpmError::InvalidTag {
105 offset: TAG_OFFSET,
106 value: u64::from(raw),
107 })
108 }
109
110 #[must_use]
112 pub fn size(&self) -> u32 {
113 read_u32(&self.0, SIZE_OFFSET)
114 }
115
116 pub fn cc(&self) -> TpmResult<TpmCc> {
123 command_code(&self.0)
124 }
125
126 pub fn set_tag(&mut self, tag: TpmSt) {
128 write_u16(&mut self.0, TAG_OFFSET, tag.value());
129 }
130
131 pub fn set_cc(&mut self, cc: TpmCc) -> TpmResult<()> {
138 let _ = dispatch_for(cc)?;
139
140 write_u32(&mut self.0, CODE_OFFSET, cc.value());
141 Ok(())
142 }
143
144 pub fn handles(&self) -> TpmResult<&[u8]> {
150 let range = self.handle_area_range()?;
151
152 Ok(&self.0[range])
153 }
154
155 pub fn handles_mut(&mut self) -> TpmResult<&mut [u8]> {
161 let range = self.handle_area_range()?;
162
163 Ok(&mut self.0[range])
164 }
165
166 pub fn auth_area(&self) -> TpmResult<&[u8]> {
173 let (auth_area, _) = self.session_and_parameter_ranges()?;
174
175 Ok(&self.0[auth_area])
176 }
177
178 pub fn auth_area_mut(&mut self) -> TpmResult<&mut [u8]> {
185 let (auth_area, _) = self.session_and_parameter_ranges()?;
186
187 Ok(&mut self.0[auth_area])
188 }
189
190 pub fn parameters(&self) -> TpmResult<&[u8]> {
196 let (_, parameters) = self.session_and_parameter_ranges()?;
197
198 Ok(&self.0[parameters])
199 }
200
201 pub fn parameters_mut(&mut self) -> TpmResult<&mut [u8]> {
207 let (_, parameters) = self.session_and_parameter_ranges()?;
208
209 Ok(&mut self.0[parameters])
210 }
211
212 pub fn unmarshal<R: super::TpmUnmarshalBody>(&self) -> TpmResult<R> {
218 self.validate()?;
219 let cc = self.cc()?;
220 if cc != R::CC {
221 return Err(TpmError::InvalidCc {
222 offset: CODE_OFFSET,
223 value: u64::from(cc.value()),
224 });
225 }
226
227 R::unmarshal_body(self.handles()?, self.parameters()?)
228 }
229
230 pub fn validate(&self) -> TpmResult<()> {
236 Self::validate_envelope(&self.0)?;
237 let auth_area = self.auth_area()?;
238
239 validate_auth_commands(&self.0, auth_area)
240 }
241
242 #[must_use]
244 pub const fn is_empty(&self) -> bool {
245 self.0.is_empty()
246 }
247
248 #[must_use]
250 pub const fn len(&self) -> usize {
251 self.0.len()
252 }
253
254 fn handle_area_range(&self) -> TpmResult<Range<usize>> {
255 let dispatch = dispatch_for(self.cc()?)?;
256 let handle_area_size = handle_area_size(dispatch.handles, HEADER_SIZE)?;
257 let handle_area_end =
258 HEADER_SIZE
259 .checked_add(handle_area_size)
260 .ok_or(TpmError::IntegerTooLarge {
261 offset: HEADER_SIZE,
262 value: crate::tpm_value(handle_area_size),
263 })?;
264
265 if self.0.len() < handle_area_end {
266 return Err(TpmError::UnexpectedEnd {
267 offset: HEADER_SIZE,
268 needed: handle_area_size,
269 available: self.0.len().saturating_sub(HEADER_SIZE),
270 });
271 }
272
273 Ok(HEADER_SIZE..handle_area_end)
274 }
275
276 fn session_and_parameter_ranges(&self) -> TpmResult<(Range<usize>, Range<usize>)> {
277 let handle_area = self.handle_area_range()?;
278 let tag = self.tag()?;
279 let after_handles_start = handle_area.end;
280
281 if tag != TpmSt::Sessions {
282 return Ok((
283 after_handles_start..after_handles_start,
284 after_handles_start..self.0.len(),
285 ));
286 }
287
288 let after_handles = &self.0[after_handles_start..];
289
290 if after_handles.len() < size_of::<u32>() {
291 return Err(TpmError::UnexpectedEnd {
292 offset: after_handles_start,
293 needed: size_of::<u32>(),
294 available: after_handles.len(),
295 });
296 }
297
298 let auth_size = read_u32(after_handles, 0) as usize;
299 let auth_start = size_of::<u32>();
300 let auth_end = auth_start
301 .checked_add(auth_size)
302 .ok_or(TpmError::IntegerTooLarge {
303 offset: after_handles_start,
304 value: crate::tpm_value(auth_size),
305 })?;
306
307 if after_handles.len() < auth_end {
308 return Err(TpmError::UnexpectedEnd {
309 offset: after_handles_start + auth_start,
310 needed: auth_size,
311 available: after_handles.len().saturating_sub(auth_start),
312 });
313 }
314
315 let auth_start = after_handles_start + auth_start;
316 let auth_end = after_handles_start + auth_end;
317
318 Ok((auth_start..auth_end, auth_end..self.0.len()))
319 }
320
321 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
322 validate_frame_size(buf)?;
323
324 let raw_tag = read_u16(buf, TAG_OFFSET);
325 let tag = TpmSt::try_from(raw_tag).map_err(|_| TpmError::InvalidTag {
326 offset: TAG_OFFSET,
327 value: u64::from(raw_tag),
328 })?;
329 if tag != TpmSt::NoSessions && tag != TpmSt::Sessions {
330 return Err(TpmError::InvalidTag {
331 offset: TAG_OFFSET,
332 value: u64::from(raw_tag),
333 });
334 }
335
336 let dispatch = dispatch_for(command_code(buf)?)?;
337 let body = &buf[HEADER_SIZE..];
338 let handle_area_size = handle_area_size(dispatch.handles, HEADER_SIZE)?;
339
340 if body.len() < handle_area_size {
341 return Err(TpmError::UnexpectedEnd {
342 offset: HEADER_SIZE,
343 needed: handle_area_size,
344 available: body.len(),
345 });
346 }
347
348 if tag == TpmSt::Sessions {
349 let after_handles = &body[handle_area_size..];
350 if after_handles.len() < size_of::<u32>() {
351 return Err(TpmError::UnexpectedEnd {
352 offset: HEADER_SIZE + handle_area_size,
353 needed: size_of::<u32>(),
354 available: after_handles.len(),
355 });
356 }
357
358 let auth_size = read_u32(after_handles, 0) as usize;
359 let auth_end =
360 size_of::<u32>()
361 .checked_add(auth_size)
362 .ok_or(TpmError::IntegerTooLarge {
363 offset: HEADER_SIZE + handle_area_size,
364 value: crate::tpm_value(auth_size),
365 })?;
366
367 if after_handles.len() < auth_end {
368 return Err(TpmError::UnexpectedEnd {
369 offset: HEADER_SIZE + handle_area_size + size_of::<u32>(),
370 needed: auth_size,
371 available: after_handles.len().saturating_sub(size_of::<u32>()),
372 });
373 }
374 }
375
376 Ok(())
377 }
378}
379
380impl TpmCast for TpmCommand {
381 fn cast(buf: &[u8]) -> TpmResult<&Self> {
382 Self::cast(buf)
383 }
384
385 fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
386 Self::cast_prefix(buf)
387 }
388
389 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
390 unsafe { Self::cast_unchecked(buf) }
392 }
393}
394
395impl TpmCastMut for TpmCommand {
396 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
397 Self::cast_mut(buf)
398 }
399
400 fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
401 Self::cast_prefix_mut(buf)
402 }
403
404 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
405 unsafe { Self::cast_mut_unchecked(buf) }
408 }
409}
410
411crate::tpm_byte_view!(TpmCommand);
412
413#[repr(transparent)]
415pub struct TpmResponse([u8]);
416
417impl TpmResponse {
418 pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
424 Self::validate_envelope(buf)?;
425
426 Ok(unsafe { Self::cast_unchecked(buf) })
429 }
430
431 pub fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
438 let frame_len = frame_prefix_size(buf)?;
439 let (frame, tail) = buf.split_at(frame_len);
440
441 Self::validate_envelope(frame)?;
442
443 Ok((unsafe { Self::cast_unchecked(frame) }, tail))
445 }
446
447 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
453 Self::validate_envelope(buf)?;
454
455 Ok(unsafe { Self::cast_mut_unchecked(buf) })
459 }
460
461 pub fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
468 let frame_len = frame_prefix_size(buf)?;
469 let (frame, tail) = buf.split_at_mut(frame_len);
470
471 Self::validate_envelope(frame)?;
472
473 Ok((unsafe { Self::cast_mut_unchecked(frame) }, tail))
475 }
476
477 #[must_use]
479 pub const fn as_bytes(&self) -> &[u8] {
480 &self.0
481 }
482
483 #[must_use]
485 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
486 &mut self.0
487 }
488
489 pub fn tag(&self) -> TpmResult<TpmSt> {
496 let raw = read_u16(&self.0, TAG_OFFSET);
497
498 TpmSt::try_from(raw).map_err(|_| TpmError::InvalidTag {
499 offset: TAG_OFFSET,
500 value: u64::from(raw),
501 })
502 }
503
504 #[must_use]
506 pub fn size(&self) -> u32 {
507 read_u32(&self.0, SIZE_OFFSET)
508 }
509
510 pub fn rc(&self) -> TpmResult<TpmRc> {
516 let raw = read_u32(&self.0, CODE_OFFSET);
517
518 TpmRc::try_from(raw).map_err(|_| TpmError::InvalidRc {
519 offset: CODE_OFFSET,
520 value: u64::from(raw),
521 })
522 }
523
524 pub fn set_tag(&mut self, tag: TpmSt) {
526 write_u16(&mut self.0, TAG_OFFSET, tag.value());
527 }
528
529 pub fn set_rc(&mut self, rc: TpmRc) {
531 write_u32(&mut self.0, CODE_OFFSET, rc.value());
532 }
533
534 #[must_use]
536 pub fn body(&self) -> &[u8] {
537 &self.0[HEADER_SIZE..]
538 }
539
540 #[must_use]
542 pub fn body_mut(&mut self) -> &mut [u8] {
543 &mut self.0[HEADER_SIZE..]
544 }
545
546 pub fn validate(&self, cc: TpmCc) -> TpmResult<()> {
553 Self::validate_envelope(&self.0)?;
554 let dispatch = dispatch_for(cc)?;
555 let tag = self.tag()?;
556
557 if !matches!(self.rc()?, TpmRc::Fmt0(TpmRcBase::Success)) {
558 if tag != TpmSt::NoSessions {
559 return Err(TpmError::InvalidTag {
560 offset: TAG_OFFSET,
561 value: u64::from(tag.value()),
562 });
563 }
564
565 if self.0.len() != HEADER_SIZE {
566 return Err(TpmError::TrailingData {
567 offset: HEADER_SIZE,
568 actual: self.0.len().saturating_sub(HEADER_SIZE),
569 });
570 }
571
572 return Ok(());
573 }
574
575 let handle_area_size = handle_area_size(dispatch.response_handles, HEADER_SIZE)?;
576 let body = self.body();
577 if body.len() < handle_area_size {
578 return Err(TpmError::UnexpectedEnd {
579 offset: HEADER_SIZE,
580 needed: handle_area_size,
581 available: body.len(),
582 });
583 }
584
585 if tag != TpmSt::Sessions {
586 return Ok(());
587 }
588
589 let after_handles = &body[handle_area_size..];
590 if after_handles.len() < size_of::<u32>() {
591 return Err(TpmError::UnexpectedEnd {
592 offset: HEADER_SIZE + handle_area_size,
593 needed: size_of::<u32>(),
594 available: after_handles.len(),
595 });
596 }
597
598 let params_len = read_u32(after_handles, 0) as usize;
599 let sessions_start =
600 size_of::<u32>()
601 .checked_add(params_len)
602 .ok_or(TpmError::IntegerTooLarge {
603 offset: HEADER_SIZE + handle_area_size,
604 value: crate::tpm_value(params_len),
605 })?;
606
607 if after_handles.len() < sessions_start {
608 return Err(TpmError::UnexpectedEnd {
609 offset: HEADER_SIZE + handle_area_size + size_of::<u32>(),
610 needed: params_len,
611 available: after_handles.len().saturating_sub(size_of::<u32>()),
612 });
613 }
614
615 validate_auth_responses(&self.0, &after_handles[sessions_start..])
616 }
617
618 pub fn unmarshal<R: super::TpmUnmarshalBody>(&self) -> TpmResult<R> {
624 self.validate(R::CC)?;
625 let (handles, parameters) = self.body_parts::<R>()?;
626 R::unmarshal_body(handles, parameters)
627 }
628
629 fn body_parts<R: super::TpmHeader>(&self) -> TpmResult<(&[u8], &[u8])> {
630 let handle_area_size = handle_area_size(R::HANDLES, HEADER_SIZE)?;
631 let body = self.body();
632 if body.len() < handle_area_size {
633 return Err(TpmError::UnexpectedEnd {
634 offset: HEADER_SIZE,
635 needed: handle_area_size,
636 available: body.len(),
637 });
638 }
639
640 let (handles, after_handles) = body.split_at(handle_area_size);
641 if self.tag()? != TpmSt::Sessions {
642 return Ok((handles, after_handles));
643 }
644
645 let (parameter_size, after_size) = TpmUint32::unmarshal(after_handles)?;
646 let parameter_size =
647 usize::try_from(parameter_size.value()).map_err(|_| TpmError::IntegerTooLarge {
648 offset: HEADER_SIZE + handle_area_size,
649 value: u64::from(parameter_size.value()),
650 })?;
651 if after_size.len() < parameter_size {
652 return Err(TpmError::UnexpectedEnd {
653 offset: HEADER_SIZE + handle_area_size + size_of::<u32>(),
654 needed: parameter_size,
655 available: after_size.len(),
656 });
657 }
658
659 Ok((handles, &after_size[..parameter_size]))
660 }
661
662 #[must_use]
664 pub const fn is_empty(&self) -> bool {
665 self.0.is_empty()
666 }
667
668 #[must_use]
670 pub const fn len(&self) -> usize {
671 self.0.len()
672 }
673
674 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
675 validate_frame_size(buf)?;
676 let raw_tag = read_u16(buf, TAG_OFFSET);
677 let tag = TpmSt::try_from(raw_tag).map_err(|_| TpmError::InvalidTag {
678 offset: TAG_OFFSET,
679 value: u64::from(raw_tag),
680 })?;
681 if tag != TpmSt::NoSessions && tag != TpmSt::Sessions {
682 return Err(TpmError::InvalidTag {
683 offset: TAG_OFFSET,
684 value: u64::from(raw_tag),
685 });
686 }
687 let raw_rc = read_u32(buf, CODE_OFFSET);
688 let _ = TpmRc::try_from(raw_rc).map_err(|_| TpmError::InvalidRc {
689 offset: CODE_OFFSET,
690 value: u64::from(raw_rc),
691 })?;
692
693 Ok(())
694 }
695}
696
697impl TpmCast for TpmResponse {
698 fn cast(buf: &[u8]) -> TpmResult<&Self> {
699 Self::cast(buf)
700 }
701
702 fn cast_prefix(buf: &[u8]) -> TpmResult<(&Self, &[u8])> {
703 Self::cast_prefix(buf)
704 }
705
706 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
707 unsafe { Self::cast_unchecked(buf) }
709 }
710}
711
712impl TpmCastMut for TpmResponse {
713 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
714 Self::cast_mut(buf)
715 }
716
717 fn cast_prefix_mut(buf: &mut [u8]) -> TpmResult<(&mut Self, &mut [u8])> {
718 Self::cast_prefix_mut(buf)
719 }
720
721 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
722 unsafe { Self::cast_mut_unchecked(buf) }
725 }
726}
727
728crate::tpm_byte_view!(TpmResponse);
729
730fn command_code(buf: &[u8]) -> TpmResult<TpmCc> {
731 let raw = read_u32(buf, CODE_OFFSET);
732
733 TpmCc::try_from(raw).map_err(|_| TpmError::InvalidCc {
734 offset: CODE_OFFSET,
735 value: u64::from(raw),
736 })
737}
738
739fn dispatch_for(cc: TpmCc) -> TpmResult<&'static super::TpmDispatch> {
740 TPM_DISPATCH_TABLE
741 .binary_search_by_key(&cc, |d| d.cc)
742 .map(|index| &TPM_DISPATCH_TABLE[index])
743 .map_err(|_| TpmError::InvalidCc {
744 offset: 0,
745 value: u64::from(cc.value()),
746 })
747}
748
749fn validate_frame_size(buf: &[u8]) -> TpmResult<()> {
750 let size = frame_prefix_size(buf)?;
751
752 if buf.len() > size {
753 return Err(TpmError::TrailingData {
754 offset: size,
755 actual: buf.len() - size,
756 });
757 }
758
759 Ok(())
760}
761
762fn handle_area_size(handles: usize, offset: usize) -> TpmResult<usize> {
763 handles
764 .checked_mul(size_of::<u32>())
765 .ok_or(TpmError::IntegerTooLarge {
766 offset,
767 value: crate::tpm_value(handles),
768 })
769}
770
771fn frame_prefix_size(buf: &[u8]) -> TpmResult<usize> {
772 if buf.len() < HEADER_SIZE {
773 return Err(TpmError::UnexpectedEnd {
774 offset: 0,
775 needed: HEADER_SIZE,
776 available: buf.len(),
777 });
778 }
779
780 let size = read_u32(buf, SIZE_OFFSET) as usize;
781 if size < HEADER_SIZE {
782 return Err(TpmError::UnexpectedEnd {
783 offset: SIZE_OFFSET,
784 needed: HEADER_SIZE,
785 available: size,
786 });
787 }
788 if buf.len() < size {
789 return Err(TpmError::UnexpectedEnd {
790 offset: buf.len(),
791 needed: size - buf.len(),
792 available: 0,
793 });
794 }
795
796 Ok(size)
797}
798
799fn read_u16(buf: &[u8], offset: usize) -> u16 {
800 u16::from_be_bytes([buf[offset], buf[offset + 1]])
801}
802
803fn read_u32(buf: &[u8], offset: usize) -> u32 {
804 u32::from_be_bytes([
805 buf[offset],
806 buf[offset + 1],
807 buf[offset + 2],
808 buf[offset + 3],
809 ])
810}
811
812fn write_u16(buf: &mut [u8], offset: usize, value: u16) {
813 buf[offset..offset + size_of::<u16>()].copy_from_slice(&value.to_be_bytes());
814}
815
816fn write_u32(buf: &mut [u8], offset: usize, value: u32) {
817 buf[offset..offset + size_of::<u32>()].copy_from_slice(&value.to_be_bytes());
818}
819
820fn validate_auth_commands(base: &[u8], mut buf: &[u8]) -> TpmResult<()> {
821 let mut count = 0;
822
823 while !buf.is_empty() {
824 if count >= MAX_SESSIONS {
825 return Err(TpmError::TooManyItems {
826 offset: crate::tpm_offset(base, buf),
827 limit: MAX_SESSIONS,
828 actual: count + 1,
829 });
830 }
831
832 if buf.len() < size_of::<u32>() {
833 return Err(TpmError::UnexpectedEnd {
834 offset: crate::tpm_offset(base, buf),
835 needed: size_of::<u32>(),
836 available: buf.len(),
837 });
838 }
839
840 buf = &buf[size_of::<u32>()..];
841 buf = skip_tpm2b(base, buf)?;
842
843 if buf.is_empty() {
844 return Err(TpmError::UnexpectedEnd {
845 offset: crate::tpm_offset(base, buf),
846 needed: 1,
847 available: 0,
848 });
849 }
850
851 buf = &buf[1..];
852 buf = skip_tpm2b(base, buf)?;
853 count += 1;
854 }
855
856 Ok(())
857}
858
859fn validate_auth_responses(base: &[u8], mut buf: &[u8]) -> TpmResult<()> {
860 let mut count = 0;
861
862 while !buf.is_empty() {
863 if count >= MAX_SESSIONS {
864 return Err(TpmError::TooManyItems {
865 offset: crate::tpm_offset(base, buf),
866 limit: MAX_SESSIONS,
867 actual: count + 1,
868 });
869 }
870
871 buf = skip_tpm2b(base, buf)?;
872
873 if buf.is_empty() {
874 return Err(TpmError::UnexpectedEnd {
875 offset: crate::tpm_offset(base, buf),
876 needed: 1,
877 available: 0,
878 });
879 }
880
881 buf = &buf[1..];
882 buf = skip_tpm2b(base, buf)?;
883 count += 1;
884 }
885
886 Ok(())
887}
888
889fn skip_tpm2b<'a>(base: &[u8], buf: &'a [u8]) -> TpmResult<&'a [u8]> {
890 if buf.len() < size_of::<u16>() {
891 return Err(TpmError::UnexpectedEnd {
892 offset: crate::tpm_offset(base, buf),
893 needed: size_of::<u16>(),
894 available: buf.len(),
895 });
896 }
897
898 let size = read_u16(buf, 0) as usize;
899 let end = size_of::<u16>()
900 .checked_add(size)
901 .ok_or(TpmError::IntegerTooLarge {
902 offset: crate::tpm_offset(base, buf),
903 value: crate::tpm_value(size),
904 })?;
905
906 if buf.len() < end {
907 return Err(TpmError::UnexpectedEnd {
908 offset: crate::tpm_offset(base, buf),
909 needed: end,
910 available: buf.len(),
911 });
912 }
913
914 Ok(&buf[end..])
915}