xref: /aosp_15_r20/external/ms-tpm-20-ref/TPMCmd/tpm/src/main/ExecCommand.c (revision 5c591343844d1f9da7da26467c4bf7efc8a7a413)
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 }