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 #ifndef NO_DL
16 #include <dlfcn.h>
17 #endif /* NO_DL */
18
19 #include "tss2_tcti.h"
20 #include "tss2_tctildr.h"
21 #include "tss2_esys.h"
22 #include "tss2_fapi.h"
23 #include "fapi_int.h"
24 #include "fapi_util.h"
25 #include "ifapi_json_deserialize.h"
26 #define LOGMODULE fapi
27 #include "util/log.h"
28 #include "util/aux_util.h"
29
30 /** One-Call function for Fapi_Initialize
31 *
32 * Initializes a FAPI_CONTEXT that holds all the state and metadata information
33 * during an interaction with the TPM.
34 *
35 * @param[out] context The FAPI_CONTEXT
36 * @param[in] uri Unused in this version of the FAPI. Must be NULL
37 *
38 * @retval TSS2_RC_SUCCESS: if the function call was a success.
39 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
40 * @retval TSS2_FAPI_RC_BAD_VALUE: if uri is not NULL.
41 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
42 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
43 * internal operations or return parameters.
44 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
45 * this function needs to be called again.
46 * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
47 * operation already pending.
48 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
49 * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
50 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
51 */
52 TSS2_RC
Fapi_Initialize(FAPI_CONTEXT ** context,char const * uri)53 Fapi_Initialize(
54 FAPI_CONTEXT **context,
55 char const *uri)
56 {
57 LOG_TRACE("called for context:%p", context);
58
59 TSS2_RC r = TSS2_RC_SUCCESS;
60
61 /* Check for NULL parameters */
62 check_not_null(context);
63 if (uri != NULL) {
64 LOG_ERROR("uri is not NULL");
65 return TSS2_FAPI_RC_BAD_VALUE;
66 }
67
68 r = Fapi_Initialize_Async(context, uri);
69 return_if_error(r, "FAPI Async call initialize");
70 check_oom(*context);
71
72 do {
73 /* We wait for file I/O to be ready if the FAPI state automata
74 are in a file I/O state. */
75 r = ifapi_io_poll(&(*context)->io);
76 return_if_error(r, "Something went wrong with IO polling");
77
78 /* Repeatedly call the finish function, until FAPI has transitioned
79 through all execution stages / states of this invocation. */
80 r = Fapi_Initialize_Finish(context);
81 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
82
83 LOG_TRACE("finished");
84 return r;
85 }
86
87 /** Asynchronous function for Fapi_Initialize
88 *
89 * Initializes a FAPI_CONTEXT that holds all the state and metadata information
90 * during an interaction with the TPM.
91 *
92 * Call Fapi_Initialize to finish the execution of this command.
93 *
94 * @param[out] context The FAPI_CONTEXT
95 * @param[in] uri Unused in this version of the FAPI. Must be NULL
96 *
97 * @retval TSS2_RC_SUCCESS: if the function call was a success.
98 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
99 * @retval TSS2_FAPI_RC_BAD_VALUE: if uri is not NULL.
100 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
101 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
102 * internal operations or return parameters.
103 */
104 TSS2_RC
Fapi_Initialize_Async(FAPI_CONTEXT ** context,char const * uri)105 Fapi_Initialize_Async(
106 FAPI_CONTEXT **context,
107 char const *uri)
108 {
109 LOG_TRACE("called for context:%p", context);
110 LOG_TRACE("uri: %s", uri);
111
112 TSS2_RC r = TSS2_RC_SUCCESS;
113
114 /* Check for NULL parameters */
115 check_not_null(context);
116 if (uri != NULL) {
117 LOG_ERROR("uri is not NULL");
118 return TSS2_FAPI_RC_BAD_VALUE;
119 }
120
121 *context = NULL;
122
123 /* Allocate memory for the FAPI context
124 * After this errors must jump to cleanup_return instead of returning. */
125 *context = calloc(1, sizeof(FAPI_CONTEXT));
126 return_if_null(*context, "Out of memory.", TSS2_FAPI_RC_MEMORY);
127 memset(*context, 0, sizeof(FAPI_CONTEXT));
128
129 /* Initialize the context */
130 r = ifapi_config_initialize_async(&(*context)->io);
131 goto_if_error(r, "Could not initialize FAPI context", cleanup_return);
132
133 /* Initialize the context state for this operation. */
134 (*context)->state = INITIALIZE_READ;
135
136 cleanup_return:
137 if (r)
138 SAFE_FREE(*context);
139 LOG_TRACE("finished");
140 return r;
141 }
142
143 /** Asynchronous finish function for Fapi_Initialize
144 *
145 * This function should be called after a previous Fapi_Initialize_Async.
146 *
147 * @param[out] context The FAPI_CONTEXT
148 *
149 * @retval TSS2_RC_SUCCESS: if the function call was a success.
150 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
151 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
152 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
153 * operation already pending.
154 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
155 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
156 * internal operations or return parameters.
157 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
158 * complete. Call this function again later.
159 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
160 * the function.
161 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
162 * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
163 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
164 */
165 TSS2_RC
Fapi_Initialize_Finish(FAPI_CONTEXT ** context)166 Fapi_Initialize_Finish(
167 FAPI_CONTEXT **context)
168 {
169 LOG_TRACE("called for context:%p", context);
170
171 TSS2_RC r;
172 TPMI_YES_NO moreData;
173 TSS2_TCTI_CONTEXT *fapi_tcti = NULL;
174
175 /* Check for NULL parameters */
176 check_not_null(context);
177 check_not_null(*context);
178
179 /* Helpful alias pointers */
180 TPMS_CAPABILITY_DATA **capability = &(*context)->cmd.Initialize.capability;
181
182 switch ((*context)->state) {
183 statecase((*context)->state, INITIALIZE_READ);
184 /* This is the entry point; finishing the initialization of the config module. */
185 r = ifapi_config_initialize_finish(&(*context)->io, &(*context)->config);
186 return_try_again(r);
187 goto_if_error(r, "Could not finish initialization", cleanup_return);
188
189 /* Initialize the event log module. */
190 r = ifapi_eventlog_initialize(&((*context)->eventlog), (*context)->config.log_dir);
191 goto_if_error(r, "Initializing evenlog module", cleanup_return);
192
193 /* Initialize the keystore. */
194 r = ifapi_keystore_initialize(&((*context)->keystore),
195 (*context)->config.keystore_dir,
196 (*context)->config.user_dir,
197 (*context)->config.profile_name);
198 goto_if_error2(r, "Keystore could not be initialized.", cleanup_return);
199
200 /* Initialize the policy store. */
201 /* Policy directory will be placed in keystore dir */
202 r = ifapi_policy_store_initialize(&((*context)->pstore),
203 (*context)->config.keystore_dir);
204 goto_if_error2(r, "Keystore could not be initialized.", cleanup_return);
205
206 fallthrough;
207
208 statecase((*context)->state, INITIALIZE_INIT_TCTI);
209 if (strcasecmp((*context)->config.tcti, "none") == 0) {
210 /* FAPI will be used in none TPM mode */
211 (*context)->esys = NULL;
212 (*context)->state = INITIALIZE_READ_PROFILE_INIT;
213 return TSS2_FAPI_RC_TRY_AGAIN;
214 }
215
216 /* Call for the TctiLdr to initialize a TCTI context given the config
217 from the FAPI config module. */
218 r = Tss2_TctiLdr_Initialize((*context)->config.tcti, &fapi_tcti);
219 goto_if_error(r, "Initializing TCTI.", cleanup_return);
220
221 /* Initialize an ESYS context using this Tcti. */
222 r = Esys_Initialize(&((*context)->esys), fapi_tcti, NULL);
223 goto_if_error(r, "Initialize esys context.", cleanup_return);
224
225 /* Call Startup on the TPM. */
226 r = Esys_Startup((*context)->esys, TPM2_SU_CLEAR);
227 if (r != TSS2_RC_SUCCESS && r != TPM2_RC_INITIALIZE) {
228 LOG_ERROR("Esys_Startup FAILED! Response Code : 0x%x", r);
229 return r;
230 }
231 fallthrough;
232
233 statecase((*context)->state, INITIALIZE_GET_CAP);
234 /* Retrieve the maximal value for transfer of nv data from the TPM. */
235 r = Esys_GetCapability_Async((*context)->esys, ESYS_TR_NONE, ESYS_TR_NONE,
236 ESYS_TR_NONE,
237 TPM2_CAP_TPM_PROPERTIES, TPM2_PT_NV_BUFFER_MAX, 1);
238 goto_if_error(r, "Error json deserialize", cleanup_return);
239
240 fallthrough;
241
242 statecase((*context)->state, INITIALIZE_WAIT_FOR_CAP);
243 r = Esys_GetCapability_Finish((*context)->esys, &moreData, capability);
244 return_try_again(r);
245 goto_if_error(r, "Get capability data.", cleanup_return);
246
247 /* Check if the TPM returns the NV_BUFFER_MAX value. */
248 if ((*capability)->data.tpmProperties.count == 1 &&
249 (*capability)->data.tpmProperties.tpmProperty[0].property ==
250 TPM2_PT_NV_BUFFER_MAX) {
251 (*context)->nv_buffer_max = (*capability)->data.tpmProperties.tpmProperty[0].value;
252 /* FAPI also contains an upper limit on the NV_MAX_BUFFER size. This is
253 useful for vTPMs that could in theory allow for several Megabytes of
254 max transfer buffer sizes. */
255 if ((*context)->nv_buffer_max > IFAPI_MAX_BUFFER_SIZE)
256 (*context)->nv_buffer_max = IFAPI_MAX_BUFFER_SIZE;
257 } else {
258 /* Note that for some time it was legal for a TPM to not return this value.
259 in that case FAPI falls back to 64 bytes for NV_BUFFER_MAX that all TPMs
260 must support. This slows down communication for NV read and write but
261 ensures that data can be exchanged with the TPM. */
262 (*context)->nv_buffer_max = 64;
263 }
264 fallthrough;
265
266 statecase((*context)->state, INITIALIZE_READ_PROFILE_INIT);
267 /* Initialize the proviles module that loads cryptographic profiles.
268 The default profile is taken from config. */
269 r = ifapi_profiles_initialize_async(&(*context)->profiles, &(*context)->io,
270 (*context)->config.profile_dir,
271 (*context)->config.profile_name);
272 return_if_error(r, "Read profile");
273
274 fallthrough;
275
276 statecase((*context)->state, INITIALIZE_READ_PROFILE);
277 r = ifapi_profiles_initialize_finish(&(*context)->profiles, &(*context)->io);
278 FAPI_SYNC(r, "Read profile.", cleanup_return);
279
280 LOG_DEBUG("success: *context %p", *context);
281 break;
282
283 statecasedefault((*context)->state);
284 }
285
286 (*context)->state = _FAPI_STATE_INIT;
287 SAFE_FREE(*capability);
288 LOG_TRACE("finished");
289 return TSS2_RC_SUCCESS;
290
291 cleanup_return:
292 /* Cleanup any intermediate results and state stored in the context. */
293 if ((*context)->esys) {
294 Esys_GetTcti((*context)->esys, &fapi_tcti);
295 Esys_Finalize(&(*context)->esys);
296 }
297 if (fapi_tcti) {
298 Tss2_TctiLdr_Finalize(&fapi_tcti);
299 }
300
301 /* Free the context memory in case of an error. */
302 free(*context);
303 *context = NULL;
304
305 return r;
306 }
307