xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_Import.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 <stdlib.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <libgen.h>
17 
18 #include "tss2_fapi.h"
19 #include "fapi_int.h"
20 #include "fapi_util.h"
21 #include "tss2_esys.h"
22 #include "ifapi_json_deserialize.h"
23 #include "ifapi_policy_json_deserialize.h"
24 #include "tpm_json_deserialize.h"
25 #define LOGMODULE fapi
26 #include "util/log.h"
27 #include "util/aux_util.h"
28 #include "fapi_crypto.h"
29 
30 /** One-Call function for Fapi_Import
31  *
32  * Imports a JSON encoded policy, policy template or key and stores it at the
33  * given path.
34  *
35  * @param[in,out] context The FAPI_CONTEXT
36  * @param[in] path the path to which the object is imported
37  * @param[in] importData The data that is imported
38  *
39  * @retval TSS2_RC_SUCCESS: if the function call was a success.
40  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, path or importData
41  *         is NULL.
42  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
43  * @retval TSS2_FAPI_RC_BAD_PATH: If path does not map to a FAPI policy or key.
44  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS: if a policy or key already exists
45  *         at path.
46  * @retval TSS2_FAPI_RC_BAD_VALUE: if importData contains invalid data.
47  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
48  *         operation already pending.
49  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
50  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
51  *         internal operations or return parameters.
52  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
53  *         config file.
54  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
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_PATH_NOT_FOUND if a FAPI object path was not found
58  *         during authorization.
59  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
60  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
61  *         is not set.
62  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
63  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
64  *         was not successful.
65  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
66  */
67 TSS2_RC
Fapi_Import(FAPI_CONTEXT * context,char const * path,char const * importData)68 Fapi_Import(
69     FAPI_CONTEXT *context,
70     char   const *path,
71     char   const *importData)
72 {
73     LOG_TRACE("called for context:%p", context);
74 
75     TSS2_RC r;
76 
77     /* Check for NULL parameters */
78     check_not_null(context);
79     check_not_null(path);
80     check_not_null(importData);
81 
82     r = Fapi_Import_Async(context, path, importData);
83     return_if_error_reset_state(r, "Entity_Import");
84 
85     do {
86         /* We wait for file I/O to be ready if the FAPI state automata
87            are in a file I/O state. */
88         r = ifapi_io_poll(&context->io);
89         return_if_error(r, "Something went wrong with IO polling");
90 
91         /* Repeatedly call the finish function, until FAPI has transitioned
92            through all execution stages / states of this invocation. */
93         r = Fapi_Import_Finish(context);
94     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
95 
96     return_if_error_reset_state(r, "Entity_Import");
97 
98     LOG_TRACE("finished");
99     return TSS2_RC_SUCCESS;
100 }
101 
102 /** Asynchronous function for Fapi_Import
103  *
104  * Imports a JSON encoded policy, policy template or key and stores it at the
105  * given path.
106  *
107  * Call Fapi_Import_Finish to finish the execution of this command.
108  *
109  * @param[in,out] context The FAPI_CONTEXT
110  * @param[in] path the path to which the object is imported
111  * @param[in] importData The data that is imported
112  *
113  * @retval TSS2_RC_SUCCESS: if the function call was a success.
114  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, path or importData
115  *         is NULL.
116  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
117  * @retval TSS2_FAPI_RC_BAD_PATH: If path does not map to a FAPI policy or key.
118  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS: if a policy or key already exists
119  *         at path.
120  * @retval TSS2_FAPI_RC_BAD_VALUE: if importData contains invalid data.
121  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
122  *         operation already pending.
123  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
124  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
125  *         internal operations or return parameters.
126  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
127  *         config file.
128  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
129  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
130  */
131 TSS2_RC
Fapi_Import_Async(FAPI_CONTEXT * context,char const * path,char const * importData)132 Fapi_Import_Async(
133     FAPI_CONTEXT *context,
134     char   const *path,
135     char   const *importData)
136 {
137     LOG_TRACE("called for context:%p", context);
138     LOG_TRACE("path: %s", path);
139     LOG_TRACE("importData: %s", importData);
140 
141     TSS2_RC r;
142     json_object *jso = NULL;
143     json_object *jso2;
144     size_t pos = 0;
145     TPMS_POLICY policy = { 0 };
146 
147     /* Check for NULL parameters */
148     check_not_null(context);
149     check_not_null(path);
150     check_not_null(importData);
151 
152     /* Helpful alias pointers */
153     IFAPI_ImportKey * command = &context->cmd.ImportKey;
154     IFAPI_OBJECT *object = &command->object;
155     IFAPI_EXT_PUB_KEY * extPubKey = &object->misc.ext_pub_key;
156     IFAPI_DUPLICATE * keyTree = &object->misc.key_tree;
157 
158     if (context->state != _FAPI_STATE_INIT) {
159         return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State");
160     }
161 
162     command->jso_string = NULL;
163     strdup_check(command->out_path, path, r, cleanup_error);
164     memset(&command->object, 0, sizeof(IFAPI_OBJECT));
165     extPubKey->pem_ext_public = NULL;
166 
167     if (strncmp(importData, IFAPI_PEM_PUBLIC_STRING,
168                 sizeof(IFAPI_PEM_PUBLIC_STRING) - 1) == 0) {
169         object->objectType = IFAPI_EXT_PUB_KEY_OBJ;
170         strdup_check(extPubKey->pem_ext_public, importData, r, cleanup_error);
171         extPubKey->certificate = NULL;
172 
173        TPM2_ALG_ID rsaOrEcc = ifapi_get_signature_algorithm_from_pem(
174                extPubKey->pem_ext_public);
175         r = ifapi_initialize_sign_public(rsaOrEcc, &extPubKey->public);
176         goto_if_error(r, "Could not initialize key template", cleanup_error);
177 
178         r = ifapi_get_tpm2b_public_from_pem(extPubKey->pem_ext_public,
179                                              &extPubKey->public);
180         goto_if_error(r, "Convert PEM public key into TPM public key.", cleanup_error);
181 
182         command->new_object = *object;
183         if (strncmp("/", path, 1) == 0)
184             pos = 1;
185         if (strncmp(&path[pos], IFAPI_PUB_KEY_DIR, strlen(IFAPI_PUB_KEY_DIR)) != 0) {
186             SAFE_FREE(command->out_path);
187             r = ifapi_asprintf(&command->out_path,
188                                "%s%s%s", IFAPI_PUB_KEY_DIR, IFAPI_FILE_DELIM,
189                                &path[pos]);
190             goto_if_error(r, "Allocate path name", cleanup_error);
191 
192         }
193         r = ifapi_non_tpm_mode_init(context);
194         return_if_error(r, "Initialize Import in none TPM mode");
195 
196         context->state = IMPORT_KEY_WRITE_OBJECT_PREPARE;
197 
198     } else if (strcmp(importData, IFAPI_PEM_PRIVATE_KEY) == 0) {
199           return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid import data");
200 
201     } else {
202         /* Check whether TCTI and ESYS are initialized */
203         return_if_null(context->esys, "Command can't be executed in none TPM mode.",
204                        TSS2_FAPI_RC_NO_TPM);
205 
206         /* If the async state automata of FAPI shall be tested, then we must not set
207        the timeouts of ESYS to blocking mode.
208        During testing, the mssim tcti will ensure multiple re-invocations.
209        Usually however the synchronous invocations of FAPI shall instruct ESYS
210        to block until a result is available. */
211 #ifndef TEST_FAPI_ASYNC
212         r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
213         return_if_error_reset_state(r, "Set Timeout to blocking");
214 #endif /* TEST_FAPI_ASYNC */
215 
216         r = ifapi_session_init(context);
217         return_if_error(r, "Initialize Import");
218 
219         /* Otherwise a JSON object has to be checked whether a key or policy is passed */
220         jso = json_tokener_parse(importData);
221         return_if_null(jso, "Json error.", TSS2_FAPI_RC_BAD_VALUE);
222 
223         if (ifapi_get_sub_object(jso, IFAPI_JSON_TAG_POLICY, &jso2) &&
224             !(ifapi_get_sub_object(jso, IFAPI_JSON_TAG_DUPLICATE, &jso2))
225             ) {
226             /* Create policy object */
227             r = ifapi_json_TPMS_POLICY_deserialize(jso, &policy);
228             goto_if_error(r, "Serialize policy", cleanup_error);
229 
230             r = ifapi_policy_store_store_async(&context->pstore, &context->io,
231                     command->out_path, &policy);
232             goto_if_error_reset_state(r, "Could not open: %s", cleanup_error,
233                     command->out_path);
234 
235             ifapi_cleanup_policy(&policy);
236 
237             context->state = IMPORT_KEY_WRITE_POLICY;
238 
239             r = TSS2_RC_SUCCESS;
240         } else {
241             /* Write key object */
242             r = ifapi_json_IFAPI_OBJECT_deserialize(jso, object);
243             goto_if_error(r, "Invalid object.", cleanup_error);
244 
245             switch (object->objectType) {
246             case IFAPI_EXT_PUB_KEY_OBJ:
247                 /* Write json string stored in importData */
248                    /* Start writing the EK to the key store */
249                 r = ifapi_keystore_store_async(&context->keystore, &context->io,
250                         command->out_path, object);
251                 goto_if_error_reset_state(r, "Could not open: %sh", cleanup_error,
252                         command->out_path);
253 
254                 context->state = IMPORT_KEY_WRITE;
255                 break;
256 
257             case IFAPI_DUPLICATE_OBJ:
258                 r = ifapi_get_name(
259                         &keyTree->public_parent.publicArea,
260                         &command->parent_name);
261                 goto_if_error2(r, "Get parent name", cleanup_error);
262 
263                 context->state = IMPORT_KEY_SEARCH;
264                 break;
265 
266             default:
267                 goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Invalid object type",
268                            cleanup_error);
269                 break;
270             }
271             command->parent_path = NULL;
272         }
273     }
274     json_object_put(jso);
275     LOG_TRACE("finished");
276     return r;
277 
278 cleanup_error:
279     if (jso)
280         json_object_put(jso);
281     context->state = _FAPI_STATE_INIT;
282     ifapi_cleanup_policy(&policy);
283     SAFE_FREE(command->jso_string);
284     SAFE_FREE(extPubKey->pem_ext_public);
285     SAFE_FREE(command->out_path);
286     return r;
287 }
288 
289 /** Asynchronous finish function for Fapi_Import_
290  *
291  * This function should be called after a previous Fapi_Import_Async.
292  *
293  * @param[in,out] context The FAPI_CONTEXT
294  *
295  * @retval TSS2_RC_SUCCESS: if the function call was a success.
296  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
297  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
298  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
299  *         operation already pending.
300  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
301  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
302  *         internal operations or return parameters.
303  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
304  *         complete. Call this function again later.
305  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
306  *         during authorization.
307  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
308  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
309  *         the function.
310  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
311  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
312  *         is not set.
313  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
314  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
315  *         was not successful.
316  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
317  */
318 TSS2_RC
Fapi_Import_Finish(FAPI_CONTEXT * context)319 Fapi_Import_Finish(
320     FAPI_CONTEXT *context)
321 {
322     LOG_TRACE("called for context:%p", context);
323 
324     TSS2_RC r;
325     ESYS_TR session;
326 
327     /* Check for NULL parameters */
328     check_not_null(context);
329 
330     /* Helpful alias pointers */
331     IFAPI_ImportKey * command = &context->cmd.ImportKey;
332     IFAPI_OBJECT *newObject = &command->new_object;
333     IFAPI_OBJECT *object = &command->object;
334     IFAPI_DUPLICATE * keyTree = &object->misc.key_tree;
335 
336     switch (context->state) {
337         statecase(context->state, IMPORT_KEY_WRITE_POLICY);
338             r = ifapi_policy_store_store_finish(&context->pstore, &context->io);
339             return_try_again(r);
340             return_if_error_reset_state(r, "write_finish failed");
341 
342             context->state =  _FAPI_STATE_INIT;
343             break;
344 
345         statecase(context->state, IMPORT_KEY_WRITE);
346             r = ifapi_keystore_store_finish(&context->keystore, &context->io);
347             return_try_again(r);
348             return_if_error_reset_state(r, "write_finish failed");
349 
350             context->state =  _FAPI_STATE_INIT;
351             break;
352 
353         statecase(context->state, IMPORT_KEY_SEARCH);
354             r = ifapi_keystore_search_obj(&context->keystore, &context->io,
355                                           &command->parent_name,
356                                           &command->parent_path);
357             return_try_again(r);
358             goto_if_error(r, "Search Key", error_cleanup);
359 
360             context->state = IMPORT_KEY_LOAD_PARENT;
361             fallthrough;
362 
363         statecase(context->state, IMPORT_KEY_LOAD_PARENT);
364             r = ifapi_load_key(context, command->parent_path,
365                                &command->parent_object);
366             return_try_again(r);
367             goto_if_error(r, "Fapi load key.", error_cleanup);
368 
369             context->state = IMPORT_KEY_AUTHORIZE_PARENT;
370             fallthrough;
371 
372         statecase(context->state, IMPORT_KEY_AUTHORIZE_PARENT);
373             r = ifapi_authorize_object(context, command->parent_object, &session);
374             return_try_again(r);
375             goto_if_error(r, "Authorize key.", error_cleanup);
376 
377             TPMT_SYM_DEF_OBJECT symmetric;
378             symmetric.algorithm = TPM2_ALG_NULL;
379             r = Esys_Import_Async(context->esys,
380                   command->parent_object->handle,
381                   session,
382                   ESYS_TR_NONE, ESYS_TR_NONE,
383                   NULL, &keyTree->public,
384                   &keyTree->duplicate,
385                   &keyTree->encrypted_seed,
386                   &symmetric);
387             goto_if_error(r, "Import Async", error_cleanup);
388 
389             context->state = IMPORT_KEY_IMPORT;
390             fallthrough;
391 
392         statecase(context->state, IMPORT_KEY_IMPORT);
393             r = Esys_Import_Finish(context->esys, &command->private);
394             try_again_or_error_goto(r, "Import", error_cleanup);
395 
396             context->state = IMPORT_KEY_WAIT_FOR_FLUSH;
397             fallthrough;
398 
399         statecase(context->state, IMPORT_KEY_WAIT_FOR_FLUSH);
400             r = ifapi_flush_object(context, command->parent_object->handle);
401             ifapi_cleanup_ifapi_object(command->parent_object);
402             return_try_again(r);
403             goto_if_error(r, "Flush key", error_cleanup);
404 
405             memset(newObject, 0, sizeof(IFAPI_OBJECT));
406             newObject->objectType = IFAPI_KEY_OBJ;
407             newObject->misc.key.public = keyTree->public;
408             newObject->policy = keyTree->policy;
409             newObject->misc.key.private.size = command->private->size;
410             newObject->misc.key.private.buffer = &command->private->buffer[0];
411             newObject->misc.key.policyInstance = NULL;
412             newObject->misc.key.description = NULL;
413             newObject->misc.key.certificate = NULL;
414             r = ifapi_get_profile_sig_scheme(&context->profiles.default_profile,
415                                              &keyTree->public.publicArea,
416                                              &newObject->misc.key.signing_scheme);
417             goto_if_error(r, "Get signing scheme.", error_cleanup);
418             fallthrough;
419 
420         statecase(context->state, IMPORT_KEY_WRITE_OBJECT_PREPARE);
421             /* Perform esys serialization if necessary */
422             r = ifapi_esys_serialize_object(context->esys, newObject);
423             goto_if_error(r, "Prepare serialization", error_cleanup);
424 
425             /* Start writing the NV object to the key store */
426             r = ifapi_keystore_store_async(&context->keystore, &context->io,
427                                            command->out_path,
428                                            newObject);
429             goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
430                                       context->nv_cmd.nvPath);
431 
432             context->state = IMPORT_KEY_WRITE_OBJECT;
433             fallthrough;
434 
435         statecase(context->state, IMPORT_KEY_WRITE_OBJECT);
436             /* Finish writing the object to the key store */
437             r = ifapi_keystore_store_finish(&context->keystore, &context->io);
438             return_try_again(r);
439             return_if_error_reset_state(r, "write_finish failed");
440 
441             fallthrough;
442 
443         statecase(context->state, IMPORT_KEY_CLEANUP)
444             r = ifapi_cleanup_session(context);
445             try_again_or_error_goto(r, "Cleanup", error_cleanup);
446 
447             break;
448 
449         statecasedefault(context->state);
450     }
451 
452     /* Reset the ESYS timeout to non-blocking, immediate response. */
453     if (context->esys) {
454         r = Esys_SetTimeout(context->esys, 0);
455         goto_if_error(r, "Set Timeout to non-blocking", error_cleanup);
456     }
457 
458     context->state = _FAPI_STATE_INIT;
459     SAFE_FREE(command->out_path);
460 
461     /* Cleanup policy for key objects.*/
462     if (newObject->objectType == IFAPI_KEY_OBJ) {
463         if (newObject->policy)
464             ifapi_cleanup_policy(newObject->policy);
465         SAFE_FREE(newObject->policy);
466     }
467     SAFE_FREE(command->parent_path);
468     ifapi_cleanup_ifapi_object(&command->object);
469     SAFE_FREE(command->private);
470     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
471     if (context->loadKey.key_object){
472         ifapi_cleanup_ifapi_object(context->loadKey.key_object);
473     }
474     LOG_TRACE("finished");
475     return TSS2_RC_SUCCESS;
476 
477 error_cleanup:
478     if (newObject)
479         ifapi_cleanup_ifapi_object(newObject);
480     SAFE_FREE(command->out_path);
481     SAFE_FREE(command->parent_path);
482     ifapi_cleanup_ifapi_object(&command->object);
483     SAFE_FREE(command->private);
484     Esys_SetTimeout(context->esys, 0);
485     ifapi_session_clean(context);
486     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
487     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
488     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
489     return r;
490 }
491