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