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