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 <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "tss2_common.h"
16
17 #include "ifapi_profiles.h"
18
19 #include "tpm_json_deserialize.h"
20 #include "ifapi_policy_json_deserialize.h"
21 #include "ifapi_json_deserialize.h"
22 #include "ifapi_helpers.h"
23 #define LOGMODULE fapi
24 #include "util/log.h"
25 #include "util/aux_util.h"
26 #include "ifapi_macros.h"
27
28 #define PROFILES_EXTENSION ".json"
29 #define PROFILES_PREFIX "P_"
30
31 static TSS2_RC
32 ifapi_profile_json_deserialize(
33 json_object *jso,
34 IFAPI_PROFILE *profile);
35
36 static TSS2_RC
37 ifapi_profile_checkpcrs(const TPML_PCR_SELECTION *pcr_profile);
38
39 /** Initialize the profiles information in the context in an asynchronous way
40 *
41 * Load the profile information from disk, fill the dictionary of loaded profiles and fill
42 * the default profile information into the context.
43 *
44 * Call ifapi_profiles_initialize_finish to complete the operation.
45 *
46 * @param[in,out] profiles The context for the profiles information.
47 * @param[in,out] io The input/output context being used for file I/O.
48 * @param[in] profilesdir The directory to load profile information from.
49 * @param[in] defaultprofile The name of the default profile to use.
50 * @retval TSS2_RC_SUCCESS on success.
51 * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in.
52 * @retval TSS2_FAPI_RC_BAD_VALUE if the profilesdir does not exist or is empty.
53 * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
54 * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
55 */
56 TSS2_RC
ifapi_profiles_initialize_async(IFAPI_PROFILES * profiles,IFAPI_IO * io,const char * profilesdir,const char * defaultprofile)57 ifapi_profiles_initialize_async(
58 IFAPI_PROFILES *profiles,
59 IFAPI_IO *io,
60 const char *profilesdir,
61 const char *defaultprofile)
62 {
63 TSS2_RC r;
64 char *tmp;
65 size_t i, j;
66 check_not_null(profiles);
67 check_not_null(profilesdir);
68
69 memset(profiles, 0, sizeof(*profiles));
70
71 profiles->default_name = strdup(defaultprofile);
72 check_oom(profiles->default_name);
73
74 r = ifapi_io_dirfiles(profilesdir, &profiles->filenames, &profiles->num_profiles);
75 return_if_error(r, "Reading profiles from profiles dir");
76
77 profiles->profiles = calloc(profiles->num_profiles, sizeof(profiles->profiles[0]));
78 check_oom(profiles->profiles);
79
80 /* Clean up list of files to only include those that match our filename pattern
81 Expand the filenames with the directory
82 Set the names in the dictionary */
83 for (i = 0; i < profiles->num_profiles; ) {
84 char *ext = strstr(profiles->filenames[i], PROFILES_EXTENSION);
85 /* Path the filename with the expected pattern */
86 if (ext != NULL && strlen(ext) == strlen(PROFILES_EXTENSION) &&
87 strncmp(profiles->filenames[i], PROFILES_PREFIX, strlen(PROFILES_PREFIX)) == 0)
88 {
89 LOG_TRACE("Using file %s in profiles directory", profiles->filenames[i]);
90 /* Add the profile name */
91 profiles->profiles[i].name = strndup(profiles->filenames[i],
92 ext - profiles->filenames[i]);
93 check_oom(profiles->profiles[i].name);
94 /* Expand the filename with the directory */
95 tmp = profiles->filenames[i];
96 r = ifapi_asprintf(&profiles->filenames[i], "%s/%s", profilesdir, tmp);
97 return_if_error(r, "Out of memory");
98
99 LOG_TRACE("Added profile-entry %s for file %s based on direntry %s",
100 profiles->profiles[i].name, profiles->filenames[i], tmp);
101
102 /* Cleanup and continue */
103 free(tmp);
104 i++;
105 } else {
106 LOG_TRACE("Skipping file %s in profiles directory", profiles->filenames[i]);
107 free(profiles->filenames[i]);
108 profiles->num_profiles -= 1;
109 for (j = i; j < profiles->num_profiles; j++) {
110 profiles->filenames[j] = profiles->filenames[j + 1];
111 }
112 }
113 }
114
115 if (profiles->num_profiles == 0) {
116 LOG_ERROR("No files found in profile dir %s that match the pattern %s*%s",
117 profilesdir, PROFILES_PREFIX, PROFILES_EXTENSION);
118 return TSS2_FAPI_RC_BAD_VALUE;
119 }
120 #ifdef HAVE_REALLOCARRAY
121 profiles->profiles = reallocarray(profiles->profiles, profiles->num_profiles,
122 sizeof(profiles->profiles[0]));
123 profiles->filenames = reallocarray(profiles->filenames, profiles->num_profiles,
124 sizeof(profiles->filenames[0]));
125 #else /* HAVE_REALLOCARRAY */
126 profiles->profiles = realloc(profiles->profiles, profiles->num_profiles *
127 sizeof(profiles->profiles[0]));
128 profiles->filenames = realloc(profiles->filenames, profiles->num_profiles *
129 sizeof(profiles->filenames[0]));
130 #endif /* HAVE_REALLOCARRAY */
131 /* No need for OOM checks, since num_profiles may only have become smaller */
132
133 r = ifapi_io_read_async(io, profiles->filenames[profiles->profiles_idx]);
134 return_if_error2(r, "Reading profile %s", profiles->filenames[profiles->profiles_idx]);
135
136 return TSS2_RC_SUCCESS;
137 }
138
139 /** Initialize the profiles information in the context in an asynchronous way
140 *
141 * Call after ifapi_profiles_initialize_async to complete the operation.
142 *
143 * @param[in,out] profiles The context for the profiles information.
144 * @param[in,out] io The input/output context being used for file I/O.
145 * @retval TSS2_RC_SUCCESS on success.
146 * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in.
147 * @retval TSS2_FAPI_RC_BAD_VALUE if a profile could not be loaded.
148 * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
149 * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
150 * @retval TSS2_FAPI_RC_TRY_AGAIN if the I/O operation is not finished yet and this function needs
151 * to be called again.
152 */
153 TSS2_RC
ifapi_profiles_initialize_finish(IFAPI_PROFILES * profiles,IFAPI_IO * io)154 ifapi_profiles_initialize_finish(
155 IFAPI_PROFILES *profiles,
156 IFAPI_IO *io)
157 {
158 TSS2_RC r;
159 uint8_t *buffer;
160 size_t i;
161 json_object *jso;
162 check_not_null(profiles);
163 check_not_null(io);
164
165 r = ifapi_io_read_finish(io, &buffer, NULL);
166 return_if_error(r, "Reading profile failed");
167
168 jso = json_tokener_parse((char *) buffer);
169 free(buffer);
170 if (jso == NULL) {
171 LOG_ERROR("Failed to parse profile %s", profiles->filenames[profiles->profiles_idx]);
172 return TSS2_FAPI_RC_BAD_VALUE;
173 }
174
175 r = ifapi_profile_json_deserialize(jso,
176 &profiles->profiles[profiles->profiles_idx].profile);
177 json_object_put(jso);
178 return_if_error2(r, "Parsing profile %s failed",
179 profiles->filenames[profiles->profiles_idx]);
180
181 r = ifapi_profile_checkpcrs(&profiles->profiles[profiles->profiles_idx].profile.pcr_selection);
182 return_if_error2(r, "Malformed profile pcr selection for profile %s",
183 profiles->filenames[profiles->profiles_idx]);
184
185 profiles->profiles_idx += 1;
186
187 if (profiles->profiles_idx < profiles->num_profiles) {
188 r = ifapi_io_read_async(io, profiles->filenames[profiles->profiles_idx]);
189 return_if_error2(r, "Reading profile %s", profiles->filenames[profiles->profiles_idx]);
190
191 return TSS2_FAPI_RC_TRY_AGAIN;
192 }
193
194 /* Get the data of the default profile into the respective variable */
195 for (i = 0; i < profiles->num_profiles; i++) {
196 if (strcmp(profiles->default_name, profiles->profiles[i].name) == 0) {
197 profiles->default_profile = profiles->profiles[i].profile;
198 break;
199 }
200 }
201 if (i == profiles->num_profiles) {
202 LOG_ERROR("Default profile %s not in the list of loaded profiles",
203 profiles->default_name);
204 return TSS2_FAPI_RC_BAD_VALUE;
205 }
206
207 for (i = 0; i < profiles->num_profiles; i++) {
208 free(profiles->filenames[i]);
209 }
210 SAFE_FREE(profiles->filenames);
211
212 return TSS2_RC_SUCCESS;
213 }
214
215 /** Return the profile data for a given profile name.
216 *
217 * Returns a (const, not to be free'd) pointer to the profile data for a requested profile.
218 * If a NULL profile is requesten, then the default profile is returned.
219 * If a keypath is passed in, then the prefix is analysed. If that keypath starts with a profile
220 * then this profile is returned. Otherwise the default profile is returned.
221 *
222 * @param[in] profiles The profiles context
223 * @param[in] name The name of the profile or the keypath
224 * @param[out] profile The pointer to the profile data.
225 * @retval TSS2_RC_SUCCESS on success.
226 * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in.
227 * @retval TSS2_FAPI_RC_BAD_VALUE if a profile is not found.
228 */
229 TSS2_RC
ifapi_profiles_get(const IFAPI_PROFILES * profiles,const char * name,const IFAPI_PROFILE ** profile)230 ifapi_profiles_get(
231 const IFAPI_PROFILES *profiles,
232 const char *name,
233 const IFAPI_PROFILE **profile)
234 {
235 check_not_null(profiles);
236 check_not_null(name);
237 check_not_null(profile);
238 char *split;
239 size_t len;
240
241 /* if no name or nor profile prefix is given, use the default profile */
242 if (!name || strncmp(name, "P_", 2) != 0 || strncmp(name, "/P_", 2) != 0) {
243 *profile = &profiles->default_profile;
244 return TSS2_RC_SUCCESS;
245 }
246
247 /* Search for path delimiter */
248 split = index(name, IFAPI_FILE_DELIM_CHAR);
249
250 /* If the path beging with delimiters, skip over those */
251 if (name == split) {
252 name += 1;
253 split = index(name, IFAPI_FILE_DELIM_CHAR);
254 }
255 if (split == NULL)
256 len = strlen(name);
257 else
258 len = split - name;
259
260 for (size_t i = 0; i < profiles->num_profiles; i++) {
261 if (len == strlen(profiles->profiles[i].name) &&
262 strncmp(name, profiles->profiles[i].name, len) == 0) {
263 *profile = &profiles->profiles[i].profile;
264 return TSS2_RC_SUCCESS;
265 }
266 }
267 LOG_ERROR("Profile %s not in the list of loaded profiles", name);
268 return TSS2_FAPI_RC_BAD_VALUE;
269 }
270
271 /** Sanitizes and frees internal data structures of loaded profiles' information.
272 *
273 * @param[in,out] profiles The context for the profiles information.
274 */
275 void
ifapi_profiles_finalize(IFAPI_PROFILES * profiles)276 ifapi_profiles_finalize(
277 IFAPI_PROFILES *profiles)
278 {
279 size_t i;
280 if (!profiles) {
281 LOG_ERROR("Called with bad reference");
282 return;
283 }
284
285 SAFE_FREE(profiles->default_name);
286
287 for (i = 0; i < profiles->num_profiles; i++) {
288 IFAPI_PROFILE_ENTRY * entry = &profiles->profiles[i];
289 SAFE_FREE(profiles->profiles[i].name);
290
291 IFAPI_PROFILE * profile = &entry->profile;
292
293 SAFE_FREE(profile->srk_template);
294 SAFE_FREE(profile->ek_template);
295
296 ifapi_cleanup_policy(profile->eh_policy);
297 SAFE_FREE(profile->eh_policy);
298
299 ifapi_cleanup_policy(profile->ek_policy);
300 SAFE_FREE(profile->ek_policy);
301
302 ifapi_cleanup_policy(profile->sh_policy);
303 SAFE_FREE(profile->sh_policy);
304 }
305 SAFE_FREE(profiles->profiles);
306
307 memset(profiles, 0, sizeof(*profiles));
308 }
309
310 /** Deserialize a IFAPI_KEY_PROFILE json object.
311 *
312 * @param[in] jso the json object to be deserialized.
313 * @param[out] out the deserialzed binary object.
314 * @retval TSS2_RC_SUCCESS if the function call was a success.
315 * @retval TSS2_FAPI_RC_BAD_VALUE if the json object can't be deserialized.
316 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
317 * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
318 * object store.
319 * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
320 */
321 static TSS2_RC
ifapi_profile_json_deserialize(json_object * jso,IFAPI_PROFILE * out)322 ifapi_profile_json_deserialize(
323 json_object *jso,
324 IFAPI_PROFILE *out)
325 {
326 json_object *jso2;
327 TSS2_RC r;
328
329 const TPMT_SYM_DEF session_symmetric_default = {
330 .algorithm = TPM2_ALG_AES,
331 .keyBits = {.aes = 128},
332 .mode = {.aes = TPM2_ALG_CFB}
333 };
334
335 LOG_TRACE("call");
336 return_if_null(out, "Bad reference.", TSS2_FAPI_RC_BAD_REFERENCE);
337
338 if (!ifapi_get_sub_object(jso, "type", &jso2)) {
339 LOG_ERROR("Bad value");
340 return TSS2_FAPI_RC_BAD_VALUE;
341 }
342 r = ifapi_json_TPMI_ALG_PUBLIC_deserialize(jso2, &out->type);
343 return_if_error(r, "BAD VALUE");
344
345 if (!ifapi_get_sub_object(jso, "srk_template", &jso2)) {
346 LOG_ERROR("Bad value");
347 return TSS2_FAPI_RC_BAD_VALUE;
348 }
349 out->srk_template = strdup(json_object_get_string(jso2));
350 return_if_null(out->srk_template, "Out of memory.", TSS2_FAPI_RC_MEMORY);
351
352 if (!ifapi_get_sub_object(jso, "ek_template", &jso2)) {
353 LOG_ERROR("Bad value");
354 return TSS2_FAPI_RC_BAD_VALUE;
355 }
356 out->ek_template = strdup(json_object_get_string(jso2));
357 return_if_null(out->ek_template, "Out of memory.", TSS2_FAPI_RC_MEMORY);
358
359 if (!ifapi_get_sub_object(jso, "ecc_signing_scheme", &jso2)) {
360 memset(&out->ecc_signing_scheme, 0, sizeof(TPMT_SIG_SCHEME));
361 } else {
362 r = ifapi_json_TPMT_SIG_SCHEME_deserialize(jso2, &out->ecc_signing_scheme);
363 return_if_error(r, "BAD VALUE");
364 }
365
366 if (!ifapi_get_sub_object(jso, "rsa_signing_scheme", &jso2)) {
367 memset(&out->rsa_signing_scheme, 0, sizeof(TPMT_SIG_SCHEME));
368 } else {
369 r = ifapi_json_TPMT_SIG_SCHEME_deserialize(jso2, &out->rsa_signing_scheme);
370 return_if_error(r, "BAD VALUE");
371 }
372
373 if (!ifapi_get_sub_object(jso, "rsa_decrypt_scheme", &jso2)) {
374 memset(&out->rsa_decrypt_scheme, 0, sizeof(TPMT_RSA_DECRYPT));
375 } else {
376 r = ifapi_json_TPMT_RSA_DECRYPT_deserialize(jso2, &out->rsa_decrypt_scheme);
377 return_if_error(r, "BAD VALUE");
378 }
379
380 if (!ifapi_get_sub_object(jso, "sym_mode", &jso2)) {
381 LOG_ERROR("Bad value");
382 return TSS2_FAPI_RC_BAD_VALUE;
383 }
384 r = ifapi_json_TPMI_ALG_SYM_MODE_deserialize(jso2, &out->sym_mode);
385 return_if_error(r, "BAD VALUE");
386
387 if (!ifapi_get_sub_object(jso, "sym_parameters", &jso2)) {
388 LOG_ERROR("Bad value");
389 return TSS2_FAPI_RC_BAD_VALUE;
390 }
391 r = ifapi_json_TPMT_SYM_DEF_OBJECT_deserialize(jso2, &out->sym_parameters);
392 return_if_error(r, "BAD VALUE");
393
394 if (!ifapi_get_sub_object(jso, "sym_block_size", &jso2)) {
395 LOG_ERROR("Bad value");
396 return TSS2_FAPI_RC_BAD_VALUE;
397 }
398 r = ifapi_json_UINT16_deserialize(jso2, &out->sym_block_size);
399 return_if_error(r, "BAD VALUE");
400
401 if (!ifapi_get_sub_object(jso, "pcr_selection", &jso2)) {
402 LOG_ERROR("Bad value");
403 return TSS2_FAPI_RC_BAD_VALUE;
404 }
405 r = ifapi_json_TPML_PCR_SELECTION_deserialize(jso2, &out->pcr_selection);
406 return_if_error(r, "BAD VALUE");
407
408 if (!ifapi_get_sub_object(jso, "nameAlg", &jso2)) {
409 LOG_ERROR("Bad value");
410 return TSS2_FAPI_RC_BAD_VALUE;
411 }
412 r = ifapi_json_TPMI_ALG_HASH_deserialize(jso2, &out->nameAlg);
413 return_if_error(r, "BAD VALUE");
414
415 if (out->type == TPM2_ALG_RSA) {
416 if (!ifapi_get_sub_object(jso, "exponent", &jso2)) {
417 LOG_ERROR("Bad value");
418 return TSS2_FAPI_RC_BAD_VALUE;
419 }
420 r = ifapi_json_UINT32_deserialize(jso2, &out->exponent);
421 return_if_error(r, "BAD VALUE");
422 if (!ifapi_get_sub_object(jso, "keyBits", &jso2)) {
423 LOG_ERROR("Bad value");
424 return TSS2_FAPI_RC_BAD_VALUE;
425
426 }
427 r = ifapi_json_TPMI_RSA_KEY_BITS_deserialize(jso2, &out->keyBits);
428 return_if_error(r, "BAD VALUE");
429
430 } else if (out->type == TPM2_ALG_ECC) {
431 if (!ifapi_get_sub_object(jso, "curveID", &jso2)) {
432 LOG_ERROR("Bad value");
433 return TSS2_FAPI_RC_BAD_VALUE;
434 }
435 r = ifapi_json_TPMI_ECC_CURVE_deserialize(jso2, &out->curveID);
436 return_if_error(r, "BAD VALUE");
437 }
438
439 if (!ifapi_get_sub_object(jso, "session_symmetric", &jso2)) {
440 out->session_symmetric = session_symmetric_default;
441 } else {
442 r = ifapi_json_TPMT_SYM_DEF_deserialize(jso2, &out->session_symmetric);
443 return_if_error(r, "BAD VALUE");
444 }
445
446 if (ifapi_get_sub_object(jso, "eh_policy", &jso2)) {
447 out->eh_policy = calloc(1, sizeof(TPMS_POLICY));
448 goto_if_null2(out->eh_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
449 cleanup);
450
451 r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->eh_policy);
452 goto_if_error(r, "Deserialize policy.", cleanup);
453 }
454
455 if (ifapi_get_sub_object(jso, "sh_policy", &jso2)) {
456 out->sh_policy = calloc(1, sizeof(TPMS_POLICY));
457 goto_if_null2(out->sh_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
458 cleanup);
459
460 r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->sh_policy);
461 goto_if_error(r, "Deserialize policy.", cleanup);
462 }
463
464 if (ifapi_get_sub_object(jso, "ek_policy", &jso2)) {
465 out->ek_policy = calloc(1, sizeof(TPMS_POLICY));
466 goto_if_null2(out->ek_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
467 cleanup);
468
469 r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->ek_policy);
470 goto_if_error(r, "Deserialize policy.", cleanup);
471 }
472
473 if (ifapi_get_sub_object(jso, "srk_policy", &jso2)) {
474 out->srk_policy = calloc(1, sizeof(TPMS_POLICY));
475 goto_if_null2(out->srk_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
476 cleanup);
477
478 r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->srk_policy);
479 goto_if_error(r, "Deserialize policy.", cleanup);
480 }
481
482 if (ifapi_get_sub_object(jso, "lockout_policy", &jso2)) {
483 out->lockout_policy = calloc(1, sizeof(TPMS_POLICY));
484 goto_if_null2(out->lockout_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
485 cleanup);
486
487 r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->lockout_policy);
488 goto_if_error(r, "Deserialize policy.", cleanup);
489 }
490
491 if (!ifapi_get_sub_object(jso, "newMaxTries", &jso2)) {
492 out->newMaxTries = 5;
493 } else {
494 r = ifapi_json_UINT32_deserialize(jso2, &out->newMaxTries);
495 return_if_error(r, "BAD VALUE");
496 }
497
498 if (!ifapi_get_sub_object(jso, "newRecoveryTime", &jso2)) {
499 out->newRecoveryTime = 1000;
500 } else {
501 r = ifapi_json_UINT32_deserialize(jso2, &out->newRecoveryTime);
502 return_if_error(r, "BAD VALUE");
503 }
504
505 if (!ifapi_get_sub_object(jso, "lockoutRecovery", &jso2)) {
506 out->lockoutRecovery = 1000;
507 } else {
508 r = ifapi_json_UINT32_deserialize(jso2, &out->lockoutRecovery);
509 return_if_error(r, "BAD VALUE");
510 }
511
512 LOG_TRACE("true");
513 return TSS2_RC_SUCCESS;
514
515 cleanup:
516 SAFE_FREE(out->eh_policy);
517 return r;
518 }
519
520 /**
521 * Check whether PCRs with muliple banks are defined in profile.
522 *
523 * This case is not allowed by FAPI.
524 */
525 static TSS2_RC
ifapi_profile_checkpcrs(const TPML_PCR_SELECTION * pcr_profile)526 ifapi_profile_checkpcrs(const TPML_PCR_SELECTION *pcr_profile)
527 {
528 size_t i, j, byte_idx;
529
530 for (i = 0; i < pcr_profile->count - 1; i++) {
531 for (j = i + 1; j < pcr_profile->count; j++) {
532 for (byte_idx = 0; byte_idx < 3; byte_idx++) {
533 /* Check whether a PCR register flag does occur in two different banks. */
534 if (pcr_profile->pcrSelections[i].pcrSelect[byte_idx] &
535 pcr_profile->pcrSelections[j].pcrSelect[byte_idx]) {
536 return_error2(TSS2_FAPI_RC_BAD_VALUE,
537 "More than one bank selected for a PCR register.");
538 }
539 }
540 }
541 }
542 return TSS2_RC_SUCCESS;
543 }
544