• 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 <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 
17 #include "tss2_fapi.h"
18 #include "fapi_int.h"
19 #include "fapi_util.h"
20 #include "fapi_policy.h"
21 #include "tss2_esys.h"
22 #define LOGMODULE fapi
23 #include "util/log.h"
24 #include "util/aux_util.h"
25 
26 /** One-Call function for Fapi_CreateNv
27  *
28  * This command creates an NV index in the TPM using a given path and type.
29  *
30  * @param[in,out] context The FAPI_CONTEXT
31  * @param[in] path The path to the new NV index
32  * @param[in] type The intended type of the new NV index. May be NULL
33  * @param[in] size The size of the new NV index in bytes. May be 0 if the size
34  *            is inferred from the type
35  * @param[in] policyPath The path to the policy that is associated with the new
36  *            NV index. May be NULL
37  * @param[in] authValue The authorization value that is associated with the new
38  *            NV index. May be NULL
39  *
40  * @retval TSS2_RC_SUCCESS: if the function call was a success.
41  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
42  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
43  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS: if an NV index already exists at
44  *         path.
45  * @retval TSS2_FAPI_RC_BAD_VALUE: if type is non-NULL but invalid or does not
46  *         match the size.
47  * @retval TSS2_FAPI_RC_BAD_PATH: if policyPath is non-NULL and does not map to
48  *         a FAPI policy or if path dos not refer to a valid NV index path.
49  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
50  *         operation already pending.
51  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
52  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
53  *         internal operations or return parameters.
54  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
55  *         config file.
56  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
57  *         this function needs to be called again.
58  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
59  *         during authorization.
60  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
61  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
62  * @retval TSS2_FAPI_RC_NV_TOO_SMALL if too many NV handles are defined.
63  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
64  *         is not set.
65  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
66  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
67  *         was not successful.
68  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
69  */
70 TSS2_RC
Fapi_CreateNv(FAPI_CONTEXT * context,char const * path,char const * type,size_t size,char const * policyPath,char const * authValue)71 Fapi_CreateNv(
72     FAPI_CONTEXT *context,
73     char   const *path,
74     char   const *type,
75     size_t size,
76     char   const *policyPath,
77     char   const *authValue)
78 {
79     LOG_TRACE("called for context:%p", context);
80 
81     TSS2_RC r, r2;
82 
83     /* Check for NULL parameters */
84     check_not_null(context);
85     check_not_null(path);
86 
87     /* Check whether TCTI and ESYS are initialized */
88     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
89                    TSS2_FAPI_RC_NO_TPM);
90 
91     /* If the async state automata of FAPI shall be tested, then we must not set
92        the timeouts of ESYS to blocking mode.
93        During testing, the mssim tcti will ensure multiple re-invocations.
94        Usually however the synchronous invocations of FAPI shall instruct ESYS
95        to block until a result is available. */
96 #ifndef TEST_FAPI_ASYNC
97     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
98     return_if_error_reset_state(r, "Set Timeout to blocking");
99 #endif /* TEST_FAPI_ASYNC */
100 
101     r = Fapi_CreateNv_Async(context, path, type, size,
102                             policyPath, authValue);
103     return_if_error_reset_state(r, "NV_CreateWithTemplate");
104 
105     do {
106         /* We wait for file I/O to be ready if the FAPI state automata
107            are in a file I/O state. */
108         r = ifapi_io_poll(&context->io);
109         return_if_error(r, "Something went wrong with IO polling");
110 
111         /* Repeatedly call the finish function, until FAPI has transitioned
112            through all execution stages / states of this invocation. */
113         r = Fapi_CreateNv_Finish(context);
114     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
115 
116     /* Reset the ESYS timeout to non-blocking, immediate response. */
117     r2 = Esys_SetTimeout(context->esys, 0);
118     return_if_error(r2, "Set Timeout to non-blocking");
119 
120     return_if_error_reset_state(r, "NV_CreateWithTemplate");
121 
122     return TSS2_RC_SUCCESS;
123 }
124 
125 /** Asynchronous function for Fapi_CreateNv
126  *
127  * This command creates an NV index in the TPM using a given path and type.
128  *
129  * Call Fapi_CreateNv_Finish to finish the execution of this command.
130  *
131  * @param[in,out] context The FAPI_CONTEXT
132  * @param[in] path The path to the new NV index
133  * @param[in] type The intended type of the new NV index. May be NULL
134  * @param[in] size The size of the new NV index in bytes. May be 0 if the size
135  *            is inferred from the type
136  * @param[in] policyPath The path to the policy that is associated with the new
137  *            NV index. May be NULL
138  * @param[in] authValue The authorization value that is associated with the new
139  *            NV index. May be NULL
140  *
141  * @retval TSS2_RC_SUCCESS: if the function call was a success.
142  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
143  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
144  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS: if an NV index already exists at
145  *         path.
146  * @retval TSS2_FAPI_RC_BAD_VALUE: if type is non-NULL but invalid or does not
147  *         match the size.
148  * @retval TSS2_FAPI_RC_BAD_PATH: if policyPath is non-NULL and does not map to
149  *         a FAPI policy or if path dos not refer to a valid NV index path.
150  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
151  *         operation already pending.
152  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
153  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
154  *         internal operations or return parameters.
155  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
156  *         config file.
157  */
158 TSS2_RC
Fapi_CreateNv_Async(FAPI_CONTEXT * context,char const * path,char const * type,size_t size,char const * policyPath,char const * authValue)159 Fapi_CreateNv_Async(
160     FAPI_CONTEXT *context,
161     char   const *path,
162     char   const *type,
163     size_t size,
164     char   const *policyPath,
165     char   const *authValue)
166 {
167     LOG_TRACE("called for context:%p", context);
168     LOG_TRACE("path: %s", path);
169     LOG_TRACE("type: %s", type);
170     LOG_TRACE("size: %zi", size);
171     LOG_TRACE("policyPath: %s", policyPath);
172     LOG_TRACE("authValue: %s", authValue);
173 
174     TSS2_RC r;
175 
176     /* Check for NULL parameters */
177     check_not_null(context);
178     check_not_null(path);
179 
180     /* Helpful alias pointers */
181     IFAPI_NV_Cmds * nvCmd = &(context->nv_cmd);
182     TPM2B_AUTH *auth = &nvCmd->auth;
183     IFAPI_NV * miscNv = &(nvCmd->nv_object.misc.nv);
184 
185     /* Reset all context-internal session state information. */
186     r = ifapi_session_init(context);
187     return_if_error(r, "Initialize NV_CreateNv");
188 
189     /* First check whether an existing object would be overwritten */
190     r = ifapi_keystore_check_overwrite(&context->keystore, &context->io,
191                                        path);
192     return_if_error2(r, "Check overwrite %s", path);
193 
194     /* Copy parameters to context for use during _Finish. */
195     memset(&context->nv_cmd, 0, sizeof(IFAPI_NV_Cmds));
196     if (authValue) {
197         if (strlen(authValue) > sizeof(TPMU_HA)) {
198             return_error(TSS2_FAPI_RC_BAD_VALUE, "AuthValue too long");
199         }
200 
201         auth->size = strlen(authValue);
202         memcpy(&auth->buffer[0], authValue, auth->size);
203     } else {
204         auth->size = 0;
205     }
206     strdup_check(nvCmd->nvPath, path, r, error_cleanup);
207     nvCmd->numBytes = size;
208     nvCmd->nv_object.objectType = IFAPI_NV_OBJ;
209     strdup_check(miscNv->policyInstance, policyPath, r, error_cleanup);
210 
211     /* Set the flags of the NV index to be created. If no type is given the empty-string
212        default type flags are set. */
213     r = ifapi_set_nv_flags(type ? type : "", &nvCmd->public_templ,
214                            policyPath);
215     goto_if_error(r, "Set key flags for NV object", error_cleanup);
216 
217     /* Initialize the context state for this operation. */
218     context->state = NV_CREATE_READ_PROFILE;
219     LOG_TRACE("finished");
220     return TSS2_RC_SUCCESS;
221 
222 error_cleanup:
223     /* Cleanup duplicated input parameters that were copied before. */
224     SAFE_FREE(nvCmd->nvPath);
225     SAFE_FREE(miscNv->policyInstance);
226     return r;
227 }
228 
229 /** Asynchronous finish function for Fapi_CreateNv
230  *
231  * This function should be called after a previous Fapi_CreateNv_Async.
232  *
233  * @param[in,out] context The FAPI_CONTEXT
234  *
235  * @retval TSS2_RC_SUCCESS: if the function call was a success.
236  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
237  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
238  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
239  *         operation already pending.
240  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
241  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
242  *         internal operations or return parameters.
243  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
244  *         complete. Call this function again later.
245  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
246  *         the function.
247  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
248  *         during authorization.
249  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
250  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
251  * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
252  * @retval TSS2_FAPI_RC_NV_TOO_SMALL if too many NV handles are defined.
253  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
254  *         is not set.
255  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
256  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
257  *         was not successful.
258  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
259  */
260 TSS2_RC
Fapi_CreateNv_Finish(FAPI_CONTEXT * context)261 Fapi_CreateNv_Finish(
262     FAPI_CONTEXT *context)
263 {
264     LOG_TRACE("called for context:%p", context);
265 
266     TSS2_RC r;
267     ESYS_TR nvHandle;
268 
269     /* Check for NULL parameters */
270     check_not_null(context);
271 
272     /* Helpful alias pointers */
273     IFAPI_NV_Cmds * nvCmd = &(context->nv_cmd);
274     TPM2B_AUTH *auth = &nvCmd->auth;
275     IFAPI_OBJECT *hierarchy = &nvCmd->auth_object;
276     IFAPI_NV * miscNv = &(nvCmd->nv_object.misc.nv);
277     TPM2B_NV_PUBLIC *publicInfo = &miscNv->public;
278     TPM2B_DIGEST * authPolicy = &(miscNv->public.nvPublic.authPolicy);
279     TPMS_POLICY * policy = &(context->policy.policy);
280     TPMS_POLICY ** nvCmdPolicy = &nvCmd->nv_object.policy;
281     ESYS_TR auth_session;
282 
283     switch (context->state) {
284         statecase(context->state, NV_CREATE_READ_PROFILE)
285             /* Mix the provided flags provided via the type with with template
286                of the current active crypto profile. */
287             r = ifapi_merge_profile_into_nv_template(context,
288                     &nvCmd->public_templ);
289             goto_if_error_reset_state(r, "Merge profile", error_cleanup);
290 
291             /* Store information from template in context */
292             miscNv->description = NULL;
293             publicInfo->nvPublic = nvCmd->public_templ.public;
294 
295             /* Check that the hierarchy for the NV index to be created is "Owner".
296                FAPI does not allow the creation of "Platform" NV indexes. */
297             if (nvCmd->public_templ.hierarchy == TPM2_RH_OWNER) {
298                 miscNv->hierarchy = ESYS_TR_RH_OWNER;
299             } else {
300                 goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Wrong hierarchy", error_cleanup);
301             }
302 
303             /* Load the Storage Hierarchy "Owner" meta data for used during
304                NV creation authorization. */
305             r = ifapi_keystore_load_async(&context->keystore, &context->io, "HS");
306             return_if_error_reset_state(r, "Could not open storage hierarchy  HS");
307             fallthrough;
308 
309         statecase(context->state, NV_CREATE_READ_HIERARCHY)
310             r = ifapi_keystore_load_finish(&context->keystore, &context->io,
311                                            &nvCmd->auth_object);
312             return_try_again(r);
313             goto_if_error_reset_state(r, "read_finish failed", error_cleanup);
314 
315             /* Initialize the esys object for the hierarchy. */
316             r = ifapi_initialize_object(context->esys, &nvCmd->auth_object);
317             goto_if_error_reset_state(r, "Initialize NV object", error_cleanup);
318 
319             nvCmd->auth_object.handle
320                 = miscNv->hierarchy;
321 
322             /* Check if a policy is set for the NV index to be created. */
323             if (miscNv->policyInstance &&
324                     strcmp(miscNv->policyInstance, "") != 0)
325                 nvCmd->skip_policy_computation = false;
326             else
327                 nvCmd->skip_policy_computation = true;
328             fallthrough;
329 
330         statecase(context->state, NV_CREATE_CALCULATE_POLICY)
331             if (!nvCmd->skip_policy_computation) {
332                 /* Calculate the policy as read for the keystore. */
333                 r = ifapi_calculate_tree(context,
334                                          miscNv->policyInstance,
335                                          policy,
336                                          miscNv->public.nvPublic.nameAlg,
337                                          &context->policy.digest_idx,
338                                          &context->policy.hash_size);
339                 return_try_again(r);
340 
341                 goto_if_error2(r, "Calculate policy tree %s", error_cleanup,
342                                context->cmd.Key_Create.policyPath);
343 
344                 /* Store the calculated policy in the NV object */
345                 *nvCmdPolicy = calloc(1,
346                         sizeof(TPMS_POLICY));
347                 goto_if_null(*nvCmdPolicy,
348                         "Out of memory,", TSS2_FAPI_RC_MEMORY, error_cleanup);
349                 **(nvCmdPolicy) = *policy;
350 
351                 authPolicy->size =
352                     context->policy.hash_size;
353                 memcpy(&authPolicy->buffer[0],
354                        &policy->policyDigests.digests[context->policy.digest_idx].digest,
355                        context->policy.hash_size);
356                 LOGBLOB_TRACE(
357                     &authPolicy->buffer[0],
358                     context->policy.hash_size, "Create Key Policy");
359             }
360             fallthrough;
361 
362         statecase(context->state, NV_CREATE_GET_INDEX)
363             r = ifapi_get_nv_start_index(nvCmd->nvPath,
364                                          &publicInfo->nvPublic.nvIndex);
365             goto_if_error_reset_state(r, "FAPI get handle index.", error_cleanup);
366 
367             /* We are searching for a new free NV-index handle. */
368             r = ifapi_get_free_handle_async(context, &publicInfo->nvPublic.nvIndex);
369             goto_if_error_reset_state(r, "FAPI get handle index.", error_cleanup);
370             nvCmd->maxNvIndex = publicInfo->nvPublic.nvIndex + 100;
371 
372             fallthrough;
373 
374         statecase(context->state, NV_CREATE_FIND_INDEX)
375             r = ifapi_get_free_handle_finish(context, &publicInfo->nvPublic.nvIndex,
376                                              nvCmd->maxNvIndex);
377             return_try_again(r);
378             goto_if_error_reset_state(r, "FAPI get handle index.", error_cleanup);
379 
380             /* Start a authorization session for the NV creation. */
381             context->primary_state = PRIMARY_INIT;
382             r = ifapi_get_sessions_async(context,
383                                          IFAPI_SESSION_GENEK | IFAPI_SESSION1,
384                                          0, 0);
385             goto_if_error_reset_state(r, "Create sessions", error_cleanup);
386             fallthrough;
387 
388         statecase(context->state, NV_CREATE_WAIT_FOR_SESSION)
389             r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
390                                           context->profiles.default_profile.nameAlg);
391             return_try_again(r);
392             goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
393 
394 
395             fallthrough;
396 
397         statecase(context->state, NV_CREATE_AUTHORIZE_HIERARCHY)
398             /* Authorize with the storage hierarhcy / "owner" for NV creation. */
399             r = ifapi_authorize_object(context, &nvCmd->auth_object, &auth_session);
400             FAPI_SYNC(r, "Authorize hierarchy.", error_cleanup);
401 
402             /* Create the NV Index. */
403             r = Esys_NV_DefineSpace_Async(context->esys,
404                                           hierarchy->handle,
405                                           auth_session,
406                                           ESYS_TR_NONE,
407                                           ESYS_TR_NONE,
408                                           auth,
409                                           publicInfo);
410             goto_if_error_reset_state(r, " Fapi_CreateNv_Async", error_cleanup);
411             fallthrough;
412 
413         statecase(context->state, NV_CREATE_AUTH_SENT)
414             r = Esys_NV_DefineSpace_Finish(context->esys, &nvHandle);
415             return_try_again(r);
416 
417             goto_if_error_reset_state(r, "FAPI CreateWithTemplate_Finish", error_cleanup);
418 
419             /* Store whether the NV index requires a password. */
420             nvCmd->nv_object.handle = nvHandle;
421             if (nvCmd->auth.size > 0)
422                 miscNv->with_auth = TPM2_YES;
423             else
424                 miscNv->with_auth = TPM2_NO;
425 
426             /* Perform esys serialization if necessary */
427             r = ifapi_esys_serialize_object(context->esys, &nvCmd->nv_object);
428             goto_if_error(r, "Prepare serialization", error_cleanup);
429 
430             /* Start writing the NV object to the key store */
431             r = ifapi_keystore_store_async(&context->keystore, &context->io,
432                                            nvCmd->nvPath,
433                                            &nvCmd->nv_object);
434             goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
435                                       nvCmd->nvPath);
436 
437             fallthrough;
438 
439         statecase(context->state, NV_CREATE_WRITE)
440             /* Finish writing the NV object to the key store */
441             r = ifapi_keystore_store_finish(&context->keystore, &context->io);
442             return_try_again(r);
443             return_if_error_reset_state(r, "write_finish failed");
444 
445             break;
446 
447         statecasedefault(context->state);
448     }
449 
450     context->state = _FAPI_STATE_INIT;
451     LOG_DEBUG("success");
452     r = TSS2_RC_SUCCESS;
453 
454 error_cleanup:
455     /* Cleanup any intermediate results and state stored in the context. */
456     ifapi_cleanup_ifapi_object(&nvCmd->nv_object);
457     ifapi_cleanup_ifapi_object(&nvCmd->auth_object);
458     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
459     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
460     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
461     SAFE_FREE(miscNv->policyInstance);
462     SAFE_FREE(nvCmd->nvPath);
463     ifapi_session_clean(context);
464     LOG_TRACE("finished");
465     return r;
466 }
467