1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
4 * All rights reserved.
5 ******************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include "tss2_mu.h"
12 #include "tss2_sys.h"
13 #include "tss2_esys.h"
14
15 #include "esys_types.h"
16 #include "esys_iutil.h"
17 #include "esys_mu.h"
18 #define LOGMODULE esys
19 #include "util/log.h"
20 #include "util/aux_util.h"
21
22 /** Store command parameters inside the ESYS_CONTEXT for use during _Finish */
store_input_parameters(ESYS_CONTEXT * esysContext,const TPM2B_SENSITIVE_CREATE * inSensitive,const TPM2B_TEMPLATE * inPublic)23 static void store_input_parameters (
24 ESYS_CONTEXT *esysContext,
25 const TPM2B_SENSITIVE_CREATE *inSensitive,
26 const TPM2B_TEMPLATE *inPublic)
27 {
28 if (inSensitive == NULL) {
29 esysContext->in.CreateLoaded.inSensitive = NULL;
30 } else {
31 esysContext->in.CreateLoaded.inSensitiveData = *inSensitive;
32 esysContext->in.CreateLoaded.inSensitive =
33 &esysContext->in.CreateLoaded.inSensitiveData;
34 }
35 if (inPublic == NULL) {
36 esysContext->in.CreateLoaded.inPublic = NULL;
37 } else {
38 esysContext->in.CreateLoaded.inPublicData = *inPublic;
39 esysContext->in.CreateLoaded.inPublic =
40 &esysContext->in.CreateLoaded.inPublicData;
41 }
42 }
43
44 /** One-Call function for TPM2_CreateLoaded
45 *
46 * This function invokes the TPM2_CreateLoaded command in a one-call
47 * variant. This means the function will block until the TPM response is
48 * available. All input parameters are const. The memory for non-simple output
49 * parameters is allocated by the function implementation.
50 *
51 * @param[in,out] esysContext The ESYS_CONTEXT.
52 * @param[in] parentHandle TPM2_Handle of a transient storage key, a persistent
53 * storage key, TPM2_RH_ENDORSEMENT, TPM2_RH_OWNER,
54 * TPM2_RH_PLATFORM+{PP}, or TPM2_RH_NULL.
55 * @param[in] shandle1 Session handle for authorization of parentHandle
56 * @param[in] shandle2 Second session handle.
57 * @param[in] shandle3 Third session handle.
58 * @param[in] inSensitive The sensitive data, see TPM 2.0 Part 1 Sensitive
59 * Values.
60 * @param[in] inPublic The public template.
61 * @param[out] outPrivate The sensitive area of the object (optional).
62 * (callee-allocated)
63 * @param[out] outPublic The public portion of the created object.
64 * (callee-allocated)
65 * @param[out] objectHandle ESYS_TR handle of ESYS resource for TPM2_HANDLE.
66 * @retval TSS2_RC_SUCCESS if the function call was a success.
67 * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
68 * pointers or required output handle references are NULL.
69 * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
70 * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
71 * internal operations or return parameters.
72 * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
73 * operation already pending.
74 * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
75 * at least contain the tag, response length, and response code.
76 * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
77 * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM
78 did not verify.
79 * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
80 * the 'decrypt' attribute bit set.
81 * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
82 * the 'encrypt' attribute bit set.
83 * @retval TSS2_ESYS_RC_BAD_TR: if any of the ESYS_TR objects are unknown
84 * to the ESYS_CONTEXT or are of the wrong type or if required
85 * ESYS_TR objects are ESYS_TR_NONE.
86 * @retval TSS2_RCs produced by lower layers of the software stack may be
87 * returned to the caller unaltered unless handled internally.
88 */
89 TSS2_RC
Esys_CreateLoaded(ESYS_CONTEXT * esysContext,ESYS_TR parentHandle,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_SENSITIVE_CREATE * inSensitive,const TPM2B_TEMPLATE * inPublic,ESYS_TR * objectHandle,TPM2B_PRIVATE ** outPrivate,TPM2B_PUBLIC ** outPublic)90 Esys_CreateLoaded(
91 ESYS_CONTEXT *esysContext,
92 ESYS_TR parentHandle,
93 ESYS_TR shandle1,
94 ESYS_TR shandle2,
95 ESYS_TR shandle3,
96 const TPM2B_SENSITIVE_CREATE *inSensitive,
97 const TPM2B_TEMPLATE *inPublic, ESYS_TR *objectHandle,
98 TPM2B_PRIVATE **outPrivate,
99 TPM2B_PUBLIC **outPublic)
100 {
101 TSS2_RC r;
102
103 r = Esys_CreateLoaded_Async(esysContext, parentHandle, shandle1, shandle2,
104 shandle3, inSensitive, inPublic);
105 return_if_error(r, "Error in async function");
106
107 /* Set the timeout to indefinite for now, since we want _Finish to block */
108 int32_t timeouttmp = esysContext->timeout;
109 esysContext->timeout = -1;
110 /*
111 * Now we call the finish function, until return code is not equal to
112 * from TSS2_BASE_RC_TRY_AGAIN.
113 * Note that the finish function may return TSS2_RC_TRY_AGAIN, even if we
114 * have set the timeout to -1. This occurs for example if the TPM requests
115 * a retransmission of the command via TPM2_RC_YIELDED.
116 */
117 do {
118 r = Esys_CreateLoaded_Finish(esysContext, objectHandle, outPrivate,
119 outPublic);
120 /* This is just debug information about the reattempt to finish the
121 command */
122 if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
123 LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32
124 " => resubmitting command", r);
125 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
126
127 /* Restore the timeout value to the original value */
128 esysContext->timeout = timeouttmp;
129 return_if_error(r, "Esys Finish");
130
131 return TSS2_RC_SUCCESS;
132 }
133
134 /** Asynchronous function for TPM2_CreateLoaded
135 *
136 * This function invokes the TPM2_CreateLoaded command in a asynchronous
137 * variant. This means the function will return as soon as the command has been
138 * sent downwards the stack to the TPM. All input parameters are const.
139 * In order to retrieve the TPM's response call Esys_CreateLoaded_Finish.
140 *
141 * @param[in,out] esysContext The ESYS_CONTEXT.
142 * @param[in] parentHandle TPM2_Handle of a transient storage key, a persistent
143 * storage key, TPM2_RH_ENDORSEMENT, TPM2_RH_OWNER,
144 * TPM2_RH_PLATFORM+{PP}, or TPM2_RH_NULL.
145 * @param[in] shandle1 Session handle for authorization of parentHandle
146 * @param[in] shandle2 Second session handle.
147 * @param[in] shandle3 Third session handle.
148 * @param[in] inSensitive The sensitive data, see TPM 2.0 Part 1 Sensitive
149 * Values.
150 * @param[in] inPublic The public template.
151 * @retval ESYS_RC_SUCCESS if the function call was a success.
152 * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
153 * pointers or required output handle references are NULL.
154 * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
155 * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
156 * internal operations or return parameters.
157 * @retval TSS2_RCs produced by lower layers of the software stack may be
158 returned to the caller unaltered unless handled internally.
159 * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
160 * the 'decrypt' attribute bit set.
161 * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
162 * the 'encrypt' attribute bit set.
163 * @retval TSS2_ESYS_RC_BAD_TR: if any of the ESYS_TR objects are unknown
164 * to the ESYS_CONTEXT or are of the wrong type or if required
165 * ESYS_TR objects are ESYS_TR_NONE.
166 */
167 TSS2_RC
Esys_CreateLoaded_Async(ESYS_CONTEXT * esysContext,ESYS_TR parentHandle,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_SENSITIVE_CREATE * inSensitive,const TPM2B_TEMPLATE * inPublic)168 Esys_CreateLoaded_Async(
169 ESYS_CONTEXT *esysContext,
170 ESYS_TR parentHandle,
171 ESYS_TR shandle1,
172 ESYS_TR shandle2,
173 ESYS_TR shandle3,
174 const TPM2B_SENSITIVE_CREATE *inSensitive,
175 const TPM2B_TEMPLATE *inPublic)
176 {
177 TSS2_RC r;
178 LOG_TRACE("context=%p, parentHandle=%"PRIx32 ", inSensitive=%p,"
179 "inPublic=%p",
180 esysContext, parentHandle, inSensitive, inPublic);
181 TSS2L_SYS_AUTH_COMMAND auths;
182 RSRC_NODE_T *parentHandleNode;
183
184 /* Check context, sequence correctness and set state to error for now */
185 if (esysContext == NULL) {
186 LOG_ERROR("esyscontext is NULL.");
187 return TSS2_ESYS_RC_BAD_REFERENCE;
188 }
189 r = iesys_check_sequence_async(esysContext);
190 if (r != TSS2_RC_SUCCESS)
191 return r;
192 esysContext->state = _ESYS_STATE_INTERNALERROR;
193
194 /* Check input parameters */
195 r = check_session_feasibility(shandle1, shandle2, shandle3, 1);
196 return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage");
197 store_input_parameters(esysContext, inSensitive, inPublic);
198
199 /* Retrieve the metadata objects for provided handles */
200 r = esys_GetResourceObject(esysContext, parentHandle, &parentHandleNode);
201 return_state_if_error(r, _ESYS_STATE_INIT, "parentHandle unknown.");
202
203 /* Initial invocation of SAPI to prepare the command buffer with parameters */
204 r = Tss2_Sys_CreateLoaded_Prepare(esysContext->sys,
205 (parentHandleNode == NULL) ? TPM2_RH_NULL
206 : parentHandleNode->rsrc.handle,
207 inSensitive, inPublic);
208 return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error.");
209
210 /* Calculate the cpHash Values */
211 r = init_session_tab(esysContext, shandle1, shandle2, shandle3);
212 return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources");
213 if (parentHandleNode != NULL)
214 iesys_compute_session_value(esysContext->session_tab[0],
215 &parentHandleNode->rsrc.name, &parentHandleNode->auth);
216 else
217 iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL);
218
219 iesys_compute_session_value(esysContext->session_tab[1], NULL, NULL);
220 iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL);
221
222 /* Generate the auth values and set them in the SAPI command buffer */
223 r = iesys_gen_auths(esysContext, parentHandleNode, NULL, NULL, &auths);
224 return_state_if_error(r, _ESYS_STATE_INIT,
225 "Error in computation of auth values");
226
227 esysContext->authsCount = auths.count;
228 if (auths.count > 0) {
229 r = Tss2_Sys_SetCmdAuths(esysContext->sys, &auths);
230 return_state_if_error(r, _ESYS_STATE_INIT, "SAPI error on SetCmdAuths");
231 }
232
233 /* Trigger execution and finish the async invocation */
234 r = Tss2_Sys_ExecuteAsync(esysContext->sys);
235 return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
236 "Finish (Execute Async)");
237
238 esysContext->state = _ESYS_STATE_SENT;
239
240 return r;
241 }
242
243 /** Asynchronous finish function for TPM2_CreateLoaded
244 *
245 * This function returns the results of a TPM2_CreateLoaded command
246 * invoked via Esys_CreateLoaded_Finish. All non-simple output parameters
247 * are allocated by the function's implementation. NULL can be passed for every
248 * output parameter if the value is not required.
249 *
250 * @param[in,out] esysContext The ESYS_CONTEXT.
251 * @param[out] outPrivate The sensitive area of the object (optional).
252 * (callee-allocated)
253 * @param[out] outPublic The public portion of the created object.
254 * (callee-allocated)
255 * @param[out] objectHandle ESYS_TR handle of ESYS resource for TPM2_HANDLE.
256 * @retval TSS2_RC_SUCCESS on success
257 * @retval ESYS_RC_SUCCESS if the function call was a success.
258 * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
259 * pointers or required output handle references are NULL.
260 * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
261 * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
262 * internal operations or return parameters.
263 * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
264 * operation already pending.
265 * @retval TSS2_ESYS_RC_TRY_AGAIN: if the timeout counter expires before the
266 * TPM response is received.
267 * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
268 * at least contain the tag, response length, and response code.
269 * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM did
270 * not verify.
271 * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
272 * @retval TSS2_RCs produced by lower layers of the software stack may be
273 * returned to the caller unaltered unless handled internally.
274 */
275 TSS2_RC
Esys_CreateLoaded_Finish(ESYS_CONTEXT * esysContext,ESYS_TR * objectHandle,TPM2B_PRIVATE ** outPrivate,TPM2B_PUBLIC ** outPublic)276 Esys_CreateLoaded_Finish(
277 ESYS_CONTEXT *esysContext, ESYS_TR *objectHandle,
278 TPM2B_PRIVATE **outPrivate,
279 TPM2B_PUBLIC **outPublic)
280 {
281 TPM2B_PUBLIC *loutPublic = NULL;
282 TSS2_RC r;
283 LOG_TRACE("context=%p, objectHandle=%p, outPrivate=%p,"
284 "outPublic=%p",
285 esysContext, objectHandle, outPrivate,
286 outPublic);
287
288 if (esysContext == NULL) {
289 LOG_ERROR("esyscontext is NULL.");
290 return TSS2_ESYS_RC_BAD_REFERENCE;
291 }
292
293 /* Check for correct sequence and set sequence to irregular for now */
294 if (esysContext->state != _ESYS_STATE_SENT &&
295 esysContext->state != _ESYS_STATE_RESUBMISSION) {
296 LOG_ERROR("Esys called in bad sequence.");
297 return TSS2_ESYS_RC_BAD_SEQUENCE;
298 }
299 esysContext->state = _ESYS_STATE_INTERNALERROR;
300 TPM2B_NAME name;
301 RSRC_NODE_T *objectHandleNode = NULL;
302
303 /* Allocate memory for response parameters */
304 if (objectHandle == NULL) {
305 LOG_ERROR("Handle objectHandle may not be NULL");
306 return TSS2_ESYS_RC_BAD_REFERENCE;
307 }
308 *objectHandle = esysContext->esys_handle_cnt++;
309 r = esys_CreateResourceObject(esysContext, *objectHandle, &objectHandleNode);
310 if (r != TSS2_RC_SUCCESS)
311 return r;
312
313 if (outPrivate != NULL) {
314 *outPrivate = calloc(sizeof(TPM2B_PRIVATE), 1);
315 if (*outPrivate == NULL) {
316 goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup);
317 }
318 }
319 loutPublic = calloc(sizeof(TPM2B_PUBLIC), 1);
320 if (loutPublic == NULL) {
321 goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup);
322 }
323
324 /*Receive the TPM response and handle resubmissions if necessary. */
325 r = Tss2_Sys_ExecuteFinish(esysContext->sys, esysContext->timeout);
326 if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
327 LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32, r);
328 esysContext->state = _ESYS_STATE_SENT;
329 goto error_cleanup;
330 }
331 /* This block handle the resubmission of TPM commands given a certain set of
332 * TPM response codes. */
333 if (r == TPM2_RC_RETRY || r == TPM2_RC_TESTING || r == TPM2_RC_YIELDED) {
334 LOG_DEBUG("TPM returned RETRY, TESTING or YIELDED, which triggers a "
335 "resubmission: %" PRIx32, r);
336 if (esysContext->submissionCount++ >= _ESYS_MAX_SUBMISSIONS) {
337 LOG_WARNING("Maximum number of (re)submissions has been reached.");
338 esysContext->state = _ESYS_STATE_INIT;
339 goto error_cleanup;
340 }
341 esysContext->state = _ESYS_STATE_RESUBMISSION;
342 r = Tss2_Sys_ExecuteAsync(esysContext->sys);
343 if (r != TSS2_RC_SUCCESS) {
344 LOG_WARNING("Error attempting to resubmit");
345 /* We do not set esysContext->state here but inherit the most recent
346 * state of the _async function. */
347 goto error_cleanup;
348 }
349 r = TSS2_ESYS_RC_TRY_AGAIN;
350 LOG_DEBUG("Resubmission initiated and returning RC_TRY_AGAIN.");
351 goto error_cleanup;
352 }
353 /* The following is the "regular error" handling. */
354 if (iesys_tpm_error(r)) {
355 LOG_WARNING("Received TPM Error");
356 esysContext->state = _ESYS_STATE_INIT;
357 goto error_cleanup;
358 } else if (r != TSS2_RC_SUCCESS) {
359 LOG_ERROR("Received a non-TPM Error");
360 esysContext->state = _ESYS_STATE_INTERNALERROR;
361 goto error_cleanup;
362 }
363
364 /*
365 * Now the verification of the response (hmac check) and if necessary the
366 * parameter decryption have to be done.
367 */
368 r = iesys_check_response(esysContext);
369 goto_state_if_error(r, _ESYS_STATE_INTERNALERROR, "Error: check response",
370 error_cleanup);
371
372 /*
373 * After the verification of the response we call the complete function
374 * to deliver the result.
375 */
376 r = Tss2_Sys_CreateLoaded_Complete(esysContext->sys,
377 &objectHandleNode->rsrc.handle,
378 (outPrivate != NULL) ? *outPrivate : NULL,
379 loutPublic, &name);
380 goto_state_if_error(r, _ESYS_STATE_INTERNALERROR,
381 "Received error from SAPI unmarshaling" ,
382 error_cleanup);
383
384
385 /* Update the meta data of the ESYS_TR object */
386 objectHandleNode->rsrc.rsrcType = IESYSC_KEY_RSRC;
387 objectHandleNode->rsrc.misc.rsrc_key_pub = *loutPublic;
388
389 /* Check name and outPublic for consistency */
390 if (!iesys_compare_name(&objectHandleNode->rsrc.misc.rsrc_key_pub, &name))
391 goto_error(r, TSS2_ESYS_RC_MALFORMED_RESPONSE,
392 "in Public name not equal name in response", error_cleanup);
393
394 /* Update the meta data of the ESYS_TR object */
395 objectHandleNode->rsrc.name = name;
396 objectHandleNode->auth = esysContext->in.CreateLoaded.inSensitive->sensitive.userAuth;
397 if (outPublic != NULL)
398 *outPublic = loutPublic;
399 else
400 SAFE_FREE(loutPublic);
401
402 esysContext->state = _ESYS_STATE_INIT;
403
404 return TSS2_RC_SUCCESS;
405
406 error_cleanup:
407 Esys_TR_Close(esysContext, objectHandle);
408 if (outPrivate != NULL)
409 SAFE_FREE(*outPrivate);
410 SAFE_FREE(loutPublic);
411
412 return r;
413 }
414