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 #include "fapi_crypto.h"
26
27 /** One-Call function for Fapi_Unseal
28 *
29 * Unseals data from a seal in the FAPI metadata store.
30 *
31 * @param[in,out] context The FAPI_CONTEXT
32 * @param[in] path The path to the sealed data
33 * @param[out] data The decrypted data after unsealing. May be NULL
34 * @param[out] size The size of data in bytes. May be NULL
35 *
36 * @retval TSS2_RC_SUCCESS: if the function call was a success.
37 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
38 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
39 * @retval TSS2_FAPI_RC_BAD_PATH: if path does not point to a sealed data object.
40 * @retval TSS2_FAPI_RC_BAD_VALUE: if the digestSize is zero.
41 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
42 * operation already pending.
43 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
44 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
45 * internal operations or return parameters.
46 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
47 * config file.
48 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
49 * this function needs to be called again.
50 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
51 * during authorization.
52 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
53 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
54 * @retval TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED if the signature could not
55 * be verified
56 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
57 */
58 TSS2_RC
Fapi_Unseal(FAPI_CONTEXT * context,char const * path,uint8_t ** data,size_t * size)59 Fapi_Unseal(
60 FAPI_CONTEXT *context,
61 char const *path,
62 uint8_t **data,
63 size_t *size)
64 {
65 LOG_TRACE("called for context:%p", context);
66
67 TSS2_RC r, r2;
68
69 /* Check for NULL parameters */
70 check_not_null(context);
71 check_not_null(path);
72
73 /* Check whether TCTI and ESYS are initialized */
74 return_if_null(context->esys, "Command can't be executed in none TPM mode.",
75 TSS2_FAPI_RC_NO_TPM);
76
77 /* If the async state automata of FAPI shall be tested, then we must not set
78 the timeouts of ESYS to blocking mode.
79 During testing, the mssim tcti will ensure multiple re-invocations.
80 Usually however the synchronous invocations of FAPI shall instruct ESYS
81 to block until a result is available. */
82 #ifndef TEST_FAPI_ASYNC
83 r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
84 return_if_error_reset_state(r, "Set Timeout to blocking");
85 #endif /* TEST_FAPI_ASYNC */
86
87 r = Fapi_Unseal_Async(context, path);
88 return_if_error_reset_state(r, "Unseal");
89
90 do {
91 /* We wait for file I/O to be ready if the FAPI state automata
92 are in a file I/O state. */
93 r = ifapi_io_poll(&context->io);
94 return_if_error(r, "Something went wrong with IO polling");
95
96 /* Repeatedly call the finish function, until FAPI has transitioned
97 through all execution stages / states of this invocation. */
98 r = Fapi_Unseal_Finish(context, data, size);
99 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
100
101 /* Reset the ESYS timeout to non-blocking, immediate response. */
102 r2 = Esys_SetTimeout(context->esys, 0);
103 return_if_error(r2, "Set Timeout to non-blocking");
104
105 return_if_error_reset_state(r, "Unseal");
106
107 LOG_TRACE("finished");
108 return TSS2_RC_SUCCESS;
109 }
110
111 /** Asynchronous function for Fapi_Unseal
112 *
113 * Unseals data from a seal in the FAPI metadata store.
114 *
115 * Call Fapi_Unseal_Finish to finish the execution of this command.
116 *
117 * @param[in,out] context The FAPI_CONTEXT
118 * @param[in] path The path to the sealed data
119 *
120 * @retval TSS2_RC_SUCCESS: if the function call was a success.
121 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
122 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
123 * @retval TSS2_FAPI_RC_BAD_PATH: if path does not point to a sealed data object.
124 * @retval TSS2_FAPI_RC_BAD_VALUE: if the digestSize is zero.
125 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
126 * operation already pending.
127 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
128 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
129 * internal operations or return parameters.
130 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
131 * config file.
132 */
133 TSS2_RC
Fapi_Unseal_Async(FAPI_CONTEXT * context,char const * path)134 Fapi_Unseal_Async(
135 FAPI_CONTEXT *context,
136 char const *path)
137 {
138 LOG_TRACE("called for context:%p", context);
139 LOG_TRACE("path: %s", path);
140
141 TSS2_RC r;
142
143 /* Check for NULL parameters */
144 check_not_null(context);
145 check_not_null(path);
146
147 /* Helpful alias pointers */
148 IFAPI_Unseal * command = &context->cmd.Unseal;
149
150 /* Reset all context-internal session state information. */
151 r = ifapi_session_init(context);
152 return_if_error(r, "Initialize Unseal");
153
154 /* Copy parameters to context for use during _Finish. */
155 strdup_check(command->keyPath, path, r, error_cleanup);
156
157 /* Initialize the context state for this operation. */
158 context->state = UNSEAL_WAIT_FOR_KEY;
159 LOG_TRACE("finished");
160 return TSS2_RC_SUCCESS;
161
162 error_cleanup:
163 /* Cleanup duplicated input parameters that were copied before. */
164 SAFE_FREE(command->keyPath);
165 return r;
166 }
167
168 /** Asynchronous finish function for Fapi_Unseal
169 *
170 * This function should be called after a previous Fapi_Unseal_Async.
171 *
172 * @param[in,out] context The FAPI_CONTEXT
173 * @param[out] data The decrypted data after unsealing. May be NULL
174 * @param[out] size The size of data in bytes. May be NULL
175 *
176 * @retval TSS2_RC_SUCCESS: if the function call was a success.
177 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
178 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
179 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
180 * operation already pending.
181 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
182 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
183 * internal operations or return parameters.
184 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
185 * complete. Call this function again later.
186 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
187 * during authorization.
188 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
189 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
190 * the function.
191 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
192 * @retval TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED if the signature could not
193 * be verified
194 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
195 */
196 TSS2_RC
Fapi_Unseal_Finish(FAPI_CONTEXT * context,uint8_t ** data,size_t * size)197 Fapi_Unseal_Finish(
198 FAPI_CONTEXT *context,
199 uint8_t **data,
200 size_t *size)
201 {
202 LOG_TRACE("called for context:%p", context);
203
204 TSS2_RC r;
205 ESYS_TR auth_session;
206
207 /* Check for NULL parameters */
208 check_not_null(context);
209
210 /* Helpful alias pointers */
211 IFAPI_Unseal * command = &context->cmd.Unseal;
212
213 switch (context->state) {
214 statecase(context->state, UNSEAL_WAIT_FOR_KEY);
215 /* Load the key to be used for unsealing from the keystore. */
216 r = ifapi_load_key(context, command->keyPath,
217 &command->object);
218 return_try_again(r);
219 goto_if_error(r, "Fapi load key.", error_cleanup);
220
221 fallthrough;
222
223 statecase(context->state, UNSEAL_AUTHORIZE_OBJECT);
224 /* Authorize the session for use with with key. */
225 r = ifapi_authorize_object(context, command->object, &auth_session);
226 return_try_again(r);
227 goto_if_error(r, "Authorize sealed object.", error_cleanup);
228
229 /* Perform the unseal operation with the TPM. */
230 r = Esys_Unseal_Async(context->esys, command->object->handle,
231 auth_session,
232 ESYS_TR_NONE, ESYS_TR_NONE);
233 goto_if_error(r, "Error esys Unseal ", error_cleanup);
234
235 fallthrough;
236
237 statecase(context->state, UNSEAL_WAIT_FOR_UNSEAL);
238 r = Esys_Unseal_Finish(context->esys, &command->unseal_data);
239 return_try_again(r);
240 goto_if_error(r, "Unseal_Finish", error_cleanup);
241
242 /* Flush the used key from the TPM. */
243 r = Esys_FlushContext_Async(context->esys, command->object->handle);
244 goto_if_error(r, "Error Esys Flush ", error_cleanup);
245
246 fallthrough;
247
248 statecase(context->state, UNSEAL_WAIT_FOR_FLUSH);
249 r = Esys_FlushContext_Finish(context->esys);
250 return_try_again(r);
251 goto_if_error(r, "Unseal_Flush", error_cleanup);
252
253 /* Return the data as requested by the caller.
254 Duplicate the unseal_data as necessary. */
255 if (size)
256 *size = command->unseal_data->size;
257 if (data) {
258 *data = malloc(command->unseal_data->size);
259 goto_if_null2(*data, "Out of memory", r, TSS2_FAPI_RC_MEMORY, error_cleanup);
260
261 memcpy(*data, &command->unseal_data->buffer[0],
262 command->unseal_data->size);
263 }
264 SAFE_FREE(command->unseal_data);
265
266 fallthrough;
267
268 statecase(context->state, UNSEAL_CLEANUP)
269 /* Cleanup the session used for authentication. */
270 r = ifapi_cleanup_session(context);
271 try_again_or_error_goto(r, "Cleanup", error_cleanup);
272
273 context->state = _FAPI_STATE_INIT;
274 break;
275
276 statecasedefault(context->state);
277 }
278
279 error_cleanup:
280 /* Cleanup any intermediate results and state stored in the context. */
281 ifapi_cleanup_ifapi_object(command->object);
282 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
283 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
284 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
285 ifapi_session_clean(context);
286 SAFE_FREE(command->keyPath);
287 LOG_TRACE("finished");
288 return r;
289 }
290