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