• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / libtpms / #2014

04 Aug 2025 07:21PM UTC coverage: 76.783% (-0.4%) from 77.225%
#2014

push

travis-ci

web-flow
Merge 24cf223e7 into 925b06ee4

33895 of 44144 relevant lines covered (76.78%)

93978.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.4
/src/tpm2/ExecCommand.c
1
/********************************************************************************/
2
/*                                                                                */
3
/*                             ExecCommand                                        */
4
/*                             Written by Ken Goldman                                */
5
/*                       IBM Thomas J. Watson Research Center                        */
6
/*                                                                                */
7
/*  Licenses and Notices                                                        */
8
/*                                                                                */
9
/*  1. Copyright Licenses:                                                        */
10
/*                                                                                */
11
/*  - Trusted Computing Group (TCG) grants to the user of the source code in        */
12
/*    this specification (the "Source Code") a worldwide, irrevocable,                 */
13
/*    nonexclusive, royalty free, copyright license to reproduce, create         */
14
/*    derivative works, distribute, display and perform the Source Code and        */
15
/*    derivative works thereof, and to grant others the rights granted herein.        */
16
/*                                                                                */
17
/*  - The TCG grants to the user of the other parts of the specification         */
18
/*    (other than the Source Code) the rights to reproduce, distribute,         */
19
/*    display, and perform the specification solely for the purpose of                 */
20
/*    developing products based on such documents.                                */
21
/*                                                                                */
22
/*  2. Source Code Distribution Conditions:                                        */
23
/*                                                                                */
24
/*  - Redistributions of Source Code must retain the above copyright licenses,         */
25
/*    this list of conditions and the following disclaimers.                        */
26
/*                                                                                */
27
/*  - Redistributions in binary form must reproduce the above copyright         */
28
/*    licenses, this list of conditions        and the following disclaimers in the         */
29
/*    documentation and/or other materials provided with the distribution.        */
30
/*                                                                                */
31
/*  3. Disclaimers:                                                                */
32
/*                                                                                */
33
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF        */
34
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH        */
35
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)        */
36
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.                */
37
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for                 */
38
/*  information on specification licensing rights available through TCG         */
39
/*  membership agreements.                                                        */
40
/*                                                                                */
41
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED         */
42
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR         */
43
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR                 */
44
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY                 */
45
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.                */
46
/*                                                                                */
47
/*  - Without limitation, TCG and its members and licensors disclaim all         */
48
/*    liability, including liability for infringement of any proprietary         */
49
/*    rights, relating to use of information in this specification and to the        */
50
/*    implementation of this specification, and TCG disclaims all liability for        */
51
/*    cost of procurement of substitute goods or services, lost profits, loss         */
52
/*    of use, loss of data or any incidental, consequential, direct, indirect,         */
53
/*    or special damages, whether under contract, tort, warranty or otherwise,         */
54
/*    arising in any way out of use or reliance upon this specification or any         */
55
/*    information herein.                                                        */
56
/*                                                                                */
57
/*  (c) Copyright IBM Corp. and others, 2016 - 2023                                */
58
/*                                                                                */
59
/********************************************************************************/
60

61
/* 6.2 ExecCommand.c */
62
/* This file contains the entry function ExecuteCommand() which provides the main control flow for
63
   TPM command execution. */
64
#include "Tpm.h"
65
#include "ExecCommand_fp.h"
66

67
#define TPM_HAVE_TPM2_DECLARATIONS
68
#include "tpm_library_intern.h"  // libtpms added
69

70
/* Uncomment this next #include if doing static command/response buffer sizing */
71
// #include "CommandResponseSizes_fp.h"
72
// The function performs the following steps.
73
// a)        Parses the command header from input buffer.
74
// b)        Calls ParseHandleBuffer() to parse the handle area of the command.
75
//     c)        Validates that each of the handles references a loaded entity.
76
//     d)        Calls ParseSessionBuffer() () to:
77
// 1)        unmarshal and parse the session area;
78
// 2)        check the authorizations; and
79
// 3)        when necessary, decrypt a parameter.
80
//       e)        Calls CommandDispatcher() to:
81
// 1)        unmarshal the command parameters from the command buffer;
82
// 2)        call the routine that performs the command actions; and
83
// 3)        marshal the responses into the response buffer.
84
// f)        If any error occurs in any of the steps above create the error response and return.
85
// g)        Calls BuildResponseSession() to:
86
// 1)        when necessary, encrypt a parameter
87
//       2)        build the response authorization sessions
88
//       3)        update the audit sessions and nonces
89
//       h)        Calls BuildResponseHeader() to complete the construction of the response.
90

91
//           responseSize is set by the caller to the maximum number of bytes available in the output
92
//           buffer. ExecuteCommand() will adjust the value and return the number of bytes placed in
93
//           the buffer.
94
//           response is also set by the caller to indicate the buffer into which ExecuteCommand() is
95
//           to place the response.
96
//           request and response may point to the same buffer
97
//           NOTE: As of February, 2016, the failure processing has been moved to the platform-specific
98
//           code. When the TPM code encounters an unrecoverable failure, it will SET g_inFailureMode
99
//           and call _plat__Fail(). That function should not return but may call ExecuteCommand().
100
LIB_EXPORT void
101
ExecuteCommand(
17,107✔
102
               uint32_t         requestSize,   // IN: command buffer size
103
               unsigned char   *request,       // IN: command buffer
104
               uint32_t        *responseSize,  // IN/OUT: response buffer size
105
               unsigned char   **response      // IN/OUT: response buffer
106
               )
107
{
108
    // Command local variables
109
    UINT32               commandSize;
17,107✔
110
    COMMAND              command;
17,107✔
111
    // Response local variables
112
    UINT32               maxResponse = *responseSize;
17,107✔
113
    TPM_RC               result;            // return code for the command
17,107✔
114
    // This next function call is used in development to size the command and response
115
    // buffers. The values printed are the sizes of the internal structures and
116
    // not the sizes of the canonical forms of he command response structures. Also,
117
    // the sizes do not include the tag, command.code, requestSize, or the authorization
118
    // fields.
119
    //CommandResponseSizes();
120
    // Set flags for NV access state. This should happen before any other
121
    // operation that may require a NV write. Note, that this needs to be done
122
    // even when in failure mode. Otherwise, g_updateNV would stay SET while in
123
    // Failure mode and the NV would be written on each call.
124
    g_updateNV = UT_NONE;
17,107✔
125
    g_clearOrderly = FALSE;
17,107✔
126
    if(g_inFailureMode)
17,107✔
127
        {
128
            // Do failure mode processing
129
            TpmFailureMode(requestSize, request, responseSize, response);
×
130
            return;
×
131
        }
132
    // Query platform to get the NV state.  The result state is saved internally
133
    // and will be reported by NvIsAvailable(). The reference code requires that
134
    // accessibility of NV does not change during the execution of a command.
135
    // Specifically, if NV is available when the command execution starts and then
136
    // is not available later when it is necessary to write to NV, then the TPM
137
    // will go into failure mode.
138
    NvCheckState();
17,107✔
139
    // Due to the limitations of the simulation, TPM clock must be explicitly
140
    // synchronized with the system clock whenever a command is received.
141
    // This function call is not necessary in a hardware TPM. However, taking
142
    // a snapshot of the hardware timer at the beginning of the command allows
143
    // the time value to be consistent for the duration of the command execution.
144
    TimeUpdateToCurrent();
17,107✔
145
    // Any command through this function will unceremoniously end the
146
    // _TPM_Hash_Data/_TPM_Hash_End sequence.
147
    if(g_DRTMHandle != TPM_RH_UNASSIGNED)
17,107✔
148
        ObjectTerminateEvent();
×
149
    // Get command buffer size and command buffer.
150
    command.parameterBuffer = request;
17,107✔
151
    command.parameterSize = requestSize;
17,107✔
152
    // Parse command header: tag, commandSize and command.code.
153
    // First parse the tag. The unmarshaling routine will validate
154
    // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
155
    result = TPMI_ST_COMMAND_TAG_Unmarshal(&command.tag,
17,107✔
156
                                           &command.parameterBuffer,
157
                                           &command.parameterSize);
158
    if(result != TPM_RC_SUCCESS)
17,107✔
159
        goto Cleanup;
8✔
160
    // Unmarshal the commandSize indicator.
161
    result = UINT32_Unmarshal(&commandSize,
17,099✔
162
                              &command.parameterBuffer,
163
                              &command.parameterSize);
164
    if(result != TPM_RC_SUCCESS)
17,099✔
165
        goto Cleanup;
4✔
166
    // On a TPM that receives bytes on a port, the number of bytes that were
167
    // received on that port is requestSize it must be identical to commandSize.
168
    // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
169
    // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
170
    // as the input processing (the function that receives the command bytes and
171
    // places them in the input buffer) would likely have the input truncated when
172
    // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
173
    if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
17,095✔
174
        {
175
            result = TPM_RC_COMMAND_SIZE;
4✔
176
            goto Cleanup;
4✔
177
        }
178
    // Unmarshal the command code.
179
    result = TPM_CC_Unmarshal(&command.code, &command.parameterBuffer,
17,091✔
180
                              &command.parameterSize);
181
    if(result != TPM_RC_SUCCESS)
17,091✔
182
        goto Cleanup;
4✔
183
    // Check to see if the command is implemented.
184
    command.index = CommandCodeToCommandIndex(command.code);
17,087✔
185
    if(UNIMPLEMENTED_COMMAND_INDEX == command.index)
17,087✔
186
        {
187
            result = TPM_RC_COMMAND_CODE;
4✔
188
            goto Cleanup;
4✔
189
        }
190
#if  FIELD_UPGRADE_IMPLEMENTED  == YES
191
    // If the TPM is in FUM, then the only allowed command is
192
    // TPM_CC_FieldUpgradeData.
193
    if(IsFieldUgradeMode() && (command.code != TPM_CC_FieldUpgradeData))
194
        {
195
            result = TPM_RC_UPGRADE;
196
            goto Cleanup;
197
        }
198
    else
199
#endif
200
        // Excepting FUM, the TPM only accepts TPM2_Startup() after
201
        // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
202
        // is no longer allowed.
203
        if((!TPMIsStarted() && command.code != TPM_CC_Startup)
17,083✔
204
           || (TPMIsStarted() && command.code == TPM_CC_Startup))
17,060✔
205
            {
206
                result = TPM_RC_INITIALIZE;
34✔
207
                goto Cleanup;
34✔
208
            }
209
    // Start regular command process.
210
    NvIndexCacheInit();
17,049✔
211
    // Parse Handle buffer.
212
    result = ParseHandleBuffer(&command);
17,049✔
213
    if(result != TPM_RC_SUCCESS)
17,049✔
214
        goto Cleanup;
514✔
215
    // All handles in the handle area are required to reference TPM-resident
216
    // entities.
217
    result = EntityGetLoadStatus(&command);
16,535✔
218
    if(result != TPM_RC_SUCCESS)
16,535✔
219
        goto Cleanup;
374✔
220
    // Authorization session handling for the command.
221
    ClearCpRpHashes(&command);
16,161✔
222
    if(command.tag == TPM_ST_SESSIONS)
16,161✔
223
        {
224
            // Find out session buffer size.
225
            result = UINT32_Unmarshal((UINT32 *)&command.authSize,
6,096✔
226
                                      &command.parameterBuffer,
227
                                      &command.parameterSize);
228
            if(result != TPM_RC_SUCCESS)
6,096✔
229
                goto Cleanup;
4✔
230
            // Perform sanity check on the unmarshaled value. If it is smaller than
231
            // the smallest possible session or larger than the remaining size of
232
            // the command, then it is an error. NOTE: This check could pass but the
233
            // session size could still be wrong. That will be determined after the
234
            // sessions are unmarshaled.
235
            if(command.authSize < 9
6,092✔
236
               || command.authSize > command.parameterSize)
6,076✔
237
                {
238
                    result = TPM_RC_SIZE;
24✔
239
                    goto Cleanup;
24✔
240
                }
241
            command.parameterSize -= command.authSize;
6,068✔
242
            // The actions of ParseSessionBuffer() are described in the introduction.
243
            // As the sessions are parsed command.parameterBuffer is advanced so, on a
244
            // successful return, command.parameterBuffer should be pointing at the
245
            // first byte of the parameters.
246
            result = ParseSessionBuffer(&command);
6,068✔
247
            if(result != TPM_RC_SUCCESS)
6,068✔
248
                goto Cleanup;
275✔
249
        }
250
    else
251
        {
252
            command.authSize = 0;
10,065✔
253
            // The command has no authorization sessions.
254
            // If the command requires authorizations, then CheckAuthNoSession() will
255
            // return an error.
256
            result = CheckAuthNoSession(&command);
10,065✔
257
            if(result != TPM_RC_SUCCESS)
10,065✔
258
                goto Cleanup;
24✔
259
        }
260
    // Set up the response buffer pointers. CommandDispatch will marshal the
261
    // response parameters starting at the address in command.responseBuffer.
262
    //    *response = MemoryGetResponseBuffer(command.index);
263
    // leave space for the command header
264
    command.responseBuffer = *response + STD_RESPONSE_HEADER;
15,834✔
265
    // leave space for the parameter size field if needed
266
    if(command.tag == TPM_ST_SESSIONS)
15,834✔
267
        command.responseBuffer += sizeof(UINT32);
5,793✔
268
    if(IsHandleInResponse(command.index))
15,834✔
269
        command.responseBuffer += sizeof(TPM_HANDLE);
2,596✔
270
    // CommandDispatcher returns a response handle buffer and a response parameter
271
    // buffer if it succeeds. It will also set the parameterSize field in the
272
    // buffer if the tag is TPM_RC_SESSIONS.
273
    result = CommandDispatcher(&command);
15,834✔
274
    if(result != TPM_RC_SUCCESS)
15,834✔
275
        goto Cleanup;
1,922✔
276
    // Build the session area at the end of the parameter area.
277
    result = BuildResponseSession(&command);
13,912✔
278
    if(result != TPM_RC_SUCCESS)
13,912✔
279
        {
280
            goto Cleanup;
281
        }
282
 Cleanup:
13,912✔
283
    if(g_clearOrderly == TRUE
17,107✔
284
       && NV_IS_ORDERLY)
481✔
285
        {
286
#if USE_DA_USED
287
            gp.orderlyState = g_daUsed ? SU_DA_USED_VALUE : SU_NONE_VALUE;
2✔
288
#else
289
            gp.orderlyState = SU_NONE_VALUE;
290
#endif
291
            NV_SYNC_PERSISTENT(orderlyState);
2✔
292
        }
293
    // This implementation loads an "evict" object to a transient object slot in
294
    // RAM whenever an "evict" object handle is used in a command so that the
295
    // access to any object is the same. These temporary objects need to be
296
    // cleared from RAM whether the command succeeds or fails.
297
    ObjectCleanupEvict();
17,107✔
298
    // The parameters and sessions have been marshaled. Now tack on the header and
299
    // set the sizes
300
    BuildResponseHeader(&command, *response, result);
17,107✔
301
    // Try to commit all the writes to NV if any NV write happened during this
302
    // command execution. This check should be made for both succeeded and failed
303
    // commands, because a failed one may trigger a NV write in DA logic as well.
304
    // This is the only place in the command execution path that may call the NV
305
    // commit. If the NV commit fails, the TPM should be put in failure mode.
306
    if((g_updateNV != UT_NONE) && !g_inFailureMode)
17,107✔
307
        {
308
            if(g_updateNV == UT_ORDERLY)
6,385✔
309
                NvUpdateIndexOrderlyData();
11✔
310
            if(!NvCommit())
6,385✔
311
                FAIL(FATAL_ERROR_INTERNAL);
×
312
            g_updateNV = UT_NONE;
6,385✔
313
        }
314
    pAssert((UINT32)command.parameterSize <= maxResponse);
17,107✔
315
    // Clear unused bits in response buffer.
316
    MemorySet(*response + *responseSize, 0, maxResponse - *responseSize);
17,107✔
317
    // as a final act, and not before, update the response size.
318
    *responseSize = (UINT32)command.parameterSize;
17,107✔
319
    return;
17,107✔
320
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc