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_GetCommandAuditDigest
23 *
24 * This function invokes the TPM2_GetCommandAuditDigest 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] privacyHandle TPM2_Handle of the privacy administrator
31 * (TPM2_RH_ENDORSEMENT).
32 * @param[in] signHandle The handle of the signing key.
33 * @param[in] shandle1 Session handle for authorization of privacyHandle
34 * @param[in] shandle2 Session handle for authorization of signHandle
35 * @param[in] shandle3 Third session handle.
36 * @param[in] qualifyingData Other data to associate with this audit digest.
37 * @param[in] inScheme TPM2_Signing scheme to use if the scheme for signHandle is
38 * TPM2_ALG_NULL.
39 * @param[out] auditInfo The auditInfo that was signed.
40 * (callee-allocated)
41 * @param[out] signature The signature over auditInfo.
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_GetCommandAuditDigest(ESYS_CONTEXT * esysContext,ESYS_TR privacyHandle,ESYS_TR signHandle,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_DATA * qualifyingData,const TPMT_SIG_SCHEME * inScheme,TPM2B_ATTEST ** auditInfo,TPMT_SIGNATURE ** signature)67 Esys_GetCommandAuditDigest(
68 ESYS_CONTEXT *esysContext,
69 ESYS_TR privacyHandle,
70 ESYS_TR signHandle,
71 ESYS_TR shandle1,
72 ESYS_TR shandle2,
73 ESYS_TR shandle3,
74 const TPM2B_DATA *qualifyingData,
75 const TPMT_SIG_SCHEME *inScheme,
76 TPM2B_ATTEST **auditInfo,
77 TPMT_SIGNATURE **signature)
78 {
79 TSS2_RC r;
80
81 r = Esys_GetCommandAuditDigest_Async(esysContext, privacyHandle, signHandle,
82 shandle1, shandle2, shandle3,
83 qualifyingData, inScheme);
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_GetCommandAuditDigest_Finish(esysContext, auditInfo,
98 signature);
99 /* This is just debug information about the reattempt to finish the
100 command */
101 if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
102 LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32
103 " => resubmitting command", r);
104 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
105
106 /* Restore the timeout value to the original value */
107 esysContext->timeout = timeouttmp;
108 return_if_error(r, "Esys Finish");
109
110 return TSS2_RC_SUCCESS;
111 }
112
113 /** Asynchronous function for TPM2_GetCommandAuditDigest
114 *
115 * This function invokes the TPM2_GetCommandAuditDigest command in a asynchronous
116 * variant. This means the function will return as soon as the command has been
117 * sent downwards the stack to the TPM. All input parameters are const.
118 * In order to retrieve the TPM's response call Esys_GetCommandAuditDigest_Finish.
119 *
120 * @param[in,out] esysContext The ESYS_CONTEXT.
121 * @param[in] privacyHandle TPM2_Handle of the privacy administrator
122 * (TPM2_RH_ENDORSEMENT).
123 * @param[in] signHandle The handle of the signing key.
124 * @param[in] shandle1 Session handle for authorization of privacyHandle
125 * @param[in] shandle2 Session handle for authorization of signHandle
126 * @param[in] shandle3 Third session handle.
127 * @param[in] qualifyingData Other data to associate with this audit digest.
128 * @param[in] inScheme TPM2_Signing scheme to use if the scheme for signHandle is
129 * TPM2_ALG_NULL.
130 * @retval ESYS_RC_SUCCESS if the function call was a success.
131 * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
132 * pointers or required output handle references are NULL.
133 * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
134 * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
135 * internal operations or return parameters.
136 * @retval TSS2_RCs produced by lower layers of the software stack may be
137 returned to the caller unaltered unless handled internally.
138 * @retval TSS2_ESYS_RC_MULTIPLE_DECRYPT_SESSIONS: if more than one session has
139 * the 'decrypt' attribute bit set.
140 * @retval TSS2_ESYS_RC_MULTIPLE_ENCRYPT_SESSIONS: if more than one session has
141 * the 'encrypt' attribute bit set.
142 * @retval TSS2_ESYS_RC_BAD_TR: if any of the ESYS_TR objects are unknown
143 * to the ESYS_CONTEXT or are of the wrong type or if required
144 * ESYS_TR objects are ESYS_TR_NONE.
145 */
146 TSS2_RC
Esys_GetCommandAuditDigest_Async(ESYS_CONTEXT * esysContext,ESYS_TR privacyHandle,ESYS_TR signHandle,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_DATA * qualifyingData,const TPMT_SIG_SCHEME * inScheme)147 Esys_GetCommandAuditDigest_Async(
148 ESYS_CONTEXT *esysContext,
149 ESYS_TR privacyHandle,
150 ESYS_TR signHandle,
151 ESYS_TR shandle1,
152 ESYS_TR shandle2,
153 ESYS_TR shandle3,
154 const TPM2B_DATA *qualifyingData,
155 const TPMT_SIG_SCHEME *inScheme)
156 {
157 TSS2_RC r;
158 LOG_TRACE("context=%p, privacyHandle=%"PRIx32 ", signHandle=%"PRIx32 ","
159 "qualifyingData=%p, inScheme=%p",
160 esysContext, privacyHandle, signHandle, qualifyingData, inScheme);
161 TSS2L_SYS_AUTH_COMMAND auths;
162 RSRC_NODE_T *privacyHandleNode;
163 RSRC_NODE_T *signHandleNode;
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, privacyHandle, &privacyHandleNode);
181 return_state_if_error(r, _ESYS_STATE_INIT, "privacyHandle unknown.");
182 r = esys_GetResourceObject(esysContext, signHandle, &signHandleNode);
183 return_state_if_error(r, _ESYS_STATE_INIT, "signHandle unknown.");
184
185 /* Initial invocation of SAPI to prepare the command buffer with parameters */
186 r = Tss2_Sys_GetCommandAuditDigest_Prepare(esysContext->sys,
187 (privacyHandleNode == NULL)
188 ? TPM2_RH_NULL
189 : privacyHandleNode->rsrc.handle,
190 (signHandleNode == NULL)
191 ? TPM2_RH_NULL
192 : signHandleNode->rsrc.handle,
193 qualifyingData, inScheme);
194 return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error.");
195
196 /* Calculate the cpHash Values */
197 r = init_session_tab(esysContext, shandle1, shandle2, shandle3);
198 return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources");
199 if (privacyHandleNode != NULL)
200 iesys_compute_session_value(esysContext->session_tab[0],
201 &privacyHandleNode->rsrc.name, &privacyHandleNode->auth);
202 else
203 iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL);
204
205 iesys_compute_session_value(esysContext->session_tab[1],
206 &signHandleNode->rsrc.name, &signHandleNode->auth);
207 iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL);
208
209 /* Generate the auth values and set them in the SAPI command buffer */
210 r = iesys_gen_auths(esysContext, privacyHandleNode, signHandleNode, NULL, &auths);
211 return_state_if_error(r, _ESYS_STATE_INIT,
212 "Error in computation of auth values");
213
214 esysContext->authsCount = auths.count;
215 if (auths.count > 0) {
216 r = Tss2_Sys_SetCmdAuths(esysContext->sys, &auths);
217 return_state_if_error(r, _ESYS_STATE_INIT, "SAPI error on SetCmdAuths");
218 }
219
220 /* Trigger execution and finish the async invocation */
221 r = Tss2_Sys_ExecuteAsync(esysContext->sys);
222 return_state_if_error(r, _ESYS_STATE_INTERNALERROR,
223 "Finish (Execute Async)");
224
225 esysContext->state = _ESYS_STATE_SENT;
226
227 return r;
228 }
229
230 /** Asynchronous finish function for TPM2_GetCommandAuditDigest
231 *
232 * This function returns the results of a TPM2_GetCommandAuditDigest command
233 * invoked via Esys_GetCommandAuditDigest_Finish. All non-simple output parameters
234 * are allocated by the function's implementation. NULL can be passed for every
235 * output parameter if the value is not required.
236 *
237 * @param[in,out] esysContext The ESYS_CONTEXT.
238 * @param[out] auditInfo The auditInfo that was signed.
239 * (callee-allocated)
240 * @param[out] signature The signature over auditInfo.
241 * (callee-allocated)
242 * @retval TSS2_RC_SUCCESS on success
243 * @retval ESYS_RC_SUCCESS if the function call was a success.
244 * @retval TSS2_ESYS_RC_BAD_REFERENCE if the esysContext or required input
245 * pointers or required output handle references are NULL.
246 * @retval TSS2_ESYS_RC_BAD_CONTEXT: if esysContext corruption is detected.
247 * @retval TSS2_ESYS_RC_MEMORY: if the ESAPI cannot allocate enough memory for
248 * internal operations or return parameters.
249 * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if the context has an asynchronous
250 * operation already pending.
251 * @retval TSS2_ESYS_RC_TRY_AGAIN: if the timeout counter expires before the
252 * TPM response is received.
253 * @retval TSS2_ESYS_RC_INSUFFICIENT_RESPONSE: if the TPM's response does not
254 * at least contain the tag, response length, and response code.
255 * @retval TSS2_ESYS_RC_RSP_AUTH_FAILED: if the response HMAC from the TPM did
256 * not verify.
257 * @retval TSS2_ESYS_RC_MALFORMED_RESPONSE: if the TPM's response is corrupted.
258 * @retval TSS2_RCs produced by lower layers of the software stack may be
259 * returned to the caller unaltered unless handled internally.
260 */
261 TSS2_RC
Esys_GetCommandAuditDigest_Finish(ESYS_CONTEXT * esysContext,TPM2B_ATTEST ** auditInfo,TPMT_SIGNATURE ** signature)262 Esys_GetCommandAuditDigest_Finish(
263 ESYS_CONTEXT *esysContext,
264 TPM2B_ATTEST **auditInfo,
265 TPMT_SIGNATURE **signature)
266 {
267 TSS2_RC r;
268 LOG_TRACE("context=%p, auditInfo=%p, signature=%p",
269 esysContext, auditInfo, signature);
270
271 if (esysContext == NULL) {
272 LOG_ERROR("esyscontext is NULL.");
273 return TSS2_ESYS_RC_BAD_REFERENCE;
274 }
275
276 /* Check for correct sequence and set sequence to irregular for now */
277 if (esysContext->state != _ESYS_STATE_SENT &&
278 esysContext->state != _ESYS_STATE_RESUBMISSION) {
279 LOG_ERROR("Esys called in bad sequence.");
280 return TSS2_ESYS_RC_BAD_SEQUENCE;
281 }
282 esysContext->state = _ESYS_STATE_INTERNALERROR;
283
284 /* Allocate memory for response parameters */
285 if (auditInfo != NULL) {
286 *auditInfo = calloc(sizeof(TPM2B_ATTEST), 1);
287 if (*auditInfo == NULL) {
288 return_error(TSS2_ESYS_RC_MEMORY, "Out of memory");
289 }
290 }
291 if (signature != NULL) {
292 *signature = calloc(sizeof(TPMT_SIGNATURE), 1);
293 if (*signature == NULL) {
294 goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup);
295 }
296 }
297
298 /*Receive the TPM response and handle resubmissions if necessary. */
299 r = Tss2_Sys_ExecuteFinish(esysContext->sys, esysContext->timeout);
300 if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
301 LOG_DEBUG("A layer below returned TRY_AGAIN: %" PRIx32, r);
302 esysContext->state = _ESYS_STATE_SENT;
303 goto error_cleanup;
304 }
305 /* This block handle the resubmission of TPM commands given a certain set of
306 * TPM response codes. */
307 if (r == TPM2_RC_RETRY || r == TPM2_RC_TESTING || r == TPM2_RC_YIELDED) {
308 LOG_DEBUG("TPM returned RETRY, TESTING or YIELDED, which triggers a "
309 "resubmission: %" PRIx32, r);
310 if (esysContext->submissionCount++ >= _ESYS_MAX_SUBMISSIONS) {
311 LOG_WARNING("Maximum number of (re)submissions has been reached.");
312 esysContext->state = _ESYS_STATE_INIT;
313 goto error_cleanup;
314 }
315 esysContext->state = _ESYS_STATE_RESUBMISSION;
316 r = Tss2_Sys_ExecuteAsync(esysContext->sys);
317 if (r != TSS2_RC_SUCCESS) {
318 LOG_WARNING("Error attempting to resubmit");
319 /* We do not set esysContext->state here but inherit the most recent
320 * state of the _async function. */
321 goto error_cleanup;
322 }
323 r = TSS2_ESYS_RC_TRY_AGAIN;
324 LOG_DEBUG("Resubmission initiated and returning RC_TRY_AGAIN.");
325 goto error_cleanup;
326 }
327 /* The following is the "regular error" handling. */
328 if (iesys_tpm_error(r)) {
329 LOG_WARNING("Received TPM Error");
330 esysContext->state = _ESYS_STATE_INIT;
331 goto error_cleanup;
332 } else if (r != TSS2_RC_SUCCESS) {
333 LOG_ERROR("Received a non-TPM Error");
334 esysContext->state = _ESYS_STATE_INTERNALERROR;
335 goto error_cleanup;
336 }
337
338 /*
339 * Now the verification of the response (hmac check) and if necessary the
340 * parameter decryption have to be done.
341 */
342 r = iesys_check_response(esysContext);
343 goto_state_if_error(r, _ESYS_STATE_INTERNALERROR, "Error: check response",
344 error_cleanup);
345
346 /*
347 * After the verification of the response we call the complete function
348 * to deliver the result.
349 */
350 r = Tss2_Sys_GetCommandAuditDigest_Complete(esysContext->sys,
351 (auditInfo != NULL) ? *auditInfo
352 : NULL,
353 (signature != NULL) ? *signature
354 : NULL);
355 goto_state_if_error(r, _ESYS_STATE_INTERNALERROR,
356 "Received error from SAPI unmarshaling" ,
357 error_cleanup);
358
359 esysContext->state = _ESYS_STATE_INIT;
360
361 return TSS2_RC_SUCCESS;
362
363 error_cleanup:
364 if (auditInfo != NULL)
365 SAFE_FREE(*auditInfo);
366 if (signature != NULL)
367 SAFE_FREE(*signature);
368
369 return r;
370 }
371