123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242 |
- /* SPDX-License-Identifier: BSD-3-Clause */
- #include <ctype.h>
- #include <dlfcn.h>
- #include <inttypes.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "files.h"
- #include "log.h"
- #include "tool_rc.h"
- #include "tpm2.h"
- #include "tpm2_alg_util.h"
- #include "tpm2_attr_util.h"
- #include "tpm2_convert.h"
- #include "tpm2_openssl.h"
- #include "tpm2_session.h"
- #include "tpm2_tool.h"
- #include "tpm2_util.h"
- // verify that the quote digest equals the digest we calculated
- bool tpm2_util_verify_digests(TPM2B_DIGEST *quoteDigest,
- TPM2B_DIGEST *pcr_digest) {
- // Sanity check -- they should at least be same size!
- if (quoteDigest->size != pcr_digest->size) {
- LOG_ERR("FATAL ERROR: PCR values failed to match quote's digest!");
- return false;
- }
- // Compare running digest with quote's digest
- int k;
- for (k = 0; k < quoteDigest->size; k++) {
- if (quoteDigest->buffer[k] != pcr_digest->buffer[k]) {
- LOG_ERR("FATAL ERROR: PCR values failed to match quote's digest!");
- return false;
- }
- }
- return true;
- }
- bool tpm2_util_concat_buffer(TPM2B_MAX_BUFFER *result, TPM2B *append) {
- if (!result || !append) {
- return false;
- }
- if (((UINT32)result->size + append->size) > TPM2_MAX_DIGEST_BUFFER) {
- return false;
- }
- memcpy(&result->buffer[result->size], append->buffer, append->size);
- result->size += append->size;
- return true;
- }
- bool tpm2_util_string_to_uint8(const char *str, uint8_t *value) {
- uint32_t tmp;
- bool result = tpm2_util_string_to_uint32(str, &tmp);
- if (!result) {
- return false;
- }
- /* overflow on 8 bits? */
- if (tmp > UINT8_MAX) {
- return false;
- }
- *value = (uint8_t) tmp;
- return true;
- }
- bool tpm2_util_string_to_uint16(const char *str, uint16_t *value) {
- uint32_t tmp;
- bool result = tpm2_util_string_to_uint32(str, &tmp);
- if (!result) {
- return false;
- }
- /* overflow on 16 bits? */
- if (tmp > UINT16_MAX) {
- return false;
- }
- *value = (uint16_t) tmp;
- return true;
- }
- bool tpm2_util_string_to_uint32(const char *str, uint32_t *value) {
- char *endptr;
- if (str == NULL || *str == '\0') {
- return false;
- }
- /* clear errno before the call, should be 0 afterwards */
- errno = 0;
- unsigned long int tmp = strtoul(str, &endptr, 0);
- if (errno || tmp > UINT32_MAX) {
- return false;
- }
- /*
- * The entire string should be able to be converted or fail
- * We already checked that str starts with a null byte, so no
- * need to check that again per the man page.
- */
- if (*endptr != '\0') {
- return false;
- }
- *value = (uint32_t) tmp;
- return true;
- }
- bool tpm2_util_string_to_uint64(const char *str, uint64_t *value) {
- char *endptr;
- if (str == NULL || *str == '\0') {
- return false;
- }
- /* clear errno before the call, should be 0 afterwards */
- errno = 0;
- /*
- * unsigned long long is at least 64 bits, although commonly just 64 bits even on 64 bit systems
- * however, ensure that on some weird system it isn't greater than 64 bits since it is allowed by
- * the standard.
- */
- unsigned long long int tmp = strtoull(str, &endptr, 0);
- if (errno || tmp > UINT64_MAX) {
- return false;
- }
- /*
- * The entire string should be able to be converted or fail
- * We already checked that str starts with a null byte, so no
- * need to check that again per the man page.
- */
- if (*endptr != '\0') {
- return false;
- }
- *value = (uint64_t) tmp;
- return true;
- }
- bool tpm2_util_string_to_int32(const char *str, int32_t *value) {
- char *endptr;
- if (str == NULL || *str == '\0') {
- return false;
- }
- /* clear errno before the call, should be 0 afterwards */
- errno = 0;
- signed long int tmp = strtol(str, &endptr, 0);
- if (errno || tmp > INT32_MAX) {
- return false;
- }
- /*
- * The entire string should be able to be converted or fail
- * We already checked that str starts with a null byte, so no
- * need to check that again per the man page.
- */
- if (*endptr != '\0') {
- return false;
- }
- *value = (int32_t) tmp;
- return true;
- }
- int tpm2_util_hex_to_byte_structure(const char *input_string, UINT16 *byte_length,
- BYTE *byte_buffer) {
- int str_length; //if the input_string likes "1a2b...", no prefix "0x"
- int i = 0;
- if (input_string == NULL || byte_length == NULL || byte_buffer == NULL)
- return -1;
- str_length = strlen(input_string);
- if (str_length % 2)
- return -2;
- for (i = 0; i < str_length; i++) {
- if (!isxdigit(input_string[i]))
- return -3;
- }
- if (*byte_length < str_length / 2)
- return -4;
- *byte_length = str_length / 2;
- for (i = 0; i < *byte_length; i++) {
- char tmp_str[4] = { 0 };
- tmp_str[0] = input_string[i * 2];
- tmp_str[1] = input_string[i * 2 + 1];
- byte_buffer[i] = strtol(tmp_str, NULL, 16);
- }
- return 0;
- }
- bool tpm2_util_bin_from_hex_or_file(const char *input, UINT16 *len, BYTE *buffer) {
- bool result = false;
- FILE *f = fopen(input, "rb");
- if (!f) {
- result = tpm2_util_hex_to_byte_structure(input, len, buffer) == 0;
- goto out;
- }
- result = file_read_bytes_from_file(f, buffer, len, input);
- fclose(f);
- out:
- if (!result) {
- LOG_ERR("Could not convert \"%s\". Neither a file path nor hex string.",
- input);
- }
- return result;
- }
- void tpm2_util_hexdump2(FILE *f, const BYTE *data, size_t len) {
- size_t i;
- for (i = 0; i < len; i++) {
- fprintf(f, "%02x", data[i]);
- }
- }
- void tpm2_util_hexdump(const BYTE *data, size_t len) {
- if (!output_enabled) {
- return;
- }
- tpm2_util_hexdump2(stdout, data, len);
- }
- bool tpm2_util_is_big_endian(void) {
- uint32_t test_word;
- uint8_t *test_byte;
- test_word = 0xFF000000;
- test_byte = (uint8_t *) (&test_word);
- return test_byte[0] == 0xFF;
- }
- #define STRING_BYTES_ENDIAN_CONVERT(size) \
- UINT##size tpm2_util_endian_swap_##size(UINT##size data) { \
- \
- UINT##size converted; \
- UINT8 *bytes = (UINT8 *)&data; \
- UINT8 *tmp = (UINT8 *)&converted; \
- \
- size_t i; \
- for(i=0; i < sizeof(UINT##size); i ++) { \
- tmp[i] = bytes[sizeof(UINT##size) - i - 1]; \
- } \
- \
- return converted; \
- }
- STRING_BYTES_ENDIAN_CONVERT(16)
- STRING_BYTES_ENDIAN_CONVERT(32)
- STRING_BYTES_ENDIAN_CONVERT(64)
- #define STRING_BYTES_ENDIAN_HTON(size) \
- UINT##size tpm2_util_hton_##size(UINT##size data) { \
- \
- bool is_big_endian = tpm2_util_is_big_endian(); \
- if (is_big_endian) { \
- return data; \
- } \
- \
- return tpm2_util_endian_swap_##size(data); \
- }
- STRING_BYTES_ENDIAN_HTON(16)
- STRING_BYTES_ENDIAN_HTON(32)
- STRING_BYTES_ENDIAN_HTON(64)
- /*
- * Converting from host-to-network (hton) or network-to-host (ntoh) is
- * the same operation: if endianess differs between host and data, swap
- * endianess. Thus we can just call the hton routines, but have some nice
- * names for folks.
- */
- UINT16 tpm2_util_ntoh_16(UINT16 data) {
- return tpm2_util_hton_16(data);
- }
- UINT32 tpm2_util_ntoh_32(UINT32 data) {
- return tpm2_util_hton_32(data);
- }
- UINT64 tpm2_util_ntoh_64(UINT64 data) {
- return tpm2_util_hton_64(data);
- }
- UINT32 tpm2_util_pop_count(UINT32 data) {
- static const UINT8 bits_per_nibble[] =
- {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
- UINT8 count = 0;
- UINT8 *d = (UINT8 *) &data;
- size_t i;
- for (i = 0; i < sizeof(data); i++) {
- count += bits_per_nibble[d[i] & 0x0f];
- count += bits_per_nibble[d[i] >> 4];
- }
- return count;
- }
- #define TPM2_UTIL_KEYDATA_INIT { .len = 0 };
- typedef struct tpm2_util_keydata tpm2_util_keydata;
- struct tpm2_util_keydata {
- UINT16 len;
- struct {
- const char *name;
- TPM2B *value;
- } entries[2];
- };
- static void tpm2_util_public_to_keydata(TPMT_PUBLIC *public,
- tpm2_util_keydata *keydata) {
- switch (public->type) {
- case TPM2_ALG_RSA:
- keydata->len = 1;
- keydata->entries[0].name = tpm2_alg_util_algtostr(
- public->type, tpm2_alg_util_flags_any);
- keydata->entries[0].value = (TPM2B *) &public->unique.rsa;
- return;
- case TPM2_ALG_KEYEDHASH:
- keydata->len = 1;
- keydata->entries[0].name = tpm2_alg_util_algtostr(
- public->type, tpm2_alg_util_flags_any);
- keydata->entries[0].value =
- (TPM2B *) &public->unique.keyedHash;
- return;
- case TPM2_ALG_SYMCIPHER:
- keydata->len = 1;
- keydata->entries[0].name = tpm2_alg_util_algtostr(
- public->type, tpm2_alg_util_flags_any);
- keydata->entries[0].value = (TPM2B *) &public->unique.sym;
- return;
- case TPM2_ALG_ECC:
- keydata->len = 2;
- keydata->entries[0].name = "x";
- keydata->entries[0].value = (TPM2B *) &public->unique.ecc.x;
- keydata->entries[1].name = "y";
- keydata->entries[1].value = (TPM2B *) &public->unique.ecc.y;
- return;
- default:
- LOG_WARN("The algorithm type(0x%4.4x) is not supported",
- public->type);
- }
- return;
- }
- void print_yaml_indent(size_t indent_count) {
- while (indent_count--) {
- tpm2_tool_output(" ");
- }
- }
- void tpm2_util_tpma_object_to_yaml(TPMA_OBJECT obj, char *indent) {
- if (!indent) {
- indent = "";
- }
- char *attrs = tpm2_attr_util_obj_attrtostr(obj);
- tpm2_tool_output("%sattributes:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent, attrs);
- tpm2_tool_output("%s raw: 0x%x\n", indent, obj);
- free(attrs);
- }
- static void print_alg_raw(const char *name, TPM2_ALG_ID alg, const char *indent) {
- tpm2_tool_output("%s%s:\n", indent, name);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(alg, tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent, alg);
- }
- static void print_scheme_common(TPMI_ALG_RSA_SCHEME scheme, const char *indent) {
- print_alg_raw("scheme", scheme, indent);
- }
- static void print_sym(TPMT_SYM_DEF_OBJECT *sym, const char *indent) {
- print_alg_raw("sym-alg", sym->algorithm, indent);
- print_alg_raw("sym-mode", sym->mode.sym, indent);
- tpm2_tool_output("%ssym-keybits: %u\n", indent, sym->keyBits.sym);
- }
- static void print_rsa_scheme(TPMT_RSA_SCHEME *scheme, const char *indent) {
- print_scheme_common(scheme->scheme, indent);
- /*
- * everything is a union on a hash algorithm except for RSAES which
- * has nothing. So on RSAES skip the hash algorithm printing
- */
- if (scheme->scheme != TPM2_ALG_RSAES) {
- print_alg_raw("scheme-halg", scheme->details.oaep.hashAlg, indent);
- }
- }
- static void print_ecc_scheme(TPMT_ECC_SCHEME *scheme, const char *indent) {
- print_scheme_common(scheme->scheme, indent);
- /*
- * everything but ecdaa uses only hash alg
- * in a union, so we only need to do things differently
- * for ecdaa.
- */
- print_alg_raw("scheme-halg", scheme->details.oaep.hashAlg, indent);
- if (scheme->scheme == TPM2_ALG_ECDAA) {
- tpm2_tool_output("%sscheme-count: %u\n", indent,
- scheme->details.ecdaa.count);
- }
- }
- static void print_kdf_scheme(TPMT_KDF_SCHEME *kdf, const char *indent) {
- print_alg_raw("kdfa-alg", kdf->scheme, indent);
- /*
- * The hash algorithm for the KDFA is in a union, just grab one of them.
- */
- print_alg_raw("kdfa-halg", kdf->details.mgf1.hashAlg, indent);
- }
- void tpm2_util_tpmt_public_to_yaml(TPMT_PUBLIC *public, char *indent) {
- if (!indent) {
- indent = "";
- }
- tpm2_tool_output("%sname-alg:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(public->nameAlg,
- tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent, public->nameAlg);
- tpm2_util_tpma_object_to_yaml(public->objectAttributes, indent);
- tpm2_tool_output("%stype:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(public->type,
- tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent, public->type);
- switch (public->type) {
- case TPM2_ALG_SYMCIPHER: {
- TPMS_SYMCIPHER_PARMS *s = &public->parameters.symDetail;
- print_sym(&s->sym, indent);
- }
- break;
- case TPM2_ALG_KEYEDHASH: {
- TPMS_KEYEDHASH_PARMS *k = &public->parameters.keyedHashDetail;
- tpm2_tool_output("%salgorithm: \n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(k->scheme.scheme,
- tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent, k->scheme.scheme);
- if (k->scheme.scheme == TPM2_ALG_HMAC) {
- tpm2_tool_output("%shash-alg:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(k->scheme.details.hmac.hashAlg,
- tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent,
- k->scheme.details.hmac.hashAlg);
- } else if (k->scheme.scheme == TPM2_ALG_XOR) {
- tpm2_tool_output("%shash-alg:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(
- k->scheme.details.exclusiveOr.hashAlg,
- tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent,
- k->scheme.details.exclusiveOr.hashAlg);
- tpm2_tool_output("%skdfa-alg:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_algtostr(k->scheme.details.exclusiveOr.kdf,
- tpm2_alg_util_flags_any));
- tpm2_tool_output("%s raw: 0x%x\n", indent,
- k->scheme.details.exclusiveOr.kdf);
- }
- }
- break;
- case TPM2_ALG_RSA: {
- TPMS_RSA_PARMS *r = &public->parameters.rsaDetail;
- tpm2_tool_output("%sexponent: %u\n", indent, r->exponent ? r->exponent : 65537);
- tpm2_tool_output("%sbits: %u\n", indent, r->keyBits);
- print_rsa_scheme(&r->scheme, indent);
- print_sym(&r->symmetric, indent);
- }
- break;
- case TPM2_ALG_ECC: {
- TPMS_ECC_PARMS *e = &public->parameters.eccDetail;
- tpm2_tool_output("%scurve-id:\n", indent);
- tpm2_tool_output("%s value: %s\n", indent,
- tpm2_alg_util_ecc_to_str(e->curveID));
- tpm2_tool_output("%s raw: 0x%x\n", indent, e->curveID);
- print_kdf_scheme(&e->kdf, indent);
- print_ecc_scheme(&e->scheme, indent);
- print_sym(&e->symmetric, indent);
- }
- break;
- }
- tpm2_util_keydata keydata = TPM2_UTIL_KEYDATA_INIT
- ;
- tpm2_util_public_to_keydata(public, &keydata);
- UINT16 i;
- /* if no keydata len will be 0 and it wont print */
- for (i = 0; i < keydata.len; i++) {
- tpm2_tool_output("%s%s: ", indent, keydata.entries[i].name);
- tpm2_util_print_tpm2b(keydata.entries[i].value);
- tpm2_tool_output("%s\n", indent);
- }
- if (public->authPolicy.size) {
- tpm2_tool_output("%sauthorization policy: ", indent);
- tpm2_util_hexdump(public->authPolicy.buffer,
- public->authPolicy.size);
- tpm2_tool_output("%s\n", indent);
- }
- }
- void tpm2_util_public_to_yaml(TPM2B_PUBLIC *public, char *indent) {
- tpm2_util_tpmt_public_to_yaml(&public->publicArea, indent);
- }
- bool tpm2_util_calc_unique(TPMI_ALG_HASH name_alg,
- TPM2B_PRIVATE_VENDOR_SPECIFIC *key, TPM2B_DIGEST *seed,
- TPM2B_DIGEST *unique_data) {
- TPM2B_MAX_BUFFER buf = { .size = key->size + seed->size };
- if (buf.size > sizeof(buf.buffer)) {
- LOG_ERR("Seed and key size are too big");
- return false;
- }
- memcpy(buf.buffer, seed->buffer, seed->size);
- memcpy(&buf.buffer[seed->size], key->buffer, key->size);
- digester d = tpm2_openssl_halg_to_digester(name_alg);
- if (!d) {
- return false;
- }
- unique_data->size = tpm2_alg_util_get_hash_size(name_alg);
- d(buf.buffer, buf.size, unique_data->buffer);
- return true;
- }
- ESYS_TR tpm2_tpmi_hierarchy_to_esys_tr(TPMI_RH_PROVISION inh) {
- switch (inh) {
- case TPM2_RH_OWNER:
- return ESYS_TR_RH_OWNER;
- case TPM2_RH_PLATFORM:
- return ESYS_TR_RH_PLATFORM;
- case TPM2_RH_ENDORSEMENT:
- return ESYS_TR_RH_ENDORSEMENT;
- case TPM2_RH_NULL:
- return ESYS_TR_RH_NULL;
- case TPM2_RH_LOCKOUT:
- return ESYS_TR_RH_LOCKOUT;
- }
- return ESYS_TR_NONE;
- }
- tool_rc tpm2_util_sys_handle_to_esys_handle(ESYS_CONTEXT *context,
- TPM2_HANDLE sys_handle, ESYS_TR *esys_handle) {
- ESYS_TR h = tpm2_tpmi_hierarchy_to_esys_tr(sys_handle);
- if (h != ESYS_TR_NONE) {
- *esys_handle = h;
- return tool_rc_success;
- }
- return tpm2_from_tpm_public(context, sys_handle, ESYS_TR_NONE, ESYS_TR_NONE,
- ESYS_TR_NONE, esys_handle);
- }
- char *tpm2_util_getenv(const char *name) {
- return getenv(name);
- }
- /**
- * Parses a hierarchy value from an option argument.
- * @param value
- * The string to parse, which can be a numerical string as
- * understood by strtoul() with a base of 0, or an:
- * - o - Owner hierarchy
- * - p - Platform hierarchy
- * - e - Endorsement hierarchy
- * - n - Null hierarchy
- * @param hierarchy
- * The parsed hierarchy as output.
- * @param flags
- * What hierarchies should be supported by
- * the parsing.
- * @return
- * True on success, False otherwise.
- */
- static bool filter_hierarchy_handles(TPMI_RH_PROVISION hierarchy,
- tpm2_handle_flags flags) {
- switch (hierarchy) {
- case TPM2_RH_OWNER:
- if (!(flags & TPM2_HANDLE_FLAGS_O)) {
- LOG_ERR("Unexpected handle - TPM2_RH_OWNER");
- return false;
- }
- break;
- case TPM2_RH_PLATFORM:
- if (!(flags & TPM2_HANDLE_FLAGS_P)) {
- LOG_ERR("Unexpected handle - TPM2_RH_PLATFORM");
- return false;
- }
- break;
- case TPM2_RH_ENDORSEMENT:
- if (!(flags & TPM2_HANDLE_FLAGS_E)) {
- LOG_ERR("Unexpected handle - TPM2_RH_ENDORSEMENT");
- return false;
- }
- break;
- case TPM2_RH_NULL:
- if (!(flags & TPM2_HANDLE_FLAGS_N)) {
- LOG_ERR("Unexpected handle - TPM2_RH_NULL");
- return false;
- }
- break;
- case TPM2_RH_LOCKOUT:
- if (!(flags & TPM2_HANDLE_FLAGS_L)) {
- LOG_ERR("Unexpected handle - TPM2_RH_LOCKOUT");
- return false;
- }
- break;
- default: //If specified a random offset to the permanent handle range
- if (flags == TPM2_HANDLE_ALL_W_NV || flags == TPM2_HANDLE_FLAGS_NONE) {
- return true;
- }
- return false;
- }
- return true;
- }
- static bool filter_handles(TPMI_RH_PROVISION *hierarchy,
- tpm2_handle_flags flags) {
- TPM2_RH range = *hierarchy & TPM2_HR_RANGE_MASK;
- /*
- * if their is no range, then it could be NV or PCR, use flags
- * to figure out what it is.
- */
- if (range == 0) {
- if (flags & TPM2_HANDLE_FLAGS_NV) {
- *hierarchy += TPM2_HR_NV_INDEX;
- range = *hierarchy & TPM2_HR_RANGE_MASK;
- } else if (flags & TPM2_HANDLE_FLAGS_PCR) {
- *hierarchy += TPM2_HR_PCR;
- range = *hierarchy & TPM2_HR_RANGE_MASK;
- } else {
- LOG_ERR("Implicit indices are not supported.");
- return false;
- }
- }
- /* now that we have fixed up any non-ranged handles, check them */
- if (range == TPM2_HR_NV_INDEX) {
- if (!(flags & TPM2_HANDLE_FLAGS_NV)) {
- LOG_ERR("NV-Index handles are not supported by this command.");
- return false;
- }
- if (*hierarchy < TPM2_NV_INDEX_FIRST
- || *hierarchy > TPM2_NV_INDEX_LAST) {
- LOG_ERR("NV-Index handle is out of range.");
- return false;
- }
- return true;
- } else if (range == TPM2_HR_PCR) {
- if (!(flags & TPM2_HANDLE_FLAGS_PCR)) {
- LOG_ERR("PCR handles are not supported by this command.");
- return false;
- }
- /* first is 0 so no possible way unsigned is less than 0, thus no check */
- if (*hierarchy > TPM2_PCR_LAST) {
- LOG_ERR("PCR handle out of range.");
- return false;
- }
- return true;
- } else if (range == TPM2_HR_TRANSIENT) {
- if (!(flags & TPM2_HANDLES_FLAGS_TRANSIENT)) {
- LOG_ERR("Transient handles are not supported by this command.");
- return false;
- }
- return true;
- } else if (range == TPM2_HR_PERMANENT) {
- return filter_hierarchy_handles(*hierarchy, flags);
- } else if (range == TPM2_HR_PERSISTENT) {
- if (!(flags & TPM2_HANDLES_FLAGS_PERSISTENT)) {
- LOG_ERR("Persistent handles are not supported by this command.");
- return false;
- }
- if (*hierarchy < TPM2_PERSISTENT_FIRST
- || *hierarchy > TPM2_PERSISTENT_LAST) {
- LOG_ERR("Persistent handle out of range.");
- return false;
- }
- return true;
- }
- /* else its a session flag and shouldn't use this interface */
- return false;
- }
- bool tpm2_util_handle_from_optarg(const char *value,
- TPMI_RH_PROVISION *hierarchy, tpm2_handle_flags flags) {
- if (!value || !value[0]) {
- return false;
- }
- if ((flags & TPM2_HANDLE_FLAGS_NV) && (flags & TPM2_HANDLE_FLAGS_PCR)) {
- LOG_ERR("Cannot specify NV and PCR index together");
- return false;
- }
- *hierarchy = 0;
- bool is_o = !strncmp(value, "owner", strlen(value));
- if (is_o) {
- *hierarchy = TPM2_RH_OWNER;
- }
- bool is_p = !strncmp(value, "platform", strlen(value));
- if (is_p) {
- *hierarchy = TPM2_RH_PLATFORM;
- }
- bool is_e = !strncmp(value, "endorsement", strlen(value));
- if (is_e) {
- *hierarchy = TPM2_RH_ENDORSEMENT;
- }
- bool is_n = !strncmp(value, "null", strlen(value));
- if (is_n) {
- *hierarchy = TPM2_RH_NULL;
- }
- bool is_l = !strncmp(value, "lockout", strlen(value));
- if (is_l) {
- *hierarchy = TPM2_RH_LOCKOUT;
- }
- bool result = true;
- if (!*hierarchy) {
- /*
- * This branch is executed when hierarchy is specified as a hex handle.
- * The raw hex returned may be a generic (non hierarchy) TPM2_HANDLE.
- */
- result = tpm2_util_string_to_uint32(value, hierarchy);
- }
- if (!result) {
- char msg[256] = { 0 };
- char print_flags[32] = { '[', '\0' };
- if (flags & TPM2_HANDLE_FLAGS_O) {
- strncat(print_flags, "o|",
- sizeof(print_flags) - strlen(print_flags) - 1);
- }
- if (flags & TPM2_HANDLE_FLAGS_P) {
- strncat(print_flags, "p|",
- sizeof(print_flags) - strlen(print_flags) - 1);
- }
- if (flags & TPM2_HANDLE_FLAGS_E) {
- strncat(print_flags, "e|",
- sizeof(print_flags) - strlen(print_flags) - 1);
- }
- if (flags & TPM2_HANDLE_FLAGS_N) {
- strncat(print_flags, "n|",
- sizeof(print_flags) - strlen(print_flags) - 1);
- }
- if (flags & TPM2_HANDLE_FLAGS_L) {
- strncat(print_flags, "l|",
- sizeof(print_flags) - strlen(print_flags) - 1);
- }
- size_t len = strlen(print_flags);
- if (print_flags[len - 1] == '|') {
- len--;
- print_flags[len] = '\0';
- }
- strncat(print_flags, "]",
- sizeof(print_flags) - strlen(print_flags) - 1);
- len++;
- bool has_print_flags = len > 2;
- if (has_print_flags) {
- snprintf(msg, sizeof(msg), "expected %s or ", print_flags);
- }
- strncat(msg, "a handle number", sizeof(msg) - strlen(msg) - 1);
- LOG_ERR("Incorrect handle value, got: \"%s\", expected %s", value, msg);
- return false;
- }
- /*
- * If the caller specifies the expected valid hierarchies, either as string,
- * or hex handles, they are additionally filtered here.
- */
- bool res = filter_handles(hierarchy, flags);
- if (!res) {
- LOG_ERR("Unknown or unsupported handle, got: \"%s\"", value);
- }
- return res;
- }
- bool tpm2_util_get_label(const char *value, TPM2B_DATA *label) {
- if (!value) {
- label->size = 0;
- return true;
- }
- FILE *f = fopen(value, "rb");
- if (f) {
- /* set size one smaller for NUL byte */
- label->size = sizeof(label->buffer) - 1;
- size_t cnt = fread(label->buffer, 1, label->size, f);
- if (!feof(f)) {
- LOG_ERR("label file \"%s\" larger than expected. Expected %u",
- value, label->size);
- fclose(f);
- return false;
- }
- if (ferror(f)) {
- LOG_ERR("reading label file \"%s\" error: %s", value,
- strerror(errno));
- fclose(f);
- return false;
- }
- fclose(f);
- label->size = cnt;
- /* Set NUL byte and increment */
- label->buffer[label->size++] = '\0';
- return true;
- }
- size_t len = strlen(value);
- if (len > sizeof(label->buffer) - 1) {
- LOG_ERR("label file \"%s\" larger than expected. Expected %zu", value,
- sizeof(label->buffer) - 1);
- return false;
- }
- memcpy(label->buffer, value, len);
- label->size = len;
- /* Set NUL byte and increment */
- label->buffer[label->size++] = '\0';
- return true;
- }
- void tpm2_util_print_time(const TPMS_TIME_INFO *current_time) {
- tpm2_tool_output("time: %"PRIu64"\n", current_time->time);
- tpm2_tool_output("clock_info:\n");
- tpm2_tool_output(" clock: %"PRIu64"\n",
- current_time->clockInfo.clock);
- tpm2_tool_output(" reset_count: %"PRIu32"\n",
- current_time->clockInfo.resetCount);
- tpm2_tool_output(" restart_count: %"PRIu32"\n",
- current_time->clockInfo.restartCount);
- tpm2_tool_output(" safe: %s\n",
- current_time->clockInfo.safe ? "yes" : "no");
- }
- bool tpm2_calq_qname(TPM2B_NAME *pqname,
- TPMI_ALG_HASH halg, TPM2B_NAME *name, TPM2B_NAME *qname) {
- // QNB ≔ HB (QNA || NAMEB)
- bool result = false;
- const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(halg);
- EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
- if (!mdctx) {
- LOG_ERR("%s", tpm2_openssl_get_err());
- return false;
- }
- int rc = EVP_DigestInit_ex(mdctx, md, NULL);
- if (!rc) {
- LOG_ERR("%s", tpm2_openssl_get_err());
- goto out;
- }
- size_t offset = sizeof(halg);
- rc = EVP_DigestUpdate(mdctx, pqname->name, pqname->size);
- if (!rc) {
- LOG_ERR("%s", tpm2_openssl_get_err());
- goto out;
- }
- rc = EVP_DigestUpdate(mdctx, name->name, name->size);
- if (!rc) {
- LOG_ERR("%s", tpm2_openssl_get_err());
- goto out;
- }
- unsigned size = EVP_MD_size(md);
- rc = EVP_DigestFinal_ex(mdctx, &qname->name[offset], &size);
- if (!rc) {
- LOG_ERR("%s", tpm2_openssl_get_err());
- goto out;
- }
- /* hash sizes are not bigger than 16 bits, safe truncate */
- qname->size = (UINT16)size;
- /* put the hash alg on the front, since name already has it in marshalled
- * proper form just use it.
- */
- memcpy(qname->name, name->name, offset);
- qname->size += offset;
- result = true;
- out:
- EVP_MD_CTX_destroy(mdctx);
- return result;
- }
- bool tpm2_safe_read_from_stdin(int length, char *data) {
- int rc;
- char *buf = malloc(length);
- char *read_data = malloc(length);
- if (buf == fgets(buf, length, stdin)) {
- rc = sscanf(buf, "%s", read_data);
- if (rc != 1) {
- free(buf);
- free(read_data);
- return false;
- }
- }
- else {
- free(buf);
- free(read_data);
- return false;
- }
- strcpy(data, read_data);
- free(buf);
- free(read_data);
- return true;
- }
- bool tpm2_pem_encoded_key_to_fingerprint(const char *pem_encoded_key,
- char *fingerprint) {
- bool is_pemkey_len_valid = strlen(pem_encoded_key) > 1024 ? false : true;
- if (!is_pemkey_len_valid) {
- return false;
- }
- char str[1024] = "";
- strcpy(str, pem_encoded_key);
- /* walk through other tokens */
- char base64[1024] = "";
- char *token = strtok(str, "\n");
- while ( token != NULL ) {
- if (!strstr(token, "-----")) {
- bool is_base64_overrun = (strlen(base64) + strlen(token)) > 1024 ?
- true : false;
- if (is_base64_overrun) {
- return false;
- }
- strcat(base64, token);
- }
- token = strtok(NULL, "\n");
- }
- BYTE buffer[1024];
- size_t buffer_length = 0;
- int rc = tpm2_base64_decode(base64, buffer, &buffer_length);
- if(!rc){
- LOG_ERR("%s", "tpm2_base64_decode");
- return false;
- }
- TPM2B_DIGEST digest;
- rc = tpm2_openssl_hash_compute_data(TPM2_ALG_SHA256, buffer,
- buffer_length, &digest);
- if(!rc){
- LOG_ERR("%s", "tpm2_openssl_hash_compute_data");
- return false;
- }
- rc = tpm2_base64_encode(buffer, buffer_length, base64);
- if(!rc){
- LOG_ERR("%s", "tpm2_base64_decode");
- return false;
- }
- strcpy(fingerprint, "SHA256:");
- strcat(fingerprint, base64);
- fingerprint[strlen(fingerprint)-1] = 0; // remove trailing \n
- return true;
- }
- #define MAX_SESSION_CNT 3
- tool_rc tpm2_util_aux_sessions_setup(ESYS_CONTEXT *ectx, uint8_t session_cnt,
- const char **session_path, ESYS_TR *session_handle,
- tpm2_session **session) {
- /*
- * If no aux sessions were specified, simply return.
- */
- if (!session_cnt) {
- return tool_rc_success;
- }
- if (session_cnt > MAX_SESSION_CNT) {
- LOG_ERR("A max of 3 sessions allowed");
- return tool_rc_general_error;
- }
- uint8_t session_idx = 0;
- for (session_idx = 0; session_idx < (session_cnt); session_idx++) {
- if (session_path[session_idx]) {
- tool_rc rc = tpm2_session_restore(ectx,
- session_path[session_idx], false, &session[session_idx]);
- if (rc != tool_rc_success) {
- LOG_ERR("Could not restore aux-session #%s",
- session_path[session_idx]);
- return rc;
- }
- session_handle[session_idx] =
- tpm2_session_get_handle(session[session_idx]);
- }
- }
- return tool_rc_success;
- }
- static TPMI_ALG_HASH calc_phash_alg_from_phash_path(const char **phash_path) {
- if (!*phash_path) {
- return TPM2_ALG_ERROR;
- }
- /*
- * Expecting single token, so tokenize just once.
- */
- char *str = malloc(strlen(*phash_path) + 1);
- strcpy(str, *phash_path);
- char *token = strtok(str, ":");
- TPMI_ALG_HASH hashalg = tpm2_alg_util_from_optarg(
- token, tpm2_alg_util_flags_hash);
- /*
- * Adjust the pHash path to skip the <halg>:
- */
- if (hashalg != TPM2_ALG_ERROR) {
- *phash_path += strlen(token) + 1;
- }
- free(str);
- return hashalg;
- }
- static TPMI_ALG_HASH tpm2_util_calc_phash_algorithm_from_session_types(
- ESYS_CONTEXT *ectx, tpm2_session **sessions) {
- TPMI_ALG_HASH rethash = TPM2_ALG_SHA256;
- size_t session_idx = 0;
- for (session_idx = 0; session_idx < MAX_SESSION_CNT; session_idx++) {
- if(!sessions[session_idx]) {
- continue;
- }
- TPM2_SE session_type = tpm2_session_get_type(sessions[session_idx]);
- if (session_type != TPM2_SE_HMAC && session_type != TPM2_SE_POLICY) {
- continue;
- }
- /*
- * If this is an audit session, use that session halg.
- * Note: Audit sessions are always HMAC type.
- */
- if (session_type == TPM2_SE_HMAC) {
- TPMA_SESSION attrs = 0;
- ESYS_TR session_handle = tpm2_session_get_handle(
- sessions[session_idx]);
- tool_rc tmp_rc = tpm2_sess_get_attributes(ectx, session_handle,
- &attrs);
- UNUSED(tmp_rc);
- if (attrs & TPMA_SESSION_AUDIT) {
- rethash = tpm2_session_get_authhash(sessions[session_idx]);
- break;
- }
- }
- /*
- * If no other sessions remain, simply use this sessions halg.
- */
- rethash = tpm2_session_get_authhash(sessions[session_idx]);
- }
- return rethash;
- }
- /*
- * It should be noted that the auths aren't checked when calculating the pHash,
- * instead the sessions are consumed to determine the pHash algorithm.
- *
- * 1. If phash_path is preceded with <halg>: use that as phash-halg return
- * Otherwise
- *
- * Consume session only if it is a policy-session or an hmac-session
- * 1. If only hmac or policy session is specified, return that session's halg
- * 2. If hmac-session with audit is specified, return that session's halg
- * 3. If policy-session, then return policy-session's halg
- *
- * Otherwise
- * return SHA256
- *
- */
- TPMI_ALG_HASH tpm2_util_calculate_phash_algorithm(ESYS_CONTEXT *ectx,
- const char **cphash_path, TPM2B_DIGEST *cp_hash, const char **rphash_path,
- TPM2B_DIGEST *rp_hash, tpm2_session **sessions) {
- if (!cphash_path && !rphash_path) {
- return TPM2_ALG_ERROR;
- }
- TPMI_ALG_HASH cphash_alg = cphash_path ? calc_phash_alg_from_phash_path(
- cphash_path) : TPM2_ALG_ERROR;
- TPMI_ALG_HASH rphash_alg = rphash_path ? calc_phash_alg_from_phash_path(
- rphash_path) : TPM2_ALG_ERROR;
- /*
- * Default to cphash_alg if both are specified.
- * This removes the conflict if cphash_alg and rphash_alg don't match.
- * This also sets the cphash_alg if only rphash_alg is specified and vice
- * versa.
- */
- TPMI_ALG_HASH phash_alg = cphash_alg != TPM2_ALG_ERROR ? cphash_alg :
- (rphash_alg != TPM2_ALG_ERROR ? rphash_alg : TPM2_ALG_ERROR);
- /*
- * pHash was enforced with <halg>:phash_path
- */
- if (phash_alg != TPM2_ALG_ERROR) {
- goto out;
- }
- phash_alg = tpm2_util_calc_phash_algorithm_from_session_types(ectx,
- sessions);
- out:
- /*
- * Calculate size here because with pHash_path information there is no
- * confusion on whether or not to set cp or rp sizes or both.
- */
- if (cphash_path) {
- cp_hash->size = tpm2_alg_util_get_hash_size(phash_alg);
- }
- if (rphash_path) {
- rp_hash->size = tpm2_alg_util_get_hash_size(phash_alg);
- }
- return phash_alg;
- }
|