1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36 //
37 // This file contains the entry function ExecuteCommand() which provides the main
38 // control flow for TPM command execution.
39
40 //** Includes
41
42 #include "Tpm.h"
43 #include "ExecCommand_fp.h"
44
45 // Uncomment this next #include if doing static command/response buffer sizing
46 // #include "CommandResponseSizes_fp.h"
47
48 //** ExecuteCommand()
49 //
50 // The function performs the following steps.
51 //
52 // a) Parses the command header from input buffer.
53 // b) Calls ParseHandleBuffer() to parse the handle area of the command.
54 // c) Validates that each of the handles references a loaded entity.
55 // d) Calls ParseSessionBuffer () to:
56 // 1) unmarshal and parse the session area;
57 // 2) check the authorizations; and
58 // 3) when necessary, decrypt a parameter.
59 // e) Calls CommandDispatcher() to:
60 // 1) unmarshal the command parameters from the command buffer;
61 // 2) call the routine that performs the command actions; and
62 // 3) marshal the responses into the response buffer.
63 // f) If any error occurs in any of the steps above create the error response
64 // and return.
65 // g) Calls BuildResponseSession() to:
66 // 1) when necessary, encrypt a parameter
67 // 2) build the response authorization sessions
68 // 3) update the audit sessions and nonces
69 // h) Calls BuildResponseHeader() to complete the construction of the response.
70 //
71 // 'responseSize' is set by the caller to the maximum number of bytes available in
72 // the output buffer. ExecuteCommand will adjust the value and return the number
73 // of bytes placed in the buffer.
74 //
75 // 'response' is also set by the caller to indicate the buffer into which
76 // ExecuteCommand is to place the response.
77 //
78 // 'request' and 'response' may point to the same buffer
79 //
80 // Note: As of February, 2016, the failure processing has been moved to the
81 // platform-specific code. When the TPM code encounters an unrecoverable failure, it
82 // will SET g_inFailureMode and call _plat__Fail(). That function should not return
83 // but may call ExecuteCommand().
84 //
85 LIB_EXPORT void
ExecuteCommand(uint32_t requestSize,unsigned char * request,uint32_t * responseSize,unsigned char ** response)86 ExecuteCommand(
87 uint32_t requestSize, // IN: command buffer size
88 unsigned char *request, // IN: command buffer
89 uint32_t *responseSize, // IN/OUT: response buffer size
90 unsigned char **response // IN/OUT: response buffer
91 )
92 {
93 // Command local variables
94 UINT32 commandSize;
95 COMMAND command;
96
97 // Response local variables
98 UINT32 maxResponse = *responseSize;
99 TPM_RC result; // return code for the command
100
101 // This next function call is used in development to size the command and response
102 // buffers. The values printed are the sizes of the internal structures and
103 // not the sizes of the canonical forms of the command response structures. Also,
104 // the sizes do not include the tag, command.code, requestSize, or the authorization
105 // fields.
106 //CommandResponseSizes();
107 // Set flags for NV access state. This should happen before any other
108 // operation that may require a NV write. Note, that this needs to be done
109 // even when in failure mode. Otherwise, g_updateNV would stay SET while in
110 // Failure mode and the NV would be written on each call.
111 g_updateNV = UT_NONE;
112 g_clearOrderly = FALSE;
113 if(g_inFailureMode)
114 {
115 // Do failure mode processing
116 TpmFailureMode(requestSize, request, responseSize, response);
117 return;
118 }
119 // Query platform to get the NV state. The result state is saved internally
120 // and will be reported by NvIsAvailable(). The reference code requires that
121 // accessibility of NV does not change during the execution of a command.
122 // Specifically, if NV is available when the command execution starts and then
123 // is not available later when it is necessary to write to NV, then the TPM
124 // will go into failure mode.
125 NvCheckState();
126
127 // Due to the limitations of the simulation, TPM clock must be explicitly
128 // synchronized with the system clock whenever a command is received.
129 // This function call is not necessary in a hardware TPM. However, taking
130 // a snapshot of the hardware timer at the beginning of the command allows
131 // the time value to be consistent for the duration of the command execution.
132 TimeUpdateToCurrent();
133
134 // Any command through this function will unceremoniously end the
135 // _TPM_Hash_Data/_TPM_Hash_End sequence.
136 if(g_DRTMHandle != TPM_RH_UNASSIGNED)
137 ObjectTerminateEvent();
138
139 // Get command buffer size and command buffer.
140 command.parameterBuffer = request;
141 command.parameterSize = requestSize;
142
143 // Parse command header: tag, commandSize and command.code.
144 // First parse the tag. The unmarshaling routine will validate
145 // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
146 result = TPMI_ST_COMMAND_TAG_Unmarshal(&command.tag,
147 &command.parameterBuffer,
148 &command.parameterSize);
149 if(result != TPM_RC_SUCCESS)
150 goto Cleanup;
151 // Unmarshal the commandSize indicator.
152 result = UINT32_Unmarshal(&commandSize,
153 &command.parameterBuffer,
154 &command.parameterSize);
155 if(result != TPM_RC_SUCCESS)
156 goto Cleanup;
157 // On a TPM that receives bytes on a port, the number of bytes that were
158 // received on that port is requestSize it must be identical to commandSize.
159 // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
160 // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
161 // as the input processing (the function that receives the command bytes and
162 // places them in the input buffer) would likely have the input truncated when
163 // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
164 if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
165 {
166 result = TPM_RC_COMMAND_SIZE;
167 goto Cleanup;
168 }
169 // Unmarshal the command code.
170 result = TPM_CC_Unmarshal(&command.code, &command.parameterBuffer,
171 &command.parameterSize);
172 if(result != TPM_RC_SUCCESS)
173 goto Cleanup;
174 // Check to see if the command is implemented.
175 command.index = CommandCodeToCommandIndex(command.code);
176 if(UNIMPLEMENTED_COMMAND_INDEX == command.index)
177 {
178 result = TPM_RC_COMMAND_CODE;
179 goto Cleanup;
180 }
181 #if FIELD_UPGRADE_IMPLEMENTED == YES
182 // If the TPM is in FUM, then the only allowed command is
183 // TPM_CC_FieldUpgradeData.
184 if(IsFieldUgradeMode() && (command.code != TPM_CC_FieldUpgradeData))
185 {
186 result = TPM_RC_UPGRADE;
187 goto Cleanup;
188 }
189 else
190 #endif
191 // Excepting FUM, the TPM only accepts TPM2_Startup() after
192 // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
193 // is no longer allowed.
194 if((!TPMIsStarted() && command.code != TPM_CC_Startup)
195 || (TPMIsStarted() && command.code == TPM_CC_Startup))
196 {
197 result = TPM_RC_INITIALIZE;
198 goto Cleanup;
199 }
200 // Start regular command process.
201 NvIndexCacheInit();
202 // Parse Handle buffer.
203 result = ParseHandleBuffer(&command);
204 if(result != TPM_RC_SUCCESS)
205 goto Cleanup;
206 // All handles in the handle area are required to reference TPM-resident
207 // entities.
208 result = EntityGetLoadStatus(&command);
209 if(result != TPM_RC_SUCCESS)
210 goto Cleanup;
211 // Authorization session handling for the command.
212 ClearCpRpHashes(&command);
213 if(command.tag == TPM_ST_SESSIONS)
214 {
215 // Find out session buffer size.
216 result = UINT32_Unmarshal((UINT32 *)&command.authSize,
217 &command.parameterBuffer,
218 &command.parameterSize);
219 if(result != TPM_RC_SUCCESS)
220 goto Cleanup;
221 // Perform sanity check on the unmarshaled value. If it is smaller than
222 // the smallest possible session or larger than the remaining size of
223 // the command, then it is an error. NOTE: This check could pass but the
224 // session size could still be wrong. That will be determined after the
225 // sessions are unmarshaled.
226 if(command.authSize < 9
227 || command.authSize > command.parameterSize)
228 {
229 result = TPM_RC_SIZE;
230 goto Cleanup;
231 }
232 command.parameterSize -= command.authSize;
233
234 // The actions of ParseSessionBuffer() are described in the introduction.
235 // As the sessions are parsed command.parameterBuffer is advanced so, on a
236 // successful return, command.parameterBuffer should be pointing at the
237 // first byte of the parameters.
238 result = ParseSessionBuffer(&command);
239 if(result != TPM_RC_SUCCESS)
240 goto Cleanup;
241 }
242 else
243 {
244 command.authSize = 0;
245 // The command has no authorization sessions.
246 // If the command requires authorizations, then CheckAuthNoSession() will
247 // return an error.
248 result = CheckAuthNoSession(&command);
249 if(result != TPM_RC_SUCCESS)
250 goto Cleanup;
251 }
252 // Set up the response buffer pointers. CommandDispatch will marshal the
253 // response parameters starting at the address in command.responseBuffer.
254 //*response = MemoryGetResponseBuffer(command.index);
255 // leave space for the command header
256 command.responseBuffer = *response + STD_RESPONSE_HEADER;
257
258 // leave space for the parameter size field if needed
259 if(command.tag == TPM_ST_SESSIONS)
260 command.responseBuffer += sizeof(UINT32);
261 if(IsHandleInResponse(command.index))
262 command.responseBuffer += sizeof(TPM_HANDLE);
263
264 // CommandDispatcher returns a response handle buffer and a response parameter
265 // buffer if it succeeds. It will also set the parameterSize field in the
266 // buffer if the tag is TPM_RC_SESSIONS.
267 result = CommandDispatcher(&command);
268 if(result != TPM_RC_SUCCESS)
269 goto Cleanup;
270
271 // Build the session area at the end of the parameter area.
272 BuildResponseSession(&command);
273
274 Cleanup:
275 if(g_clearOrderly == TRUE
276 && NV_IS_ORDERLY)
277 {
278 #if USE_DA_USED
279 gp.orderlyState = g_daUsed ? SU_DA_USED_VALUE : SU_NONE_VALUE;
280 #else
281 gp.orderlyState = SU_NONE_VALUE;
282 #endif
283 NV_SYNC_PERSISTENT(orderlyState);
284 }
285 // This implementation loads an "evict" object to a transient object slot in
286 // RAM whenever an "evict" object handle is used in a command so that the
287 // access to any object is the same. These temporary objects need to be
288 // cleared from RAM whether the command succeeds or fails.
289 ObjectCleanupEvict();
290
291 // The parameters and sessions have been marshaled. Now tack on the header and
292 // set the sizes
293 BuildResponseHeader(&command, *response, result);
294
295 // Try to commit all the writes to NV if any NV write happened during this
296 // command execution. This check should be made for both succeeded and failed
297 // commands, because a failed one may trigger a NV write in DA logic as well.
298 // This is the only place in the command execution path that may call the NV
299 // commit. If the NV commit fails, the TPM should be put in failure mode.
300 if((g_updateNV != UT_NONE) && !g_inFailureMode)
301 {
302 if(g_updateNV == UT_ORDERLY)
303 NvUpdateIndexOrderlyData();
304 if(!NvCommit())
305 FAIL(FATAL_ERROR_INTERNAL);
306 g_updateNV = UT_NONE;
307 }
308 pAssert((UINT32)command.parameterSize <= maxResponse);
309
310 // Clear unused bits in response buffer.
311 MemorySet(*response + *responseSize, 0, maxResponse - *responseSize);
312
313 // as a final act, and not before, update the response size.
314 *responseSize = (UINT32)command.parameterSize;
315
316 return;
317 }