• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_policy_execute.h"
19 #include "ifapi_policyutil_execute.h"
20 #include "ifapi_helpers.h"
21 #include "ifapi_json_deserialize.h"
22 #include "tpm_json_deserialize.h"
23 #include "ifapi_policy_callbacks.h"
24 #include "ifapi_policyutil_execute.h"
25 #define LOGMODULE fapi
26 #include "util/log.h"
27 #include "util/aux_util.h"
28 
29 /** Create a new policy on policy stack.
30  *
31  * The structures for policy and callback execution are allocated
32  * and the callbacks are assigned.
33  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
34  */
35 static TSS2_RC
new_policy(FAPI_CONTEXT * context,TPMS_POLICY * policy,IFAPI_POLICYUTIL_STACK ** current_policy)36 new_policy(
37     FAPI_CONTEXT *context,
38     TPMS_POLICY *policy,
39     IFAPI_POLICYUTIL_STACK **current_policy)
40 {
41     LOG_DEBUG("ADD POLICY");
42     IFAPI_POLICY_EXEC_CTX *pol_exec_ctx;
43     IFAPI_POLICY_EXEC_CB_CTX *pol_exec_cb_ctx;
44 
45     *current_policy = calloc(sizeof(IFAPI_POLICYUTIL_STACK), 1);
46     if (!*current_policy) {
47         return_error(TSS2_FAPI_RC_MEMORY, "Out of memory");
48     }
49 
50     pol_exec_ctx = calloc(sizeof(IFAPI_POLICY_EXEC_CTX), 1);
51     if (!pol_exec_ctx) {
52         return_error(TSS2_FAPI_RC_MEMORY, "Out of memory");
53     }
54     (*current_policy)->pol_exec_ctx = pol_exec_ctx;
55     pol_exec_ctx->callbacks.cbauth = ifapi_policyeval_cbauth;
56     pol_exec_ctx->callbacks.cbauth_userdata = context;
57     pol_exec_ctx->callbacks.cbpolsel = ifapi_branch_selection;
58     pol_exec_ctx->callbacks.cbpolsel_userdata = context;
59     pol_exec_ctx->callbacks.cbsign = ifapi_sign_buffer;
60     pol_exec_ctx->callbacks.cbsign_userdata = context;
61     pol_exec_ctx->callbacks.cbauthpol = ifapi_exec_auth_policy;
62     pol_exec_ctx->callbacks.cbauthpol_userdata = context;
63     pol_exec_ctx->callbacks.cbauthnv = ifapi_exec_auth_nv_policy;
64     pol_exec_ctx->callbacks.cbauthnv_userdata = context;
65     pol_exec_ctx->callbacks.cbdup = ifapi_get_duplicate_name;
66     pol_exec_ctx->callbacks.cbdup_userdata = context;
67     pol_exec_ctx->callbacks.cbaction = ifapi_policy_action;
68     pol_exec_ctx->callbacks.cbaction_userdata = context;
69 
70     pol_exec_cb_ctx = calloc(sizeof(IFAPI_POLICY_EXEC_CB_CTX), 1);
71     if (!pol_exec_cb_ctx) {
72         return_error(TSS2_FAPI_RC_MEMORY, "Out of memory");
73     }
74     pol_exec_ctx->app_data = pol_exec_cb_ctx;
75     pol_exec_ctx->policy = policy;
76     if (!context->policy.policyutil_stack) {
77         context->policy.policyutil_stack = *current_policy;
78         context->policy.util_current_policy = *current_policy;
79     } else {
80         context->policy.util_current_policy->next = *current_policy;
81         (*current_policy)->prev = context->policy.util_current_policy;
82     }
83     return TSS2_RC_SUCCESS;
84 }
85 
86 /** Compute a new session which will be uses as policy session.
87  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
88  *         this function needs to be called again.
89  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
90  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
91  */
92 static TSS2_RC
create_session(FAPI_CONTEXT * context,ESYS_TR * session,TPMI_ALG_HASH hash_alg)93 create_session(
94     FAPI_CONTEXT *context,
95     ESYS_TR *session,
96     TPMI_ALG_HASH hash_alg)
97 {
98     TSS2_RC r = TSS2_RC_SUCCESS;
99 
100     switch (context->policy.create_session_state) {
101     case CREATE_SESSION_INIT:
102         r = Esys_StartAuthSession_Async(context->esys,
103                                         context->srk_handle ? context->srk_handle : ESYS_TR_NONE,
104                                         ESYS_TR_NONE,
105                                         ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
106                                         NULL,
107                                         TPM2_SE_POLICY,
108                                         &context->profiles.default_profile.session_symmetric,
109                                         hash_alg);
110 
111         return_if_error(r, "Creating session.");
112 
113         context->policy.create_session_state = WAIT_FOR_CREATE_SESSION;
114         return TSS2_FAPI_RC_TRY_AGAIN;
115 
116     case WAIT_FOR_CREATE_SESSION:
117         r = Esys_StartAuthSession_Finish(context->esys, session);
118         if (r != TSS2_RC_SUCCESS)
119             return r;
120         context->policy.create_session_state = CREATE_SESSION_INIT;
121         break;
122 
123     default:
124         context->state = _FAPI_STATE_INTERNALERROR;
125         goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Invalid state for create session.",
126                    cleanup);
127     }
128 
129 cleanup:
130     return r;
131 }
132 
133 /** Cleanup the current policy and adapt the policy stack.
134  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
135  */
136 static TSS2_RC
clear_current_policy(FAPI_CONTEXT * context)137 clear_current_policy(FAPI_CONTEXT *context)
138 {
139     LOG_DEBUG("CLEAR POLICY");
140     IFAPI_POLICYUTIL_STACK *prev_pol;
141     if (!context->policy.util_current_policy) {
142         return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "No current policy.");
143     }
144     prev_pol = context->policy.util_current_policy->prev;
145 
146     SAFE_FREE(context->policy.util_current_policy->pol_exec_ctx->app_data);
147     SAFE_FREE(context->policy.util_current_policy->pol_exec_ctx);
148     SAFE_FREE(context->policy.util_current_policy);
149 
150     if (!prev_pol) {
151         context->policy.policyutil_stack = NULL;
152     } else {
153         prev_pol->next = NULL;
154     }
155     return TSS2_RC_SUCCESS;
156 }
157 
158 /** Cleanup the policy stack.
159   *
160   * Will be used if an error occurs.
161   */
162 static void
clear_all_policies(FAPI_CONTEXT * context)163 clear_all_policies(FAPI_CONTEXT *context)
164 {
165     LOG_DEBUG("CLEAR ALL POLICIES");
166 
167     IFAPI_POLICYUTIL_STACK *policy = context->policy.policyutil_stack;
168     IFAPI_POLICYUTIL_STACK *next_policy;
169 
170     while (policy) {
171         next_policy = policy->next;
172         SAFE_FREE(policy->pol_exec_ctx->app_data);
173         if (policy->pol_exec_ctx->session)
174             Esys_FlushContext(context->esys, policy->pol_exec_ctx->session);
175         SAFE_FREE(policy->pol_exec_ctx);
176         ;
177         SAFE_FREE(policy);
178         policy = next_policy;
179     }
180     context->policy.policyutil_stack = NULL;
181 }
182 
183 /** Prepare the execution of a new policy on policy stack.
184  *
185  * The context for the  policy utility, the policy execution and the needed
186  * callbacks is initialized.
187  * The policy execution will be prepared. In this step the list of policies
188  * to be executed will be computed.
189  * @param[in,out] context The fapi context with the pointer to the policy stack.
190  * @param[in] hash_alg The hash algorithm used for the policy computation.
191  * @param[in,out] policy The policy to be executed. Some policy elements will
192  *                be used to store computed parameters needed for policy
193  *                execution.
194  * @retval TSS2_RC_SUCCESS on success.
195  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN If the callback for branch selection is
196  *         not defined. This callback will be needed of or policies have to be
197  *         executed.
198  * @retval TSS2_FAPI_RC_BAD_VALUE If the computed branch index deliverd by the
199  *         callback does not identify a branch.
200  * @retval TSS2_FAPI_RC_BAD_REFERENCE If no context is passed.
201  *
202  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
203  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
204  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
205  */
206 TSS2_RC
ifapi_policyutil_execute_prepare(FAPI_CONTEXT * context,TPMI_ALG_HASH hash_alg,TPMS_POLICY * policy)207 ifapi_policyutil_execute_prepare(
208     FAPI_CONTEXT *context,
209     TPMI_ALG_HASH hash_alg,
210     TPMS_POLICY *policy)
211 {
212     TSS2_RC r;
213     IFAPI_POLICYUTIL_STACK *current_policy;
214 
215     return_if_null(context, "Bad context.", TSS2_FAPI_RC_BAD_REFERENCE);
216 
217     r = new_policy(context, policy, &current_policy);
218     goto_if_error(r, "Create new policy.", error);
219 
220     r = ifapi_policyeval_execute_prepare(current_policy->pol_exec_ctx, hash_alg, policy);
221     goto_if_error(r, "Prepare policy execution.", error);
222 
223     return r;
224 
225 error:
226     while (context->policy.policyutil_stack) {
227         clear_all_policies(context);
228     }
229     SAFE_FREE(current_policy);
230     return r;
231 }
232 /** State machine to Execute the TPM policy commands needed for the current policy.
233  *
234  * In the first step a session will be created if no session is passed.
235  * In the second step the policy engine will execute the policy.
236  *
237  * @param[in,out] context The fapi context with the pointer to the policy stack.
238  * @param[in,out] session The policy session to be extended or if the value is
239  *                equal zero or ESYS_TR_NONE a new created session will been
240  *                be stored in this parameter.
241  * @retval TSS2_RC_SUCCESS on success.
242  * @retval TSS2_FAPI_RC_MEMORY: if not enough memory can be allocated.
243  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
244  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy
245  *         store.
246  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
247  *         not successful.
248  * @retval TSS2_FAPI_RC_BAD_TEMPLATE In a invalid policy is loaded during execution.
249  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for policy
250  *         execution fails.
251  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
252  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
253  *         this function needs to be called again.
254  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
255  *         operation already pending.
256  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
257  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
258  *         during authorization.
259  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
260  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
261  *         is not set.
262  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
263  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
264  */
265 TSS2_RC
ifapi_policyutil_execute(FAPI_CONTEXT * context,ESYS_TR * session)266 ifapi_policyutil_execute(FAPI_CONTEXT *context, ESYS_TR *session)
267 {
268     TSS2_RC r;
269     IFAPI_POLICYUTIL_STACK *pol_util_ctx;
270     TPMI_ALG_HASH hash_alg;
271 
272     if (context->policy.util_current_policy) {
273         pol_util_ctx = context->policy.util_current_policy->next;
274         context->policy.util_current_policy = context->policy.util_current_policy->next;
275     } else {
276         pol_util_ctx = context->policy.policyutil_stack;
277         context->policy.util_current_policy = pol_util_ctx;
278     }
279     LOG_TRACE("Util context: %p", pol_util_ctx);
280 
281     if (!pol_util_ctx) {
282         return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "No policy util stack.");
283     }
284 
285     switch (pol_util_ctx->state) {
286         statecase(pol_util_ctx->state, POLICY_UTIL_INIT);
287             LOG_DEBUG("Util session: %x", pol_util_ctx->policy_session);
288             if (*session == ESYS_TR_NONE  || *session == 0) {
289                 /* Create a new  policy session for the current policy execution */
290                 hash_alg = pol_util_ctx->pol_exec_ctx->hash_alg;
291                 r = create_session(context, &pol_util_ctx->policy_session,
292                                   hash_alg);
293                 if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
294                     context->policy.util_current_policy = pol_util_ctx->prev;
295                     return TSS2_FAPI_RC_TRY_AGAIN;
296                 }
297                 goto_if_error(r, "Create policy session", error);
298 
299                 pol_util_ctx->pol_exec_ctx->session = pol_util_ctx->policy_session;
300             } else {
301                 pol_util_ctx->pol_exec_ctx->session = *session;
302             }
303             fallthrough;
304 
305         statecase(pol_util_ctx->state, POLICY_UTIL_EXEC_POLICY);
306             r = ifapi_policyeval_execute(context->esys,
307                                          pol_util_ctx->pol_exec_ctx);
308             if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) {
309                 context->policy.util_current_policy = pol_util_ctx->prev;
310                 return TSS2_FAPI_RC_TRY_AGAIN;
311             }
312             goto_if_error(r, "Execute policy.", error);
313 
314             break;
315 
316         statecasedefault(pol_util_ctx->state);
317     }
318     *session = pol_util_ctx->policy_session;
319 
320     pol_util_ctx = pol_util_ctx->prev;
321 
322     r = clear_current_policy(context);
323     goto_if_error(r, "Clear policy.", error);
324 
325     context->policy.util_current_policy = pol_util_ctx;
326 
327     LOG_TRACE("success");
328     return r;
329 
330 error:
331     while (context->policy.policyutil_stack) {
332         clear_all_policies(context);
333     }
334     return r;
335 }
336