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