1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3 * Copyright 2018-2019, 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_fapi.h"
12 #include "fapi_int.h"
13 #include "fapi_util.h"
14 #include "tss2_esys.h"
15 #include "fapi_policy.h"
16 #include "fapi_crypto.h"
17 #define LOGMODULE fapi
18 #include "util/log.h"
19 #include "util/aux_util.h"
20
21 /** One-Call function for Fapi_AuthorizePolicy
22 *
23 * If a current policy happens to be a PolicyAuthorize, then for it to be used,
24 * the user must first satisfy a policy authorized by a having been signed (and
25 * made into a ticket) by an authorized party.
26 *
27 * @param[in,out] context The FAPI context
28 * @param[in] policyPath The path to the policy file
29 * @param[in] keyPath The path to the signing key
30 * @param[in] policyRef A byte buffer that is included in the signature. May be
31 * NULL
32 * @param[in] policyRefSize The size of policyRef. Must be 0 if policyRef is
33 * NULL
34 *
35 * @retval TSS2_RC_SUCCESS: if the function call was a success.
36 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, policyPath or keyPath
37 * is NULL.
38 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
39 * @retval TSS2_FAPI_RC_BAD_PATH: if policyPath or keyPath does not
40 * map to a FAPI policy or key object.
41 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
42 * operation already pending.
43 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
44 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
45 * internal operations or return parameters.
46 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
47 * config file.
48 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
49 * the function.
50 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
51 * this function needs to be called again.
52 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
53 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
54 * during authorization.
55 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
56 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
57 * is not set.
58 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
59 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
60 * was not successful.
61 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
62 */
63 TSS2_RC
Fapi_AuthorizePolicy(FAPI_CONTEXT * context,char const * policyPath,char const * keyPath,uint8_t const * policyRef,size_t policyRefSize)64 Fapi_AuthorizePolicy(
65 FAPI_CONTEXT *context,
66 char const *policyPath,
67 char const *keyPath,
68 uint8_t const *policyRef,
69 size_t policyRefSize)
70 {
71 TSS2_RC r, r2;
72
73 LOG_TRACE("called for context:%p", context);
74
75 /* Check for NULL parameters */
76 check_not_null(context);
77 check_not_null(policyPath);
78 check_not_null(keyPath);
79
80 /* Check whether TCTI and ESYS are initialized */
81 return_if_null(context->esys, "Command can't be executed in none TPM mode.",
82 TSS2_FAPI_RC_NO_TPM);
83
84 /* If the async state automata of FAPI shall be tested, then we must not set
85 the timeouts of ESYS to blocking mode.
86 During testing, the mssim tcti will ensure multiple re-invocations.
87 Usually however the synchronous invocations of FAPI shall instruct ESYS
88 to block until a result is available. */
89 #ifndef TEST_FAPI_ASYNC
90 r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
91 return_if_error_reset_state(r, "Set Timeout to blocking");
92 #endif /* TEST_FAPI_ASYNC */
93
94 r = Fapi_AuthorizePolicy_Async(context, policyPath, keyPath,
95 policyRef, policyRefSize);
96 return_if_error_reset_state(r, "Policy_AuthorizeNewpolicy");
97
98 do {
99 /* We wait for file I/O to be ready if the FAPI state automata
100 are in a file I/O state. */
101 r = ifapi_io_poll(&context->io);
102 return_if_error(r, "Something went wrong with IO polling");
103
104 /* Repeatedly call the finish function, until FAPI has transitioned
105 through all execution stages / states of this invocation. */
106 r = Fapi_AuthorizePolicy_Finish(context);
107 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
108
109 /* Reset the ESYS timeout to non-blocking, immediate response. */
110 r2 = Esys_SetTimeout(context->esys, 0);
111 return_if_error(r2, "Set Timeout to non-blocking");
112
113 return_if_error_reset_state(r, "PolicyAuthorizeNewPolicy");
114
115 return TSS2_RC_SUCCESS;
116 }
117
118 /** Asynchronous function for Fapi_AuthorizePolicy
119 *
120 * If a current policy happens to be a PolicyAuthorize, then for it to be used,
121 * the user must first satisfy a policy authorized by a having been signed (and
122 * made into a ticket) by an authorized party.
123 *
124 * Call Fapi_AuthorizePolicy_Finish to finish the execution of this command.
125 *
126 * @param[in,out] context The FAPI context
127 * @param[in] policyPath The path to the policy file
128 * @param[in] keyPath The path to the signing key
129 * @param[in] policyRef A byte buffer that is included in the signature. May be
130 * NULL
131 * @param[in] policyRefSize The size of policyRef. Must be 0 if policyRef is
132 * NULL
133 *
134 * @retval TSS2_RC_SUCCESS: if the function call was a success.
135 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, policyPath or keyPath
136 * is NULL.
137 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
138 * @retval TSS2_FAPI_RC_BAD_PATH: if policyPath or keyPath does not
139 * map to a FAPI policy or key object.
140 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
141 * operation already pending.
142 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
143 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
144 * internal operations or return parameters.
145 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
146 * the function.
147 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
148 * config file.
149 */
150 TSS2_RC
Fapi_AuthorizePolicy_Async(FAPI_CONTEXT * context,char const * policyPath,char const * keyPath,uint8_t const * policyRef,size_t policyRefSize)151 Fapi_AuthorizePolicy_Async(
152 FAPI_CONTEXT *context,
153 char const *policyPath,
154 char const *keyPath,
155 uint8_t const *policyRef,
156 size_t policyRefSize)
157 {
158 LOG_TRACE("called for context:%p", context);
159 LOG_TRACE("policyPath: %s", policyPath);
160 LOG_TRACE("keyPath: %s", keyPath);
161 if (policyRef) {
162 LOGBLOB_TRACE(policyRef, policyRefSize, "policyRef");
163 } else {
164 LOG_TRACE("policyRef: (null) policyRefSize: %zi", policyRefSize);
165 }
166
167 TSS2_RC r;
168 IFAPI_Fapi_AuthorizePolicy *policy;
169
170 /* Check for NULL parameters */
171 check_not_null(context);
172 check_not_null(policyPath);
173 check_not_null(keyPath);
174
175 /* Reset all context-internal session state information. */
176 r = ifapi_session_init(context);
177 return_if_error(r, "Initialize AuthorizePolicy");
178
179 /* Copy parameters to context for use during _Finish. */
180 policy = &context->cmd.Policy_AuthorizeNewPolicy;
181 strdup_check(policy->policyPath, policyPath, r, error_cleanup);
182 strdup_check(policy->signingKeyPath, keyPath, r, error_cleanup);
183 if (policyRef) {
184 FAPI_COPY_DIGEST(&policy->policyRef.buffer[0],
185 policy->policyRef.size, policyRef, policyRefSize);
186 } else {
187 policy->policyRef.size = 0;
188 }
189
190 /* Initialize the context state for this operation. */
191 context->state = AUTHORIZE_NEW_LOAD_KEY;
192
193 LOG_TRACE("finished");
194 return TSS2_RC_SUCCESS;
195
196 error_cleanup:
197 /* Cleanup duplicated input parameters that were copied before. */
198 SAFE_FREE(policy->policyPath);
199 SAFE_FREE(policy->signingKeyPath);
200 return r;
201 }
202
203 /** Asynchronous finish function for Fapi_AuthorizePolicy
204 *
205 * This function should be called after a previous Fapi_AuthorizePolicy_Async.
206 *
207 * @param[in,out] context The FAPI_CONTEXT
208 *
209 * @retval TSS2_RC_SUCCESS: if the function call was a success.
210 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
211 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
212 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
213 * operation already pending.
214 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
215 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
216 * internal operations or return parameters.
217 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
218 * complete. Call this function again later.
219 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
220 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
221 * during authorization.
222 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
223 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
224 * the function.
225 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
226 * is not set.
227 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
228 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
229 * was not successful.
230 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
231 */
232 TSS2_RC
Fapi_AuthorizePolicy_Finish(FAPI_CONTEXT * context)233 Fapi_AuthorizePolicy_Finish(
234 FAPI_CONTEXT *context)
235 {
236 LOG_TRACE("called for context:%p", context);
237
238 TSS2_RC r;
239 TPMI_ALG_HASH hashAlg;
240 IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL;
241 size_t hashSize;
242 size_t digestIdx;
243 TPM2B_DIGEST aHash;
244 char *publicKey = NULL;
245
246 /* Check for NULL parameters */
247 check_not_null(context);
248
249 /* Helpful alias pointers */
250 IFAPI_Fapi_AuthorizePolicy * command =
251 &context->cmd.Policy_AuthorizeNewPolicy;
252 TPMS_POLICYAUTHORIZATION *authorization = &command->authorization;
253 TPMS_POLICY *policy = &context->policy.policy;
254 TPMT_SIGNATURE *signature;
255 IFAPI_OBJECT ** keyObject = &context->Key_Sign.key_object;
256
257 switch (context->state) {
258 statecase(context->state, AUTHORIZE_NEW_LOAD_KEY);
259 /* Load the key used for signing the policy authorization. */
260 r = ifapi_load_key(context, command->signingKeyPath,
261 keyObject);
262 return_try_again(r);
263 goto_if_error(r, "Fapi sign.", cleanup);
264
265 fallthrough;
266
267 statecase(context->state, AUTHORIZE_NEW_CALCULATE_POLICY);
268 /*
269 * NameAlg of signing key will be used to compute the aHash digest.
270 * This NameAlg will also be used to compute the policy digest.
271 * Thus the NameAlg must be equal to the NameAlg of the object to
272 * be authorized.
273 */
274 hashAlg = (*keyObject)->misc.key.public.publicArea.nameAlg;
275
276 if (!(hashSize = ifapi_hash_get_digest_size(hashAlg))) {
277 goto_error(r, TSS2_ESYS_RC_NOT_IMPLEMENTED,
278 "Unsupported hash algorithm (%" PRIu16 ")",
279 cleanup, hashAlg);
280 }
281
282 /* Calculate the policy digest of the policy to be authorized. */
283 r = ifapi_calculate_tree(context,
284 command->policyPath, policy,
285 hashAlg, &digestIdx, &hashSize);
286 return_try_again(r);
287 goto_if_error(r, "Fapi calculate tree.", cleanup);
288
289 /* Compute the aHash from policy digest and policyRef */
290 r = ifapi_crypto_hash_start(&cryptoContext, hashAlg);
291 goto_if_error(r, "crypto hash start", cleanup);
292
293 HASH_UPDATE_BUFFER(cryptoContext,
294 &policy->
295 policyDigests.digests[digestIdx].digest, hashSize,
296 r, cleanup);
297 if (command->policyRef.size > 0) {
298 HASH_UPDATE_BUFFER(cryptoContext,
299 &command->policyRef.buffer[0],
300 command->policyRef.size, r, cleanup);
301 }
302 r = ifapi_crypto_hash_finish(&cryptoContext,
303 (uint8_t *) & aHash.buffer[0], &hashSize);
304 goto_if_error(r, "crypto hash finish", cleanup);
305
306 aHash.size = hashSize;
307 LOGBLOB_TRACE(&command->policyRef.buffer[0], command->policyRef.size, "policyRef");
308 LOGBLOB_TRACE(&aHash.buffer[0], aHash.size, "aHash");
309
310 fallthrough;
311
312 statecase(context->state, AUTHORIZE_NEW_KEY_SIGN_POLICY);
313 /* Perform the singing operation on the policy's aHash. */
314 r = ifapi_key_sign(context, *keyObject, NULL,
315 &aHash, &signature, &publicKey, NULL);
316 return_try_again(r);
317 goto_if_error(r, "Fapi sign.", cleanup);
318
319 SAFE_FREE(publicKey);
320
321 /* Store the signature results and cleanup remainters. */
322 authorization->signature = *signature;
323 authorization->policyRef = command->policyRef;
324 strdup_check(authorization->type, "tpm", r, cleanup);
325 authorization->key =
326 (*keyObject)->misc.key.public.publicArea;
327 SAFE_FREE(signature);
328 ifapi_cleanup_ifapi_object(*keyObject);
329
330 /* Extend the authorization to the policy stored. */
331 ifapi_extend_authorization(policy, authorization);
332 goto_if_null(policy->policyAuthorizations,
333 "Out of memory", TSS2_FAPI_RC_MEMORY, cleanup);
334
335 fallthrough;
336
337 statecase(context->state, AUTHORIZE_NEW_WRITE_POLICY_PREPARE);
338 /* Store the newly authorized policy in the policy store. */
339 r = ifapi_policy_store_store_async(&context->pstore, &context->io,
340 command->policyPath, policy);
341 goto_if_error_reset_state(r, "Could not open: %s", cleanup,
342 command->policyPath);
343
344 fallthrough;
345
346 statecase(context->state, AUTHORIZE_NEW_WRITE_POLICY);
347 r = ifapi_policy_store_store_finish(&context->pstore, &context->io);
348 return_try_again(r);
349 return_if_error_reset_state(r, "write_finish failed");
350
351 fallthrough;
352
353 statecase(context->state, AUTHORIZE_NEW_CLEANUP)
354 /* Cleanup and reset the context state. */
355 r = ifapi_cleanup_session(context);
356 try_again_or_error_goto(r, "Cleanup", cleanup);
357
358 context->state = _FAPI_STATE_INIT;
359 break;
360
361 statecasedefault(context->state);
362 }
363
364 cleanup:
365 /* Cleanup any intermediate results and state stored in the context. */
366 if (cryptoContext)
367 ifapi_crypto_hash_abort(&cryptoContext);
368 ifapi_session_clean(context);
369 ifapi_cleanup_policy(policy);
370 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
371 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
372 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
373 SAFE_FREE(command->policyPath);
374 SAFE_FREE(command->signingKeyPath);
375 LOG_TRACE("finished");
376 return r;
377 }
378