• 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 <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15 
16 #include "tss2_fapi.h"
17 #include "fapi_int.h"
18 #include "fapi_util.h"
19 #include "tss2_esys.h"
20 #define LOGMODULE fapi
21 #include "util/log.h"
22 #include "util/aux_util.h"
23 
24 /** One-Call function for Fapi_NvRead
25  *
26  * Reads data from an NV index within the TPM.
27  * The FAPI will automatically do the multiple reads if the NV index is larger
28  * than the TPM's TPM2_MAX_NV_BUFFER_SIZE.
29  *
30  * @param[in,out] context The FAPI_CONTEXT
31  * @param[in] nvPath The path of the NV index to read
32  * @param[out] data The data that was read from the NV index
33  * @param[out] size The size of data in bytes. May be NULL
34  * @param[out] logData The log data of the NV index if the index is of type
35  *             "extend". May be NULL
36  *
37  * @retval TSS2_RC_SUCCESS: if the function call was a success.
38  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, nvPath or data is NULL.
39  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
40  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath is not found.
41  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED: if authorization fails.
42  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN: if don’t know how to authenticate.
43  * @retval TSS2_FAPI_RC_NV_NOT_READABLE: if the NV is not a readable index.
44  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
45  *         operation already pending.
46  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
47  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
48  *         internal operations or return parameters.
49  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
50  *         config file.
51  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
52  *         during authorization.
53  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
54  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
55  *         the function.
56  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
57  *         this function needs to be called again.
58  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
59  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
60  *         was not successful.
61  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
62  */
63 TSS2_RC
Fapi_NvRead(FAPI_CONTEXT * context,char const * nvPath,uint8_t ** data,size_t * size,char ** logData)64 Fapi_NvRead(
65     FAPI_CONTEXT   *context,
66     char     const *nvPath,
67     uint8_t       **data,
68     size_t         *size,
69     char          **logData)
70 {
71     LOG_TRACE("called for context:%p", context);
72 
73     TSS2_RC r, r2;
74 
75     /* Check for NULL parameters */
76     check_not_null(context);
77     check_not_null(nvPath);
78     check_not_null(data);
79 
80     /* Check whether TCTI and ESYS are initialized */
81     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
82                    TSS2_FAPI_RC_NO_TPM);
83 
84     /* If the async state automata of FAPI shall be tested, then we must not set
85        the timeouts of ESYS to blocking mode.
86        During testing, the mssim tcti will ensure multiple re-invocations.
87        Usually however the synchronous invocations of FAPI shall instruct ESYS
88        to block until a result is available. */
89 #ifndef TEST_FAPI_ASYNC
90     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
91     return_if_error_reset_state(r, "Set Timeout to blocking");
92 #endif /* TEST_FAPI_ASYNC */
93 
94     r = Fapi_NvRead_Async(context, nvPath);
95     return_if_error_reset_state(r, "NV_Read");
96 
97     do {
98         /* We wait for file I/O to be ready if the FAPI state automata
99            are in a file I/O state. */
100         r = ifapi_io_poll(&context->io);
101         return_if_error(r, "Something went wrong with IO polling");
102 
103         /* Repeatedly call the finish function, until FAPI has transitioned
104            through all execution stages / states of this invocation. */
105         r = Fapi_NvRead_Finish(context, data, size, logData);
106     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
107 
108     /* Reset the ESYS timeout to non-blocking, immediate response. */
109     r2 = Esys_SetTimeout(context->esys, 0);
110     return_if_error(r2, "Set Timeout to non-blocking");
111 
112     return_if_error_reset_state(r, "NV_Read");
113 
114     LOG_TRACE("finished");
115     return TSS2_RC_SUCCESS;
116 }
117 
118 /** Asynchronous function for Fapi_NvRead
119  *
120  * Reads data from an NV index within the TPM.
121  * The FAPI will automatically do the multiple reads if the NV index is larger
122  * than the TPM's TPM2_MAX_NV_BUFFER_SIZE.
123  *
124  * Call Fapi_NvRead_Finish to finish the execution of this command.
125  *
126  * @param[in,out] context The FAPI_CONTEXT
127  * @param[in] nvPath The path of the NV index to read
128  *
129  * @retval TSS2_RC_SUCCESS: if the function call was a success.
130  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or nvPath is NULL. *
131  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
132  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath is not found.
133  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED: if authorization fails.
134  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN: if don’t know how to authenticate.
135  * @retval TSS2_FAPI_RC_NV_NOT_READABLE: if the NV is not a readable index.
136  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
137  *         operation already pending.
138  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
139  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
140  *         internal operations or return parameters.
141  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
142  *         config file.
143  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
144  *         during authorization.
145  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
146  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
147  *         the function.
148  */
149 TSS2_RC
Fapi_NvRead_Async(FAPI_CONTEXT * context,char const * nvPath)150 Fapi_NvRead_Async(
151     FAPI_CONTEXT   *context,
152     char     const *nvPath)
153 {
154     LOG_TRACE("called for context:%p", context);
155     LOG_TRACE("nvPath: %s", nvPath);
156 
157     TSS2_RC r;
158 
159     /* Check for NULL parameters */
160     check_not_null(context);
161     check_not_null(nvPath);
162 
163     /* Helpful alias pointers */
164     IFAPI_NV_Cmds * command = &context->nv_cmd;
165 
166     /* Reset all context-internal session state information. */
167     r = ifapi_session_init(context);
168     return_if_error(r, "Initialize NvRead");
169 
170     memset(command, 0, sizeof(IFAPI_NV_Cmds));
171 
172     /* Copy parameters to context for use during _Finish. */
173     strdup_check(command->nvPath, nvPath, r, error_cleanup);
174 
175     /* Load the NV index metadata from keystore. */
176     r = ifapi_keystore_load_async(&context->keystore, &context->io, command->nvPath);
177     goto_if_error_reset_state(r, "Could not open: %s", error_cleanup, command->nvPath);
178 
179     /* Initialize the context state for this operation. */
180     context->state = NV_READ_READ;
181     LOG_TRACE("finished");
182     return TSS2_RC_SUCCESS;
183 
184 error_cleanup:
185     /* Cleanup duplicated input parameters that were copied before. */
186     SAFE_FREE(command->nvPath);
187     return r;
188 }
189 
190 /** Asynchronous finish function for Fapi_NvRead
191  *
192  * This function should be called after a previous Fapi_NvRead_Async.
193  *
194  * @param[in,out] context The FAPI_CONTEXT
195  * @param[out] data The data that was read from the NV index
196  * @param[out] size The size of data in bytes. May be NULL
197  * @param[out] logData The log data of the NV index if the index is of type
198  *			   "extend". May be NULL
199  *
200  * @retval TSS2_RC_SUCCESS: if the function call was a success.
201  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or data is NULL.
202  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
203  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
204  *         operation already pending.
205  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
206  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
207  *         internal operations or return parameters.
208  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
209  *         complete. Call this function again later.
210  * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
211  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
212  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
213  *         the function.
214  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
215  *         during authorization.
216  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
217  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
218  *         is not set.
219  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
220  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
221  *         was not successful.
222  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
223  */
224 TSS2_RC
Fapi_NvRead_Finish(FAPI_CONTEXT * context,uint8_t ** data,size_t * size,char ** logData)225 Fapi_NvRead_Finish(
226     FAPI_CONTEXT   *context,
227     uint8_t       **data,
228     size_t         *size,
229     char          **logData)
230 {
231     LOG_TRACE("called for context:%p", context);
232 
233     TSS2_RC r;
234     ESYS_TR authIndex;
235     size_t readSize;
236 
237     /* Check for NULL parameters */
238     check_not_null(context);
239     check_not_null(data);
240 
241     /* Helpful alias pointers */
242     IFAPI_NV_Cmds *command = &context->nv_cmd;
243     IFAPI_OBJECT *object = &command->nv_object;
244     IFAPI_OBJECT *authObject = &command->auth_object;
245 
246     switch (context->state) {
247     statecase(context->state, NV_READ_READ)
248         r = ifapi_keystore_load_finish(&context->keystore, &context->io, object);
249         return_try_again(r);
250         return_if_error_reset_state(r, "read_finish failed");
251 
252         if (object->objectType != IFAPI_NV_OBJ)
253             goto_error(r, TSS2_FAPI_RC_BAD_PATH, "%s is no NV object.", error_cleanup,
254                        command->nvPath);
255 
256         /* Initialize the NV index object for use with ESYS. */
257         r = ifapi_initialize_object(context->esys, object);
258         goto_if_error_reset_state(r, "Initialize NV object", error_cleanup);
259 
260         command->esys_handle = object->handle;
261         command->nv_obj = object->misc.nv;
262 
263         if (size)
264             *size = object->misc.nv.public.nvPublic.dataSize;
265         command->numBytes = object->misc.nv.public.nvPublic.dataSize;
266 
267         /* Determine auth object */
268         if (object->misc.nv.public.nvPublic.attributes & TPMA_NV_PPREAD) {
269             ifapi_init_hierarchy_object(authObject, ESYS_TR_RH_PLATFORM);
270             authIndex = ESYS_TR_RH_PLATFORM;
271         } else {
272             if (object->misc.nv.public.nvPublic.attributes & TPMA_NV_OWNERREAD) {
273                 ifapi_init_hierarchy_object(authObject, ESYS_TR_RH_OWNER);
274                 authIndex = ESYS_TR_RH_OWNER;
275             } else {
276                 authIndex = object->handle;
277             }
278             *authObject = *object;
279         }
280         command->auth_index = authIndex;
281         context->primary_state = PRIMARY_INIT;
282 
283         /* Prepare session for authorization and data encryption. */
284         r = ifapi_get_sessions_async(context,
285                                      IFAPI_SESSION_GENEK | IFAPI_SESSION1,
286                                      TPMA_SESSION_ENCRYPT, 0);
287         goto_if_error_reset_state(r, "Create sessions", error_cleanup);
288 
289         fallthrough;
290 
291     statecase(context->state, NV_READ_WAIT_FOR_SESSION)
292         r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
293                                       object->misc.nv.public.nvPublic.nameAlg);
294         return_try_again(r);
295         goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
296 
297         command->nv_read_state = NV_READ_INIT;
298 
299         fallthrough;
300 
301     statecase(context->state, NV_READ_WAIT)
302         if (data) {
303             /* Read the data from the TPM. */
304             r = ifapi_nv_read(context, data, &readSize);
305             return_try_again(r);
306 
307             goto_if_error_reset_state(r, " FAPI NV_Read", error_cleanup);
308         }
309 
310         if (logData) {
311             /* Duplicate the logdata that may have been stored during a
312                NvExtend command. */
313             strdup_check(*logData, object->misc.nv.event_log, r, error_cleanup);
314         }
315         fallthrough;
316 
317     statecase(context->state, NV_READ_CLEANUP)
318         /* Cleanup the session used for authorization. */
319         r = ifapi_cleanup_session(context);
320         try_again_or_error_goto(r, "Cleanup", error_cleanup);
321 
322         context->state = _FAPI_STATE_INIT;
323         break;
324 
325     statecasedefault(context->state);
326     }
327 
328 error_cleanup:
329     /* Cleanup any intermediate results and state stored in the context. */
330     ifapi_cleanup_ifapi_object(&command->nv_object);
331     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
332     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
333     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
334     SAFE_FREE(command->nvPath);
335     //SAFE_FREE(context->nv_cmd.tes);
336     ifapi_session_clean(context);
337     LOG_TRACE("finished");
338     return r;
339 }
340