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,ESYS_TR tpmKey,ESYS_TR bind,const TPM2B_NONCE * nonceCaller,TPM2_SE sessionType,const TPMT_SYM_DEF * symmetric,TPMI_ALG_HASH authHash)23 static void store_input_parameters (
24     ESYS_CONTEXT *esysContext,
25     ESYS_TR tpmKey,
26     ESYS_TR bind,
27     const TPM2B_NONCE *nonceCaller,
28     TPM2_SE sessionType,
29     const TPMT_SYM_DEF *symmetric,
30     TPMI_ALG_HASH authHash)
31 {
32     esysContext->in.StartAuthSession.tpmKey = tpmKey;
33     esysContext->in.StartAuthSession.bind = bind;
34     esysContext->in.StartAuthSession.sessionType = sessionType;
35     esysContext->in.StartAuthSession.authHash = authHash;
36     if (nonceCaller == NULL) {
37         esysContext->in.StartAuthSession.nonceCaller = NULL;
38     } else {
39         esysContext->in.StartAuthSession.nonceCallerData = *nonceCaller;
40         esysContext->in.StartAuthSession.nonceCaller =
41             &esysContext->in.StartAuthSession.nonceCallerData;
42     }
43     if (symmetric == NULL) {
44         esysContext->in.StartAuthSession.symmetric = NULL;
45     } else {
46         esysContext->in.StartAuthSession.symmetricData = *symmetric;
47         esysContext->in.StartAuthSession.symmetric =
48             &esysContext->in.StartAuthSession.symmetricData;
49     }
50 }
51 
52 /** One-Call function for TPM2_StartAuthSession
53  *
54  * This function invokes the TPM2_StartAuthSession command in a one-call
55  * variant. This means the function will block until the TPM response is
56  * available. All input parameters are const. The memory for non-simple output
57  * parameters is allocated by the function implementation.
58  *
59  * @param[in,out] esysContext The ESYS_CONTEXT.
60  * @param[in]  tpmKey Handle of a loaded decrypt key used to encrypt salt.
61  * @param[in]  bind Entity providing the authValue.
62  * @param[in]  shandle1 First session handle.
63  * @param[in]  shandle2 Second session handle.
64  * @param[in]  shandle3 Third session handle.
65  * @param[in]  nonceCaller Initial nonceCaller, sets nonceTPM size for the
66  *             session.
67  * @param[in]  sessionType Indicates the type of the session; simple HMAC or
68  *             policy (including a trial policy).
69  * @param[in]  symmetric The algorithm and key size for parameter encryption.
70  * @param[in]  authHash Hash algorithm to use for the session.
71  * @param[out] sessionHandle  ESYS_TR handle of ESYS resource for TPMI_SH_AUTH_SESSION.
72  * @retval TSS2_RC_SUCCESS if the function call was a success.
73  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
74  *         pointers or required output handle references are NULL.
75  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
76  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
77  *         internal operations or return parameters.
78  * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
79  *         operation already pending.
80  * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
81  *          at least contain the tag, response length, and response code.
82  * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
83  * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM
84            did not verify.
85  * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
86  *         the 'decrypt' attribute bit set.
87  * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
88  *         the 'encrypt' attribute bit set.
89  * @retval TSS2_ESYS_RC_BAD_TR: if any of the ESYS_TR objects are unknown
90  *         to the ESYS_CONTEXT or are of the wrong type or if required
91  *         ESYS_TR objects are ESYS_TR_NONE.
92  * @retval TSS2_RCs produced by lower layers of the software stack may be
93  *         returned to the caller unaltered unless handled internally.
94  */
95 TSS2_RC
Esys_StartAuthSession(ESYS_CONTEXT * esysContext,ESYS_TR tpmKey,ESYS_TR bind,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_NONCE * nonceCaller,TPM2_SE sessionType,const TPMT_SYM_DEF * symmetric,TPMI_ALG_HASH authHash,ESYS_TR * sessionHandle)96 Esys_StartAuthSession(
97     ESYS_CONTEXT *esysContext,
98     ESYS_TR tpmKey,
99     ESYS_TR bind,
100     ESYS_TR shandle1,
101     ESYS_TR shandle2,
102     ESYS_TR shandle3,
103     const TPM2B_NONCE *nonceCaller,
104     TPM2_SE sessionType,
105     const TPMT_SYM_DEF *symmetric,
106     TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle)
107 {
108     TSS2_RC r;
109 
110     r = Esys_StartAuthSession_Async(esysContext, tpmKey, bind, shandle1,
111                                     shandle2, shandle3, nonceCaller, sessionType,
112                                     symmetric, authHash);
113     return_if_error(r, "Error in async function");
114 
115     /* Set the timeout to indefinite for now, since we want _Finish to block */
116     int32_t timeouttmp = esysContext->timeout;
117     esysContext->timeout = -1;
118     /*
119      * Now we call the finish function, until return code is not equal to
120      * from TSS2_BASE_RC_TRY_AGAIN.
121      * Note that the finish function may return TSS2_RC_TRY_AGAIN, even if we
122      * have set the timeout to -1. This occurs for example if the TPM requests
123      * a retransmission of the command via TPM2_RC_YIELDED.
124      */
125     do {
126         r = Esys_StartAuthSession_Finish(esysContext, sessionHandle);
127         /* This is just debug information about the reattempt to finish the
128            command */
129         if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
130             LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32
131                       " => resubmitting command", r);
132     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
133 
134     /* Restore the timeout value to the original value */
135     esysContext->timeout = timeouttmp;
136     return_if_error(r, "Esys Finish");
137 
138     return TSS2_RC_SUCCESS;
139 }
140 
141 /** Asynchronous function for TPM2_StartAuthSession
142  *
143  * This function invokes the TPM2_StartAuthSession command in a asynchronous
144  * variant. This means the function will return as soon as the command has been
145  * sent downwards the stack to the TPM. All input parameters are const.
146  * In order to retrieve the TPM's response call Esys_StartAuthSession_Finish.
147  *
148  * @param[in,out] esysContext The ESYS_CONTEXT.
149  * @param[in]  tpmKey Handle of a loaded decrypt key used to encrypt salt.
150  * @param[in]  bind Entity providing the authValue.
151  * @param[in]  shandle1 First session handle.
152  * @param[in]  shandle2 Second session handle.
153  * @param[in]  shandle3 Third session handle.
154  * @param[in]  nonceCaller Initial nonceCaller, sets nonceTPM size for the
155  *             session.
156  * @param[in]  sessionType Indicates the type of the session; simple HMAC or
157  *             policy (including a trial policy).
158  * @param[in]  symmetric The algorithm and key size for parameter encryption.
159  * @param[in]  authHash Hash algorithm to use for the session.
160  * @retval ESYS_RC_SUCCESS if the function call was a success.
161  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
162  *         pointers or required output handle references are NULL.
163  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
164  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
165  *         internal operations or return parameters.
166  * @retval TSS2_RCs produced by lower layers of the software stack may be
167            returned to the caller unaltered unless handled internally.
168  * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
169  *         the 'decrypt' attribute bit set.
170  * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
171  *         the 'encrypt' attribute bit set.
172  * @retval TSS2_ESYS_RC_BAD_TR: if any of the ESYS_TR objects are unknown
173  *         to the ESYS_CONTEXT or are of the wrong type or if required
174  *         ESYS_TR objects are ESYS_TR_NONE.
175  */
176 TSS2_RC
Esys_StartAuthSession_Async(ESYS_CONTEXT * esysContext,ESYS_TR tpmKey,ESYS_TR bind,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_NONCE * nonceCaller,TPM2_SE sessionType,const TPMT_SYM_DEF * symmetric,TPMI_ALG_HASH authHash)177 Esys_StartAuthSession_Async(
178     ESYS_CONTEXT *esysContext,
179     ESYS_TR tpmKey,
180     ESYS_TR bind,
181     ESYS_TR shandle1,
182     ESYS_TR shandle2,
183     ESYS_TR shandle3,
184     const TPM2B_NONCE *nonceCaller,
185     TPM2_SE sessionType,
186     const TPMT_SYM_DEF *symmetric,
187     TPMI_ALG_HASH authHash)
188 {
189     TSS2_RC r;
190     LOG_TRACE("context=%p, tpmKey=%"PRIx32 ", bind=%"PRIx32 ","
191               "nonceCaller=%p, sessionType=%02"PRIx8", symmetric=%p,"
192               "authHash=%04"PRIx16"",
193               esysContext, tpmKey, bind, nonceCaller, sessionType,
194               symmetric, authHash);
195     TPM2B_ENCRYPTED_SECRET encryptedSaltAux;
196     const TPM2B_ENCRYPTED_SECRET *encryptedSalt = &encryptedSaltAux;
197     TSS2L_SYS_AUTH_COMMAND auths;
198     RSRC_NODE_T *tpmKeyNode;
199     RSRC_NODE_T *bindNode;
200 
201     /* Check context, sequence correctness and set state to error for now */
202     if (esysContext == NULL) {
203         LOG_ERROR("esyscontext is NULL.");
204         return TSS2_ESYS_RC_BAD_REFERENCE;
205     }
206     r = iesys_check_sequence_async(esysContext);
207     if (r != TSS2_RC_SUCCESS)
208         return r;
209     esysContext->state = _ESYS_STATE_INTERNALERROR;
210 
211     /* Check input parameters */
212     r = check_session_feasibility(shandle1, shandle2, shandle3, 0);
213     return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage");
214     store_input_parameters(esysContext, tpmKey, bind, nonceCaller, sessionType,
215                            symmetric, authHash);
216 
217     /* Retrieve the metadata objects for provided handles */
218     r = esys_GetResourceObject(esysContext, tpmKey, &tpmKeyNode);
219     return_state_if_error(r, _ESYS_STATE_INIT, "tpmKey unknown.");
220     r = esys_GetResourceObject(esysContext, bind, &bindNode);
221     return_state_if_error(r, _ESYS_STATE_INIT, "bind unknown.");
222     size_t authHash_size = 0;
223     TSS2_RC r2;
224     r2 = iesys_compute_encrypted_salt(esysContext, tpmKeyNode,
225                                       &encryptedSaltAux);
226     return_state_if_error(r2, _ESYS_STATE_INIT, "Error in parameter encryption.");
227 
228     if (nonceCaller == NULL) {
229         r2 = iesys_crypto_hash_get_digest_size(authHash,&authHash_size);
230         return_state_if_error(r2, _ESYS_STATE_INIT, "Error in hash_get_digest_size.");
231 
232         r2 = iesys_crypto_random2b(&esysContext->in.StartAuthSession.nonceCallerData,
233                                    authHash_size);
234         return_state_if_error(r2, _ESYS_STATE_INIT, "Error in crypto_random2b.");
235         esysContext->in.StartAuthSession.nonceCaller
236            = &esysContext->in.StartAuthSession.nonceCallerData;
237         nonceCaller = esysContext->in.StartAuthSession.nonceCaller;
238     }
239 
240     /* Initial invocation of SAPI to prepare the command buffer with parameters */
241     r = Tss2_Sys_StartAuthSession_Prepare(esysContext->sys,
242                                           (tpmKeyNode == NULL) ? TPM2_RH_NULL
243                                            : tpmKeyNode->rsrc.handle,
244                                           (bindNode == NULL) ? TPM2_RH_NULL
245                                            : bindNode->rsrc.handle, nonceCaller,
246                                           encryptedSalt, sessionType, symmetric,
247                                           authHash);
248     return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error.");
249 
250     /* Calculate the cpHash Values */
251     r = init_session_tab(esysContext, shandle1, shandle2, shandle3);
252     return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources");
253     iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL);
254     iesys_compute_session_value(esysContext->session_tab[1], NULL, NULL);
255     iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL);
256 
257     /* Generate the auth values and set them in the SAPI command buffer */
258 
259     RSRC_NODE_T none;
260     size_t offset = 0;
261     none.rsrc.handle = TPM2_RH_NULL;
262     none.rsrc.rsrcType = IESYSC_WITHOUT_MISC_RSRC;
263     r = Tss2_MU_TPM2_HANDLE_Marshal(TPM2_RH_NULL,
264                                 none.rsrc.name.name,
265                                 sizeof(none.rsrc.name.name),
266                                 &offset);
267     return_state_if_error(r, _ESYS_STATE_INIT, "Marshaling TPM handle.");
268     none.rsrc.name.size = offset;
269     r = iesys_gen_auths(esysContext, tpmKeyNode ? tpmKeyNode : &none,
270                                      bindNode ? bindNode : &none, NULL, &auths);
271     return_state_if_error(r, _ESYS_STATE_INIT,
272                           "Error in computation of auth values");
273 
274     esysContext->authsCount = auths.count;
275     if (auths.count > 0) {
276         r = Tss2_Sys_SetCmdAuths(esysContext->sys, &auths);
277         return_state_if_error(r, _ESYS_STATE_INIT, "SAPI error on SetCmdAuths");
278     }
279 
280     /* Trigger execution and finish the async invocation */
281     r = Tss2_Sys_ExecuteAsync(esysContext->sys);
282     return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
283                           "Finish (Execute Async)");
284 
285     esysContext->state = _ESYS_STATE_SENT;
286 
287     return r;
288 }
289 
290 /** Asynchronous finish function for TPM2_StartAuthSession
291  *
292  * This function returns the results of a TPM2_StartAuthSession command
293  * invoked via Esys_StartAuthSession_Finish. All non-simple output parameters
294  * are allocated by the function's implementation. NULL can be passed for every
295  * output parameter if the value is not required.
296  *
297  * @param[in,out] esysContext The ESYS_CONTEXT.
298  * @param[out] sessionHandle  ESYS_TR handle of ESYS resource for TPMI_SH_AUTH_SESSION.
299  * @retval TSS2_RC_SUCCESS on success
300  * @retval ESYS_RC_SUCCESS if the function call was a success.
301  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
302  *         pointers or required output handle references are NULL.
303  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
304  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
305  *         internal operations or return parameters.
306  * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
307  *         operation already pending.
308  * @retval TSS2_ESYS_RC_TRY_AGAIN: if the timeout counter expires before the
309  *         TPM response is received.
310  * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
311  *         at least contain the tag, response length, and response code.
312  * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM did
313  *         not verify.
314  * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
315  * @retval TSS2_RCs produced by lower layers of the software stack may be
316  *         returned to the caller unaltered unless handled internally.
317  */
318 TSS2_RC
Esys_StartAuthSession_Finish(ESYS_CONTEXT * esysContext,ESYS_TR * sessionHandle)319 Esys_StartAuthSession_Finish(
320     ESYS_CONTEXT *esysContext, ESYS_TR *sessionHandle)
321 {
322     TPM2B_NONCE lnonceTPM;
323     TSS2_RC r;
324     LOG_TRACE("context=%p, sessionHandle=%p",
325               esysContext, sessionHandle);
326 
327     if (esysContext == NULL) {
328         LOG_ERROR("esyscontext is NULL.");
329         return TSS2_ESYS_RC_BAD_REFERENCE;
330     }
331 
332     /* Check for correct sequence and set sequence to irregular for now */
333     if (esysContext->state != _ESYS_STATE_SENT &&
334         esysContext->state != _ESYS_STATE_RESUBMISSION) {
335         LOG_ERROR("Esys called in bad sequence.");
336         return TSS2_ESYS_RC_BAD_SEQUENCE;
337     }
338     esysContext->state = _ESYS_STATE_INTERNALERROR;
339     RSRC_NODE_T *sessionHandleNode = NULL;
340 
341     /* Allocate memory for response parameters */
342     if (sessionHandle == NULL) {
343         LOG_ERROR("Handle sessionHandle may not be NULL");
344         return TSS2_ESYS_RC_BAD_REFERENCE;
345     }
346     *sessionHandle = esysContext->esys_handle_cnt++;
347     r = esys_CreateResourceObject(esysContext, *sessionHandle, &sessionHandleNode);
348     if (r != TSS2_RC_SUCCESS)
349         return r;
350 
351     IESYS_RESOURCE *rsrc = &sessionHandleNode->rsrc;
352     rsrc->handle = ESYS_TR_NONE;
353     rsrc->misc.rsrc_session.sessionAttributes = TPMA_SESSION_CONTINUESESSION;
354     rsrc->misc.rsrc_session.sessionType = esysContext->in.StartAuthSession.sessionType;
355     rsrc->misc.rsrc_session.authHash = esysContext->in.StartAuthSession.authHash;
356     rsrc->misc.rsrc_session.symmetric = *esysContext->in.StartAuthSession.symmetric;
357     rsrc->misc.rsrc_session.nonceCaller = esysContext->in.StartAuthSession.nonceCallerData;
358 
359     /* Receive the TPM response and handle resubmissions if necessary. */
360     r = Tss2_Sys_ExecuteFinish(esysContext->sys, esysContext->timeout);
361     if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
362         LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32, r);
363         esysContext->state = _ESYS_STATE_SENT;
364         goto error_cleanup;
365     }
366     /* This block handle the resubmission of TPM commands given a certain set of
367      * TPM response codes. */
368     if (r == TPM2_RC_RETRY || r == TPM2_RC_TESTING || r == TPM2_RC_YIELDED) {
369         LOG_DEBUG("TPM returned RETRY, TESTING or YIELDED, which triggers a "
370             "resubmission: %" PRIx32, r);
371         if (esysContext->submissionCount++ >= _ESYS_MAX_SUBMISSIONS) {
372             LOG_WARNING("Maximum number of (re)submissions has been reached.");
373             esysContext->state = _ESYS_STATE_INIT;
374             goto error_cleanup;
375         }
376         esysContext->state = _ESYS_STATE_RESUBMISSION;
377         r = Tss2_Sys_ExecuteAsync(esysContext->sys);
378         if (r != TSS2_RC_SUCCESS) {
379             LOG_WARNING("Error attempting to resubmit");
380             /* We do not set esysContext->state here but inherit the most recent
381              * state of the _async function. */
382             goto error_cleanup;
383         }
384         r = TSS2_ESYS_RC_TRY_AGAIN;
385         LOG_DEBUG("Resubmission initiated and returning RC_TRY_AGAIN.");
386         goto error_cleanup;
387     }
388     /* The following is the "regular error" handling. */
389     if (iesys_tpm_error(r)) {
390         LOG_WARNING("Received TPM Error");
391         esysContext->state = _ESYS_STATE_INIT;
392         goto error_cleanup;
393     } else if (r != TSS2_RC_SUCCESS) {
394         LOG_ERROR("Received a non-TPM Error");
395         esysContext->state = _ESYS_STATE_INTERNALERROR;
396         goto error_cleanup;
397     }
398 
399     /*
400      * Now the verification of the response (hmac check) and if necessary the
401      * parameter decryption have to be done.
402      */
403     r = iesys_check_response(esysContext);
404     goto_state_if_error(r, _ESYS_STATE_INTERNALERROR, "Error: check response",
405                         error_cleanup);
406 
407     /*
408      * After the verification of the response we call the complete function
409      * to deliver the result.
410      */
411     r = Tss2_Sys_StartAuthSession_Complete(esysContext->sys,
412                                            &sessionHandleNode->rsrc.handle,
413                                            &lnonceTPM);
414     goto_state_if_error(r, _ESYS_STATE_INTERNALERROR,
415                         "Received error from SAPI unmarshaling" ,
416                         error_cleanup);
417 
418     sessionHandleNode->rsrc.misc.rsrc_session.nonceTPM = lnonceTPM;
419     sessionHandleNode->rsrc.rsrcType = IESYSC_SESSION_RSRC;
420     if (esysContext->in.StartAuthSession.bind != ESYS_TR_NONE || esysContext->salt.size > 0) {
421         ESYS_TR bind = esysContext->in.StartAuthSession.bind;
422         ESYS_TR tpmKey = esysContext->in.StartAuthSession.tpmKey;
423         RSRC_NODE_T *bindNode;
424         r = esys_GetResourceObject(esysContext, bind, &bindNode);
425         goto_if_error(r, "get resource", error_cleanup);
426 
427         RSRC_NODE_T *tpmKeyNode;
428         r = esys_GetResourceObject(esysContext, tpmKey, &tpmKeyNode);
429         goto_if_error(r, "get resource", error_cleanup);
430 
431         size_t keyHash_size = 0;
432         size_t authHash_size = 0;
433         if (tpmKeyNode != NULL) {
434             r = iesys_crypto_hash_get_digest_size(
435                      tpmKeyNode->rsrc.misc.rsrc_key_pub.publicArea.nameAlg, &
436                      keyHash_size);
437             if (r != TSS2_RC_SUCCESS) {
438                 LOG_ERROR("Error: initialize auth session (%x).", r);
439                 return r;
440             }
441         }
442         r = iesys_crypto_hash_get_digest_size(esysContext->in.StartAuthSession.
443                                               authHash,&authHash_size);
444         if (r != TSS2_RC_SUCCESS) {
445             LOG_ERROR("Error: initialize auth session (%x).", r);
446             return r;
447         }
448         /* compute session key */
449         size_t secret_size = 0;
450         if (tpmKey != ESYS_TR_NONE)
451             secret_size += keyHash_size;
452         if (bind != ESYS_TR_NONE && bindNode != NULL)
453             secret_size += bindNode->auth.size;
454         /*
455          * A non null pointer for secret is required by the subsequent functions,
456          * hence a malloc is called with size 1 if secret_size is zero.
457          */
458         uint8_t *secret = malloc(secret_size ? secret_size : 1);
459         if (secret == NULL) {
460             LOG_ERROR("Out of memory.");
461             return TSS2_ESYS_RC_MEMORY;
462          }
463         if  (bind != ESYS_TR_NONE && bindNode != NULL
464              && bindNode->auth.size > 0)
465              memcpy(&secret[0], &bindNode->auth.buffer[0], bindNode->auth.size);
466         if (tpmKey != ESYS_TR_NONE)
467             memcpy(&secret[(bind == ESYS_TR_NONE || bindNode == NULL) ? 0
468                                : bindNode->auth.size],
469                            &esysContext->salt.buffer[0], keyHash_size);
470         if (bind != ESYS_TR_NONE &&  bindNode != NULL)
471             iesys_compute_bound_entity(&bindNode->rsrc.name,
472                                        &bindNode->auth,
473                                        &sessionHandleNode->rsrc.misc.rsrc_session.bound_entity);
474         LOGBLOB_DEBUG(secret, secret_size, "ESYS Session Secret");
475         r = iesys_crypto_KDFa(esysContext->in.StartAuthSession.authHash, secret,
476                               secret_size, "ATH",
477                                &lnonceTPM, esysContext->in.StartAuthSession.nonceCaller,
478                                authHash_size*8, NULL,
479                      &sessionHandleNode->rsrc.misc.rsrc_session.sessionKey.buffer[0], FALSE);
480         free(secret);
481         return_if_error(r, "Error in KDFa computation.");
482 
483         sessionHandleNode->rsrc.misc.rsrc_session.sessionKey.size = authHash_size;
484         LOGBLOB_DEBUG(&sessionHandleNode->rsrc.misc.rsrc_session.sessionKey
485                       .buffer[0], authHash_size, "Session Key");
486         return_if_error(r,"Error KDFa");
487     }
488     size_t offset = 0;
489     r = Tss2_MU_TPM2_HANDLE_Marshal(sessionHandleNode->rsrc.handle,
490                                     &sessionHandleNode->rsrc.name.name[0],
491                                     sizeof(sessionHandleNode->rsrc.name.name),
492                                     &offset);
493     goto_if_error(r, "Marshal session name", error_cleanup);
494 
495     sessionHandleNode->rsrc.name.size = offset;
496     memset(&esysContext->salt, '\0', sizeof(esysContext->salt));
497     esysContext->state = _ESYS_STATE_INIT;
498 
499     return TSS2_RC_SUCCESS;
500 
501 error_cleanup:
502     if (sessionHandleNode->rsrc.handle != ESYS_TR_NONE) {
503         r = Esys_FlushContext(esysContext, sessionHandleNode->rsrc.handle);
504         if (r != TSS2_RC_SUCCESS)
505             LOG_ERROR("FlushContext failed.");
506     }
507     Esys_TR_Close(esysContext, sessionHandle);
508 
509     return r;
510 }
511