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