tpm2_protocol/message/
parse.rs1use super::{
6 TpmAuthCommands, TpmAuthResponses, TpmCommandBody, TpmHandles, TpmResponseBody,
7 PARSE_COMMAND_MAP, PARSE_RESPONSE_MAP, TPM_HEADER_SIZE,
8};
9use crate::{
10 data::{TpmCc, TpmRc, TpmSt, TpmsAuthCommand, TpmsAuthResponse},
11 TpmErrorKind, TpmNotDiscriminant, TpmParse, TpmResult, TPM_MAX_COMMAND_SIZE,
12};
13use core::{convert::TryFrom, mem::size_of};
14
15pub type TpmParseResult<'a> = Result<(TpmRc, TpmResponseBody, TpmAuthResponses), (TpmRc, &'a [u8])>;
18
19pub fn tpm_parse_command(buf: &[u8]) -> TpmResult<(TpmHandles, TpmCommandBody, TpmAuthCommands)> {
27 if buf.len() < TPM_HEADER_SIZE {
28 return Err(TpmErrorKind::ParseUnderflow);
29 }
30 let command_len = buf.len();
31
32 let (tag_raw, buf) = u16::parse(buf)?;
33 let tag = TpmSt::try_from(tag_raw).map_err(|()| {
34 TpmErrorKind::NotDiscriminant("TpmSt", TpmNotDiscriminant::Unsigned(u64::from(tag_raw)))
35 })?;
36 let (size, buf) = u32::parse(buf)?;
37 let (cc_raw, body_buf) = u32::parse(buf)?;
38
39 if command_len != size as usize {
40 return Err(TpmErrorKind::ParseUnderflow);
41 }
42
43 let cc = TpmCc::try_from(cc_raw).map_err(|()| {
44 TpmErrorKind::NotDiscriminant("TpmCc", TpmNotDiscriminant::Unsigned(u64::from(cc_raw)))
45 })?;
46 let dispatch = PARSE_COMMAND_MAP
47 .binary_search_by_key(&cc, |d| d.0)
48 .map(|index| &PARSE_COMMAND_MAP[index])
49 .map_err(|_| {
50 TpmErrorKind::NotDiscriminant("TpmCc", TpmNotDiscriminant::Unsigned(u64::from(cc_raw)))
51 })?;
52
53 if tag == TpmSt::Sessions && !dispatch.2 {
54 return Err(TpmErrorKind::InvalidTag {
55 type_name: "TpmSt",
56 expected: TpmSt::NoSessions as u16,
57 got: tag_raw,
58 });
59 }
60 if tag == TpmSt::NoSessions && !dispatch.1 {
61 return Err(TpmErrorKind::InvalidTag {
62 type_name: "TpmSt",
63 expected: TpmSt::Sessions as u16,
64 got: tag_raw,
65 });
66 }
67
68 let handle_area_size = dispatch.3 * size_of::<u32>();
69 if body_buf.len() < handle_area_size {
70 return Err(TpmErrorKind::ParseUnderflow);
71 }
72 let (handle_area, after_handles) = body_buf.split_at(handle_area_size);
73
74 let mut sessions = TpmAuthCommands::new();
75 let param_area = if tag == TpmSt::Sessions {
76 let (auth_area_size, buf_after_auth_size) = u32::parse(after_handles)?;
77 let auth_area_size = auth_area_size as usize;
78 if buf_after_auth_size.len() < auth_area_size {
79 return Err(TpmErrorKind::ParseUnderflow);
80 }
81 let (mut auth_area, param_area) = buf_after_auth_size.split_at(auth_area_size);
82 while !auth_area.is_empty() {
83 let (session, rest) = TpmsAuthCommand::parse(auth_area)?;
84 sessions
85 .try_push(session)
86 .map_err(|_| TpmErrorKind::ParseCapacity)?;
87 auth_area = rest;
88 }
89 if !auth_area.is_empty() {
90 return Err(TpmErrorKind::TrailingData);
91 }
92 param_area
93 } else {
94 after_handles
95 };
96
97 let mut temp_body_buf = [0u8; TPM_MAX_COMMAND_SIZE];
98 let full_body_len = handle_area.len() + param_area.len();
99 if full_body_len > temp_body_buf.len() {
100 return Err(TpmErrorKind::ParseCapacity);
101 }
102 let full_body_for_parser = &mut temp_body_buf[..full_body_len];
103 full_body_for_parser[..handle_area.len()].copy_from_slice(handle_area);
104 full_body_for_parser[handle_area.len()..].copy_from_slice(param_area);
105
106 let (command_data, remainder) = (dispatch.4)(full_body_for_parser)?;
107
108 if !remainder.is_empty() {
109 return Err(TpmErrorKind::TrailingData);
110 }
111
112 let mut handles = TpmHandles::new();
113 let mut temp_handle_cursor = handle_area;
114 while !temp_handle_cursor.is_empty() {
115 let (handle, rest) = u32::parse(temp_handle_cursor)?;
116 handles.try_push(handle)?;
117 temp_handle_cursor = rest;
118 }
119
120 Ok((handles, command_data, sessions))
121}
122
123pub fn tpm_parse_response(cc: TpmCc, buf: &[u8]) -> TpmResult<TpmParseResult<'_>> {
132 if buf.len() < TPM_HEADER_SIZE {
133 return Err(TpmErrorKind::ParseUnderflow);
134 }
135
136 let (tag_raw, remainder) = u16::parse(buf)?;
137 let (size, remainder) = u32::parse(remainder)?;
138 let (code, body_buf) = u32::parse(remainder)?;
139
140 if buf.len() != size as usize {
141 return Err(TpmErrorKind::ParseUnderflow);
142 }
143
144 let rc = TpmRc::try_from(code)?;
145 if rc.is_error() {
146 return Ok(Err((rc, body_buf)));
147 }
148
149 let tag = TpmSt::try_from(tag_raw).map_err(|()| {
150 TpmErrorKind::NotDiscriminant("TpmSt", TpmNotDiscriminant::Unsigned(u64::from(tag_raw)))
151 })?;
152
153 let dispatch = PARSE_RESPONSE_MAP
154 .binary_search_by_key(&cc, |d| d.0)
155 .map(|index| &PARSE_RESPONSE_MAP[index])
156 .map_err(|_| {
157 TpmErrorKind::NotDiscriminant(
158 "TpmCc",
159 TpmNotDiscriminant::Unsigned(u64::from(cc as u32)),
160 )
161 })?;
162
163 let (body, mut session_area) = (dispatch.2)(body_buf)?;
164
165 let mut auth_responses = TpmAuthResponses::new();
166 if tag == TpmSt::Sessions {
167 while !session_area.is_empty() {
168 let (session, rest) = TpmsAuthResponse::parse(session_area)?;
169 auth_responses
170 .try_push(session)
171 .map_err(|_| TpmErrorKind::ParseCapacity)?;
172 session_area = rest;
173 }
174 }
175
176 if !session_area.is_empty() {
177 return Err(TpmErrorKind::TrailingData);
178 }
179
180 Ok(Ok((rc, body, auth_responses)))
181}