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