• 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 <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