1 //**********************************************************************;
2 // Copyright (c) 2017, Intel Corporation
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
15 // 3. Neither the name of Intel Corporation nor the names of its contributors
16 // may be used to endorse or promote products derived from this software without
17 // specific prior written permission.
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29 // THE POSSIBILITY OF SUCH DAMAGE.
30 //**********************************************************************;
35 #include <tss2/tss2_sys.h>
38 #include "tpm2_attr_util.h"
39 #include "tpm2_util.h"
41 #define dispatch_no_arg_add(x) \
42 { .name = str(x), .callback=(action)x, .width = 1 }
44 #define dispatch_arg_add(x, w) \
45 { .name = str(x), .callback=(action)x, .width = w }
47 #define dispatch_reserved(pos) \
48 { .name = "<reserved("xstr(pos)")>", .callback=NULL, .width = 1 }
50 typedef enum dispatch_error dispatch_error;
57 typedef bool (*action)(void *obj, char *arg);
59 typedef struct dispatch_table dispatch_table;
60 struct dispatch_table {
63 unsigned width; /* the width of the field, CANNOT be 0 */
66 static bool authread(TPMA_NV *nv, char *arg) {
69 *nv |= TPMA_NV_AUTHREAD;
73 static bool authwrite(TPMA_NV *nv, char *arg) {
76 *nv |= TPMA_NV_AUTHWRITE;
80 static bool clear_stclear(TPMA_NV *nv, char *arg) {
83 *nv |= TPMA_NV_CLEAR_STCLEAR;
87 static bool globallock(TPMA_NV *nv, char *arg) {
90 *nv |= TPMA_NV_GLOBALLOCK;
94 static bool no_da(TPMA_NV *nv, char *arg) {
101 static bool orderly(TPMA_NV *nv, char *arg) {
104 *nv |= TPMA_NV_ORDERLY;
108 static bool ownerread(TPMA_NV *nv, char *arg) {
111 *nv |= TPMA_NV_OWNERREAD;
115 static bool ownerwrite(TPMA_NV *nv, char *arg) {
118 *nv |= TPMA_NV_OWNERWRITE;
122 static bool platformcreate(TPMA_NV *nv, char *arg) {
125 *nv |= TPMA_NV_PLATFORMCREATE;
129 static bool policyread(TPMA_NV *nv, char *arg) {
132 *nv |= TPMA_NV_POLICYREAD;
136 static bool policywrite(TPMA_NV *nv, char *arg) {
139 *nv |= TPMA_NV_POLICYWRITE;
143 static bool policydelete(TPMA_NV *nv, char *arg) {
146 *nv |= TPMA_NV_POLICY_DELETE;
150 static bool ppread(TPMA_NV *nv, char *arg) {
153 *nv |= TPMA_NV_PPREAD;
157 static bool ppwrite(TPMA_NV *nv, char *arg) {
160 *nv |= TPMA_NV_PPWRITE;
164 static bool readlocked(TPMA_NV *nv, char *arg) {
167 *nv |= TPMA_NV_READLOCKED;
171 static bool read_stclear(TPMA_NV *nv, char *arg) {
174 *nv |= TPMA_NV_READ_STCLEAR;
178 static bool writeall(TPMA_NV *nv, char *arg) {
181 *nv |= TPMA_NV_WRITEALL;
185 static bool writedefine(TPMA_NV *nv, char *arg) {
188 *nv |= TPMA_NV_WRITEDEFINE;
192 static bool writelocked(TPMA_NV *nv, char *arg) {
195 *nv |= TPMA_NV_WRITELOCKED;
199 static bool write_stclear(TPMA_NV *nv, char *arg) {
202 *nv |= TPMA_NV_WRITE_STCLEAR;
206 static bool written(TPMA_NV *nv, char *arg) {
209 *nv |= TPMA_NV_WRITTEN;
213 static bool nt(TPMA_NV *nv, char *arg) {
216 bool result = tpm2_util_string_to_uint16(arg, &value);
218 LOG_ERR("Could not convert \"%s\", to a number", arg);
222 /* nt space is 4 bits, so max of 15 */
224 LOG_ERR("Field TPM_NT of type TPMA_NV is only 4 bits,"
225 "value \"%s\" to big!", arg);
229 *nv &= ~TPMA_NV_TPM2_NT_MASK;
235 * The order of this table must be in order with the bit defines in table 204:
236 * https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
238 * This table is in bitfield order, thus the index of a bit set in a TPMA_NV
239 * can be used to lookup the name.
241 * if not the logic in tpm2_nv_util_strtoattr would need to change!
243 static dispatch_table nv_attr_table[] = { // Bit Index
244 dispatch_no_arg_add(ppwrite), // 0
245 dispatch_no_arg_add(ownerwrite), // 1
246 dispatch_no_arg_add(authwrite), // 2
247 dispatch_no_arg_add(policywrite), // 3
248 dispatch_arg_add(nt, 4), // 4
249 dispatch_arg_add(nt, 3), // 5
250 dispatch_arg_add(nt, 2), // 6
251 dispatch_arg_add(nt, 1), // 7
252 dispatch_reserved(8), // 8
253 dispatch_reserved(9), // 9
254 dispatch_no_arg_add(policydelete), // 10
255 dispatch_no_arg_add(writelocked), // 11
256 dispatch_no_arg_add(writeall), // 12
257 dispatch_no_arg_add(writedefine), // 13
258 dispatch_no_arg_add(write_stclear), // 14
259 dispatch_no_arg_add(globallock), // 15
260 dispatch_no_arg_add(ppread), // 16
261 dispatch_no_arg_add(ownerread), // 17
262 dispatch_no_arg_add(authread), // 18
263 dispatch_no_arg_add(policyread), // 19
264 dispatch_reserved(20), // 20
265 dispatch_reserved(21), // 21
266 dispatch_reserved(22), // 22
267 dispatch_reserved(23), // 23
268 dispatch_reserved(24), // 24
269 dispatch_no_arg_add(no_da), // 25
270 dispatch_no_arg_add(orderly), // 26
271 dispatch_no_arg_add(clear_stclear), // 27
272 dispatch_no_arg_add(readlocked), // 28
273 dispatch_no_arg_add(written), // 29
274 dispatch_no_arg_add(platformcreate), // 30
275 dispatch_no_arg_add(read_stclear), // 31
278 static bool fixedtpm(TPMA_OBJECT *obj, char *arg) {
281 *obj |= TPMA_OBJECT_FIXEDTPM;
285 static bool stclear(TPMA_OBJECT *obj, char *arg) {
288 *obj |= TPMA_OBJECT_STCLEAR;
292 static bool fixedparent(TPMA_OBJECT *obj, char *arg) {
295 *obj |= TPMA_OBJECT_FIXEDPARENT;
299 static bool sensitivedataorigin(TPMA_OBJECT *obj, char *arg) {
302 *obj |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
306 static bool userwithauth(TPMA_OBJECT *obj, char *arg) {
309 *obj |= TPMA_OBJECT_USERWITHAUTH;
313 static bool adminwithpolicy(TPMA_OBJECT *obj, char *arg) {
316 *obj |= TPMA_OBJECT_ADMINWITHPOLICY;
320 static bool noda(TPMA_OBJECT *obj, char *arg) {
323 *obj |= TPMA_OBJECT_NODA;
327 static bool encryptedduplication(TPMA_OBJECT *obj, char *arg) {
330 *obj |= TPMA_OBJECT_ENCRYPTEDDUPLICATION;
334 static bool restricted(TPMA_OBJECT *obj, char *arg) {
337 *obj |= TPMA_OBJECT_RESTRICTED;
341 static bool decrypt(TPMA_OBJECT *obj, char *arg) {
344 *obj |= TPMA_OBJECT_DECRYPT;
348 static bool sign(TPMA_OBJECT *obj, char *arg) {
351 *obj |= TPMA_OBJECT_SIGN_ENCRYPT;
355 static dispatch_table obj_attr_table[] = { // Bit Index
356 dispatch_reserved(0), // 0
357 dispatch_no_arg_add(fixedtpm), // 1
358 dispatch_no_arg_add(stclear), // 2
359 dispatch_reserved(3), // 3
360 dispatch_no_arg_add(fixedparent), // 4
361 dispatch_no_arg_add(sensitivedataorigin), // 5
362 dispatch_no_arg_add(userwithauth), // 6
363 dispatch_no_arg_add(adminwithpolicy), // 7
364 dispatch_reserved(8), // 8
365 dispatch_reserved(9), // 9
366 dispatch_no_arg_add(noda), // 10
367 dispatch_no_arg_add(encryptedduplication), // 11
368 dispatch_reserved(12), // 12
369 dispatch_reserved(13), // 13
370 dispatch_reserved(14), // 14
371 dispatch_reserved(15), // 15
372 dispatch_no_arg_add(restricted), // 16
373 dispatch_no_arg_add(decrypt), // 17
374 dispatch_no_arg_add(sign), // 18
375 dispatch_reserved(19), // 19
376 dispatch_reserved(20), // 20
377 dispatch_reserved(21), // 21
378 dispatch_reserved(22), // 22
379 dispatch_reserved(23), // 23
380 dispatch_reserved(24), // 24
381 dispatch_reserved(25), // 25
382 dispatch_reserved(26), // 26
383 dispatch_reserved(27), // 27
384 dispatch_reserved(28), // 28
385 dispatch_reserved(29), // 29
386 dispatch_reserved(30), // 30
387 dispatch_reserved(31), // 31
390 static bool token_match(const char *name, const char *token, bool has_arg, char **sep) {
392 /* if it has an argument, we expect a separator */
393 size_t match_len = strlen(token);
395 *sep = strchr(token, '=');
397 match_len = *sep - token;
401 return !strncmp(name, token, match_len);
404 static dispatch_error handle_dispatch(dispatch_table *d, char *token,
407 char *name = d->name;
408 action cb = d->callback;
409 bool has_arg = d->width > 1;
411 /* if no callback, then its a reserved block, just skip it */
413 return dispatch_no_match;
417 bool match = token_match(name, token, has_arg, &sep);
419 return dispatch_no_match;
423 * If it has an argument, match should have found the seperator.
428 LOG_ERR("Expected argument for \"%s\", got none.", token);
432 /* split token on = */
436 LOG_ERR("Expected argument for \"%s\", got none.", token);
440 /* valid argument string, assign */
444 bool result = cb(nvattrs, arg);
445 return result ? dispatch_ok : dispatch_err;
448 static bool common_strtoattr(char *attribute_list, void *attrs, dispatch_table *table, size_t size) {
454 * This check is soley to prevent GCC from complaining on:
455 * error: ‘attribute_list’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
456 * Might as well check nvattrs as well.
458 if (!attribute_list || !attrs) {
459 LOG_ERR("attribute list or attributes structure is NULL");
463 while ((token = strtok_r(attribute_list, "|", &save))) {
464 attribute_list = NULL;
466 bool did_dispatch = false;
469 for (i = 0; i < size; i++) {
470 dispatch_table *d = &table[i];
472 dispatch_error err = handle_dispatch(d, token, attrs);
473 if (err == dispatch_ok) {
476 } else if (err == dispatch_err) {
479 /* dispatch_no_match --> keep looking */
482 /* did we dispatch?, If not log error and return */
484 char *tmp = strchr(token, '=');
488 LOG_ERR("Unknown token: \"%s\" found.", token);
496 bool tpm2_attr_util_nv_strtoattr(char *attribute_list, TPMA_NV *nvattrs) {
498 return common_strtoattr(attribute_list, nvattrs, nv_attr_table, ARRAY_LEN(nv_attr_table));
501 bool tpm2_attr_util_obj_strtoattr(char *attribute_list, TPMA_OBJECT *objattrs) {
503 return common_strtoattr(attribute_list, objattrs, obj_attr_table, ARRAY_LEN(obj_attr_table));
507 static UINT8 find_first_set(UINT32 bits) {
515 if (!(bits & 0x0000FFFF)) { n += 16; bits >>= 16; }
516 if (!(bits & 0x000000FF)) { n += 8; bits >>= 8; }
517 if (!(bits & 0x0000000F)) { n += 4; bits >>= 4; }
518 if (!(bits & 0x00000003)) { n += 2; bits >>= 2; }
519 if (!(bits & 0x00000001)) n += 1;
524 static char *tpm2_attr_util_common_attrtostr(UINT32 attrs, dispatch_table *table, size_t size) {
527 return strdup("<none>");
531 * Get how many bits are set in the attributes and then find the longest
534 * pop_cnt * max_name_len + pop_cnt - 1 (for the | separators) + 4
535 * (for nv field equals in hex) + 1 for null byte.
537 * This will provide us an ample buffer size for generating the string
538 * in without having to constantly realloc.
540 UINT32 pop_cnt = tpm2_util_pop_count(attrs);
543 size_t max_name_len = 0;
544 for (i=0; i < size; i++) {
545 dispatch_table *d = &table[i];
546 size_t name_len = strlen(d->name);
547 max_name_len = name_len > max_name_len ? name_len : max_name_len;
550 size_t length = pop_cnt * max_name_len + pop_cnt - 1 + 3;
552 char *str = calloc(length, 1);
558 size_t string_index = 0;
561 * Start at the lowest, first bit set, index into the array,
562 * grab the data needed, and move on.
565 UINT8 bit_index = find_first_set(attrs);
567 dispatch_table *d = &table[bit_index];
569 const char *name = d->name;
570 unsigned w = d->width;
572 /* current position and size left of the string */
573 char *s = &str[string_index];
574 size_t left = length - string_index;
576 /* this is a mask that is field width wide */
577 UINT8 mask = ((UINT32)1 << w) - 1;
579 /* get the value in the field before clearing attrs out */
580 UINT8 field_values = (attrs & mask << bit_index) >> bit_index;
583 * turn off the parsed bit(s) index, using width to turn off everything in a
586 attrs &= ~(mask << bit_index);
589 * if the callback is NULL, we are either in a field middle or reserved
590 * section which is weird, just add the name in. In the case of being
591 * in the middle of the field, we will add a bunch of errors to the string,
592 * but it would be better to attempt to show all the data in string form,
595 * Fields are either 1 or > 1.
599 * set the format to a middle output, unless we're parsing
600 * the first or last. Let the format be static with the routine
601 * so the compiler can do printf style format specifier checking.
604 /* on the first write, if we are already done, no pipes */
605 string_index += !attrs ? snprintf(s, left, "%s", name) :
606 snprintf(s, left, "%s|", name);
608 string_index += snprintf(s, left, "%s", name);
610 string_index += snprintf(s, left, "%s|", name);
613 /* deal with the field */
615 /* on the first write, if we are already done, no pipes */
616 string_index += !attrs ? snprintf(s, left, "%s=0x%X", name, field_values) :
617 snprintf(s, left, "%s=0x%X|", name, field_values);
619 string_index += snprintf(s, left, "%s=0x%X", name, field_values);
621 string_index += snprintf(s, left, "%s=0x%X|", name, field_values);
629 char *tpm2_attr_util_nv_attrtostr(TPMA_NV nvattrs) {
630 return tpm2_attr_util_common_attrtostr(nvattrs, nv_attr_table, ARRAY_LEN(nv_attr_table));
633 char *tpm2_attr_util_obj_attrtostr(TPMA_OBJECT objattrs) {
634 return tpm2_attr_util_common_attrtostr(objattrs, obj_attr_table, ARRAY_LEN(obj_attr_table));
637 bool tpm2_attr_util_obj_from_optarg(char *argvalue, TPMA_OBJECT *objattrs) {
639 bool res = tpm2_util_string_to_uint32(argvalue, objattrs);
641 res = tpm2_attr_util_obj_strtoattr(argvalue, objattrs);