tpm2_protocol/frame/
wire.rs1use super::{TPM_DISPATCH_TABLE, TPM_HEADER_SIZE};
6use crate::{
7 TpmCast, TpmCastMut, TpmProtocolError, 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 TpmSt::try_from(read_u16(&self.0, TAG_OFFSET))
101 }
102
103 #[must_use]
105 pub fn size(&self) -> u32 {
106 read_u32(&self.0, SIZE_OFFSET)
107 }
108
109 pub fn cc(&self) -> TpmResult<TpmCc> {
116 command_code(&self.0)
117 }
118
119 pub fn set_tag(&mut self, tag: TpmSt) {
121 write_u16(&mut self.0, TAG_OFFSET, tag.value());
122 }
123
124 pub fn set_cc(&mut self, cc: TpmCc) -> TpmResult<()> {
131 let _ = dispatch_for(cc)?;
132
133 write_u32(&mut self.0, CODE_OFFSET, cc.value());
134 Ok(())
135 }
136
137 pub fn handles(&self) -> TpmResult<&[u8]> {
143 let range = self.handle_area_range()?;
144
145 Ok(&self.0[range])
146 }
147
148 pub fn handles_mut(&mut self) -> TpmResult<&mut [u8]> {
154 let range = self.handle_area_range()?;
155
156 Ok(&mut self.0[range])
157 }
158
159 pub fn auth_area(&self) -> TpmResult<&[u8]> {
166 let (auth_area, _) = self.session_and_parameter_ranges()?;
167
168 Ok(&self.0[auth_area])
169 }
170
171 pub fn auth_area_mut(&mut self) -> TpmResult<&mut [u8]> {
178 let (auth_area, _) = self.session_and_parameter_ranges()?;
179
180 Ok(&mut self.0[auth_area])
181 }
182
183 pub fn parameters(&self) -> TpmResult<&[u8]> {
189 let (_, parameters) = self.session_and_parameter_ranges()?;
190
191 Ok(&self.0[parameters])
192 }
193
194 pub fn parameters_mut(&mut self) -> TpmResult<&mut [u8]> {
200 let (_, parameters) = self.session_and_parameter_ranges()?;
201
202 Ok(&mut self.0[parameters])
203 }
204
205 pub fn validate(&self) -> TpmResult<()> {
211 Self::validate_envelope(&self.0)?;
212 validate_auth_commands(self.auth_area()?)
213 }
214
215 #[must_use]
217 pub const fn is_empty(&self) -> bool {
218 self.0.is_empty()
219 }
220
221 #[must_use]
223 pub const fn len(&self) -> usize {
224 self.0.len()
225 }
226
227 fn handle_area_range(&self) -> TpmResult<Range<usize>> {
228 let dispatch = dispatch_for(self.cc()?)?;
229 let handle_area_size = dispatch.handles * size_of::<u32>();
230
231 Ok(HEADER_SIZE..HEADER_SIZE + handle_area_size)
232 }
233
234 fn session_and_parameter_ranges(&self) -> TpmResult<(Range<usize>, Range<usize>)> {
235 let handle_area = self.handle_area_range()?;
236 let tag = self.tag()?;
237 let after_handles_start = handle_area.end;
238
239 if tag != TpmSt::Sessions {
240 return Ok((
241 after_handles_start..after_handles_start,
242 after_handles_start..self.0.len(),
243 ));
244 }
245
246 let after_handles = &self.0[after_handles_start..];
247
248 if after_handles.len() < size_of::<u32>() {
249 return Err(TpmProtocolError::UnexpectedEnd);
250 }
251
252 let auth_size = read_u32(after_handles, 0) as usize;
253 let auth_start = size_of::<u32>();
254 let auth_end = auth_start
255 .checked_add(auth_size)
256 .ok_or(TpmProtocolError::IntegerTooLarge)?;
257
258 if after_handles.len() < auth_end {
259 return Err(TpmProtocolError::UnexpectedEnd);
260 }
261
262 let auth_start = after_handles_start + auth_start;
263 let auth_end = after_handles_start + auth_end;
264
265 Ok((auth_start..auth_end, auth_end..self.0.len()))
266 }
267
268 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
269 validate_frame_size(buf)?;
270
271 let tag = TpmSt::try_from(read_u16(buf, TAG_OFFSET))?;
272 if tag != TpmSt::NoSessions && tag != TpmSt::Sessions {
273 return Err(TpmProtocolError::InvalidTag);
274 }
275
276 let dispatch = dispatch_for(command_code(buf)?)?;
277 let body = &buf[HEADER_SIZE..];
278 let handle_area_size = dispatch.handles * size_of::<u32>();
279
280 if body.len() < handle_area_size {
281 return Err(TpmProtocolError::UnexpectedEnd);
282 }
283
284 if tag == TpmSt::Sessions {
285 let after_handles = &body[handle_area_size..];
286 if after_handles.len() < size_of::<u32>() {
287 return Err(TpmProtocolError::UnexpectedEnd);
288 }
289
290 let auth_size = read_u32(after_handles, 0) as usize;
291 let auth_end = size_of::<u32>()
292 .checked_add(auth_size)
293 .ok_or(TpmProtocolError::IntegerTooLarge)?;
294
295 if after_handles.len() < auth_end {
296 return Err(TpmProtocolError::UnexpectedEnd);
297 }
298 }
299
300 Ok(())
301 }
302}
303
304impl TpmCast for TpmCommand {
305 fn cast(buf: &[u8]) -> TpmResult<&Self> {
306 Self::cast(buf)
307 }
308
309 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
310 unsafe { Self::cast_unchecked(buf) }
312 }
313}
314
315impl TpmCastMut for TpmCommand {
316 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
317 Self::cast_mut(buf)
318 }
319
320 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
321 unsafe { Self::cast_mut_unchecked(buf) }
324 }
325}
326
327impl AsRef<[u8]> for TpmCommand {
328 fn as_ref(&self) -> &[u8] {
329 self.as_bytes()
330 }
331}
332
333impl AsMut<[u8]> for TpmCommand {
334 fn as_mut(&mut self) -> &mut [u8] {
335 self.as_bytes_mut()
336 }
337}
338
339#[repr(transparent)]
341pub struct TpmResponse([u8]);
342
343impl TpmResponse {
344 pub fn cast(buf: &[u8]) -> TpmResult<&Self> {
350 Self::validate_envelope(buf)?;
351
352 Ok(unsafe { Self::cast_unchecked(buf) })
355 }
356
357 #[must_use]
364 pub unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
365 let ptr = core::ptr::from_ref(buf) as *const Self;
366
367 unsafe { &*ptr }
370 }
371
372 pub fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
378 Self::validate_envelope(buf)?;
379
380 Ok(unsafe { Self::cast_mut_unchecked(buf) })
384 }
385
386 #[must_use]
394 pub unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
395 let ptr = core::ptr::from_mut(buf) as *mut Self;
396
397 unsafe { &mut *ptr }
400 }
401
402 #[must_use]
404 pub const fn as_bytes(&self) -> &[u8] {
405 &self.0
406 }
407
408 #[must_use]
410 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
411 &mut self.0
412 }
413
414 pub fn tag(&self) -> TpmResult<TpmSt> {
421 TpmSt::try_from(read_u16(&self.0, TAG_OFFSET))
422 }
423
424 #[must_use]
426 pub fn size(&self) -> u32 {
427 read_u32(&self.0, SIZE_OFFSET)
428 }
429
430 pub fn rc(&self) -> TpmResult<TpmRc> {
436 TpmRc::try_from(read_u32(&self.0, CODE_OFFSET))
437 }
438
439 pub fn set_tag(&mut self, tag: TpmSt) {
441 write_u16(&mut self.0, TAG_OFFSET, tag.value());
442 }
443
444 pub fn set_rc(&mut self, rc: TpmRc) {
446 write_u32(&mut self.0, CODE_OFFSET, rc.value());
447 }
448
449 #[must_use]
451 pub fn body(&self) -> &[u8] {
452 &self.0[HEADER_SIZE..]
453 }
454
455 #[must_use]
457 pub fn body_mut(&mut self) -> &mut [u8] {
458 &mut self.0[HEADER_SIZE..]
459 }
460
461 pub fn validate(&self, cc: TpmCc) -> TpmResult<()> {
468 Self::validate_envelope(&self.0)?;
469 let dispatch = dispatch_for(cc)?;
470
471 if !matches!(self.rc()?, TpmRc::Fmt0(TpmRcBase::Success)) {
472 return Ok(());
473 }
474
475 if self.tag()? != TpmSt::Sessions {
476 return Ok(());
477 }
478
479 let handle_area_size = dispatch.response_handles * size_of::<u32>();
480 let body = self.body();
481 if body.len() < handle_area_size {
482 return Err(TpmProtocolError::UnexpectedEnd);
483 }
484
485 let after_handles = &body[handle_area_size..];
486 if after_handles.len() < size_of::<u32>() {
487 return Err(TpmProtocolError::UnexpectedEnd);
488 }
489
490 let params_len = read_u32(after_handles, 0) as usize;
491 let sessions_start = size_of::<u32>()
492 .checked_add(params_len)
493 .ok_or(TpmProtocolError::IntegerTooLarge)?;
494
495 if after_handles.len() < sessions_start {
496 return Err(TpmProtocolError::UnexpectedEnd);
497 }
498
499 validate_auth_responses(&after_handles[sessions_start..])
500 }
501
502 #[must_use]
504 pub const fn is_empty(&self) -> bool {
505 self.0.is_empty()
506 }
507
508 #[must_use]
510 pub const fn len(&self) -> usize {
511 self.0.len()
512 }
513
514 fn validate_envelope(buf: &[u8]) -> TpmResult<()> {
515 validate_frame_size(buf)?;
516 let _ = TpmSt::try_from(read_u16(buf, TAG_OFFSET))?;
517 let _ = TpmRc::try_from(read_u32(buf, CODE_OFFSET))?;
518
519 Ok(())
520 }
521}
522
523impl TpmCast for TpmResponse {
524 fn cast(buf: &[u8]) -> TpmResult<&Self> {
525 Self::cast(buf)
526 }
527
528 unsafe fn cast_unchecked(buf: &[u8]) -> &Self {
529 unsafe { Self::cast_unchecked(buf) }
531 }
532}
533
534impl TpmCastMut for TpmResponse {
535 fn cast_mut(buf: &mut [u8]) -> TpmResult<&mut Self> {
536 Self::cast_mut(buf)
537 }
538
539 unsafe fn cast_mut_unchecked(buf: &mut [u8]) -> &mut Self {
540 unsafe { Self::cast_mut_unchecked(buf) }
543 }
544}
545
546impl AsRef<[u8]> for TpmResponse {
547 fn as_ref(&self) -> &[u8] {
548 self.as_bytes()
549 }
550}
551
552impl AsMut<[u8]> for TpmResponse {
553 fn as_mut(&mut self) -> &mut [u8] {
554 self.as_bytes_mut()
555 }
556}
557
558fn command_code(buf: &[u8]) -> TpmResult<TpmCc> {
559 TpmCc::try_from(read_u32(buf, CODE_OFFSET)).map_err(|_| TpmProtocolError::InvalidCc)
560}
561
562fn dispatch_for(cc: TpmCc) -> TpmResult<&'static super::TpmDispatch> {
563 TPM_DISPATCH_TABLE
564 .binary_search_by_key(&cc, |d| d.cc)
565 .map(|index| &TPM_DISPATCH_TABLE[index])
566 .map_err(|_| TpmProtocolError::InvalidCc)
567}
568
569fn validate_frame_size(buf: &[u8]) -> TpmResult<()> {
570 if buf.len() < HEADER_SIZE {
571 return Err(TpmProtocolError::UnexpectedEnd);
572 }
573
574 let size = read_u32(buf, SIZE_OFFSET) as usize;
575 if buf.len() < size {
576 return Err(TpmProtocolError::UnexpectedEnd);
577 }
578
579 if buf.len() > size {
580 return Err(TpmProtocolError::TrailingData);
581 }
582
583 Ok(())
584}
585
586fn read_u16(buf: &[u8], offset: usize) -> u16 {
587 u16::from_be_bytes([buf[offset], buf[offset + 1]])
588}
589
590fn read_u32(buf: &[u8], offset: usize) -> u32 {
591 u32::from_be_bytes([
592 buf[offset],
593 buf[offset + 1],
594 buf[offset + 2],
595 buf[offset + 3],
596 ])
597}
598
599fn write_u16(buf: &mut [u8], offset: usize, value: u16) {
600 buf[offset..offset + size_of::<u16>()].copy_from_slice(&value.to_be_bytes());
601}
602
603fn write_u32(buf: &mut [u8], offset: usize, value: u32) {
604 buf[offset..offset + size_of::<u32>()].copy_from_slice(&value.to_be_bytes());
605}
606
607fn validate_auth_commands(mut buf: &[u8]) -> TpmResult<()> {
608 let mut count = 0;
609
610 while !buf.is_empty() {
611 if count >= MAX_SESSIONS {
612 return Err(TpmProtocolError::TooManyItems);
613 }
614
615 if buf.len() < size_of::<u32>() {
616 return Err(TpmProtocolError::UnexpectedEnd);
617 }
618
619 buf = &buf[size_of::<u32>()..];
620 buf = skip_tpm2b(buf)?;
621
622 if buf.is_empty() {
623 return Err(TpmProtocolError::UnexpectedEnd);
624 }
625
626 buf = &buf[1..];
627 buf = skip_tpm2b(buf)?;
628 count += 1;
629 }
630
631 Ok(())
632}
633
634fn validate_auth_responses(mut buf: &[u8]) -> TpmResult<()> {
635 let mut count = 0;
636
637 while !buf.is_empty() {
638 if count >= MAX_SESSIONS {
639 return Err(TpmProtocolError::TooManyItems);
640 }
641
642 buf = skip_tpm2b(buf)?;
643
644 if buf.is_empty() {
645 return Err(TpmProtocolError::UnexpectedEnd);
646 }
647
648 buf = &buf[1..];
649 buf = skip_tpm2b(buf)?;
650 count += 1;
651 }
652
653 Ok(())
654}
655
656fn skip_tpm2b(buf: &[u8]) -> TpmResult<&[u8]> {
657 if buf.len() < size_of::<u16>() {
658 return Err(TpmProtocolError::UnexpectedEnd);
659 }
660
661 let size = read_u16(buf, 0) as usize;
662 let end = size_of::<u16>()
663 .checked_add(size)
664 .ok_or(TpmProtocolError::IntegerTooLarge)?;
665
666 if buf.len() < end {
667 return Err(TpmProtocolError::UnexpectedEnd);
668 }
669
670 Ok(&buf[end..])
671}