xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/ifapi_policy_instantiate.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 <string.h>
12 #include <stdlib.h>
13 
14 #include "tss2_mu.h"
15 #include "fapi_util.h"
16 #include "fapi_crypto.h"
17 //#include "fapi_policy.h"
18 #include "ifapi_helpers.h"
19 #include "ifapi_policy_instantiate.h"
20 #include "ifapi_json_deserialize.h"
21 #include "tpm_json_deserialize.h"
22 #define LOGMODULE fapi
23 #include "util/log.h"
24 #include "util/aux_util.h"
25 
26 static TSS2_RC
27 get_policy_elements(TPML_POLICYELEMENTS *policy, NODE_OBJECT_T **policy_element_list);
28 
29 /** Compute linked list with a list of policy elements which could be instantiated.
30  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
31  */
32 static TSS2_RC
get_policy_elements(TPML_POLICYELEMENTS * policy,NODE_OBJECT_T ** policy_element_list)33 get_policy_elements(TPML_POLICYELEMENTS *policy, NODE_OBJECT_T **policy_element_list)
34 {
35     TSS2_RC r = TSS2_RC_SUCCESS;
36     size_t i, j;
37 
38     for (i = 0; i < policy->count; i++) {
39         if (policy->elements[i].type == POLICYOR) {
40             /* Policy with sub policies */
41             TPML_POLICYBRANCHES *branches = policy->elements[i].element.PolicyOr.branches;
42             for (j = 0; j < branches->count; j++) {
43                 r = get_policy_elements(branches->authorizations[j].policy,
44                                         policy_element_list);
45                 goto_if_error(r, "Get policy elements.", error_cleanup);
46             }
47         } else {
48             r = push_object_to_list(&policy->elements[i], policy_element_list);
49             goto_if_error(r, "Get policy elements.", error_cleanup);
50         }
51     }
52     return r;
53 
54 error_cleanup:
55     ifapi_free_node_list(*policy_element_list);
56     return r;
57 }
58 
59 /** Prepare instantiation a policy template.
60  *
61  * Parts of policies which are referenced by object paths will be replaced with
62  * the appropriate values of the referenced objects.
63  *
64  * @param[in] context The context storing information for re-entry after try again.
65  * @param[in] policy The policy to be instantiated.
66  * @param[in] callbacks The needed callback functions with the corresponding user data
67  *           which will be passed to the callback.
68  * @retval TSS2_RC_SUCCESS on success.
69  * @retval FAPI error codes on failure
70  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
71  */
72 TSS2_RC
ifapi_policyeval_instantiate_async(IFAPI_POLICY_EVAL_INST_CTX * context,TPMS_POLICY * policy,ifapi_policyeval_INST_CB * callbacks)73 ifapi_policyeval_instantiate_async(
74     IFAPI_POLICY_EVAL_INST_CTX *context, /* For re-entry after try_again for offsets and such */
75     TPMS_POLICY *policy, /* in */
76     ifapi_policyeval_INST_CB *callbacks)
77 {
78     TSS2_RC r;
79 
80     /* Store callbacks and their parameters in context */
81     context->callbacks = *callbacks;
82 
83     /* Compute list of all policy elements which have to be instantiated */
84     if (context->policy_elements) {
85         ifapi_free_object_list(context->policy_elements);
86         context->policy_elements = NULL;
87     }
88     r = get_policy_elements(policy->policy, &context->policy_elements);
89     return r;
90 }
91 
92 /** Compute name and public information format a PEM key.
93  *
94  * @param[in]  keyPEM The key in PEM format.
95  * @param[out] keyPublic The public information of the PEM key.
96  * @param[out] name the name computed from the public information.
97  * @param[in]  hash_alg The name alg of the key has to passed.
98  * @retval TSS2_RC_SUCCESS on success.
99  */
100 static TSS2_RC
set_pem_key_param(const char * keyPEM,TPMT_PUBLIC * keyPublic,TPM2B_NAME * name,TPMI_ALG_HASH hash_alg)101 set_pem_key_param(
102     const char *keyPEM,
103     TPMT_PUBLIC *keyPublic,
104     TPM2B_NAME *name,
105     TPMI_ALG_HASH hash_alg)
106 {
107     TSS2_RC r;
108     TPM2B_PUBLIC public;
109 
110     if (!keyPEM || strlen(keyPEM) == 0) {
111         /* No PEM key used. Parameters are already set in policy. */
112         return TSS2_RC_SUCCESS;
113     }
114 
115     /* Use PEM key to compute public information and name */
116     name->size = 0;
117 
118     TPM2_ALG_ID rsaOrEcc = ifapi_get_signature_algorithm_from_pem(keyPEM);
119     r = ifapi_initialize_sign_public(rsaOrEcc, &public);
120     return_if_error(r, "Could not initialize public info of key");
121 
122     r = ifapi_get_tpm2b_public_from_pem(keyPEM, &public);
123     return_if_error(r, "Invalid PEM key.");
124 
125     *keyPublic = public.publicArea;
126     keyPublic->nameAlg = hash_alg;
127     r = ifapi_get_name(&public.publicArea, name);
128     return_if_error(r, "Compute key name.");
129 
130     return TSS2_RC_SUCCESS;
131 }
132 
133 #define CHECK_TEMPLATE_PATH(path, template) \
134      if (!path) { \
135          return_error2(TSS2_FAPI_RC_BAD_TEMPLATE, "No path for policy %s", template); \
136      }
137 
138 /** Finalize  instantiation a policy template.
139  *
140  * All needed asyncroous callbacks will be executed for all policy elements offset
141  * The policy.
142  *
143  * @param[in] context The context storing information for re-entry after try again.
144  * @retval TSS2_RC_SUCCESS on success.
145  * @retval TSS2_FAPI_RC_BAD_TEMPLATE If the templayte is not complete for instantiation.
146  * @retval FAPI error codes on failure
147  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
148  *         this function needs to be called again.
149  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
150  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
151  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
152  *         the function.
153  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
154  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
155  *         operation already pending.
156  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
157  *         during authorization.
158  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
159  * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
160  *         object store.
161  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
162  */
163 TSS2_RC
ifapi_policyeval_instantiate_finish(IFAPI_POLICY_EVAL_INST_CTX * context)164 ifapi_policyeval_instantiate_finish(
165     IFAPI_POLICY_EVAL_INST_CTX *context)
166 {
167     TSS2_RC r = TSS2_RC_SUCCESS;
168     NODE_OBJECT_T *first_in_pol_list = context->policy_elements;
169     size_t i_last;
170 
171     /* While not all policy elements are instantiated */
172     while (first_in_pol_list) {
173         TPMT_POLICYELEMENT *pol_element = first_in_pol_list->object;
174         switch (pol_element->type) {
175         case POLICYSIGNED:
176             if (pol_element->element.PolicySigned.keyPublic.type) {
177                 /* Public info found in template, key path will not be needed. */
178                 SAFE_FREE(pol_element->element.PolicySigned.keyPath);
179                 break;
180             }
181 
182             if (pol_element->element.PolicySigned.keyPEM &&
183                 strlen(pol_element->element.PolicySigned.keyPEM) > 0) {
184                 /* Determine name and public info for PEM key. */
185                 r = set_pem_key_param(pol_element->element.PolicySigned.keyPEM,
186                                       &pol_element->element.PolicySigned.keyPublic,
187                                       &pol_element->element.PolicySigned.publicKey,
188                                       pol_element->element.PolicySigned.keyPEMhashAlg);
189                 return_if_error(r, "Set parameter of pem key.");
190 
191                 /* Clear pem key, will be recreated during execution. */
192                 SAFE_FREE(pol_element->element.PolicySigned.keyPEM);
193 
194                 break;
195             }
196             CHECK_TEMPLATE_PATH(pol_element->element.PolicySigned.keyPath, "PolicySigned");
197 
198             /* Public info will be added to policy. */
199             r = context->callbacks.cbpublic(pol_element->element.PolicySigned.keyPath,
200                                             &pol_element->element.PolicySigned.keyPublic,
201                                             context->callbacks.cbpublic_userdata);
202             return_try_again(r);
203             return_if_error(r, "read_finish failed");
204             /* Clear keypath, only public data will be needed */
205             SAFE_FREE(pol_element->element.PolicySigned.keyPath);
206 
207             break;
208 
209         case POLICYNAMEHASH:
210             /* Set index of last name to be computed. */
211             i_last = pol_element->element.PolicyNameHash.count - 1;
212             while (!pol_element->element.PolicyNameHash.objectNames[i_last].size) {
213                 /* Not all object names have been computed or were initialized */
214                 size_t i = pol_element->element.PolicyNameHash.i;
215                 r = context->callbacks.cbname(pol_element->element.PolicyNameHash.namePaths[i],
216                                               &pol_element->element.PolicyNameHash.objectNames[i],
217                                               context->callbacks.cbname_userdata);
218                 return_try_again(r);
219                 return_if_error(r, "get object name.");
220                 pol_element->element.PolicyNameHash.i++;
221                 SAFE_FREE(pol_element->element.PolicyNameHash.namePaths[i]);
222             }
223             break;
224 
225         case POLICYSECRET:
226             if (pol_element->element.PolicySecret.objectName.size) {
227                 /* Name found in template, object path will not be needed. */
228                 SAFE_FREE(pol_element->element.PolicySecret.objectPath);
229                 break;
230             }
231             CHECK_TEMPLATE_PATH(pol_element->element.PolicySecret.objectPath, "PolicySecret");
232             /* Object name will be added to policy. */
233             r = context->callbacks.cbname(pol_element->element.PolicySecret.objectPath,
234                                           &pol_element->element.PolicySecret.objectName,
235                                           context->callbacks.cbname_userdata);
236             return_try_again(r);
237             return_if_error(r, "read_finish failed");
238             SAFE_FREE(pol_element->element.PolicySecret.objectPath);
239             break;
240 
241         case POLICYPCR:
242             if (pol_element->element.PolicyPCR.pcrs &&
243                 pol_element->element.PolicyPCR.pcrs->count) {
244                 /* PCR values already defined */
245                 break;
246             }
247             /* Current values of PCRs will be used for policy */
248             r = context->callbacks.cbpcr(&pol_element->element.PolicyPCR.currentPCRs,
249                                          &pol_element->element.PolicyPCR.currentPCRandBanks,
250                                          &pol_element->element.PolicyPCR.pcrs,
251                                          context->callbacks.cbpcr_userdata);
252             return_try_again(r);
253             return_if_error(r, "read_finish failed");
254 
255             pol_element->element.PolicyPCR.currentPCRs.sizeofSelect = 0;
256             pol_element->element.PolicyPCR.currentPCRandBanks.count = 0;
257             break;
258 
259         case POLICYNV:
260             if (pol_element->element.PolicyNV.nvPublic.nvPublic.nvIndex) {
261                 /* nvIndex is already set in policy. Path will not be needed */
262                 pol_element->element.PolicyNV.nvIndex
263                     = pol_element->element.PolicyNV.nvPublic.nvPublic.nvIndex;
264                 SAFE_FREE(pol_element->element.PolicyNV.nvPath);
265                 break;
266             }
267 
268             CHECK_TEMPLATE_PATH(pol_element->element.PolicyNV.nvPath, "PolicyNv");
269             /* Object name will be added to policy. */
270             r = context->callbacks.cbnvpublic(pol_element->element.PolicyNV.nvPath,
271                                               &pol_element->element.PolicyNV.nvPublic,
272                                               context->callbacks.cbnvpublic_userdata);
273             return_try_again(r);
274             return_if_error(r, "read_finish failed");
275 
276             pol_element->element.PolicyNV.nvIndex
277                 = pol_element->element.PolicyNV.nvPublic.nvPublic.nvIndex;
278 
279             /* Clear NV path, only public data will be needed */
280             SAFE_FREE(pol_element->element.PolicyNV.nvPath);
281             break;
282 
283         case POLICYDUPLICATIONSELECT:
284             if (pol_element->element.PolicyDuplicationSelect.newParentPublic.publicArea.type) {
285                 /* public data is already set in policy. Path will not be needed. */
286                 SAFE_FREE(pol_element->element.PolicyDuplicationSelect.newParentPath);
287                 break;
288             }
289 
290             CHECK_TEMPLATE_PATH(pol_element->element.PolicyDuplicationSelect.newParentPath,
291                                 "PolicyDuplicationselect");
292 
293             /* Public info will be added to policy. */
294             r = context->callbacks.cbpublic(
295                      pol_element->element.PolicyDuplicationSelect.newParentPath,
296                      &pol_element->element.PolicyDuplicationSelect.newParentPublic.publicArea,
297                      context->callbacks.cbpublic_userdata);
298             return_try_again(r);
299             return_if_error(r, "read_finish failed");
300 
301             r = ifapi_get_name(
302                      &pol_element->element.PolicyDuplicationSelect.newParentPublic.publicArea,
303                      &pol_element->element.PolicyDuplicationSelect.newParentName);
304             return_if_error(r, "Compute key name");
305 
306             /* Clear keypath, only public data will be needed */
307             SAFE_FREE(pol_element->element.PolicyDuplicationSelect.newParentPath);
308             break;
309 
310         case POLICYAUTHORIZENV:
311             if (pol_element->element.PolicyAuthorizeNv.nvPublic.nvPublic.nvIndex) {
312                 /* nvIndex is already set in policy. Path will not be needed */
313                 SAFE_FREE(pol_element->element.PolicyAuthorizeNv.nvPath);
314                 break;
315             }
316 
317             CHECK_TEMPLATE_PATH(pol_element->element.PolicyAuthorizeNv.nvPath,
318                                 "PolicyAuthorizeNv");
319             /* Object name will be added to policy. */
320             r = context->callbacks.cbnvpublic(pol_element->element.PolicyAuthorizeNv.nvPath,
321                                               &pol_element->element.PolicyAuthorizeNv.nvPublic,
322                                               context->callbacks.cbnvpublic_userdata);
323             return_try_again(r);
324             return_if_error(r, "read_finish failed");
325             /* Clear NV path, only public data will be needed */
326             SAFE_FREE(pol_element->element.PolicyAuthorizeNv.nvPath);
327             break;
328 
329         case POLICYAUTHORIZE:
330             if (pol_element->element.PolicyAuthorize.keyPublic.type) {
331                 /* Public info found in template, key path will not be needed. */
332                 SAFE_FREE(pol_element->element.PolicyAuthorize.keyPath);
333                 r = ifapi_get_name(&pol_element->element.PolicyAuthorize.keyPublic,
334                                    &pol_element->element.PolicyAuthorize.keyName);
335                 return_if_error(r, "Compute key name");
336 
337                 break;
338             }
339 
340             if (pol_element->element.PolicyAuthorize.keyPEM &&
341                 strlen(pol_element->element.PolicyAuthorize.keyPEM) > 0) {
342                 /* Determine name and public info for PEM key. */
343                 r = set_pem_key_param(pol_element->element.PolicyAuthorize.keyPEM,
344                                       &pol_element->element.PolicyAuthorize.keyPublic,
345                                       &pol_element->element.PolicyAuthorize.keyName,
346                                       pol_element->element.PolicyAuthorize.keyPEMhashAlg);
347                 return_if_error(r, "Set parameter of pem key.");
348 
349                 pol_element->element.PolicyAuthorize.keyPEM = NULL;
350 
351                 break;
352             }
353 
354             CHECK_TEMPLATE_PATH(pol_element->element.PolicyAuthorize.keyPath, "PolicyAuthorize");
355 
356             /* Object public data will be added to policy. */
357             r = context->callbacks.cbpublic(pol_element->element.PolicyAuthorize.keyPath,
358                                             &pol_element->element.PolicyAuthorize.keyPublic,
359                                             context->callbacks.cbpublic_userdata);
360             return_try_again(r);
361             return_if_error(r, "read_finish failed");
362 
363             /* Compute key name from public info */
364             r = ifapi_get_name(&pol_element->element.PolicyAuthorize.keyPublic,
365                                &pol_element->element.PolicyAuthorize.keyName);
366             return_if_error(r, "Compute key name");
367 
368             /* Clear key path, only public data will be needed */
369             SAFE_FREE(pol_element->element.PolicyAuthorize.keyPath);
370             break;
371         }
372         /* Cleanup head of list and use next policy element */
373         context->policy_elements = first_in_pol_list->next;
374         SAFE_FREE(first_in_pol_list);
375     }
376     return r;
377 }
378