| //**********************************************************************; |
| // Copyright (c) 2017, Intel Corporation |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of Intel Corporation nor the names of its contributors |
| // may be used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| // THE POSSIBILITY OF SUCH DAMAGE. |
| //**********************************************************************; |
| #include <ctype.h> |
| #include <errno.h> |
| #include <stdbool.h> |
| |
| #include "log.h" |
| #include "files.h" |
| #include "tpm2_alg_util.h" |
| #include "tpm2_attr_util.h" |
| #include "tpm2_util.h" |
| bool output_enabled; |
| bool tpm2_util_concat_buffer(TPM2B_MAX_BUFFER *result, TPM2B *append) { |
| |
| if (!result || !append) { |
| return false; |
| } |
| |
| if ((result->size + append->size) < result->size) { |
| return false; |
| } |
| |
| if ((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_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; |
| uint32_t tmp = strtoul(str, &endptr, 0); |
| if (errno) { |
| 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 = tmp; |
| return true; |
| } |
| |
| int tpm2_util_hex_to_byte_structure(const char *inStr, UINT16 *byteLength, |
| BYTE *byteBuffer) { |
| int strLength; //if the inStr likes "1a2b...", no prefix "0x" |
| int i = 0; |
| if (inStr == NULL || byteLength == NULL || byteBuffer == NULL) |
| return -1; |
| strLength = strlen(inStr); |
| if (strLength % 2) |
| return -2; |
| for (i = 0; i < strLength; i++) { |
| if (!isxdigit(inStr[i])) |
| return -3; |
| } |
| |
| if (*byteLength < strLength / 2) |
| return -4; |
| |
| *byteLength = strLength / 2; |
| |
| for (i = 0; i < *byteLength; i++) { |
| char tmpStr[4] = { 0 }; |
| tmpStr[0] = inStr[i * 2]; |
| tmpStr[1] = inStr[i * 2 + 1]; |
| byteBuffer[i] = strtol(tmpStr, NULL, 16); |
| } |
| return 0; |
| } |
| |
| void tpm2_util_hexdump(const BYTE *data, size_t len, bool plain) { |
| |
| if (!output_enabled) { |
| return; |
| } |
| |
| if (plain) { |
| size_t i; |
| for (i=0; i < len; i++) { |
| printf("%02x", data[i]); |
| } |
| return; |
| } |
| |
| size_t i; |
| size_t j; |
| for (i = 0; i < len; i += 16) { |
| printf("%06zx: ", i); |
| |
| for (j = 0; j < 16; j++) { |
| if (i + j < len) { |
| printf("%02x ", data[i + j]); |
| } else { |
| printf(" "); |
| } |
| } |
| |
| printf(" "); |
| |
| for (j = 0; j < 16; j++) { |
| if (i + j < len) { |
| printf("%c", isprint(data[i + j]) ? data[i + j] : '.'); |
| } |
| } |
| printf("\n"); |
| } |
| } |
| |
| bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain) { |
| BYTE* buff = (BYTE*)malloc(len); |
| if (!buff) { |
| LOG_ERR("malloc() failed"); |
| return false; |
| } |
| |
| bool res = files_read_bytes(fd, buff, len); |
| if (!res) { |
| LOG_ERR("Failed to read file"); |
| free(buff); |
| return false; |
| } |
| |
| tpm2_util_hexdump(buff, len, plain); |
| |
| free(buff); |
| return true; |
| } |
| |
| bool tpm2_util_print_tpm2b_file(FILE *fd) |
| { |
| UINT16 len; |
| bool res = files_read_16(fd, &len); |
| if(!res) { |
| LOG_ERR("File read failed"); |
| return false; |
| } |
| return tpm2_util_hexdump_file(fd, len, true); |
| } |
| |
| /* TODO OPTIMIZE ME */ |
| UINT16 tpm2_util_copy_tpm2b(TPM2B *dest, TPM2B *src) { |
| int i; |
| UINT16 rval = 0; |
| |
| if (dest != 0) { |
| if (src == 0) { |
| dest->size = 0; |
| rval = 0; |
| } else { |
| dest->size = src->size; |
| for (i = 0; i < src->size; i++) |
| dest->buffer[i] = src->buffer[i]; |
| rval = (sizeof(UINT16) + src->size); |
| } |
| } else { |
| rval = 0; |
| } |
| |
| return rval; |
| } |
| |
| 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(TPM2B_PUBLIC *public, tpm2_util_keydata *keydata) { |
| |
| switch (public->publicArea.type) { |
| case TPM2_ALG_RSA: |
| keydata->len = 1; |
| keydata->entries[0].name = tpm2_alg_util_algtostr(public->publicArea.type); |
| keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.rsa; |
| return; |
| case TPM2_ALG_KEYEDHASH: |
| keydata->len = 1; |
| keydata->entries[0].name = tpm2_alg_util_algtostr(public->publicArea.type); |
| keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.keyedHash; |
| return; |
| case TPM2_ALG_SYMCIPHER: |
| keydata->len = 1; |
| keydata->entries[0].name = tpm2_alg_util_algtostr(public->publicArea.type); |
| keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.sym; |
| return; |
| case TPM2_ALG_ECC: |
| keydata->len = 2; |
| keydata->entries[0].name = "x"; |
| keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.ecc.x; |
| keydata->entries[1].name = "y"; |
| keydata->entries[1].value = (TPM2B *)&public->publicArea.unique.ecc.y; |
| return; |
| default: |
| LOG_WARN("The algorithm type(0x%4.4x) is not supported", |
| public->publicArea.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 *attrs = tpm2_attr_util_obj_attrtostr(obj); |
| tpm2_tool_output("attributes:\n"); |
| tpm2_tool_output(" value: %s\n", attrs); |
| tpm2_tool_output(" raw: 0x%x\n", obj); |
| free(attrs); |
| } |
| |
| void tpm2_util_public_to_yaml(TPM2B_PUBLIC *public) { |
| |
| tpm2_tool_output("algorithm:\n"); |
| tpm2_tool_output(" value: %s\n", tpm2_alg_util_algtostr(public->publicArea.nameAlg)); |
| tpm2_tool_output(" raw: 0x%x\n", public->publicArea.nameAlg); |
| |
| tpm2_util_tpma_object_to_yaml(public->publicArea.objectAttributes); |
| |
| tpm2_tool_output("type: \n"); |
| tpm2_tool_output(" value: %s\n", tpm2_alg_util_algtostr(public->publicArea.type)); |
| tpm2_tool_output(" raw: 0x%x\n", public->publicArea.type); |
| |
| 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: ", keydata.entries[i].name); |
| tpm2_util_print_tpm2b(keydata.entries[i].value); |
| tpm2_tool_output("\n"); |
| } |
| |
| if (public->publicArea.authPolicy.size) { |
| tpm2_tool_output("authorization policy: "); |
| tpm2_util_hexdump(public->publicArea.authPolicy.buffer, |
| public->publicArea.authPolicy.size, true); |
| tpm2_tool_output("\n"); |
| } |
| } |