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 <json-c/json_util.h>
12 #include <json-c/json_tokener.h>
13 #include <string.h>
14
15 #include "ifapi_json_serialize.h"
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 typedef struct {
25 char *description;
26 TPMI_POLICYTYPE capability;
27 UINT32 property;
28 UINT32 max;
29 } IFAPI_INFO_CAP;
30
31 static IFAPI_INFO_CAP info_cap_tab[] = {
32 { "algorithms", TPM2_CAP_ALGS, TPM2_ALG_FIRST, TPM2_MAX_CAP_ALGS},
33 { "handles-transient", TPM2_CAP_HANDLES, TPM2_TRANSIENT_FIRST, TPM2_MAX_CAP_HANDLES},
34 { "handles-persistent", TPM2_CAP_HANDLES, TPM2_PERSISTENT_FIRST, TPM2_MAX_CAP_HANDLES},
35 { "handles-permanent", TPM2_CAP_HANDLES, TPM2_PERMANENT_FIRST, TPM2_MAX_CAP_HANDLES},
36 { "handles-pcr", TPM2_CAP_HANDLES, TPM2_PCR_FIRST, TPM2_MAX_CAP_HANDLES},
37 { "handles-nv-index", TPM2_CAP_HANDLES, TPM2_NV_INDEX_FIRST, TPM2_MAX_CAP_HANDLES},
38 { "handles-loaded-session", TPM2_CAP_HANDLES, TPM2_LOADED_SESSION_FIRST, TPM2_MAX_CAP_HANDLES},
39 { "handles-action-session", TPM2_CAP_HANDLES, TPM2_ACTIVE_SESSION_FIRST, TPM2_MAX_CAP_HANDLES},
40 { "handles-saved-session", TPM2_CAP_HANDLES, TPM2_ACTIVE_SESSION_FIRST, TPM2_MAX_CAP_HANDLES},
41 { "properties-fixed", TPM2_CAP_TPM_PROPERTIES, TPM2_PT_FIXED, TPM2_MAX_TPM_PROPERTIES },
42 { "properties-variable", TPM2_CAP_TPM_PROPERTIES, TPM2_PT_VAR, TPM2_MAX_TPM_PROPERTIES },
43 { "commands", TPM2_CAP_COMMANDS, TPM2_CC_FIRST, TPM2_MAX_CAP_CC },
44 { "pp-commands", TPM2_CAP_PP_COMMANDS, TPM2_CC_FIRST, TPM2_MAX_CAP_CC },
45 { "audit-commands", TPM2_CAP_AUDIT_COMMANDS, TPM2_CC_FIRST, TPM2_MAX_CAP_CC },
46 { "pcrs", TPM2_CAP_PCRS, 0, TPM2_NUM_PCR_BANKS },
47 { "pcr-properties", TPM2_CAP_PCR_PROPERTIES, TPM2_PCR_FIRST, TPM2_MAX_PCR_PROPERTIES },
48 { "ecc-curves", TPM2_CAP_ECC_CURVES, 0, TPM2_MAX_ECC_CURVES },
49 };
50
51 /** One-Call function for Fapi_GetInfo
52 *
53 * Returns a UTF-8 encoded string that identifies the versions of FAPI, TPM,
54 * configurations and other relevant information.
55 *
56 * @param[in,out] context The FAPI_CONTEXT
57 * @param[out] info The byte buffer for the information string
58 *
59 * @retval TSS2_RC_SUCCESS: if the function call was a success.
60 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or info is NULL.
61 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
62 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
63 * operation already pending.
64 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
65 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
66 * internal operations or return parameters.
67 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
68 * config file.
69 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
70 * this function needs to be called again.
71 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
72 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
73 * the function.
74 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
75 */
76 TSS2_RC
Fapi_GetInfo(FAPI_CONTEXT * context,char ** info)77 Fapi_GetInfo(
78 FAPI_CONTEXT *context,
79 char **info)
80 {
81 LOG_TRACE("called for context:%p", context);
82
83 TSS2_RC r, r2;
84
85 /* Check for NULL parameters */
86 check_not_null(context);
87 check_not_null(info);
88
89 /* Check whether TCTI and ESYS are initialized */
90 return_if_null(context->esys, "Command can't be executed in none TPM mode.",
91 TSS2_FAPI_RC_NO_TPM);
92
93 /* If the async state automata of FAPI shall be tested, then we must not set
94 the timeouts of ESYS to blocking mode.
95 During testing, the mssim tcti will ensure multiple re-invocations.
96 Usually however the synchronous invocations of FAPI shall instruct ESYS
97 to block until a result is available. */
98 #ifndef TEST_FAPI_ASYNC
99 r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
100 return_if_error_reset_state(r, "Set Timeout to blocking");
101 #endif /* TEST_FAPI_ASYNC */
102
103 r = Fapi_GetInfo_Async(context);
104 return_if_error_reset_state(r, "GetTPMInfo");
105
106 do {
107 /* We wait for file I/O to be ready if the FAPI state automata
108 are in a file I/O state. */
109 r = ifapi_io_poll(&context->io);
110 return_if_error(r, "Something went wrong with IO polling");
111
112 /* Repeatedly call the finish function, until FAPI has transitioned
113 through all execution stages / states of this invocation. */
114 r = Fapi_GetInfo_Finish(context, info);
115 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
116
117 /* Reset the ESYS timeout to non-blocking, immediate response. */
118 r2 = Esys_SetTimeout(context->esys, 0);
119 return_if_error(r2, "Set Timeout to non-blocking");
120
121 return_if_error_reset_state(r, "GetTPMInfo");
122
123 LOG_TRACE("finished");
124 return TSS2_RC_SUCCESS;
125 }
126
127 /** Asynchronous function for Fapi_GetInfo
128 *
129 * Returns a UTF-8 encoded string that identifies the versions of FAPI, TPM,
130 * configurations and other relevant information.
131 *
132 * Call Fapi_GetInfo_Finish to finish the execution of this command.
133 *
134 * @param[in,out] context The FAPI_CONTEXT
135 *
136 * @retval TSS2_RC_SUCCESS: if the function call was a success.
137 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
138 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
139 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
140 * operation already pending.
141 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
142 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
143 * internal operations or return parameters.
144 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
145 * config file.
146 */
147 TSS2_RC
Fapi_GetInfo_Async(FAPI_CONTEXT * context)148 Fapi_GetInfo_Async(
149 FAPI_CONTEXT *context)
150 {
151 LOG_TRACE("called for context:%p", context);
152
153 TSS2_RC r;
154
155 /* Check for NULL parameters */
156 check_not_null(context);
157
158 /* Helpful alias pointers */
159 IFAPI_GetInfo * command = &context->cmd.GetInfo;
160
161 /* Reset all context-internal session state information. */
162 r = ifapi_session_init(context);
163 return_if_error(r, "Initialize GetInfo");
164
165 memset(command, 0, sizeof(IFAPI_GetInfo));
166 r = ifapi_capability_init(context);
167 return_if_error(r, "Capability init");
168
169 /* Initialize the context state for this operation. */
170 command->idx_info_cap = 0;
171 context->state = GET_INFO_GET_CAP;
172
173 LOG_TRACE("finished");
174 return TSS2_RC_SUCCESS;
175 }
176
177 /** Asynchronous finish function for Fapi_GetInfo
178 *
179 * This function should be called after a previous Fapi_GetInfo_Async.
180 *
181 * @param[in,out] context The FAPI_CONTEXT
182 * @param[out] info The byte buffer for the information string
183 *
184 * @retval TSS2_RC_SUCCESS: if the function call was a success.
185 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or info is NULL.
186 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
187 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
188 * operation already pending.
189 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
190 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
191 * internal operations or return parameters.
192 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
193 * complete. Call this function again later.
194 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
195 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
196 * the function.
197 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
198 */
199 TSS2_RC
Fapi_GetInfo_Finish(FAPI_CONTEXT * context,char ** info)200 Fapi_GetInfo_Finish(
201 FAPI_CONTEXT *context,
202 char **info)
203 {
204 LOG_TRACE("called for context:%p", context);
205
206 TSS2_RC r;
207 json_object *jso = NULL;
208 size_t capIdx;
209
210 /* Check for NULL parameters */
211 check_not_null(context);
212 check_not_null(info);
213
214 /* Helpful alias pointers */
215 IFAPI_GetInfo * command = &context->cmd.GetInfo;
216 IFAPI_INFO *infoObj = &command->info_obj;
217 TPMS_CAPABILITY_DATA *capabilityData = NULL;
218
219 switch (context->state) {
220 case GET_INFO_GET_CAP:
221 /* Initialize the property for the first ESAPI call */
222 command->property
223 = info_cap_tab[command->idx_info_cap].property;
224 fallthrough;
225
226 case GET_INFO_GET_CAP_MORE:
227 /* This state is a helper used from fapi_util.c */
228 fallthrough;
229
230 case GET_INFO_WAIT_FOR_CAP:
231 /* State will be set by sub routine */
232 capIdx = command->idx_info_cap;
233 r = ifapi_capability_get(context,
234 info_cap_tab[capIdx].capability,
235 info_cap_tab[capIdx].max,
236 &capabilityData);
237 return_try_again(r);
238 goto_if_error(r, "Get capability", cleanup);
239
240 infoObj->cap[capIdx].description = info_cap_tab[capIdx].description;
241 infoObj->cap[capIdx].capability = capabilityData;
242 command->property_count = 0;
243 command->idx_info_cap += 1;
244 if (command->idx_info_cap < sizeof(info_cap_tab)
245 / sizeof(info_cap_tab[0])) {
246 /* Not all capabilities have been collected */
247 context->state = GET_INFO_GET_CAP;
248 return TSS2_FAPI_RC_TRY_AGAIN;
249 }
250
251 infoObj->fapi_version = "OSSTSS 2.2.x";
252 infoObj->fapi_config = "Properties of config have to specified by TCG";
253
254 /* Serialize the information. */
255 r = ifapi_json_IFAPI_INFO_serialize(infoObj, &jso);
256 goto_if_error(r, "Error serialize info object", cleanup);
257
258 /* Duplicate the information to be returned to the caller. */
259 *info = strdup(json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY));
260 goto_if_null2(*info, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, cleanup);
261
262 context->state = _FAPI_STATE_INIT;
263 r = TSS2_RC_SUCCESS;
264 break;
265
266 statecasedefault(context->state);
267 }
268
269 cleanup:
270 /* Cleanup any intermediate results and state stored in the context. */
271 json_object_put(jso);
272 for (capIdx = 0; capIdx < IFAPI_MAX_CAP_INFO; capIdx++) {
273 SAFE_FREE(infoObj->cap[capIdx].capability);
274 }
275 LOG_TRACE("finished");
276 return r;
277 }
278