xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_Initialize.c (revision 758e9fba6fc9adbf15340f70c73baee7b168b1c9)
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