• 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_StirRandom
23  *
24  * This function invokes the TPM2_StirRandom 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]  inData Additional information.
34  * @retval TSS2_RC_SUCCESS if the function call was a success.
35  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
36  *         pointers or required output handle references are NULL.
37  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
38  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
39  *         internal operations or return parameters.
40  * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
41  *         operation already pending.
42  * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
43  *          at least contain the tag, response length, and response code.
44  * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
45  * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM
46            did not verify.
47  * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
48  *         the 'decrypt' attribute bit set.
49  * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
50  *         the 'encrypt' attribute bit set.
51  * @retval TSS2_ESYS_RC_NO_ENCRYPT_PARAM: if one of the sessions has the
52  *         'encrypt' attribute set and the command does not support encryption
53  *          of the first response parameter.
54  * @retval TSS2_RCs produced by lower layers of the software stack may be
55  *         returned to the caller unaltered unless handled internally.
56  */
57 TSS2_RC
Esys_StirRandom(ESYS_CONTEXT * esysContext,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_SENSITIVE_DATA * inData)58 Esys_StirRandom(
59     ESYS_CONTEXT *esysContext,
60     ESYS_TR shandle1,
61     ESYS_TR shandle2,
62     ESYS_TR shandle3,
63     const TPM2B_SENSITIVE_DATA *inData)
64 {
65     TSS2_RC r;
66 
67     r = Esys_StirRandom_Async(esysContext, shandle1, shandle2, shandle3,
68                               inData);
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_StirRandom_Finish(esysContext);
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_StirRandom
98  *
99  * This function invokes the TPM2_StirRandom 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_StirRandom_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]  inData Additional information.
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  * @retval TSS2_ESYS_RC_NO_ENCRYPT_PARAM: if one of the sessions has the
122  *         'encrypt' attribute set and the command does not support encryption
123  *          of the first response parameter.
124  */
125 TSS2_RC
Esys_StirRandom_Async(ESYS_CONTEXT * esysContext,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_SENSITIVE_DATA * inData)126 Esys_StirRandom_Async(
127     ESYS_CONTEXT *esysContext,
128     ESYS_TR shandle1,
129     ESYS_TR shandle2,
130     ESYS_TR shandle3,
131     const TPM2B_SENSITIVE_DATA *inData)
132 {
133     TSS2_RC r;
134     LOG_TRACE("context=%p, inData=%p",
135               esysContext, inData);
136     TSS2L_SYS_AUTH_COMMAND auths;
137 
138     /* Check context, sequence correctness and set state to error for now */
139     if (esysContext == NULL) {
140         LOG_ERROR("esyscontext is NULL.");
141         return TSS2_ESYS_RC_BAD_REFERENCE;
142     }
143     r = iesys_check_sequence_async(esysContext);
144     if (r != TSS2_RC_SUCCESS)
145         return r;
146     esysContext->state = _ESYS_STATE_INTERNALERROR;
147 
148     /* Check input parameters */
149     r = check_session_feasibility(shandle1, shandle2, shandle3, 0);
150     return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage");
151 
152     /* Initial invocation of SAPI to prepare the command buffer with parameters */
153     r = Tss2_Sys_StirRandom_Prepare(esysContext->sys, inData);
154     return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error.");
155 
156     /* Calculate the cpHash Values */
157     r = init_session_tab(esysContext, shandle1, shandle2, shandle3);
158     return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources");
159     iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL);
160     iesys_compute_session_value(esysContext->session_tab[1], NULL, NULL);
161     iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL);
162 
163     /* Generate the auth values and set them in the SAPI command buffer */
164     r = iesys_gen_auths(esysContext, NULL, NULL, NULL, &auths);
165     return_state_if_error(r, _ESYS_STATE_INIT,
166                           "Error in computation of auth values");
167 
168     esysContext->authsCount = auths.count;
169     if (auths.count > 0) {
170         r = Tss2_Sys_SetCmdAuths(esysContext->sys, &auths);
171         return_state_if_error(r, _ESYS_STATE_INIT, "SAPI error on SetCmdAuths");
172     }
173 
174     /* Trigger execution and finish the async invocation */
175     r = Tss2_Sys_ExecuteAsync(esysContext->sys);
176     return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
177                           "Finish (Execute Async)");
178 
179     esysContext->state = _ESYS_STATE_SENT;
180 
181     return r;
182 }
183 
184 /** Asynchronous finish function for TPM2_StirRandom
185  *
186  * This function returns the results of a TPM2_StirRandom command
187  * invoked via Esys_StirRandom_Finish. All non-simple output parameters
188  * are allocated by the function's implementation. NULL can be passed for every
189  * output parameter if the value is not required.
190  *
191  * @param[in,out] esysContext The ESYS_CONTEXT.
192  * @retval TSS2_RC_SUCCESS on success
193  * @retval ESYS_RC_SUCCESS if the function call was a success.
194  * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
195  *         pointers or required output handle references are NULL.
196  * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
197  * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
198  *         internal operations or return parameters.
199  * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
200  *         operation already pending.
201  * @retval TSS2_ESYS_RC_TRY_AGAIN: if the timeout counter expires before the
202  *         TPM response is received.
203  * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
204  *         at least contain the tag, response length, and response code.
205  * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM did
206  *         not verify.
207  * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
208  * @retval TSS2_RCs produced by lower layers of the software stack may be
209  *         returned to the caller unaltered unless handled internally.
210  */
211 TSS2_RC
Esys_StirRandom_Finish(ESYS_CONTEXT * esysContext)212 Esys_StirRandom_Finish(
213     ESYS_CONTEXT *esysContext)
214 {
215     TSS2_RC r;
216     LOG_TRACE("context=%p",
217               esysContext);
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     /*Receive the TPM response and handle resubmissions if necessary. */
233     r = Tss2_Sys_ExecuteFinish(esysContext->sys, esysContext->timeout);
234     if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
235         LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32, r);
236         esysContext->state = _ESYS_STATE_SENT;
237         return r;
238     }
239     /* This block handle the resubmission of TPM commands given a certain set of
240      * TPM response codes. */
241     if (r == TPM2_RC_RETRY || r == TPM2_RC_TESTING || r == TPM2_RC_YIELDED) {
242         LOG_DEBUG("TPM returned RETRY, TESTING or YIELDED, which triggers a "
243             "resubmission: %" PRIx32, r);
244         if (esysContext->submissionCount++ >= _ESYS_MAX_SUBMISSIONS) {
245             LOG_WARNING("Maximum number of (re)submissions has been reached.");
246             esysContext->state = _ESYS_STATE_INIT;
247             return r;
248         }
249         esysContext->state = _ESYS_STATE_RESUBMISSION;
250         r = Tss2_Sys_ExecuteAsync(esysContext->sys);
251         if (r != TSS2_RC_SUCCESS) {
252             LOG_WARNING("Error attempting to resubmit");
253             /* We do not set esysContext->state here but inherit the most recent
254              * state of the _async function. */
255             return r;
256         }
257         r = TSS2_ESYS_RC_TRY_AGAIN;
258         LOG_DEBUG("Resubmission initiated and returning RC_TRY_AGAIN.");
259         return r;
260     }
261     /* The following is the "regular error" handling. */
262     if (iesys_tpm_error(r)) {
263         LOG_WARNING("Received TPM Error");
264         esysContext->state = _ESYS_STATE_INIT;
265         return r;
266     } else if (r != TSS2_RC_SUCCESS) {
267         LOG_ERROR("Received a non-TPM Error");
268         esysContext->state = _ESYS_STATE_INTERNALERROR;
269         return r;
270     }
271 
272     /*
273      * Now the verification of the response (hmac check) and if necessary the
274      * parameter decryption have to be done.
275      */
276     r = iesys_check_response(esysContext);
277     return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
278                           "Error: check response");
279 
280     /*
281      * After the verification of the response we call the complete function
282      * to deliver the result.
283      */
284     r = Tss2_Sys_StirRandom_Complete(esysContext->sys);
285     return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
286                           "Received error from SAPI unmarshaling" );
287 
288     esysContext->state = _ESYS_STATE_INIT;
289 
290     return TSS2_RC_SUCCESS;
291 }
292