xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_AuthorizePolicy.c (revision 758e9fba6fc9adbf15340f70c73baee7b168b1c9)
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