• 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_Vendor_TCG_Test
23  *
24  * This function invokes the TPM2_Vendor_TCG_Test 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]  shandle1 First session handle.
31  * @param[in]  shandle2 Second session handle.
32  * @param[in]  shandle3 Third session handle.
33  * @param[in]  inputData Dummy data.
34  * @param[out] outputData Dummy data.
35  *             (callee-allocated)
36  * @retval TSS2_RC_SUCCESS if the function call was a success.
37  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
38  *         pointers or required output handle references are NULL.
39  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
40  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
41  *         internal operations or return parameters.
42  * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
43  *         operation already pending.
44  * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
45  *          at least contain the tag, response length, and response code.
46  * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
47  * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM
48            did not verify.
49  * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
50  *         the 'decrypt' attribute bit set.
51  * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
52  *         the 'encrypt' attribute bit set.
53  * @retval TSS2_RCs produced by lower layers of the software stack may be
54  *         returned to the caller unaltered unless handled internally.
55  */
56 TSS2_RC
Esys_Vendor_TCG_Test(ESYS_CONTEXT * esysContext,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_DATA * inputData,TPM2B_DATA ** outputData)57 Esys_Vendor_TCG_Test(
58     ESYS_CONTEXT *esysContext,
59     ESYS_TR shandle1,
60     ESYS_TR shandle2,
61     ESYS_TR shandle3,
62     const TPM2B_DATA *inputData,
63     TPM2B_DATA **outputData)
64 {
65     TSS2_RC r;
66 
67     r = Esys_Vendor_TCG_Test_Async(esysContext, shandle1, shandle2, shandle3,
68                                    inputData);
69     return_if_error(r, "Error in async function");
70 
71     /* Set the timeout to indefinite for now, since we want _Finish to block */
72     int32_t timeouttmp = esysContext->timeout;
73     esysContext->timeout = -1;
74     /*
75      * Now we call the finish function, until return code is not equal to
76      * from TSS2_BASE_RC_TRY_AGAIN.
77      * Note that the finish function may return TSS2_RC_TRY_AGAIN, even if we
78      * have set the timeout to -1. This occurs for example if the TPM requests
79      * a retransmission of the command via TPM2_RC_YIELDED.
80      */
81     do {
82         r = Esys_Vendor_TCG_Test_Finish(esysContext, outputData);
83         /* This is just debug information about the reattempt to finish the
84            command */
85         if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
86             LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32
87                       " => resubmitting command", r);
88     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
89 
90     /* Restore the timeout value to the original value */
91     esysContext->timeout = timeouttmp;
92     return_if_error(r, "Esys Finish");
93 
94     return TSS2_RC_SUCCESS;
95 }
96 
97 /** Asynchronous function for TPM2_Vendor_TCG_Test
98  *
99  * This function invokes the TPM2_Vendor_TCG_Test command in a asynchronous
100  * variant. This means the function will return as soon as the command has been
101  * sent downwards the stack to the TPM. All input parameters are const.
102  * In order to retrieve the TPM's response call Esys_Vendor_TCG_Test_Finish.
103  *
104  * @param[in,out] esysContext The ESYS_CONTEXT.
105  * @param[in]  shandle1 First session handle.
106  * @param[in]  shandle2 Second session handle.
107  * @param[in]  shandle3 Third session handle.
108  * @param[in]  inputData Dummy data.
109  * @retval ESYS_RC_SUCCESS if the function call was a success.
110  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
111  *         pointers or required output handle references are NULL.
112  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
113  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
114  *         internal operations or return parameters.
115  * @retval TSS2_RCs produced by lower layers of the software stack may be
116            returned to the caller unaltered unless handled internally.
117  * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
118  *         the 'decrypt' attribute bit set.
119  * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
120  *         the 'encrypt' attribute bit set.
121  */
122 TSS2_RC
Esys_Vendor_TCG_Test_Async(ESYS_CONTEXT * esysContext,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_DATA * inputData)123 Esys_Vendor_TCG_Test_Async(
124     ESYS_CONTEXT *esysContext,
125     ESYS_TR shandle1,
126     ESYS_TR shandle2,
127     ESYS_TR shandle3,
128     const TPM2B_DATA *inputData)
129 {
130     TSS2_RC r;
131     LOG_TRACE("context=%p, inputData=%p",
132               esysContext, inputData);
133     TSS2L_SYS_AUTH_COMMAND auths;
134 
135     /* Check context, sequence correctness and set state to error for now */
136     if (esysContext == NULL) {
137         LOG_ERROR("esyscontext is NULL.");
138         return TSS2_ESYS_RC_BAD_REFERENCE;
139     }
140     r = iesys_check_sequence_async(esysContext);
141     if (r != TSS2_RC_SUCCESS)
142         return r;
143     esysContext->state = _ESYS_STATE_INTERNALERROR;
144 
145     /* Check input parameters */
146     r = check_session_feasibility(shandle1, shandle2, shandle3, 0);
147     return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage");
148 
149     /* Initial invocation of SAPI to prepare the command buffer with parameters */
150     r = Tss2_Sys_Vendor_TCG_Test_Prepare(esysContext->sys, inputData);
151     return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error.");
152 
153     /* Calculate the cpHash Values */
154     r = init_session_tab(esysContext, shandle1, shandle2, shandle3);
155     return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources");
156     iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL);
157     iesys_compute_session_value(esysContext->session_tab[1], NULL, NULL);
158     iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL);
159 
160     /* Generate the auth values and set them in the SAPI command buffer */
161     r = iesys_gen_auths(esysContext, NULL, NULL, NULL, &auths);
162     return_state_if_error(r, _ESYS_STATE_INIT,
163                           "Error in computation of auth values");
164 
165     esysContext->authsCount = auths.count;
166     if (auths.count > 0) {
167         r = Tss2_Sys_SetCmdAuths(esysContext->sys, &auths);
168         return_state_if_error(r, _ESYS_STATE_INIT, "SAPI error on SetCmdAuths");
169     }
170 
171     /* Trigger execution and finish the async invocation */
172     r = Tss2_Sys_ExecuteAsync(esysContext->sys);
173     return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
174                           "Finish (Execute Async)");
175 
176     esysContext->state = _ESYS_STATE_SENT;
177 
178     return r;
179 }
180 
181 /** Asynchronous finish function for TPM2_Vendor_TCG_Test
182  *
183  * This function returns the results of a TPM2_Vendor_TCG_Test command
184  * invoked via Esys_Vendor_TCG_Test_Finish. All non-simple output parameters
185  * are allocated by the function's implementation. NULL can be passed for every
186  * output parameter if the value is not required.
187  *
188  * @param[in,out] esysContext The ESYS_CONTEXT.
189  * @param[out] outputData Dummy data.
190  *             (callee-allocated)
191  * @retval TSS2_RC_SUCCESS on success
192  * @retval ESYS_RC_SUCCESS if the function call was a success.
193  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
194  *         pointers or required output handle references are NULL.
195  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
196  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
197  *         internal operations or return parameters.
198  * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
199  *         operation already pending.
200  * @retval TSS2_ESYS_RC_TRY_AGAIN: if the timeout counter expires before the
201  *         TPM response is received.
202  * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
203  *         at least contain the tag, response length, and response code.
204  * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM did
205  *         not verify.
206  * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
207  * @retval TSS2_RCs produced by lower layers of the software stack may be
208  *         returned to the caller unaltered unless handled internally.
209  */
210 TSS2_RC
Esys_Vendor_TCG_Test_Finish(ESYS_CONTEXT * esysContext,TPM2B_DATA ** outputData)211 Esys_Vendor_TCG_Test_Finish(
212     ESYS_CONTEXT *esysContext,
213     TPM2B_DATA **outputData)
214 {
215     TSS2_RC r;
216     LOG_TRACE("context=%p, outputData=%p",
217               esysContext, outputData);
218 
219     if (esysContext == NULL) {
220         LOG_ERROR("esyscontext is NULL.");
221         return TSS2_ESYS_RC_BAD_REFERENCE;
222     }
223 
224     /* Check for correct sequence and set sequence to irregular for now */
225     if (esysContext->state != _ESYS_STATE_SENT &&
226         esysContext->state != _ESYS_STATE_RESUBMISSION) {
227         LOG_ERROR("Esys called in bad sequence.");
228         return TSS2_ESYS_RC_BAD_SEQUENCE;
229     }
230     esysContext->state = _ESYS_STATE_INTERNALERROR;
231 
232     /* Allocate memory for response parameters */
233     if (outputData != NULL) {
234         *outputData = calloc(sizeof(TPM2B_DATA), 1);
235         if (*outputData == NULL) {
236             return_error(TSS2_ESYS_RC_MEMORY, "Out of memory");
237         }
238     }
239 
240     /*Receive the TPM response and handle resubmissions if necessary. */
241     r = Tss2_Sys_ExecuteFinish(esysContext->sys, esysContext->timeout);
242     if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
243         LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32, r);
244         esysContext->state = _ESYS_STATE_SENT;
245         goto error_cleanup;
246     }
247     /* This block handle the resubmission of TPM commands given a certain set of
248      * TPM response codes. */
249     if (r == TPM2_RC_RETRY || r == TPM2_RC_TESTING || r == TPM2_RC_YIELDED) {
250         LOG_DEBUG("TPM returned RETRY, TESTING or YIELDED, which triggers a "
251             "resubmission: %" PRIx32, r);
252         if (esysContext->submissionCount++ >= _ESYS_MAX_SUBMISSIONS) {
253             LOG_WARNING("Maximum number of (re)submissions has been reached.");
254             esysContext->state = _ESYS_STATE_INIT;
255             goto error_cleanup;
256         }
257         esysContext->state = _ESYS_STATE_RESUBMISSION;
258         r = Tss2_Sys_ExecuteAsync(esysContext->sys);
259         if (r != TSS2_RC_SUCCESS) {
260             LOG_WARNING("Error attempting to resubmit");
261             /* We do not set esysContext->state here but inherit the most recent
262              * state of the _async function. */
263             goto error_cleanup;
264         }
265         r = TSS2_ESYS_RC_TRY_AGAIN;
266         LOG_DEBUG("Resubmission initiated and returning RC_TRY_AGAIN.");
267         goto error_cleanup;
268     }
269     /* The following is the "regular error" handling. */
270     if (iesys_tpm_error(r)) {
271         LOG_WARNING("Received TPM Error");
272         esysContext->state = _ESYS_STATE_INIT;
273         goto error_cleanup;
274     } else if (r != TSS2_RC_SUCCESS) {
275         LOG_ERROR("Received a non-TPM Error");
276         esysContext->state = _ESYS_STATE_INTERNALERROR;
277         goto error_cleanup;
278     }
279 
280     /*
281      * Now the verification of the response (hmac check) and if necessary the
282      * parameter decryption have to be done.
283      */
284     r = iesys_check_response(esysContext);
285     goto_state_if_error(r, _ESYS_STATE_INTERNALERROR, "Error: check response",
286                         error_cleanup);
287 
288     /*
289      * After the verification of the response we call the complete function
290      * to deliver the result.
291      */
292     r = Tss2_Sys_Vendor_TCG_Test_Complete(esysContext->sys,
293                                           (outputData != NULL) ? *outputData
294                                            : NULL);
295     goto_state_if_error(r, _ESYS_STATE_INTERNALERROR,
296                         "Received error from SAPI unmarshaling" ,
297                         error_cleanup);
298 
299     esysContext->state = _ESYS_STATE_INIT;
300 
301     return TSS2_RC_SUCCESS;
302 
303 error_cleanup:
304     if (outputData != NULL)
305         SAFE_FREE(*outputData);
306 
307     return r;
308 }
309