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 <stdlib.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <string.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_CreateKey
27  *
28  * Creates a key inside the TPM based on the Key type, using the supplied
29  * policy and authValue. The key is then stored either in the FAPI metadata
30  * store or the TPM.
31  *
32  * @param[in,out] context The FAPI_CONTEXT
33  * @param[in] path The path where the new key is stored
34  * @param[in] type The type of the new key. May be NULL
35  * @param[in] policyPath The path to the policy that is associated with the new
36  *       key. May be NULL
37  * @param[in] authValue The authorization value for the new key. May be NULL
38  *
39  * @retval TSS2_RC_SUCCESS: if the function call was a success.
40  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
41  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
42  * @retval TSS2_FAPI_RC_BAD_PATH: if policyPath is non-NULL and does not map to
43  *         a FAPI policy.
44  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if the parent key does not map to a FAPI
45  *         key.
46  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS: if a file already exists at path.
47  * @retval TSS2_FAPI_RC_BAD_VALUE: if the keyType is non-NULL and invalid.
48  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
49  *         operation already pending.
50  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
51  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
52  *         internal operations or return parameters.
53  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
54  *         config file.
55  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
56  *         this function needs to be called again.
57  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
58  *         is not set.
59  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
60  */
61 TSS2_RC
Fapi_CreateKey(FAPI_CONTEXT * context,char const * path,char const * type,char const * policyPath,char const * authValue)62 Fapi_CreateKey(
63     FAPI_CONTEXT *context,
64     char   const *path,
65     char   const *type,
66     char   const *policyPath,
67     char   const *authValue)
68 {
69     LOG_TRACE("called for context:%p", context);
70 
71     TSS2_RC r, r2;
72 
73     /* Check for NULL parameters */
74     check_not_null(context);
75     check_not_null(path);
76 
77     /* Check whether TCTI and ESYS are initialized */
78     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
79                    TSS2_FAPI_RC_NO_TPM);
80 
81     /* If the async state automata of FAPI shall be tested, then we must not set
82        the timeouts of ESYS to blocking mode.
83        During testing, the mssim tcti will ensure multiple re-invocations.
84        Usually however the synchronous invocations of FAPI shall instruct ESYS
85        to block until a result is available. */
86 #ifndef TEST_FAPI_ASYNC
87     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
88     return_if_error_reset_state(r, "Set Timeout to blocking");
89 #endif /* TEST_FAPI_ASYNC */
90 
91     r = Fapi_CreateKey_Async(context, path, type, policyPath, authValue);
92     return_if_error_reset_state(r, "Key_Create");
93 
94     do {
95         /* We wait for file I/O to be ready if the FAPI state automata
96            are in a file I/O state. */
97         r = ifapi_io_poll(&context->io);
98         return_if_error(r, "Something went wrong with IO polling");
99 
100         /* Repeatedly call the finish function, until FAPI has transitioned
101            through all execution stages / states of this invocation. */
102         r = Fapi_CreateKey_Finish(context);
103     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
104 
105     /* Reset the ESYS timeout to non-blocking, immediate response. */
106     r2 = Esys_SetTimeout(context->esys, 0);
107     return_if_error(r2, "Set Timeout to non-blocking");
108 
109     return_if_error_reset_state(r, "Key_Create");
110 
111     return TSS2_RC_SUCCESS;
112 }
113 
114 /** Asynchronous function for Fapi_CreateKey
115  *
116  * Creates a key inside the TPM based on the Key type, using the supplied
117  * policy and authValue. The key is then stored either in the FAPI metadata
118  * store or the TPM.
119  *
120  * Call Fapi_CreateKey_Finish to finish the execution of this command.
121  *
122  * @param[in,out] context The FAPI_CONTEXT
123  * @param[in] path The path where the new key is stored
124  * @param[in] type The type of the new key. May be NULL
125  * @param[in] policyPath The path to the policy that is associated with the new
126  *            key. May be NULL
127  * @param[in] authValue The authorization value for the new key. May be NULL
128  *
129  * @retval TSS2_RC_SUCCESS: if the function call was a success.
130  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
131  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
132  * @retval TSS2_FAPI_RC_BAD_PATH: if policyPath is non-NULL and does not map to
133  *         a FAPI policy.
134  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if the parent key does not map to a FAPI
135  *         key.
136  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS: if a file already exists at path.
137  * @retval TSS2_FAPI_RC_BAD_VALUE: if the keyType is non-NULL and invalid.
138  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
139  *         operation already pending.
140  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
141  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
142  *         internal operations or return parameters.
143  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
144  *         config file.
145  */
146 TSS2_RC
Fapi_CreateKey_Async(FAPI_CONTEXT * context,char const * path,char const * type,char const * policyPath,char const * authValue)147 Fapi_CreateKey_Async(
148     FAPI_CONTEXT *context,
149     char   const *path,
150     char   const *type,
151     char   const *policyPath,
152     char   const *authValue)
153 {
154     LOG_TRACE("called for context:%p", context);
155     LOG_TRACE("path: %s", path);
156     LOG_TRACE("type: %s", type);
157     LOG_TRACE("policyPath: %s", policyPath);
158     LOG_TRACE("authValue: %s", authValue);
159 
160     TSS2_RC r;
161 
162     /* Check for NULL parameters */
163     check_not_null(context);
164     check_not_null(path);
165 
166     /* Reset all context-internal session state information. */
167     r = ifapi_session_init(context);
168     return_if_error(r, "Initialize CreateKey");
169 
170     /* Prepare the key creation with the authValue.
171        This will also copy the input information for use during the finish call. */
172     r = ifapi_key_create_prepare_auth(context, path, policyPath, authValue);
173     return_if_error(r, "Key create.");
174 
175     /* Set the flags of the key to be created. If no type is given the empty-string
176        default type flags are set. If no policy is given, userWithAuth flag is set. */
177     r = ifapi_set_key_flags(type ? type : "",
178                             (policyPath && strcmp(policyPath, "") != 0) ? true : false,
179                             &context->cmd.Key_Create.public_templ);
180     return_if_error(r, "Set key flags for key");
181 
182     /* Initialize the context state for this operation. */
183     context->state = KEY_CREATE;
184     LOG_TRACE("finished");
185     return TSS2_RC_SUCCESS;
186 }
187 
188 /** Asynchronous finish function for Fapi_CreateKey
189  *
190  * This function should be called after a previous Fapi_CreateKey_Async.
191  *
192  * @param[in,out] context The FAPI_CONTEXT
193  *
194  * @retval TSS2_RC_SUCCESS: if the function call was a success.
195  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
196  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
197  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
198  *         operation already pending.
199  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
200  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
201  *         internal operations or return parameters.
202  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
203  *         complete. Call this function again later.
204  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
205  *         the function.
206  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
207  *         is not set.
208  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
209  */
210 TSS2_RC
Fapi_CreateKey_Finish(FAPI_CONTEXT * context)211 Fapi_CreateKey_Finish(
212     FAPI_CONTEXT *context)
213 {
214     LOG_TRACE("called for context:%p", context);
215 
216     TSS2_RC r;
217 
218     /* Check for NULL parameters */
219     check_not_null(context);
220 
221     /* Helpful alias pointers */
222     IFAPI_Key_Create * command = &context->cmd.Key_Create;
223 
224     switch (context->state) {
225         statecase(context->state, KEY_CREATE);
226             /* Finish the key creation inside the helper function. */
227             r = ifapi_key_create(context, &command->public_templ);
228             return_try_again(r);
229             goto_if_error(r, "Key create", error_cleanup);
230 
231             /* Cleanup any intermediate results and state stored in the context. */
232             ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
233             ifapi_cleanup_ifapi_object(context->loadKey.key_object);
234             ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
235             context->state = _FAPI_STATE_INIT;
236             LOG_TRACE("finished");
237             return TSS2_RC_SUCCESS;
238 
239         statecasedefault(context->state);
240     }
241 
242 error_cleanup:
243     /* Cleanup any intermediate results and state stored in the context. */
244     context->cmd.Key_Create.state = KEY_CREATE_INIT;
245     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
246     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
247     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
248     LOG_TRACE("finished");
249     return r;
250 }
251