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