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