diff options
Diffstat (limited to 'TPM2-Plugin/lib')
24 files changed, 5519 insertions, 0 deletions
diff --git a/TPM2-Plugin/lib/Makefile.am b/TPM2-Plugin/lib/Makefile.am new file mode 100644 index 0000000..c82cf86 --- /dev/null +++ b/TPM2-Plugin/lib/Makefile.am @@ -0,0 +1,4 @@ +AM_CPPFLAGS = -I ./include +lib_LTLIBRARIES = libtpm2-plugin.la +libtpm2_plugin_la_SOURCES = tpm2_error.c tpm2_plugin_api.c tpm2_plugin_init.c tpm2_tcti_ldr.c tpm2_util.c log.c plugin_register.c files.c tpm2_attr_util.c tpm2_alg_util.c tpm2_hash.c +libtpm2_plugin_la_LDFLAGS = -version-info @VERSION_INFO@ -lsapi -ltcti-socket -ltcti-device -lcrypto -lssl -ldl diff --git a/TPM2-Plugin/lib/files.c b/TPM2-Plugin/lib/files.c new file mode 100644 index 0000000..e2e41f4 --- /dev/null +++ b/TPM2-Plugin/lib/files.c @@ -0,0 +1,636 @@ +//**********************************************************************; +// 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 <errno.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> + +#include <sapi/tpm20.h> +#include <sapi/tss2_mu.h> + +#include "files.h" +#include "log.h" +#include "tpm2_util.h" + +bool files_get_file_size(FILE *fp, unsigned long *file_size, const char *path) { + + long current = ftell(fp); + if (current < 0) { + if (path) { + LOG_ERR("Error getting current file offset for file \"%s\" error: %s", path, strerror(errno)); + } + return false; + } + + int rc = fseek(fp, 0, SEEK_END); + if (rc < 0) { + if (path) { + LOG_ERR("Error seeking to end of file \"%s\" error: %s", path, strerror(errno)); + } + return false; + } + + long size = ftell(fp); + if (size < 0) { + if (path) { + LOG_ERR("ftell on file \"%s\" failed: %s", path, strerror(errno)); + } + return false; + } + + rc = fseek(fp, current, SEEK_SET); + if (rc < 0) { + if (path) { + LOG_ERR("Could not restore initial stream position for file \"%s\" failed: %s", path, strerror(errno)); + } + return false; + } + + /* size cannot be negative at this point */ + *file_size = (unsigned long)size; + return true; +} + +static bool read_bytes_from_file(FILE *f, UINT8 *buf, UINT16 *size, + const char *path) { + unsigned long file_size; + bool result = files_get_file_size(f, &file_size, path); + if (!result) { + /* get_file_size() logs errors */ + return false; + } + + /* max is bounded on UINT16 */ + if (file_size > *size) { + if (path) { + LOG_ERR( + "File \"%s\" size is larger than buffer, got %lu expected less than %u", + path, file_size, *size); + } + return false; + } + + result = files_read_bytes(f, buf, file_size); + if (!result) { + if (path) { + LOG_ERR("Could not read data from file \"%s\"", path); + } + return false; + } + + *size = file_size; + + return true; +} + +bool files_load_bytes_from_path(const char *path, UINT8 *buf, UINT16 *size) { + if (!buf || !size || !path) { + return false; + } + + FILE *f = fopen(path, "rb"); + if (!f) { + LOG_ERR("Could not open file \"%s\" error %s", path, strerror(errno)); + return false; + } + + bool result = read_bytes_from_file(f, buf, size, path); + + fclose(f); + return result; +} + +bool files_save_bytes_to_file(const char *path, UINT8 *buf, UINT16 size) { + + if (!path || !buf) { + return false; + } + + FILE *fp = fopen(path, "wb+"); + if (!fp) { + LOG_ERR("Could not open file \"%s\", error: %s", path, strerror(errno)); + return false; + } + + bool result = files_write_bytes(fp, buf, size); + if (!result) { + LOG_ERR("Could not write data to file \"%s\"", path); + } + fclose(fp); + return result; +} + +/* + * Current version to write TPMS_CONTEXT to disk. + */ +#define CONTEXT_VERSION 1 + +bool files_save_tpm_context_to_file(TSS2_SYS_CONTEXT *sysContext, TPM2_HANDLE handle, + FILE *stream) { + + TPMS_CONTEXT context; + + TSS2_RC rval = Tss2_Sys_ContextSave(sysContext, handle, &context); + if (rval != TPM2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_ContextSave, rval); + return false; + } + + /* + * Saving the TPMS_CONTEXT structure to disk, format: + * TPM2.0-TOOLS HEADER + * U32 hiearchy + * U32 savedHandle + * U64 sequence + * U16 contextBlobLength + * BYTE[] contextBlob + */ + bool result = files_write_header(stream, CONTEXT_VERSION); + if (!result) { + LOG_ERR("Could not write context file header"); + goto out; + } + + // UINT32 + result = files_write_32(stream, context.hierarchy); + if (!result) { + LOG_ERR("Could not write hierarchy"); + goto out; + } + + result = files_write_32(stream, context.savedHandle); + if (!result) { + LOG_ERR("Could not write savedHandle"); + goto out; + } + + // UINT64 + result = files_write_64(stream, context.sequence); + if (!result) { + LOG_ERR("Could not write sequence"); + goto out; + } + + // U16 LENGTH + result = files_write_16(stream, context.contextBlob.size); + if (!result) { + LOG_ERR("Could not write contextBob size"); + goto out; + } + + // BYTE[] contextBlob + result = files_write_bytes(stream, context.contextBlob.buffer, + context.contextBlob.size); + if (!result) { + LOG_ERR("Could not write contextBlob buffer"); + } + /* result is set by file_write_bytes() */ + +out: + return result; +} + +bool files_save_tpm_context_to_path(TSS2_SYS_CONTEXT *sysContext, TPM2_HANDLE handle, + const char *path) { + + FILE *f = fopen(path, "w+b"); + if (!f) { + LOG_ERR("Error opening file \"%s\" due to error: %s", path, + strerror(errno)); + return false; + } + + bool result = files_save_tpm_context_to_file(sysContext, handle, f); + fclose(f); + return result; +} + + +bool files_load_tpm_context_from_file(TSS2_SYS_CONTEXT *sapi_context, + TPM2_HANDLE *handle, FILE *fstream) { + + TSS2_RC rval; + + /* + * Reading the TPMS_CONTEXT structure to disk, format: + * TPM2.0-TOOLS HEADER + * U32 hiearchy + * U32 savedHandle + * U64 sequence + * U16 contextBlobLength + * BYTE[] contextBlob + */ + UINT32 version; + TPMS_CONTEXT context; + bool result = files_read_header(fstream, &version); + if (!result) { + LOG_WARN( + "The loaded tpm context does not appear to be in the proper format," + "assuming old format, this will be converted on the next save."); + rewind(fstream); + result = files_read_bytes(fstream, (UINT8 *) &context, sizeof(context)); + if (!result) { + LOG_ERR("Could not load tpm context file"); + goto out; + } + /* Success load the context into the TPM */ + goto load_to_tpm; + } + + if (version != CONTEXT_VERSION) { + LOG_ERR("Unsupported context file format version found, got: %"PRIu32, + version); + result = false; + goto out; + } + + result = files_read_32(fstream, &context.hierarchy); + if (!result) { + LOG_ERR("Error reading hierarchy!"); + goto out; + } + + result = files_read_32(fstream, &context.savedHandle); + if (!result) { + LOG_ERR("Error reading savedHandle!"); + goto out; + } + + result = files_read_64(fstream, &context.sequence); + if (!result) { + LOG_ERR("Error reading sequence!"); + goto out; + } + + result = files_read_16(fstream, &context.contextBlob.size); + if (!result) { + LOG_ERR("Error reading contextBlob.size!"); + goto out; + } + + if (context.contextBlob.size > sizeof(context.contextBlob.buffer)) { + LOG_ERR( + "Size mismatch found on contextBlob, got %"PRIu16" expected less than or equal to %zu", + context.contextBlob.size, + sizeof(context.contextBlob.buffer)); + result = false; + goto out; + } + + result = files_read_bytes(fstream, context.contextBlob.buffer, + context.contextBlob.size); + if (!result) { + LOG_ERR("Error reading contextBlob.size!"); + goto out; + } + +load_to_tpm: + rval = Tss2_Sys_ContextLoad(sapi_context, &context, handle); + if (rval != TPM2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_ContextLoad, rval); + result = false; + goto out; + } + + result = true; + +out: + return result; +} + +bool files_load_tpm_context_from_path(TSS2_SYS_CONTEXT *sapi_context, + TPM2_HANDLE *handle, const char *path) { + + FILE *f = fopen(path, "rb"); + if (!f) { + LOG_ERR("Error opening file \"%s\" due to error: %s", path, + strerror(errno)); + return false; + } + + bool result = files_load_tpm_context_from_file(sapi_context, handle, f); + + fclose(f); + return result; +} + +bool files_does_file_exist(const char *path) { + + if (!path) { + LOG_ERR("Path cannot be NULL"); + return false; + } + + FILE *fp = fopen(path,"rb"); + if (fp) { + fclose(fp); + LOG_ERR("Path: %s already exists. Please rename or delete the file!", + path); + return true; + } + return false; +} + +bool files_get_file_size_path(const char *path, unsigned long *file_size) { + + bool result = false; + + if (!path) { + LOG_ERR("Must specify a path argument, cannot be NULL!"); + return false; + } + + if (!file_size) { + LOG_ERR("Must specify a file size argument, cannot be NULL!"); + return false; + } + + FILE *fp = fopen(path,"rb"); + if(!fp) { + LOG_ERR("Could not open file: \"%s\" error: %s", path, strerror(errno)); + return false; + } + + result = files_get_file_size(fp, file_size, path); + + fclose(fp); + return result; +} + +/** + * This is the magic for the file header. The header is organized + * as a big endian U32 (BEU32) of MAGIC followed by a BEU32 of the + * version number. Tools can define their own, individual file + * formats as they make sense, but they should always have the header. + */ +static const UINT32 MAGIC = 0xBADCC0DE; + +/** + * Writes size bytes to a file, continuing on EINTR short writes. + * @param f + * The file to write to. + * @param data + * The data to write. + * @param size + * The size, in bytes, of that data. + * @return + * True on success, False otherwise. + */ +static bool writex(FILE *f, UINT8 *data, size_t size) { + + size_t wrote = 0; + size_t index = 0; + do { + wrote = fwrite(&data[index], 1, size, f); + if (wrote != size) { + if (errno != EINTR) { + return false; + } + /* continue on EINTR */ + } + size -= wrote; + index += wrote; + } while (size > 0); + + return true; +} + +/** + * Reads size bytes from a file, continuing on EINTR short reads. + * @param f + * The file to read from. + * @param data + * The data buffer to read into. + * @param size + * The size of the buffer, which is also the amount of bytes to read. + * @return + * True on success, False otherwise. + */ +static bool readx(FILE *f, UINT8 *data, size_t size) { + + size_t bread = 0; + size_t index = 0; + do { + bread = fread(&data[index], 1, size, f); + if (bread != size) { + if (feof(f) || (errno != EINTR)) { + return false; + } + /* continue on EINTR */ + } + size -= bread; + index += bread; + } while (size > 0); + + return true; +} + +#define BAIL_ON_NULL(param, x) \ + do { \ + if (!x) { \ + LOG_ERR(param" must be specified"); \ + return false; \ + } \ + } while(0) + +#define BE_CONVERT(value, size) \ + do { \ + if (!tpm2_util_is_big_endian()) { \ + value = tpm2_util_endian_swap_##size(value); \ + } \ + } while (0) + +#define FILE_WRITE(size) \ + bool files_write_##size(FILE *out, UINT##size data) { \ + BAIL_ON_NULL("FILE", out); \ + BE_CONVERT(data, size); \ + return writex(out, (UINT8 *)&data, sizeof(data)); \ + } + +#define FILE_READ(size) \ + bool files_read_##size(FILE *out, UINT##size *data) { \ + BAIL_ON_NULL("FILE", out); \ + BAIL_ON_NULL("data", data); \ + bool res = readx(out, (UINT8 *)data, sizeof(*data)); \ + if (res) { \ + BE_CONVERT(*data, size); \ + } \ + return res; \ + } + +/* + * all the files_read|write_bytes_16|32|64 functions + */ +FILE_READ(16); +FILE_WRITE(16) + +FILE_READ(32); +FILE_WRITE(32) + +FILE_READ(64) +FILE_WRITE(64) + +bool files_read_bytes(FILE *out, UINT8 bytes[], size_t len) { + + BAIL_ON_NULL("FILE", out); + BAIL_ON_NULL("bytes", bytes); + return readx(out, bytes, len); +} + +bool files_write_bytes(FILE *out, uint8_t bytes[], size_t len) { + + BAIL_ON_NULL("FILE", out); + BAIL_ON_NULL("bytes", bytes); + return writex(out, bytes, len); +} + +bool files_write_header(FILE *out, UINT32 version) { + + BAIL_ON_NULL("FILE", out); + + bool res = files_write_32(out, MAGIC); + if (!res) { + return false; + } + return files_write_32(out, version); +} + +bool files_read_header(FILE *out, uint32_t *version) { + + BAIL_ON_NULL("FILE", out); + BAIL_ON_NULL("version", version); + + UINT32 magic; + bool res = files_read_32(out, &magic); + if (!res) { + return false; + } + + if (magic != MAGIC) { + LOG_ERR("Found magic 0x%x did not match expected magic of 0x%x!", + magic, MAGIC); + return false; + } + + return files_read_32(out, version); +} + +bool files_load_bytes_from_file_or_stdin(const char *path, UINT16 *size, BYTE *buf) { + + FILE *file = path ? fopen(path, "rb") : stdin; + path = file != stdin ? path : "<stdin>"; + if (!file) { + LOG_ERR("Could not open file: \"%s\", error: %s", path, + strerror(errno)); + return false; + } + + /* + * Attempt to accurately read the file based on the file size. + * This may fail on stdin when it's a pipe. + */ + if (file == stdin) { + path = NULL; + } + + UINT16 original_size = *size; + bool res = files_load_bytes_from_path(path, buf, + size); + if (!res) { + res = true; + *size = fread(buf, 1, + *size, file); + if (!feof(file)) { + LOG_ERR("Data to be sealed larger than expected. Got %u expected %u", + original_size, res); + res = false; + } + else if (ferror(file)) { + LOG_ERR("Error reading sealed data from \"<stdin>\""); + res = false; + } + } + + if (file != stdin) { + fclose(file); + } + + return res; +} + +#define SAVE_TYPE(type, name) \ + bool files_save_##name(type *name, const char *path) { \ + \ + size_t offset = 0; \ + UINT8 buffer[sizeof(*name)]; \ + TSS2_RC rc = Tss2_MU_##type##_Marshal(name, buffer, sizeof(buffer), &offset); \ + if (rc != TSS2_RC_SUCCESS) { \ + LOG_ERR("Error serializing "str(name)" structure: 0x%x", rc); \ + return false; \ + } \ + \ + return files_save_bytes_to_file(path, buffer, offset); \ + } + +#define LOAD_TYPE(type, name) \ + bool files_load_##name(const char *path, type *name) { \ + \ + UINT8 buffer[sizeof(*name)]; \ + UINT16 size = sizeof(buffer); \ + bool res = files_load_bytes_from_path(path, buffer, &size); \ + if (!res) { \ + return false; \ + } \ + \ + size_t offset = 0; \ + TSS2_RC rc = Tss2_MU_##type##_Unmarshal(buffer, size, &offset, name); \ + if (rc != TSS2_RC_SUCCESS) { \ + LOG_ERR("Error serializing "str(name)" structure: 0x%x", rc); \ + return false; \ + } \ + \ + return rc == TPM2_RC_SUCCESS; \ + } + +SAVE_TYPE(TPM2B_PUBLIC, public) +LOAD_TYPE(TPM2B_PUBLIC, public) + +SAVE_TYPE(TPMT_SIGNATURE, signature) +LOAD_TYPE(TPMT_SIGNATURE, signature) + +SAVE_TYPE(TPMT_TK_VERIFIED, ticket) +LOAD_TYPE(TPMT_TK_VERIFIED, ticket) + +SAVE_TYPE(TPM2B_SENSITIVE, sensitive) +LOAD_TYPE(TPM2B_SENSITIVE, sensitive) + +SAVE_TYPE(TPMT_TK_HASHCHECK, validation) +LOAD_TYPE(TPMT_TK_HASHCHECK, validation) diff --git a/TPM2-Plugin/lib/include/files.h b/TPM2-Plugin/lib/include/files.h new file mode 100644 index 0000000..164e308 --- /dev/null +++ b/TPM2-Plugin/lib/include/files.h @@ -0,0 +1,366 @@ +//**********************************************************************; +// 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. +//**********************************************************************; +#ifndef FILES_H +#define FILES_H + +#include <stdbool.h> +#include <stdio.h> + +#include <sapi/tpm20.h> + +/** + * Reads a series of bytes from a file as a byte array. This is similar to files_read_bytes(), + * but opens and closes the FILE for the caller. Size is both an input and output value where + * the size value is the max buffer size on call and the returned size is how much was read. + * + * This interface could be cleaned up in a later revision. + * @param path + * The path to the file to open. + * @param buf + * The buffer to read the data into + * @param size + * The max size of the buffer on call, and the size of the data read on return. + * @return + * True on success, false otherwise. + */ +bool files_load_bytes_from_path(const char *path, UINT8 *buf, UINT16 *size); + +/** + * Loads data from a file path or stdin enforcing an upper bound on size. + * @param path + * The path to load data from, NULL means stdin. + * @param size + * The maximum size. + * @param buf + * The buffer to write the data into. + * @return + * True on success or false otherwise. + */ +bool files_load_bytes_from_file_or_stdin(const char *path, UINT16 *size, BYTE *buf); + +/** + * Similar to files_write_bytes(), in that it writes an array of bytes to disk, + * but this routine opens and closes the file on the callers behalf. + * @param path + * The path to the file to write the data to. + * @param buf + * The buffer of data to write + * @param size + * The size of the data to write in bytes. + * @return + * True on success, false otherwise. + */ +bool files_save_bytes_to_file(const char *path, UINT8 *buf, UINT16 size); + +/** + * Saves the TPM context for an object handle to disk by calling Tss2_Sys_ContextSave() and serializing the + * resulting TPMS_CONTEXT structure to disk. + * @param sapi_context + * The system api context + * @param handle + * The object handle for the object to save. + * @param path + * The output path of the file. + * + * @return + * True on success, False on error. + */ +bool files_save_tpm_context_to_path(TSS2_SYS_CONTEXT *sapi_context, TPM2_HANDLE handle, const char *path); + +/** + * Like files_save_tpm_context_to_path() but saves a tpm session to a FILE stream. + * @param sapi_context + * The system api context + * @param handle + * The object handle for the object to save. + * @param stream + * The FILE stream to save too. + * @return + * True on success, False on error. + */ +bool files_save_tpm_context_to_file(TSS2_SYS_CONTEXT *sapi_context, TPM2_HANDLE handle, + FILE *stream); + +/** + * Loads a TPM object context from disk. + * @param sapi_context + * The system API context + * @param handle + * The object handle that was saved. + * @param path + * The path to the input file. + * @return + * True on Success, false on error. + */ +bool files_load_tpm_context_from_path(TSS2_SYS_CONTEXT *sapi_context, TPM2_HANDLE *handle, const char *path); + +/** + * Like files_load_tpm_context_from_path() but loads the context from a FILE stream. + * @param sapi_context + * The system API context + * @param handle + * The object handle that was saved. + * @param stream + * The FILE stream to read from. + * @return + * True on success, False on error. + */ +bool files_load_tpm_context_from_file(TSS2_SYS_CONTEXT *sapi_context, + TPM2_HANDLE *handle, FILE *stream); + +/** + * Serializes a TPM2B_PUBLIC to the file path provided. + * @param public + * The TPM2B_PUBLIC to save to disk. + * @param path + * The path to save to. + * @return + * true on success, false on error. + */ +bool files_save_public(TPM2B_PUBLIC *public, const char *path); + +/** + * Loads a TPM2B_PUBLIC from disk that was saved with files_save_pubkey() + * @param path + * The path to load from. + * @param public + * The TPM2B_PUBLIC to load. + * @return + * true on success, false on error. + */ +bool files_load_public(const char *path, TPM2B_PUBLIC *public); + +/** + * Serializes a TPMT_SIGNATURE to the file path provided. + * @param signature + * The TPMT_SIGNATURE to save to disk. + * @param path + * The path to save to. + * @return + * true on success, false on error. + */ +bool files_save_signature(TPMT_SIGNATURE *signature, const char *path); + +/** + * Loads a TPMT_SIGNATURE from disk that was saved with files_save_signature() + * @param path + * The path to load from. + * @param signature + * The TPMT_SIGNATURE to load. + * @return + * true on success, false on error. + */ +bool files_load_signature(const char *path, TPMT_SIGNATURE *signature); + +/** + * Serializes a TPMT_TK_VERIFIED to the file path provided. + * @param signature + * The TPMT_SIGNATURE to save to disk. + * @param path + * The path to save to. + * @return + * true on success, false on error. + */ +bool files_save_ticket(TPMT_TK_VERIFIED *ticket, const char *path); + +/** + * Loads a TPMT_TK_VERIFIED from disk that was saved with files_save_ticket() + * @param path + * The path to load from. + * @param signature + * The TPMT_TK_VERIFIED to load. + * @return + * true on success, false on error. + */ +bool files_load_ticket(const char *path, TPMT_TK_VERIFIED *ticket); + +/** + * Loads a TPM2B_SENSITIVE from disk. + * @param path + * The path to load from. + * @param signature + * The TPM2B_SENSITIVE to load. + * @return + * true on success, false on error. + */ +bool files_load_sensitive(const char *path, TPM2B_SENSITIVE *sensitive); + +/** + * Serializes a TPMT_TK_HASHCHECK to the file path provided. + * @param validation + * The TPMT_TK_HASHCHECK to save to disk. + * @param path + * The path to save to. + * @return + * true on success, false on error. + */ +bool files_save_validation(TPMT_TK_HASHCHECK *validation, const char *path); + +/** + * Loads a TPMT_TK_HASHCHECK from disk. + * @param path + * The path to load from. + * @param validation + * The TPMT_TK_HASHCHECK to load. + * @return + * true on success, false on error. + */ +bool files_load_validation(const char *path, TPMT_TK_HASHCHECK *validation); + +/** + * Checks a file for existence. + * @param path + * The file to check for existence. + * @return + * true if a file exists with read permissions, false if it doesn't exist or an error occurs. + * + */ +bool files_does_file_exist(const char *path); + +/** + * Retrieves a files size given a file path. + * @param path + * The path of the file to retreive the size of. + * @param file_size + * A pointer to an unsigned long to return the file size. The + * pointed to value is valid only on a true return. + * + * @return + * True for success or False for error. + */ +bool files_get_file_size_path(const char *path, unsigned long *file_size); + +/** + * Similar to files_get_file_size_path(), but uses an already opened FILE object. + * @param fp + * The file pointer to query the size of. + * @param file_size + * Output of the file size. + * @param path + * An optional path used for error reporting, a NULL path disables error logging. + * @return + * True on success, False otherwise. + */ +bool files_get_file_size(FILE *fp, unsigned long *file_size, const char *path); + +/** + * Writes a TPM2.0 header to a file. + * @param f + * The file to write to. + * @param version + * The version number of the format of the file. + * @return + * True on success, false on error. + */ +bool files_write_header(FILE *f, UINT32 version); + +/** + * Reads a TPM2.0 header from a file. + * @param f + * The file to read. + * @param version + * The version that was found. + * @return + * True on Success, False on error. + */ +bool files_read_header(FILE *f, UINT32 *version); + +/** + * Writes a 16 bit value to the file in big endian, converting + * if needed. + * @param out + * The file to write. + * @param data + * The 16 bit value to write. + * @return + * True on success, False on error. + */ +bool files_write_16(FILE *out, UINT16 data); + +/** + * Same as files_write_16 but for 32 bit values. + */ +bool files_write_32(FILE *out, UINT32 data); + +/** + * Same as files_write_16 but for 64 bit values. + */ +bool files_write_64(FILE *out, UINT64 data); + +/** + * Writes a byte array out to a file. + * @param out + * The file to write to. + * @param data + * The data to write. + * @param size + * The size of the data to write in bytes. + * @return + * True on success, False otherwise. + */ +bool files_write_bytes(FILE *out, UINT8 data[], size_t size); + +/** + * Reads a 16 bit value from a file converting from big endian to host + * endianess. + * @param out + * The file to read from. + * @param data + * The data that is read, valid on a true return. + * @return + * True on success, False on error. + */ +bool files_read_16(FILE *out, UINT16 *data); + +/** + * Same as files_read_16 but for 32 bit values. + */ +bool files_read_32(FILE *out, UINT32 *data); + +/** + * Same as files_read_16 but for 64 bit values. + */ +bool files_read_64(FILE *out, UINT64 *data); + +/** + * Reads len bytes from a file. + * @param out + * The file to read from. + * @param data + * The buffer to read into, only valid on a True return. + * @param size + * The number of bytes to read. + * @return + * True on success, False otherwise. + */ +bool files_read_bytes(FILE *out, UINT8 data[], size_t size); + +#endif /* FILES_H */ diff --git a/TPM2-Plugin/lib/include/log.h b/TPM2-Plugin/lib/include/log.h new file mode 100644 index 0000000..c4ae0bd --- /dev/null +++ b/TPM2-Plugin/lib/include/log.h @@ -0,0 +1,107 @@ +//**********************************************************************; +// 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. +//**********************************************************************; +#ifndef SRC_LOG_H_ +#define SRC_LOG_H_ + +#include <stdbool.h> +#include <stdio.h> + +#include <sapi/tpm20.h> + +#include "tpm2_error.h" +#include "tpm2_util.h" + +typedef enum log_level log_level; +enum log_level { + log_level_error, + log_level_warning, + log_level_verbose +}; + +void _log (log_level level, const char *file, unsigned lineno, const char *fmt, ...) + COMPILER_ATTR(format (printf, 4, 5)); + +/* + * Prints an error message. The fmt and variadic arguments mirror printf. + * + * Use this to log all error conditions. + */ +#define LOG_ERR(fmt, ...) _log(log_level_error, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + +/** + * Prints an error message for a TSS2_Sys call to the TPM. + * The format is <function-name>(0x<rc>) - <error string> + * @param func + * The function that caused the error + * @param rc + * The return code to print. + */ +#define LOG_PERR(func, rc) _LOG_PERR(xstr(func), rc) + +/** + * Internal use only. + * + * Handles the expanded LOG_PERR call checking argument values + * and handing them off to LOG_ERR. + * @param func + * The function name. + * @param rc + * The rc to decode. + */ +static inline void _LOG_PERR(const char *func, TSS2_RC rc) { + + LOG_ERR("%s(0x%X) - %s", func, rc, tpm2_error_str(rc)); +} + +/* + * Prints an warning message. The fmt and variadic arguments mirror printf. + * + * Use this to log a warning. A warning is when something is wrong, but it is not a fatal + * issue. + */ +#define LOG_WARN(fmt, ...) _log(log_level_warning, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + +/* + * Prints an informational message. The fmt and variadic arguments mirror printf. + * + * Informational messages are only shown when verboseness is increased. Valid messages + * would be debugging type messages where additional, extraneous information is printed. + */ +#define LOG_INFO(fmt, ...) _log(log_level_verbose, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + +/** + * Sets the log level so only messages <= to it print. + * @param level + * The logging level to set. + */ +void log_set_level (log_level level); + +#endif /* SRC_LOG_H_ */ diff --git a/TPM2-Plugin/lib/include/plugin_api.h b/TPM2-Plugin/lib/include/plugin_api.h new file mode 100644 index 0000000..5f4b924 --- /dev/null +++ b/TPM2-Plugin/lib/include/plugin_api.h @@ -0,0 +1,48 @@ +//**********************************************************************; +// 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. +//**********************************************************************; + +#ifndef __PLUGIN_API_H__ +#define __PLUGIN_API_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int plugin_configure(char *configPath); + +void plugin_assign_hw_instance(); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/TPM2-Plugin/lib/include/plugin_register.h b/TPM2-Plugin/lib/include/plugin_register.h new file mode 100644 index 0000000..a154a24 --- /dev/null +++ b/TPM2-Plugin/lib/include/plugin_register.h @@ -0,0 +1,196 @@ +//**********************************************************************; +// 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. +//**********************************************************************; + +#ifndef __PLUGIN_REGISTER_H__ +#define __PLUGIN_REGISTER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Callback function definitions + */ + +typedef int (*fp_crypto_rsa_decrypt_init) ( + /* IN */ + unsigned long mechanism, /* PKCS#11 Mechanism */ + void *param, /* PKCS#11 Paramter */ + unsigned long param_len, /* PKCS#11 Parameter len */ + /* OUT */ + void *cb /* Address of pointer to store context block */ + ); + +typedef int (*fp_crypto_rsa_decrypt) ( + /* IN */ + void* cb, /* Pointer Crypto Block which is created during decrypt_init */ + unsigned char* cipher, /* Input Cipher data */ + int cipher_length, /* Ciphet data length */ + /* OUT */ + unsigned char* out_data, /* Decrypted output data */ + int* out_data_len /* output length */ + ); + +typedef int (*fp_crypto_rsa_sign_init) ( + /* IN */ + unsigned long mechanism, /* PKCS#11 Mechanism */ + void *param, /* PKCS#11 Paramter */ + unsigned long param_len, /* PKCS#11 Parameter len */ + /* OUT */ + void *cb /* Address of pointer to store context block */ + ); + +typedef int (*fp_crypto_rsa_sign_update) ( + /* IN */ + void *cb, /* Previously created context block (during sign_init) passed */ + void *pPart, /* pPart */ + unsigned long ulPartLen /* ulPartLen */ + ); + +typedef int (*fp_crypto_rsa_sign_final) ( + /* IN */ + void *cb, /* Previously passed context block */ + /* OUT */ + unsigned char *sig, /* Output Signature buffer */ + int *sigLen /* Pointer to hold signature buffer length */ + ); + +typedef int (*fp_crypto_rsa_sign) ( + /* IN */ + void *cb, /* Previously created context block (during sign_init) passed */ + unsigned char* msg, /* Data to be signed */ + int msg_len, /* Input data length */ + /* OUT */ + unsigned char *sig, /* Output Signature buffer */ + int *sig_len /* Pointer to hold signature buffer length */ + ); + +typedef int (*fp_crypto_ecdsa_sign) ( + /* IN */ + void *cb, /* Previously created context block (during sign_init) passed */ + unsigned char* data, /* Data to be signed */ + int data_len, /* Input data length */ + /* OUT */ + unsigned char *sig, /* Output Signature buffer */ + int *sig_len /* Pointer to hold signature buffer length */ + ); + +typedef int (*fp_crypto_ecdsa_verify) ( + /* IN */ + unsigned long appHandle, /* Application handle needed for QAT KPT mode */ + //DhsmWPKECDSAFormat *wpk, /* Wrapped Private Key strcuture for ECDSA */ + void *wpk, /* Wrapped Private Key strcuture for ECDSA */ + unsigned char* swk, /* Symmetric Wrapping Key (SWK) value */ + int swk_len, /* SWK length */ + unsigned char* iv, /* IV value used during Application Key encryption */ + int iv_len, /* IV length */ + int tag_len, /* AES-GCM tag length */ + unsigned char* data, /* Data which is used for signing */ + int data_len, /* Input data length */ + unsigned char *sig, /* Signature value */ + int sig_len, /* Signature length */ + /* OUT */ + int* verifyResult /* Pointer to hold the verification result */ + ); + +typedef int (*fp_crypto_del_apphandle) (unsigned long skmKeyHandle); + +// SWK related operations +typedef int (*fp_crypto_swk_getParentKey) (unsigned char** tlvbuffer, int* buflen); +typedef int (*fp_crypto_swk_import) ( + unsigned long appHandle, + unsigned char* tlvbuffer, + int buflen, + unsigned char* iv, + int iv_len, + unsigned char* tpm_pwd, + int tpm_pwd_len); + +typedef int (*fp_crypto_rsa_create_object) ( + unsigned long appHandle, /* Application handle needed for QAT KPT mode */ + //DhsmWPKRSAFormat *wpk, /* Wrapped Private Key structure for RSA */ + void *wpk, /* Wrapped Private Key structure for RSA */ + unsigned char* swk, /* Symmetric Wrapping Key (SWK) value */ + int swk_len, /* SWK length */ + unsigned char* iv, /* IV value used during Application Key encryption */ + int iv_len, /* IV length */ + int tag_len, /* AES-GCM tag length */ + void **cb_object /* Pointer to store context block */ + ); + +typedef int (*fp_crypto_rsa_delete_object) ( + void *cb_object /* Pointer Crypto Block which is created during decrypt_create_object */ + ); + +typedef int (*fp_crypto_ecdsa_create_object) ( + unsigned long appHandle, /* Application handle needed for QAT KPT mode */ + //DhsmWPKECDSAFormat *wpk, /* Wrapped Private Key structure for RSA */ + void *wpk, /* Wrapped Private Key structure for RSA */ + unsigned char* swk, /* Symmetric Wrapping Key (SWK) value */ + int swk_len, /* SWK length */ + unsigned char* iv, /* IV value used during Application Key encryption */ + int iv_len, /* IV length */ + int tag_len, /* AES-GCM tag length */ + void **cb_object /* Pointer to store context block */ + ); + +typedef int (*fp_crypto_ecdsa_delete_object) ( + void *cb_object /* Pointer Crypto Block which is created during decrypt_create_object */ + ); + + +typedef struct +{ + fp_crypto_rsa_decrypt_init cb_crypto_rsa_decrypt_init; + fp_crypto_rsa_decrypt cb_crypto_rsa_decrypt; + fp_crypto_rsa_sign_init cb_crypto_rsa_sign_init; + fp_crypto_rsa_sign_update cb_crypto_rsa_sign_update; + fp_crypto_rsa_sign_final cb_crypto_rsa_sign_final; + fp_crypto_rsa_sign cb_crypto_rsa_sign; + fp_crypto_ecdsa_sign cb_crypto_ecdsa_sign; + fp_crypto_ecdsa_verify cb_crypto_ecdsa_verify; + fp_crypto_del_apphandle cb_crypto_del_apphandle; + fp_crypto_swk_getParentKey cb_crypto_swk_getParentKey; + fp_crypto_swk_import cb_crypto_swk_import; + fp_crypto_rsa_create_object cb_crypto_rsa_create_object; + fp_crypto_rsa_delete_object cb_crypto_rsa_delete_object; + fp_crypto_ecdsa_create_object cb_crypto_ecdsa_create_object; + fp_crypto_ecdsa_delete_object cb_crypto_ecdsa_delete_object; + +} plugin_register; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/TPM2-Plugin/lib/include/tcti_util.h b/TPM2-Plugin/lib/include/tcti_util.h new file mode 100644 index 0000000..1b3b289 --- /dev/null +++ b/TPM2-Plugin/lib/include/tcti_util.h @@ -0,0 +1,109 @@ +//**********************************************************************; +// 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. +// +// 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. +//**********************************************************************; + +// +// The context for TCTI implementations is on opaque +// structure. There shall never be a definition of its content. +// Implementation provide the size information to +// applications via the initialize call. +// This makes use of a compiler trick that allows type +// checking of the pointer even though the type isn't +// defined. +// +// The first field of a Context must be the common part +// (see below). +#ifndef TSS2_TCTI_UTIL_H +#define TSS2_TCTI_UTIL_H + +#if defined linux || defined unix +#include <sys/socket.h> +#define SOCKET int +#endif + +#include <tcti/common.h> + +#define TCTI_MAGIC 0x7e18e9defa8bc9e2 +#define TCTI_VERSION 0x1 + +#define TCTI_LOG_CALLBACK(ctx) ((TSS2_TCTI_CONTEXT_INTEL*)ctx)->logCallback +#define TCTI_LOG_DATA(ctx) ((TSS2_TCTI_CONTEXT_INTEL*)ctx)->logData +#define TCTI_LOG_BUFFER_CALLBACK(ctx) ((TSS2_TCTI_CONTEXT_INTEL*)ctx)->logBufferCallback + +typedef TSS2_RC (*TCTI_TRANSMIT_PTR)( TSS2_TCTI_CONTEXT *tctiContext, size_t size, uint8_t *command); +typedef TSS2_RC (*TCTI_RECEIVE_PTR) (TSS2_TCTI_CONTEXT *tctiContext, size_t *size, uint8_t *response, int32_t timeout); + +enum tctiStates { TCTI_STAGE_INITIALIZE, TCTI_STAGE_SEND_COMMAND, TCTI_STAGE_RECEIVE_RESPONSE }; + +/* current Intel version */ +typedef struct { + uint64_t magic; + uint32_t version; + TCTI_TRANSMIT_PTR transmit; + TCTI_RECEIVE_PTR receive; + TSS2_RC (*finalize) (TSS2_TCTI_CONTEXT *tctiContext); + TSS2_RC (*cancel) (TSS2_TCTI_CONTEXT *tctiContext); + TSS2_RC (*getPollHandles) (TSS2_TCTI_CONTEXT *tctiContext, + TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles); + TSS2_RC (*setLocality) (TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality); + struct { + UINT32 debugMsgEnabled: 1; + UINT32 locality: 8; + UINT32 commandSent: 1; + UINT32 rmDebugPrefix: 1; // Used to add a prefix to RM debug messages. This is ONLY used + // for TPM commands and responses as a way to differentiate + // RM generated TPM commands from application generated ones. + + // Following two fields used to save partial response status in case receive buffer's too small. + UINT32 tagReceived: 1; + UINT32 responseSizeReceived: 1; + UINT32 protocolResponseSizeReceived: 1; + } status; + + // Following two fields used to save partial response in case receive buffer's too small. + TPM_ST tag; + TPM_RC responseSize; + + TSS2_TCTI_CONTEXT *currentTctiContext; + + // Sockets if socket interface is being used. + SOCKET otherSock; + SOCKET tpmSock; + SOCKET currentConnectSock; + + // File descriptor for device file if real TPM is being used. + int devFile; + UINT8 previousStage; // Used to check for sequencing errors. + unsigned char responseBuffer[4096]; + TCTI_LOG_CALLBACK logCallback; + TCTI_LOG_BUFFER_CALLBACK logBufferCallback; + void *logData; +} TSS2_TCTI_CONTEXT_INTEL; + +#define TCTI_CONTEXT ( (TSS2_TCTI_CONTEXT_COMMON_CURRENT *)(SYS_CONTEXT->tctiContext) ) +#define TCTI_CONTEXT_INTEL ( (TSS2_TCTI_CONTEXT_INTEL *)tctiContext ) + +#endif diff --git a/TPM2-Plugin/lib/include/tpm2_alg_util.h b/TPM2-Plugin/lib/include/tpm2_alg_util.h new file mode 100644 index 0000000..ce4083c --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_alg_util.h @@ -0,0 +1,196 @@ +//**********************************************************************; +// 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. +//**********************************************************************; +#ifndef LIB_TPM2_ALG_UTIL_H_ +#define LIB_TPM2_ALG_UTIL_H_ + +#include <stdbool.h> + +#include <sapi/tpm20.h> + +/** + * Iterator callback routine for iterating over known algorithm name and value + * pairs. + * @param id + * The algorithm id. + * @param name + * The associated "nice-name". + * @param userdata + * A user supplied data pointer. + * @return + * True to stop iterating, false to keep iterating. + */ +typedef bool (*tpm2_alg_util_alg_iteraror)(TPM2_ALG_ID id, const char *name, void *userdata); + +/** + * Iterate over the algorithm name-value pairs calling the iterator callback for each pair. + * @param iterator + * The iterator callback function. + * @param userdata + * A pointer to user supplied data, this is passed to the iterator for each call. + */ +void tpm2_alg_util_for_each_alg(tpm2_alg_util_alg_iteraror iterator, void *userdata); + +/** + * Convert a "nice-name" string to an algorithm id. + * @param name + * The "nice-name" to convert. + * @return + * TPM2_ALG_ERROR on error, or a valid algorithm identifier. + */ +TPM2_ALG_ID tpm2_alg_util_strtoalg(const char *name); + +/** + * Convert an id to a nice-name. + * @param id + * The id to convert. + * @return + * The nice-name. + */ +const char *tpm2_alg_util_algtostr(TPM2_ALG_ID id); + +/** + * Converts either a string from algrotithm number or algorithm nice-name to + * an algorithm id. + * @param optarg + * The string to convert from an algorithm number or nice name. + * @return + * TPM2_ALG_ERROR on error or the algorithm id. + */ +TPM2_ALG_ID tpm2_alg_util_from_optarg(char *optarg); + +/** + * Detects if an algorithm is considered a hashing algorithm. + * @param id + * The algorithm id to check. + * @return + * True if it is a hash algorithm, False otherwise. + */ +bool tpm2_alg_util_is_hash_alg(TPM2_ALG_ID id); + +/** + * Contains the information from parsing an argv style vector of strings for + * pcr digest language specifications. + */ +typedef struct tpm2_pcr_digest_spec tpm2_pcr_digest_spec; +struct tpm2_pcr_digest_spec { + TPML_DIGEST_VALUES digests; + TPMI_DH_PCR pcr_index; +}; + +/** + * Parses an argv array that contains a digest specification at each location + * within argv. + * + * The digest specification is as follows: + * - A pcr identifier as understood by strtoul with 0 as the base. + * - A colon followed by the algorithm hash specification. + * - The algorithm hash specification is as follows: + * - The algorithm friendly name or raw numerical as understood by + * strtoul with a base of 0. + * - An equals sign + * - The hex hash value, + * + * This all distills to a string that looks like this: + * <pcr index>:<hash alg id>=<hash value> + * + * Example: + * "4:sha=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15" + * + * Note: + * Multiple specifications of PCR and hash are OK. Multiple hashes + * cause the pcr to be extended with both hashes. Multiple same PCR + * values cause the PCR to be extended multiple times. Extension + * is done in order from left to right as specified. + * + * At most 5 hash extensions per PCR entry are supported. This + * is to keep the parser simple. + * + * @param sapi_context + * The system API context for hashing files with the tpm. This can + * be NULL if the argument vector doesn't have a file spec for the hash. + * @param argv + * The argv of digest specifications to parse. + * @param len + * The number of digest specifications to parse. + * @param digests + * An array of tpm2_pcr_digest_spec big enough to hold len items. + * @return + * True if parsing was successful, False otherwise. + * @note + * This function logs errors via LOG_ERR. + */ +bool pcr_parse_digest_list(char **argv, int len, + tpm2_pcr_digest_spec *digest_spec); + +/** + * Retrieves the size of a hash in bytes for a given hash + * algorithm or 0 if unknown/not found. + * @param id + * The HASH algorithm identifier. + * @return + * 0 on failure or the size of the hash bytes. + */ +UINT16 tpm2_alg_util_get_hash_size(TPMI_ALG_HASH id); + +/** + * Extracts the plain signature data without any headers + * + * Communicates errors via LOG_ERR. + * + * @param size + * Will receive the number of bytes stored in buffer. + * @signature The actual signature struct to extract the plain signature from. + * @return + * Returns a buffer filled with the extracted signature or NULL on error. + * Needs to be free()'d by the caller. + */ +UINT8* tpm2_extract_plain_signature(UINT16 *size, TPMT_SIGNATURE *signature); + +/** + * Retrieves an approproate signature scheme (scheme) signable by + * specified key (keyHandle) and hash algorithm (halg). + * @param sapi_context + * System API context for tpm + * @param keyHandle + * Handle to key used in signing operation + * @param halg + * Hash algoritm for message + * @param scheme + * Signature scheme output + * @return + * True if successful + * False otherwise, and scheme is left unmodified + */ +bool get_signature_scheme(TSS2_SYS_CONTEXT *sapi_context, + TPMI_DH_OBJECT keyHandle, TPMI_ALG_HASH halg, + TPMT_SIG_SCHEME *scheme); + +#endif /* LIB_TPM2_ALG_UTIL_H_ */ diff --git a/TPM2-Plugin/lib/include/tpm2_attr_util.h b/TPM2-Plugin/lib/include/tpm2_attr_util.h new file mode 100644 index 0000000..2487982 --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_attr_util.h @@ -0,0 +1,98 @@ +//**********************************************************************; +// 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. +//**********************************************************************; +#ifndef LIB_TPM2_ATTR_UTIL_H_ +#define LIB_TPM2_ATTR_UTIL_H_ + +#include <stdbool.h> + +#include <sapi/tpm20.h> + +/** + * Converts a list of | (pipe) separated attributes as defined in tavle 204 + * of https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf + * to an actual bit field representation. The trailing TPMA_NV_ can be omitted and must be lower-case. + * For exmaple, TPMA_NV_PPWRITE, bcomes ppwrite. To append them together, just do the pipe inbetwwen. + * ppwrite|ownerwrite. + * + * @param attribute_list + * The attribute string to parse, which may be modified in place. + * @param nvattrs + * The TPMA_NV attributes set based on the attribute list. Only valid on true returns. + * @return + * true on success, false on error. + */ +bool tpm2_attr_util_nv_strtoattr(char *attribute_list, TPMA_NV *nvattrs); + +/** + * Like tpm2_attr_util_nv_strtoattr() but converts TPMA_OBJECT attributes as defined in: + * Table 31 of https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf + * @param attribute_list + * The attribute string to parse, which may be modified in place. + * The TPMA_OBJECT attributes set based on the attribute list. Only valid on true returns. + * @return + * true on success, false on error. + */ +bool tpm2_attr_util_obj_strtoattr(char *attribute_list, TPMA_OBJECT *objattrs); + +/** + * Converts a numerical or friendly string described object attribute into the + * TPMA_OBJECT. Similar to tpm2_alg_util_from_optarg(). + * @param argvalue + * Either a raw numeric for a UINT32 or a friendly name object attribute list + * as in tpm2_attr_util_nv_strtoattr(). + * @param objattrs + * The converted bits for a TPMA_OBJECT + * @return + * true on success or false on error. + */ +bool tpm2_attr_util_obj_from_optarg(char *argvalue, TPMA_OBJECT *objattrs); + +/** + * Converts a TPMA_NV structure to a friendly name style string. + * @param nvattrs + * The nvattrs to convert to nice name. + * @return A string allocated with calloc(), callers shall use + * free() to free it. The string is a null terminated text representation + * of the TPMA_NV attributes. + */ +char *tpm2_attr_util_nv_attrtostr(TPMA_NV nvattrs); + +/** + * Like tpm2_nv_util_obj_strtoattr() but converts TPMA_OBJECT attributes as defined in: + * Table 31 of https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf + * @param objattrs + * The object parameters to convert to a name + * @return + * The name of the object attrs as a string that must be freed via free(). + */ +char *tpm2_attr_util_obj_attrtostr(TPMA_OBJECT objattrs); + +#endif /* LIB_TPM2_ATTR_UTIL_H_ */ diff --git a/TPM2-Plugin/lib/include/tpm2_error.h b/TPM2-Plugin/lib/include/tpm2_error.h new file mode 100644 index 0000000..0549edc --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_error.h @@ -0,0 +1,136 @@ +//**********************************************************************; +// Copyright (c) 2018, 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. +// +// 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. +//**********************************************************************; + +#ifndef LIB_TPM2_ERROR_H_ +#define LIB_TPM2_ERROR_H_ + +#include <stdbool.h> + +#include <sapi/tpm20.h> + +/** + * Number of error layers + */ +#define TPM2_ERROR_TSS2_RC_LAYER_COUNT (TSS2_RC_LAYER_MASK >> TSS2_RC_LAYER_SHIFT) + +/** + * Mask for the error bits of tpm2 compliant return code. + */ +#define TPM2_ERROR_TSS2_RC_ERROR_MASK 0xFFFF + +/** + * Retrieves the error bits from a TSS2_RC. The error bits are + * contained in the first 2 octets. + * @param rc + * The rc to query for the error bits. + * @return + * The error bits. + */ +static inline UINT16 tpm2_error_get(TSS2_RC rc) { + return ((rc & TPM2_ERROR_TSS2_RC_ERROR_MASK)); +} + +/** + * A custom error handler prototype. + * @param rc + * The rc to decode with only the error bits set, ie no need to mask the + * layer bits out. Handlers will never be invoked with the error bits set + * to 0, as zero always indicates success. + * @return + * An error string describing the rc. If the handler cannot determine + * a valid response, it can return NULL indicating that the framework + * should just print the raw hexidecimal value of the error field of + * a tpm2_err_layer_rc. + * Note that this WILL NOT BE FREED by the caller, + * i.e. static. + */ +typedef const char *(*tpm2_error_handler)(TSS2_RC rc); + +/** + * Register or unregister a custom layer error handler. + * @param layer + * The layer in which to register a handler for. It is an error + * to register for the following reserved layers: + * - TSS2_TPM_RC_LAYER - layer 0 + * - TSS2_SYS_RC_LAYER - layer 8 + * - TSS2_MU_RC_LAYER - layer 9 + * - TSS2_TCTI_RC_LAYER - layer 10 + * @param name + * A friendly layer name. It is an error for the name to be of + * length 0 or greater than 4. + * @param handler + * The handler function to register or NULL to unregister. + * @return + * True on success or False on error. + */ +bool tpm2_error_set_handler(UINT8 layer, const char *name, + tpm2_error_handler handler); + +/** + * Given a TSS2_RC return code, provides a static error string in the format: + * <layer-name>:<layer-specific-msg>. + * + * The layer-name section will either be the friendly name, or if no layer + * handler is registered, the base10 layer number. + * + * The "layer-specific-msg" is layer specific and will contain details on the + * error that occurred or the error code if it couldn't look it up. + * + * Known layer specific substrings: + * TPM - The tpm layer produces 2 distinct format codes that allign with: + * - Section 6.6 of: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf + * - Section 39.4 of: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf + * + * The two formats are format 0 and format 1. + * Format 0 string format: + * - "<error|warn>(<version>): <description> + * - Examples: + * - error(1.2): bad tag + * - warn(2.0): the 1st handle in the handle area references a transient object or session that is not loaded + * + * Format 1 string format: + * - <handle|session|parameter>(<index>):<description> + * - Examples: + * - handle(unk):value is out of range or is not correct for the context + * - tpm:handle(5):value is out of range or is not correct for the context + * + * Note that passing TPM2_RC_SUCCESS results in the layer specific message of "success". + * + * The System, TCTI and Marshaling (MU) layers, all define simple string + * returns analogous to strerror(3). + * + * Unknown layers will have the layer number in decimal and then a layer specific string of + * a hex value representing the error code. For example: 9:0x3 + * + * @param rc + * The error code to decode. + * @return + * A human understandable error description string. + */ +const char *tpm2_error_str(TSS2_RC rc); + +#endif /* LIB_TPM2_ERROR_H_ */ diff --git a/TPM2-Plugin/lib/include/tpm2_hash.h b/TPM2-Plugin/lib/include/tpm2_hash.h new file mode 100644 index 0000000..7fab882 --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_hash.h @@ -0,0 +1,84 @@ +//**********************************************************************; +// 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. +//**********************************************************************; +#ifndef SRC_TPM_HASH_H_ +#define SRC_TPM_HASH_H_ + +#include <stdbool.h> + +#include <sapi/tpm20.h> + +/** + * Hashes a BYTE array via the tpm. + * @param sapi_context + * The system api context. + * @param hash_alg + * The hashing algorithm to use. + * @param hierarchy + * The hierarchy. + * @param buffer + * The data to hash. + * @param length + * The length of the data. + * @param result + * The digest result. + * @param validation + * The validation ticket. Note that some hierarchies don't produce a + * validation ticket and thus size will be 0. + * @return + * True on success, false otherwise. + */ +bool tpm2_hash_compute_data(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH halg, + TPMI_RH_HIERARCHY hierarchy, BYTE *buffer, UINT16 length, + TPM2B_DIGEST *result, TPMT_TK_HASHCHECK *validation); + +/** + * Hashes a FILE * object via the tpm. + * @param sapi_context + * The system api context. + * @param hash_alg + * The hashing algorithm to use. + * @param hierarchy + * The hierarchy. + * @param input + * The FILE object to hash. + * @param result + * The digest result. + * @param validation + * The validation ticket. Note that some hierarchies don't produce a + * validation ticket and thus size will be 0. + * @return + * True on success, false otherwise. + */ +bool tpm2_hash_file(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH halg, + TPMI_RH_HIERARCHY hierarchy, FILE *input, TPM2B_DIGEST *result, + TPMT_TK_HASHCHECK *validation); + +#endif /* SRC_TPM_HASH_H_ */ diff --git a/TPM2-Plugin/lib/include/tpm2_plugin_api.h b/TPM2-Plugin/lib/include/tpm2_plugin_api.h new file mode 100644 index 0000000..238af99 --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_plugin_api.h @@ -0,0 +1,136 @@ +//**********************************************************************; +// 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. +// +// 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. +//**********************************************************************; + +#ifndef __TPM_API_H__ +#define __TPM_API_H__ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <ctype.h> +#include <getopt.h> + +#include <sapi/tpm20.h> + +#include "plugin_register.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TPM_SKM_SRK_HANDLE 0x81000011 + +#define TPM_SKM_AC0_HANDLE 0x90000000 +#define TPM_SKM_AC1_HANDLE 0x90000001 +#define TPM_SKM_AC2_HANDLE 0x90000002 + +#define TPM_SKM_APP_HANDLE 0x91100001 + +#define INIT_SIMPLE_TPM2B_SIZE( type ) (type).t.size = sizeof( type ) - 2; + +#define APP_RC_OFFSET 0x100 + +#define TSS2_APP_RC_PASSED (APP_RC_PASSED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_GET_NAME_FAILED (APP_RC_GET_NAME_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_CREATE_SESSION_KEY_FAILED (APP_RC_CREATE_SESSION_KEY_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_SESSION_SLOT_NOT_FOUND (APP_RC_SESSION_SLOT_NOT_FOUND + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_BAD_ALGORITHM (APP_RC_BAD_ALGORITHM + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_SYS_CONTEXT_CREATE_FAILED (APP_RC_SYS_CONTEXT_CREATE_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_GET_SESSION_STRUCT_FAILED (APP_RC_GET_SESSION_STRUCT_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_GET_SESSION_ALG_ID_FAILED (APP_RC_GET_SESSION_ALG_ID_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_INIT_SYS_CONTEXT_FAILED (APP_RC_INIT_SYS_CONTEXT_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_TEARDOWN_SYS_CONTEXT_FAILED (APP_RC_TEARDOWN_SYS_CONTEXT_FAILED + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) +#define TSS2_APP_RC_BAD_LOCALITY (APP_RC_BAD_LOCALITY + APP_RC_OFFSET + TSS2_APP_ERROR_LEVEL) + +enum TSS2_APP_RC_CODE +{ + APP_RC_PASSED, + APP_RC_GET_NAME_FAILED, + APP_RC_CREATE_SESSION_KEY_FAILED, + APP_RC_SESSION_SLOT_NOT_FOUND, + APP_RC_BAD_ALGORITHM, + APP_RC_SYS_CONTEXT_CREATE_FAILED, + APP_RC_GET_SESSION_STRUCT_FAILED, + APP_RC_GET_SESSION_ALG_ID_FAILED, + APP_RC_INIT_SYS_CONTEXT_FAILED, + APP_RC_TEARDOWN_SYS_CONTEXT_FAILED, + APP_RC_BAD_LOCALITY +}; + +TSS2_SYS_CONTEXT *InitSysContext (UINT16 maxCommandSize, + TSS2_TCTI_CONTEXT *tctiContext, + TSS2_ABI_VERSION *abiVersion ); + +void TeardownSysContext( TSS2_SYS_CONTEXT **sysContext ); + +TSS2_RC TeardownTctiResMgrContext( TSS2_TCTI_CONTEXT *tctiContext ); + +int tpm2_rsa_create_object( + unsigned long appHandle, + //DhsmWPKRSAFormat* wpk, + void *wpk, + unsigned char* swk, + int swk_len, + unsigned char* iv, + int iv_len, + int tag_len, + void **cb_object); + +int tpm2_rsa_delete_object( + void *cb_object); + +int tpm2_rsa_sign_init( + unsigned long mechanish, + void *param, + size_t len, + void *ctx); + +int tpm2_rsa_sign( + void *ctx, + unsigned char *msg, + int msg_len, + unsigned char *sig, + int *sig_len); + + +int tpm2_import_object( + unsigned long appHandle, + unsigned char* tlvbuffer, + int buflen, + unsigned char* iv, + int iv_len, + unsigned char* tpm_pwd, + int tpm_pwd_len); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h b/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h new file mode 100644 index 0000000..1e20d3d --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h @@ -0,0 +1,62 @@ +//**********************************************************************; +// Copyright (c) 2018, 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. +// +// 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 <sapi/tpm20.h> + +#ifndef LIB_TPM2_TCTI_LDR_H_ +#define LIB_TPM2_TCTI_LDR_H_ + +/** + * Loads a TCTI from a friendly name, library name, or path. + * For example + * friendly: path = tabrmd + * library name: path = libtcti-socket.so + * full path: path = /home/user/lib/libtcti-custom.so + * @param path + * The path/library to load. + * @param opts + * The tcti option configs. + * @return + * A tcti context on success or NULL on failure. + */ +TSS2_TCTI_CONTEXT *tpm2_tcti_ldr_load(const char *path, const char *opts); + +/** + * Returns the loaded TCTIs information structure, + * which contains the initialization routine, description + * and help string amongst other things. + * @return + * NULL if no TCTI is loaded, else the info structure pointer. + */ +const TSS2_TCTI_INFO *tpm2_tcti_ldr_getinfo(void); + +/** + * Unloads the tcti loaded via tpm2_tcti_ldr_load(); + */ +void tpm2_tcti_ldr_unload(void); + +#endif /* LIB_TPM2_TCTI_LDR_H_ */ diff --git a/TPM2-Plugin/lib/include/tpm2_util.h b/TPM2-Plugin/lib/include/tpm2_util.h new file mode 100644 index 0000000..edc759d --- /dev/null +++ b/TPM2-Plugin/lib/include/tpm2_util.h @@ -0,0 +1,325 @@ +//**********************************************************************; +// 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. +//**********************************************************************; +#ifndef STRING_BYTES_H +#define STRING_BYTES_H + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +#include <sapi/tpm20.h> + +#include "tpm2_error.h" + +#if defined (__GNUC__) +#define COMPILER_ATTR(...) __attribute__((__VA_ARGS__)) +#else +#define COMPILER_ATTR(...) +#endif + +#define xstr(s) str(s) +#define str(s) #s + +#define UNUSED(x) (void)x + +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +#define BUFFER_SIZE(type, field) (sizeof((((type *)NULL)->field))) + +#define TSS2_APP_RC_LAYER TSS2_RC_LAYER(5) + +#define TPM2B_TYPE_INIT(type, field) { .size = BUFFER_SIZE(type, field), } +#define TPM2B_INIT(xsize) { .size = xsize, } +#define TPM2B_EMPTY_INIT TPM2B_INIT(0) +#define TPM2B_SENSITIVE_CREATE_EMPTY_INIT { \ + .sensitive = { \ + .data = { \ + .size = 0 \ + }, \ + .userAuth = { \ + .size = 0 \ + } \ + } \ + } + +#define TPMS_AUTH_COMMAND_INIT(session_handle) { \ + .sessionHandle = session_handle,\ + .nonce = TPM2B_EMPTY_INIT, \ + .sessionAttributes = TPMA_SESSION_CONTINUESESSION, \ + .hmac = TPM2B_EMPTY_INIT \ + } + +#define TPMS_AUTH_COMMAND_EMPTY_INIT TPMS_AUTH_COMMAND_INIT(0) + + +#define TPMT_TK_CREATION_EMPTY_INIT { \ + .tag = 0, \ + .hierarchy = 0, \ + .digest = TPM2B_EMPTY_INIT \ + } + +#define TPML_PCR_SELECTION_EMPTY_INIT { \ + .count = 0, \ + } //ignore pcrSelections since count is 0. + +#define TPMS_CAPABILITY_DATA_EMPTY_INIT { \ + .capability = 0, \ + } // ignore data since capability is 0. + +#define TPMT_TK_HASHCHECK_EMPTY_INIT { \ + .tag = 0, \ + .hierarchy = 0, \ + .digest = TPM2B_EMPTY_INIT \ + } + +#define TSS2L_SYS_AUTH_COMMAND_INIT(cnt, array) { \ + .count = cnt, \ + .auths = array, \ + } + +/* + * This macro is useful as a wrapper around SAPI functions to automatically + * retry function calls when the RC is TPM2_RC_RETRY. + */ +#define TSS2_RETRY_EXP(expression) \ + ({ \ + TSS2_RC __result = 0; \ + do { \ + __result = (expression); \ + } while (tpm2_error_get(__result) == TPM2_RC_RETRY); \ + __result; \ + }) + +/** + * prints output to stdout respecting the quiet option. + * Ie when quiet, don't print. + * @param fmt + * The format specifier, ala printf. + * @param ... + * The varargs, just like printf. + */ +#define tpm2_tool_output(fmt, ...) \ + do { \ + if (output_enabled) { \ + printf(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +int tpm2_util_hex_to_byte_structure(const char *inStr, UINT16 *byteLenth, BYTE *byteBuffer); + +/** + * Appends a TPM2B buffer to a MAX buffer. + * @param result + * The MAX buffer to append to + * @param append + * The buffer to append to result. + * @return + * true on success, false otherwise. + */ +bool tpm2_util_concat_buffer(TPM2B_MAX_BUFFER *result, TPM2B *append); + +/** + * Converts a numerical string into a uint32 value. + * @param str + * The numerical string to convert. + * @param value + * The value to store the conversion into. + * @return + * true on success, false otherwise. + */ +bool tpm2_util_string_to_uint32(const char *str, uint32_t *value); + +/** + * Converts a numerical string into a uint16 value. + * @param str + * The numerical string to convert. + * @param value + * The value to store the conversion into. + * @return + * true on success, false otherwise. + */ +bool tpm2_util_string_to_uint16(const char *str, uint16_t *value); + +/** + * Prints an xxd compatible hexdump to stdout if output is enabled, + * ie no -Q option. + * + * @param data + * The data to print. + * @param len + * The length of the data. + * @param plain + * true for a plain hex string false for an xxd compatable + * dump. + */ +void tpm2_util_hexdump(const BYTE *data, size_t len, bool plain); + +/** + * Prints an xxd compatible hexdump to stdout if output is enabled, + * ie no -Q option. + * + * @param fd + * A readable open file. + * @param len + * The length of the data to read and print. + * @param plain + * true for a plain hex string false for an xxd compatable + * dump. + * @return + * true if len bytes were successfully read and printed, + * false otherwise + */ +bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain); + +/** + * Prints a TPM2B as a hex dump. + * @param buffer the TPM2B to print. + */ +static inline void tpm2_util_print_tpm2b(TPM2B *buffer) { + + return tpm2_util_hexdump(buffer->buffer, buffer->size, true); +} + +/** + * Reads a TPM2B object from FILE* and prints data in hex. + * @param fd + * A readable open file. + */ +bool tpm2_util_print_tpm2b_file(FILE *fd); + +/** + * Copies a tpm2b from dest to src and clears dest if src is NULL. + * If src is NULL, it is a NOP. + * @param dest + * The destination TPM2B + * @param src + * The source TPM2B + * @return + * The number of bytes copied. + */ +UINT16 tpm2_util_copy_tpm2b(TPM2B *dest, TPM2B *src); + +/** + * Checks if the host is big endian + * @return + * True of the host is big endian false otherwise. + */ +bool tpm2_util_is_big_endian(void); + +/** + * Swaps the endianess of 16 bit value. + * @param data + * A 16 bit value to swap the endianess on. + * @return + * The 16 bit value with the endianess swapped. + */ +UINT16 tpm2_util_endian_swap_16(UINT16 data); + +/** + * Just like string_bytes_endian_convert_16 but for 32 bit values. + */ +UINT32 tpm2_util_endian_swap_32(UINT32 data); + +/** + * Just like string_bytes_endian_convert_16 but for 64 bit values. + */ +UINT64 tpm2_util_endian_swap_64(UINT64 data); + +/** + * Converts a 16 bit value from host endianess to network endianess. + * @param data + * The data to possibly swap endianess. + * @return + * The swapped data. + */ +UINT16 tpm2_util_hton_16(UINT16 data); + +/** + * Just like string_bytes_endian_hton_16 but for 32 bit values. + */ +UINT32 tpm2_util_hton_32(UINT32 data); + +/** + * Just like string_bytes_endian_hton_16 but for 64 bit values. + */ +UINT64 tpm2_util_hton_64(UINT64 data); + +/** + * Converts a 16 bit value from network endianess to host endianess. + * @param data + * The data to possibly swap endianess. + * @return + * The swapped data. + */ +UINT16 tpm2_util_ntoh_16(UINT16 data); + +/** + * Just like string_bytes_endian_ntoh_16 but for 32 bit values. + */ +UINT32 tpm2_util_ntoh_32(UINT32 data); + +/** + * Just like string_bytes_endian_ntoh_16 but for 64 bit values. + */ +UINT64 tpm2_util_ntoh_64(UINT64 data); + +/** + * Counts the number of set bits aka a population count. + * @param data + * The data to count set bits in. + * @return + * The number of set bits or population count. + */ +UINT32 tpm2_util_pop_count(UINT32 data); + +/** + * Prints whitespace indention for yaml output. + * @param indent_count + * Number of times to indent + */ +void print_yaml_indent(size_t indent_count); + +/** + * Convert a TPM2B_PUBLIC into a yaml format and output if not quiet. + * @param public + * The TPM2B_PUBLIC to output in YAML format. + */ +void tpm2_util_public_to_yaml(TPM2B_PUBLIC *public); + + +/** + * Convert a TPMA_OBJECT to a yaml format and output if not quiet. + * @param obj + * The TPMA_OBJECT attributes to print. + */ +void tpm2_util_tpma_object_to_yaml(TPMA_OBJECT obj); + +#endif /* STRING_BYTES_H */ diff --git a/TPM2-Plugin/lib/log.c b/TPM2-Plugin/lib/log.c new file mode 100644 index 0000000..14797e4 --- /dev/null +++ b/TPM2-Plugin/lib/log.c @@ -0,0 +1,93 @@ +//**********************************************************************; +// 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 <stdarg.h> +#include <stdbool.h> +#include <stdio.h> + +#include "log.h" + +/* + * Note that the logging library is not thread safe, thus calls on separate + * threads will yield an interleaved output on stderr. + */ + +static log_level current_log_level = log_level_warning; + +void +log_set_level (log_level value) +{ + current_log_level = value; +} + +static const char * +get_level_msg (log_level level) +{ + const char *value = "UNK"; + switch (level) + { + case log_level_error: + value = "ERROR"; + break; + case log_level_warning: + value = "WARN"; + break; + case log_level_verbose: + value = "INFO"; + } + return value; +} + +void +_log (log_level level, const char *file, unsigned lineno, const char *fmt, ...) +{ + + /* Skip printing messages outside of the log level */ + if (level > current_log_level) + return; + + va_list argptr; + va_start(argptr, fmt); + + /* Verbose output prints file and line on error */ + if (current_log_level >= log_level_verbose) + fprintf (stderr, "%s on line: \"%u\" in file: \"%s\": ", + get_level_msg (level), lineno, file); + else + fprintf (stderr, "%s: ", get_level_msg (level)); + + /* Print the user supplied message */ + vfprintf (stderr, fmt, argptr); + + /* always add a new line so the user doesn't have to */ + fprintf (stderr, "\n"); + + va_end(argptr); +} diff --git a/TPM2-Plugin/lib/plugin_register.c b/TPM2-Plugin/lib/plugin_register.c new file mode 100644 index 0000000..3de390c --- /dev/null +++ b/TPM2-Plugin/lib/plugin_register.c @@ -0,0 +1,40 @@ +//**********************************************************************; +// 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 <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <dirent.h> + +#include "plugin_register.h" +int (*plugin_init)(char* configPath); +int (*plugin_functions_mapping)(plugin_register *plugin_fp); +int (*plugin_finalize)(); diff --git a/TPM2-Plugin/lib/tpm2_alg_util.c b/TPM2-Plugin/lib/tpm2_alg_util.c new file mode 100644 index 0000000..975f4ae --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_alg_util.c @@ -0,0 +1,437 @@ +//**********************************************************************; +// 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 <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include <sapi/tpm20.h> + +#include "files.h" +#include "log.h" +#include "tpm2_hash.h" +#include "tpm2_alg_util.h" +#include "tpm2_util.h" + +typedef struct alg_pair alg_pair; +struct alg_pair { + const char *name; + TPM2_ALG_ID id; +}; + +void tpm2_alg_util_for_each_alg(tpm2_alg_util_alg_iteraror iterator, void *userdata) { + + static const alg_pair algs[] = { + { .name = "rsa", .id = TPM2_ALG_RSA }, + { .name = "sha1", .id = TPM2_ALG_SHA1 }, + { .name = "hmac", .id = TPM2_ALG_HMAC }, + { .name = "aes", .id = TPM2_ALG_AES }, + { .name = "mgf1", .id = TPM2_ALG_MGF1 }, + { .name = "keyedhash", .id = TPM2_ALG_KEYEDHASH }, + { .name = "xor", .id = TPM2_ALG_XOR }, + { .name = "sha256", .id = TPM2_ALG_SHA256 }, + { .name = "sha384", .id = TPM2_ALG_SHA384 }, + { .name = "sha512", .id = TPM2_ALG_SHA512 }, + { .name = "null", .id = TPM2_ALG_NULL }, + { .name = "sm3_256", .id = TPM2_ALG_SM3_256 }, + { .name = "sm4", .id = TPM2_ALG_SM4 }, + { .name = "rsassa", .id = TPM2_ALG_RSASSA }, + { .name = "rsaes", .id = TPM2_ALG_RSAES }, + { .name = "rsapss", .id = TPM2_ALG_RSAPSS }, + { .name = "oaep", .id = TPM2_ALG_OAEP }, + { .name = "ecdsa", .id = TPM2_ALG_ECDSA }, + { .name = "ecdh", .id = TPM2_ALG_ECDH }, + { .name = "ecdaa", .id = TPM2_ALG_ECDAA }, + { .name = "sm2", .id = TPM2_ALG_SM2 }, + { .name = "ecschnorr", .id = TPM2_ALG_ECSCHNORR }, + { .name = "ecmqv", .id = TPM2_ALG_ECMQV }, + { .name = "kdf1_sp800_56a", .id = TPM2_ALG_KDF1_SP800_56A }, + { .name = "kdf2", .id = TPM2_ALG_KDF2 }, + { .name = "kdf1_sp800_108", .id = TPM2_ALG_KDF1_SP800_108 }, + { .name = "ecc", .id = TPM2_ALG_ECC }, + { .name = "symcipher", .id = TPM2_ALG_SYMCIPHER }, + { .name = "camellia", .id = TPM2_ALG_CAMELLIA }, + { .name = "sha3_256", .id = TPM2_ALG_SHA3_256 }, + { .name = "sha3_384", .id = TPM2_ALG_SHA3_384 }, + { .name = "sha3_512", .id = TPM2_ALG_SHA3_512 }, + { .name = "ctr", .id = TPM2_ALG_CTR }, + { .name = "ofb", .id = TPM2_ALG_OFB }, + { .name = "cbc", .id = TPM2_ALG_CBC }, + { .name = "cfb", .id = TPM2_ALG_CFB }, + { .name = "ecb", .id = TPM2_ALG_ECB }, + }; + + size_t i; + for (i=0; i < ARRAY_LEN(algs); i++) { + const alg_pair *alg = &algs[i]; + bool result = iterator(alg->id, alg->name, userdata); + if (result) { + return; + } + } +} + +static bool find_match(TPM2_ALG_ID id, const char *name, void *userdata) { + + alg_pair *search_data = (alg_pair *)userdata; + + /* + * if name, then search on name, else + * search by id. + */ + if (search_data->name && !strcmp(search_data->name, name)) { + search_data->id = id; + return true; + } else if (search_data->id == id) { + search_data->name = name; + return true; + } + + return false; +} + +TPM2_ALG_ID tpm2_alg_util_strtoalg(const char *name) { + + alg_pair userdata = { + .name = name, + .id = TPM2_ALG_ERROR + }; + + if (name) { + tpm2_alg_util_for_each_alg(find_match, &userdata); + } + + return userdata.id; +} + +const char *tpm2_alg_util_algtostr(TPM2_ALG_ID id) { + + alg_pair userdata = { + .name = NULL, + .id = id + }; + + tpm2_alg_util_for_each_alg(find_match, &userdata); + + return userdata.name; +} + +TPM2_ALG_ID tpm2_alg_util_from_optarg(char *optarg) { + + TPM2_ALG_ID halg; + bool res = tpm2_util_string_to_uint16(optarg, &halg); + if (!res) { + halg = tpm2_alg_util_strtoalg(optarg); + } + return halg; +} + +bool tpm2_alg_util_is_hash_alg(TPM2_ALG_ID id) { + + switch (id) { + case TPM2_ALG_SHA1 : + /* fallsthrough */ + case TPM2_ALG_SHA256 : + /* fallsthrough */ + case TPM2_ALG_SHA384 : + /* fallsthrough */ + case TPM2_ALG_SHA512 : + /* fallsthrough */ + case TPM2_ALG_SM3_256 : + return true; + /* no default */ + } + + return false; +} + +UINT16 tpm2_alg_util_get_hash_size(TPMI_ALG_HASH id) { + + switch (id) { + case TPM2_ALG_SHA1 : + return TPM2_SHA1_DIGEST_SIZE; + case TPM2_ALG_SHA256 : + return TPM2_SHA256_DIGEST_SIZE; + case TPM2_ALG_SHA384 : + return TPM2_SHA384_DIGEST_SIZE; + case TPM2_ALG_SHA512 : + return TPM2_SHA512_DIGEST_SIZE; + case TPM2_ALG_SM3_256 : + return TPM2_SM3_256_DIGEST_SIZE; + /* no default */ + } + + return 0; +} + +static const char *hex_to_byte_err(int rc) { + + switch (rc) { + case -2: + return "String not even in length"; + case -3: + return "Non hex digit found"; + case -4: + return "Hex value too big for digest"; + } + return "unknown"; +} + +bool pcr_parse_digest_list(char **argv, int len, + tpm2_pcr_digest_spec *digest_spec) { + + /* + * int is chosen because of what is passed in from main, avoids + * sign differences. + * */ + int i; + for (i = 0; i < len; i++) { + tpm2_pcr_digest_spec *dspec = &digest_spec[i]; + + UINT32 count = 0; + + /* + * Split <pcr index>:<hash alg>=<hash value>,... on : and separate with null byte, ie: + * <pce index> '\0' <hash alg>'\0'<data> + * + * Start by splitting out the pcr index, and validating it. + */ + char *spec_str = argv[i]; + char *pcr_index_str = spec_str; + char *digest_spec_str = strchr(spec_str, ':'); + if (!digest_spec_str) { + LOG_ERR("Expecting : in digest spec, not found, got: \"%s\"", spec_str); + return false; + } + + *digest_spec_str = '\0'; + digest_spec_str++; + + bool result = tpm2_util_string_to_uint32(pcr_index_str, &dspec->pcr_index); + if (!result) { + LOG_ERR("Got invalid PCR Index: \"%s\", in digest spec: \"%s\"", + pcr_index_str, spec_str); + return false; + } + + /* now that the pcr_index is removed, parse the remaining <hash_name>=<hash_value>,.. */ + char *digest_hash_tok; + char *save_ptr = NULL; + + /* keep track of digests we have seen */ + + while ((digest_hash_tok = strtok_r(digest_spec_str, ",", &save_ptr))) { + digest_spec_str = NULL; + + if (count >= ARRAY_LEN(dspec->digests.digests)) { + LOG_ERR("Specified too many digests per spec, max is: %zu", + ARRAY_LEN(dspec->digests.digests)); + return false; + } + + TPMT_HA *d = &dspec->digests.digests[count]; + + char *stralg = digest_hash_tok; + char *split = strchr(digest_hash_tok, '='); + if (!split) { + LOG_ERR("Expecting = in <hash alg>=<hash value> spec, got: " + "\"%s\"", digest_hash_tok); + return false; + } + *split = '\0'; + split++; + + char *data = split; + + /* + * Convert and validate the hash algorithm. It should be a hash algorithm + */ + TPM2_ALG_ID alg = tpm2_alg_util_from_optarg(stralg); + if (alg == TPM2_ALG_ERROR) { + LOG_ERR("Could not convert algorithm, got: \"%s\"", stralg); + return false; + } + + bool is_hash_alg = tpm2_alg_util_is_hash_alg(alg); + if (!is_hash_alg) { + LOG_ERR("Algorithm is not a hash algorithm, got: \"%s\"", + stralg); + return false; + } + + d->hashAlg = alg; + + /* fill up the TPMT_HA structure with algorithm and digest */ + BYTE *digest_data = (BYTE *) &d->digest; + + UINT16 expected_hash_size = tpm2_alg_util_get_hash_size(alg); + /* strip any preceding hex on the data as tpm2_util_hex_to_byte_structure doesn't support it */ + bool is_hex = !strncmp("0x", data, 2); + if (is_hex) { + data += 2; + } + + UINT16 size = expected_hash_size; + int rc = tpm2_util_hex_to_byte_structure(data, &size, + digest_data); + if (rc) { + LOG_ERR("Error \"%s\" converting hex string as data, got:" + " \"%s\"", hex_to_byte_err(rc), data); + return false; + } + + if (expected_hash_size != size) { + LOG_ERR( + "Algorithm \"%s\" expects a size of %u bytes, got: %u", + stralg, expected_hash_size, size); + return false; + } + + count++; + } + + if (!count) { + LOG_ERR("Missing or invalid <hash alg>=<hash value> spec for pcr:" + " \"%s\"", pcr_index_str); + return false; + } + + /* assign count at the end, so count is 0 on error */ + dspec->digests.count = count; + } + + return true; +} + +UINT8* tpm2_extract_plain_signature(UINT16 *size, TPMT_SIGNATURE *signature) { + + UINT8 *buffer = NULL; + *size = 0; + + switch (signature->sigAlg) { + case TPM2_ALG_RSASSA: + *size = sizeof(signature->signature.rsassa.sig.buffer); + buffer = malloc(*size); + if (!buffer) { + goto nomem; + } + memcpy(buffer, signature->signature.rsassa.sig.buffer, *size); + break; + case TPM2_ALG_HMAC: { + TPMU_HA *hmac_sig = &(signature->signature.hmac.digest); + *size = tpm2_alg_util_get_hash_size(signature->signature.hmac.hashAlg); + buffer = malloc(*size); + if (!buffer) { + goto nomem; + } + memcpy(buffer, hmac_sig, *size); + break; + } + case TPM2_ALG_ECDSA: { + const size_t ECC_PAR_LEN = sizeof(TPM2B_ECC_PARAMETER); + *size = ECC_PAR_LEN * 2; + buffer = malloc(*size); + if (!buffer) { + goto nomem; + } + memcpy(buffer, + (UINT8*)&(signature->signature.ecdsa.signatureR), + ECC_PAR_LEN + ); + memcpy(buffer + ECC_PAR_LEN, + (UINT8*)&(signature->signature.ecdsa.signatureS), + ECC_PAR_LEN + ); + break; + } + default: + LOG_ERR("%s: unknown signature scheme: 0x%x", __func__, + signature->sigAlg); + return NULL; + } + + return buffer; +nomem: + LOG_ERR("%s: couldn't allocate memory", __func__); + return NULL; +} + +static bool get_key_type(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_OBJECT objectHandle, + TPMI_ALG_PUBLIC *type) { + + TSS2L_SYS_AUTH_RESPONSE sessions_data_out; + + TPM2B_PUBLIC out_public = TPM2B_EMPTY_INIT; + + TPM2B_NAME name = TPM2B_TYPE_INIT(TPM2B_NAME, name); + + TPM2B_NAME qaulified_name = TPM2B_TYPE_INIT(TPM2B_NAME, name); + + TSS2_RC rval = Tss2_Sys_ReadPublic(sapi_context, objectHandle, 0, &out_public, &name, + &qaulified_name, &sessions_data_out); + if (rval != TPM2_RC_SUCCESS) { + LOG_ERR("Sys_ReadPublic failed, error code: 0x%x", rval); + return false; + } + *type = out_public.publicArea.type; + return true; +} + +bool get_signature_scheme(TSS2_SYS_CONTEXT *sapi_context, + TPMI_DH_OBJECT keyHandle, TPMI_ALG_HASH halg, + TPMT_SIG_SCHEME *scheme) { + + TPM2_ALG_ID type; + bool result = get_key_type(sapi_context, keyHandle, &type); + if (!result) { + return false; + } + + switch (type) { + case TPM2_ALG_RSA : + scheme->scheme = TPM2_ALG_RSASSA; + scheme->details.rsassa.hashAlg = halg; + break; + case TPM2_ALG_KEYEDHASH : + scheme->scheme = TPM2_ALG_HMAC; + scheme->details.hmac.hashAlg = halg; + break; + case TPM2_ALG_ECC : + scheme->scheme = TPM2_ALG_ECDSA; + scheme->details.ecdsa.hashAlg = halg; + break; + case TPM2_ALG_SYMCIPHER : + default: + LOG_ERR("Unknown key type, got: 0x%x", type); + return false; + } + + return true; +} diff --git a/TPM2-Plugin/lib/tpm2_attr_util.c b/TPM2-Plugin/lib/tpm2_attr_util.c new file mode 100644 index 0000000..03ce2d5 --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_attr_util.c @@ -0,0 +1,645 @@ +//**********************************************************************; +// 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 <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include <sapi/tpm20.h> + +#include "log.h" +#include "tpm2_attr_util.h" +#include "tpm2_util.h" + +#define dispatch_no_arg_add(x) \ + { .name = str(x), .callback=(action)x, .width = 1 } + +#define dispatch_arg_add(x, w) \ + { .name = str(x), .callback=(action)x, .width = w } + +#define dispatch_reserved(pos) \ + { .name = "<reserved("xstr(pos)")>", .callback=NULL, .width = 1 } + +typedef enum dispatch_error dispatch_error; +enum dispatch_error { + dispatch_ok = 0, + dispatch_err, + dispatch_no_match, +}; + +typedef bool (*action)(void *obj, char *arg); + +typedef struct dispatch_table dispatch_table; +struct dispatch_table { + char *name; + action callback; + unsigned width; /* the width of the field, CANNOT be 0 */ +}; + +static bool authread(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_AUTHREAD; + return true; +} + +static bool authwrite(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_AUTHWRITE; + return true; +} + +static bool clear_stclear(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_CLEAR_STCLEAR; + return true; +} + +static bool globallock(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_GLOBALLOCK; + return true; +} + +static bool no_da(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_NO_DA; + return true; +} + +static bool orderly(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_ORDERLY; + return true; +} + +static bool ownerread(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_OWNERREAD; + return true; +} + +static bool ownerwrite(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_OWNERWRITE; + return true; +} + +static bool platformcreate(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_PLATFORMCREATE; + return true; +} + +static bool policyread(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_POLICYREAD; + return true; +} + +static bool policywrite(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_POLICYWRITE; + return true; +} + +static bool policydelete(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_POLICY_DELETE; + return true; +} + +static bool ppread(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_PPREAD; + return true; +} + +static bool ppwrite(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_PPWRITE; + return true; +} + +static bool readlocked(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_READLOCKED; + return true; +} + +static bool read_stclear(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_READ_STCLEAR; + return true; +} + +static bool writeall(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_WRITEALL; + return true; +} + +static bool writedefine(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_WRITEDEFINE; + return true; +} + +static bool writelocked(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_WRITELOCKED; + return true; +} + +static bool write_stclear(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_WRITE_STCLEAR; + return true; +} + +static bool written(TPMA_NV *nv, char *arg) { + + UNUSED(arg); + *nv |= TPMA_NV_TPMA_NV_WRITTEN; + return true; +} + +static bool nt(TPMA_NV *nv, char *arg) { + + uint16_t value; + bool result = tpm2_util_string_to_uint16(arg, &value); + if (!result) { + LOG_ERR("Could not convert \"%s\", to a number", arg); + return false; + } + + /* nt space is 4 bits, so max of 15 */ + if (value > 0x0F) { + LOG_ERR("Field TPM_NT of type TPMA_NV is only 4 bits," + "value \"%s\" to big!", arg); + return false; + } + + *nv &= ~TPMA_NV_TPM2_NT; + *nv |= value << 4; + return true; +} + +/* + * The order of this table must be in order with the bit defines in table 204: + * https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf + * + * This table is in bitfield order, thus the index of a bit set in a TPMA_NV + * can be used to lookup the name. + * + * if not the logic in tpm2_nv_util_strtoattr would need to change! + */ +static dispatch_table nv_attr_table[] = { // Bit Index + dispatch_no_arg_add(ppwrite), // 0 + dispatch_no_arg_add(ownerwrite), // 1 + dispatch_no_arg_add(authwrite), // 2 + dispatch_no_arg_add(policywrite), // 3 + dispatch_arg_add(nt, 4), // 4 + dispatch_arg_add(nt, 3), // 5 + dispatch_arg_add(nt, 2), // 6 + dispatch_arg_add(nt, 1), // 7 + dispatch_reserved(8), // 8 + dispatch_reserved(9), // 9 + dispatch_no_arg_add(policydelete), // 10 + dispatch_no_arg_add(writelocked), // 11 + dispatch_no_arg_add(writeall), // 12 + dispatch_no_arg_add(writedefine), // 13 + dispatch_no_arg_add(write_stclear), // 14 + dispatch_no_arg_add(globallock), // 15 + dispatch_no_arg_add(ppread), // 16 + dispatch_no_arg_add(ownerread), // 17 + dispatch_no_arg_add(authread), // 18 + dispatch_no_arg_add(policyread), // 19 + dispatch_reserved(20), // 20 + dispatch_reserved(21), // 21 + dispatch_reserved(22), // 22 + dispatch_reserved(23), // 23 + dispatch_reserved(24), // 24 + dispatch_no_arg_add(no_da), // 25 + dispatch_no_arg_add(orderly), // 26 + dispatch_no_arg_add(clear_stclear), // 27 + dispatch_no_arg_add(readlocked), // 28 + dispatch_no_arg_add(written), // 29 + dispatch_no_arg_add(platformcreate), // 30 + dispatch_no_arg_add(read_stclear), // 31 +}; + +static bool fixedtpm(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_FIXEDTPM; + return true; +} + +static bool stclear(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_STCLEAR; + return true; +} + +static bool fixedparent(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_FIXEDPARENT; + return true; +} + +static bool sensitivedataorigin(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_SENSITIVEDATAORIGIN; + return true; +} + +static bool userwithauth(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_USERWITHAUTH; + return true; +} + +static bool adminwithpolicy(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_ADMINWITHPOLICY; + return true; +} + +static bool noda(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_NODA; + return true; +} + +static bool encryptedduplication(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_ENCRYPTEDDUPLICATION; + return true; +} + +static bool restricted(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_RESTRICTED; + return true; +} + +static bool decrypt(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_DECRYPT; + return true; +} + +static bool sign(TPMA_OBJECT *obj, char *arg) { + + UNUSED(arg); + *obj |= TPMA_OBJECT_SIGN; + return true; +} + +static dispatch_table obj_attr_table[] = { // Bit Index + dispatch_reserved(0), // 0 + dispatch_no_arg_add(fixedtpm), // 1 + dispatch_no_arg_add(stclear), // 2 + dispatch_reserved(3), // 3 + dispatch_no_arg_add(fixedparent), // 4 + dispatch_no_arg_add(sensitivedataorigin), // 5 + dispatch_no_arg_add(userwithauth), // 6 + dispatch_no_arg_add(adminwithpolicy), // 7 + dispatch_reserved(8), // 8 + dispatch_reserved(9), // 9 + dispatch_no_arg_add(noda), // 10 + dispatch_no_arg_add(encryptedduplication), // 11 + dispatch_reserved(12), // 12 + dispatch_reserved(13), // 13 + dispatch_reserved(14), // 14 + dispatch_reserved(15), // 15 + dispatch_no_arg_add(restricted), // 16 + dispatch_no_arg_add(decrypt), // 17 + dispatch_no_arg_add(sign), // 18 + dispatch_reserved(19), // 19 + dispatch_reserved(20), // 20 + dispatch_reserved(21), // 21 + dispatch_reserved(22), // 22 + dispatch_reserved(23), // 23 + dispatch_reserved(24), // 24 + dispatch_reserved(25), // 25 + dispatch_reserved(26), // 26 + dispatch_reserved(27), // 27 + dispatch_reserved(28), // 28 + dispatch_reserved(29), // 29 + dispatch_reserved(30), // 30 + dispatch_reserved(31), // 31 +}; + +static bool token_match(const char *name, const char *token, bool has_arg, char **sep) { + + /* if it has an argument, we expect a separator */ + size_t match_len = strlen(token); + if (has_arg) { + *sep = strchr(token, '='); + if (*sep) { + match_len = *sep - token; + } + } + + return !strncmp(name, token, match_len); +} + +static dispatch_error handle_dispatch(dispatch_table *d, char *token, + TPMA_NV *nvattrs) { + + char *name = d->name; + action cb = d->callback; + bool has_arg = d->width > 1; + + /* if no callback, then its a reserved block, just skip it */ + if (!cb) { + return dispatch_no_match; + } + + char *sep = NULL; + bool match = token_match(name, token, has_arg, &sep); + if (!match) { + return dispatch_no_match; + } + + /* + * If it has an argument, match should have found the seperator. + */ + char *arg = NULL; + if (has_arg) { + if (!sep) { + LOG_ERR("Expected argument for \"%s\", got none.", token); + return dispatch_err; + } + + /* split token on = */ + *sep = '\0'; + sep++; + if (!*sep) { + LOG_ERR("Expected argument for \"%s\", got none.", token); + return dispatch_err; + } + + /* valid argument string, assign */ + arg = sep; + } + + bool result = cb(nvattrs, arg); + return result ? dispatch_ok : dispatch_err; +} + +static bool common_strtoattr(char *attribute_list, void *attrs, dispatch_table *table, size_t size) { + + char *token; + char *save; + + /* + * This check is soley to prevent GCC from complaining on: + * error: ‘attribute_list’ may be used uninitialized in this function [-Werror=maybe-uninitialized] + * Might as well check nvattrs as well. + */ + if (!attribute_list || !attrs) { + LOG_ERR("attribute list or attributes structure is NULL"); + return false; + } + + while ((token = strtok_r(attribute_list, "|", &save))) { + attribute_list = NULL; + + bool did_dispatch = false; + + size_t i; + for (i = 0; i < size; i++) { + dispatch_table *d = &table[i]; + + dispatch_error err = handle_dispatch(d, token, attrs); + if (err == dispatch_ok) { + did_dispatch = true; + break; + } else if (err == dispatch_err) { + return false; + } + /* dispatch_no_match --> keep looking */ + } + + /* did we dispatch?, If not log error and return */ + if (!did_dispatch) { + char *tmp = strchr(token, '='); + if (tmp) { + *tmp = '\0'; + } + LOG_ERR("Unknown token: \"%s\" found.", token); + return false; + } + } + + return true; +} + +bool tpm2_attr_util_nv_strtoattr(char *attribute_list, TPMA_NV *nvattrs) { + + return common_strtoattr(attribute_list, nvattrs, nv_attr_table, ARRAY_LEN(nv_attr_table)); +} + +bool tpm2_attr_util_obj_strtoattr(char *attribute_list, TPMA_OBJECT *objattrs) { + + return common_strtoattr(attribute_list, objattrs, obj_attr_table, ARRAY_LEN(obj_attr_table)); +} + + +static UINT8 find_first_set(UINT32 bits) { + + UINT8 n = 0; + + if (!bits) { + return n; + } + + if (!(bits & 0x0000FFFF)) { n += 16; bits >>= 16; } + if (!(bits & 0x000000FF)) { n += 8; bits >>= 8; } + if (!(bits & 0x0000000F)) { n += 4; bits >>= 4; } + if (!(bits & 0x00000003)) { n += 2; bits >>= 2; } + if (!(bits & 0x00000001)) n += 1; + + return n; +} + +static char *tpm2_attr_util_common_attrtostr(UINT32 attrs, dispatch_table *table, size_t size) { + + if (attrs == 0) { + return strdup("<none>"); + } + + /* + * Get how many bits are set in the attributes and then find the longest + * "name". + * + * pop_cnt * max_name_len + pop_cnt - 1 (for the | separators) + 4 + * (for nv field equals in hex) + 1 for null byte. + * + * This will provide us an ample buffer size for generating the string + * in without having to constantly realloc. + */ + UINT32 pop_cnt = tpm2_util_pop_count(attrs); + + size_t i; + size_t max_name_len = 0; + for (i=0; i < size; i++) { + dispatch_table *d = &table[i]; + size_t name_len = strlen(d->name); + max_name_len = name_len > max_name_len ? name_len : max_name_len; + } + + size_t length = pop_cnt * max_name_len + pop_cnt - 1 + 3; + + char *str = calloc(length, 1); + if (!str) { + return NULL; + } + + + size_t string_index = 0; + + /* + * Start at the lowest, first bit set, index into the array, + * grab the data needed, and move on. + */ + while (attrs) { + UINT8 bit_index = find_first_set(attrs); + + dispatch_table *d = &table[bit_index]; + + const char *name = d->name; + unsigned w = d->width; + + /* current position and size left of the string */ + char *s = &str[string_index]; + size_t left = length - string_index; + + /* this is a mask that is field width wide */ + UINT8 mask = ((UINT32)1 << w) - 1; + + /* get the value in the field before clearing attrs out */ + UINT8 field_values = (attrs & mask << bit_index) >> bit_index; + + /* + * turn off the parsed bit(s) index, using width to turn off everything in a + * field + */ + attrs &= ~(mask << bit_index); + + /* + * if the callback is NULL, we are either in a field middle or reserved + * section which is weird, just add the name in. In the case of being + * in the middle of the field, we will add a bunch of errors to the string, + * but it would be better to attempt to show all the data in string form, + * rather than bail. + * + * Fields are either 1 or > 1. + */ + if (w == 1) { + /* + * set the format to a middle output, unless we're parsing + * the first or last. Let the format be static with the routine + * so the compiler can do printf style format specifier checking. + */ + if (!string_index) { + /* on the first write, if we are already done, no pipes */ + string_index += !attrs ? snprintf(s, left, "%s", name) : + snprintf(s, left, "%s|", name); + } else if (!attrs) { + string_index += snprintf(s, left, "%s", name); + } else { + string_index += snprintf(s, left, "%s|", name); + } + } else { + /* deal with the field */ + if (!string_index) { + /* on the first write, if we are already done, no pipes */ + string_index += !attrs ? snprintf(s, left, "%s=0x%X", name, field_values) : + snprintf(s, left, "%s=0x%X|", name, field_values); + } else if (!attrs) { + string_index += snprintf(s, left, "%s=0x%X", name, field_values); + } else { + string_index += snprintf(s, left, "%s=0x%X|", name, field_values); + } + } + } + + return str; +} + +char *tpm2_attr_util_nv_attrtostr(TPMA_NV nvattrs) { + return tpm2_attr_util_common_attrtostr(nvattrs, nv_attr_table, ARRAY_LEN(nv_attr_table)); +} + +char *tpm2_attr_util_obj_attrtostr(TPMA_OBJECT objattrs) { + return tpm2_attr_util_common_attrtostr(objattrs, obj_attr_table, ARRAY_LEN(obj_attr_table)); +} + +bool tpm2_attr_util_obj_from_optarg(char *argvalue, TPMA_OBJECT *objattrs) { + + bool res = tpm2_util_string_to_uint32(argvalue, objattrs); + if (!res) { + res = tpm2_attr_util_obj_strtoattr(argvalue, objattrs); + } + + return res; +} diff --git a/TPM2-Plugin/lib/tpm2_error.c b/TPM2-Plugin/lib/tpm2_error.c new file mode 100644 index 0000000..7bc024d --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_error.c @@ -0,0 +1,870 @@ +//**********************************************************************; +// Copyright (c) 2018, 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. +// +// 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 <stdarg.h> +#include <stdbool.h> +#include <stdio.h> + +#include <sapi/tpm20.h> + +#include "tpm2_error.h" +#include "tpm2_util.h" + +/** + * The maximum size of a layer name. + */ +#define TSS2_ERR_LAYER_NAME_MAX 4 + +/** + * The maximum size for layer specific error strings. + */ +#define TSS2_ERR_LAYER_ERROR_STR_MAX 512 + +/** + * Concatenates (safely) onto a static buffer given a format and varaidic + * arguments similar to sprintf. + * @param b + * The static buffer to concatenate onto. + * @param fmt + * The format specifier as understood by printf followed by the variadic + * parameters for the specifier. + */ +#define catbuf(b, fmt, ...) _catbuf(b, sizeof(b), fmt, ##__VA_ARGS__) + +/** + * Clears out a static buffer by setting index 0 to the null byte. + * @param buffer + * The buffer to clear out. + */ +static void clearbuf(char *buffer) { + buffer[0] = '\0'; +} + +/** + * Prints to a buffer using snprintf(3) using the supplied fmt + * and varaiadic arguments. + * @param buf + * The buffer to print into. + * @param len + * The length of that buffer. + * @param fmt + * The format string + * @warning + * DO NOT CALL DIRECTLY, use the catbuf() macro. + */ +static void COMPILER_ATTR(format (printf, 3, 4)) +_catbuf(char *buf, size_t len, const char *fmt, ...) { + va_list argptr; + va_start(argptr, fmt); + size_t offset = strlen(buf); + vsnprintf(&buf[offset], len - offset, fmt, argptr); + va_end(argptr); +} + +/** + * Retrieves the layer number. The layer number is in the 3rd + * octet and is thus 1 byte big. + * + * @param rc + * The rc to query for the layer number. + * @return + * The layer number. + */ +static inline UINT8 tss2_rc_layer_number_get(TSS2_RC rc) { + return ((rc & TSS2_RC_LAYER_MASK) >> TSS2_RC_LAYER_SHIFT); +} + +/** + * Queries a TPM format 1 error codes N field. The N field + * is a 4 bit field located at bits 8:12. + * @param rc + * The rc to query the N field for. + * @return + * The N field value. + */ +static inline UINT8 tpm2_rc_fmt1_N_get(TPM2_RC rc) { + return ((rc & (0xF << 8)) >> 8); +} + +/** + * Queries the index bits out of the N field contained in a TPM format 1 + * error code. The index bits are the low 3 bits of the N field. + * @param rc + * The TPM format 1 error code to query for the index bits. + * @return + * The index bits from the N field. + */ +static inline UINT8 tpm2_rc_fmt1_N_index_get(TPM2_RC rc) { + return (tpm2_rc_fmt1_N_get(rc) & 0x7); +} + +/** + * Determines if the N field in a TPM format 1 error code is + * a handle or not. + * @param rc + * The TPM format 1 error code to query. + * @return + * True if it is a handle, false otherwise. + */ +static inline bool tpm2_rc_fmt1_N_is_handle(TPM2_RC rc) { + return ((tpm2_rc_fmt1_N_get(rc) & 0x8) == 0); +} + +static inline UINT8 tpm2_rc_fmt1_P_get(TPM2_RC rc) { + return ((rc & (1 << 6)) >> 6); +} + +static inline UINT16 tpm2_rc_fmt1_error_get(TPM2_RC rc) { + return (rc & 0x3F); +} + +static inline UINT16 tpm2_rc_fmt0_error_get(TPM2_RC rc) { + return (rc & 0x7F); +} + +static inline UINT8 tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc) { + return ((rc & (1 << 8)) >> 8); +} + +static inline UINT8 tpm2_rc_fmt0_T_get(TPM2_RC rc) { + return ((rc & (1 << 10)) >> 8); +} + +static inline UINT8 tpm2_rc_fmt0_S_get(TSS2_RC rc) { + return ((rc & (1 << 11)) >> 8); +} + +/** + * Helper macro for adding a layer handler to the layer + * registration array. + */ +#define ADD_HANDLER(name, handler) \ + { name, handler } + +/** + * Same as ADD_HANDLER but sets it to NULL. Used as a placeholder + * for non-registered indexes into the handler array. + */ +#define ADD_NULL_HANDLER ADD_HANDLER(NULL, NULL) + +static const char *tpm2_err_handler_fmt1(TPM2_RC rc) { + + /* + * format 1 error codes start at 1, so + * add a NULL entry to index 0. + */ + static const char *fmt1_err_strs[] = { + // 0x0 - EMPTY + NULL, + // 0x1 - TPM2_RC_ASYMMETRIC + "asymmetric algorithm not supported or not correct", + // 0x2 - TPM2_RC_ATTRIBUTES + "inconsistent attributes", + // 0x3 - TPM2_RC_HASH + "hash algorithm not supported or not appropriate", + // 0x4 - TPM2_RC_VALUE + "value is out of range or is not correct for the context", + // 0x5 - TPM2_RC_HIERARCHY + "hierarchy is not enabled or is not correct for the use", + // 0x6 - EMPTY + NULL, + // 0x7 - TPM2_RC_KEY_SIZE + "key size is not supported", + // 0x8 - TPM2_RC_MGF + "mask generation function not supported", + // 0x9 - TPM2_RC_MODE + "mode of operation not supported", + // 0xA - TPM2_RC_TYPE + "the type of the value is not appropriate for the use", + // 0xB - TPM2_RC_HANDLE + "the handle is not correct for the use", + // 0xC - TPM2_RC_KDF + "unsupported key derivation function or function not appropriate for " + "use", + // 0xD - TPM2_RC_RANGE + "value was out of allowed range", + // 0xE - TPM2_RC_AUTH_FAIL + "the authorization HMAC check failed and DA counter incremented", + // 0xF - TPM2_RC_NONCE + "invalid nonce size or nonce value mismatch", + // 0x10 - TPM2_RC_PP + "authorization requires assertion of PP", + // 0x11 - EMPTY + NULL, + // 0x12 - TPM2_RC_SCHEME + "unsupported or incompatible scheme", + // 0x13 - EMPTY + NULL, + // 0x14 - EMPTY + NULL, + // 0x15 - TPM2_RC_SIZE + "structure is the wrong size", + // 0x16 - TPM2_RC_SYMMETRIC + "unsupported symmetric algorithm or key size, or not appropriate for" + " instance", + // 0x17 - TPM2_RC_TAG + "incorrect structure tag", + // 0x18 - TPM2_RC_SELECTOR + "union selector is incorrect", + // 0x19 - EMPTY + NULL, + // 0x1A - TPM2_RC_INSUFFICIENT + "the TPM was unable to unmarshal a value because there were not enough" + " octets in the input buffer", + // 0x1B - TPM2_RC_SIGNATURE + "the signature is not valid", + // 0x1C - TPM2_RC_KEY + "key fields are not compatible with the selected use", + // 0x1D - TPM2_RC_POLICY_FAIL + "a policy check failed", + // 0x1E - EMPTY + NULL, + // 0x1F - TPM2_RC_INTEGRITY + "integrity check failed", + // 0x20 - TPM2_RC_TICKET + "invalid ticket", + // 0x21 - TPM2_RC_RESERVED_BITS + "reserved bits not set to zero as required", + // 0x22 - TPM2_RC_BAD_AUTH + "authorization failure without DA implications", + // 0x23 - TPM2_RC_EXPIRED + "the policy has expired", + // 0x24 - TPM2_RC_POLICY_CC + "the commandCode in the policy is not the commandCode of the command" + " or the command code in a policy command references a command that" + " is not implemented", + // 0x25 - TPM2_RC_BINDING + "public and sensitive portions of an object are not cryptographically bound", + // 0x26 - TPM2_RC_CURVE + "curve not supported", + // 0x27 - TPM2_RC_ECC_POINT + "point is not on the required curve", + }; + + static char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1]; + + clearbuf(buf); + + /* Print whether or not the error is caused by a bad + * handle or parameter. On the case of a Handle (P == 0) + * then the N field top bit will be set. Un-set this bit + * to get the handle index by subtracting 8 as N is a 4 + * bit field. + * + * the lower 3 bits of N indicate index, and the high bit + * indicates + */ + UINT8 index = tpm2_rc_fmt1_N_index_get(rc); + + bool is_handle = tpm2_rc_fmt1_N_is_handle(rc); + const char *m = tpm2_rc_fmt1_P_get(rc) ? "parameter" : + is_handle ? "handle" : "session"; + catbuf(buf, "%s", m); + + if (index) { + catbuf(buf, "(%u):", index); + } else { + catbuf(buf, "%s", "(unk):"); + } + + UINT8 errnum = tpm2_rc_fmt1_error_get(rc); + if (errnum < ARRAY_LEN(fmt1_err_strs)) { + m = fmt1_err_strs[errnum]; + catbuf(buf, "%s", m); + } else { + catbuf(buf, "unknown error num: 0x%X", errnum); + } + + return buf; +} + +static const char *tpm2_err_handler_fmt0(TSS2_RC rc) { + + /* + * format 0 error codes start at 1, so + * add a NULL entry to index 0. + * Thus, no need to offset the error bits + * and fmt0 and fmt1 arrays can be used + * in-place of each other for lookups. + */ + static const char *fmt0_warn_strs[] = { + // 0x0 - EMPTY + NULL, + // 0x1 - TPM2_RC_CONTEXT_GAP + "gap for context ID is too large", + // 0x2 - TPM2_RC_OBJECT_MEMORY + "out of memory for object contexts", + // 0x3 - TPM2_RC_SESSION_MEMORY + "out of memory for session contexts", + // 0x4 - TPM2_RC_MEMORY + "out of shared object/session memory or need space for internal" + " operations", + // 0x5 - TPM2_RC_SESSION_HANDLES + "out of session handles", + // 0x6 - TPM2_RC_OBJECT_HANDLES + "out of object handles", + // 0x7 - TPM2_RC_LOCALITY + "bad locality", + // 0x8 - TPM2_RC_YIELDED + "the TPM has suspended operation on the command; forward progress" + " was made and the command may be retried", + // 0x9 - TPM2_RC_CANCELED + "the command was canceled", + // 0xA - TPM2_RC_TESTING + "TPM is performing self-tests", + // 0xB - EMPTY + NULL, + // 0xC - EMPTY + NULL, + // 0xD - EMPTY + NULL, + // 0xE - EMPTY + NULL, + // 0xF - EMPTY + NULL, + // 0x10 - TPM2_RC_REFERENCE_H0 + "the 1st handle in the handle area references a transient object" + " or session that is not loaded", + // 0x11 - TPM2_RC_REFERENCE_H1 + "the 2nd handle in the handle area references a transient object" + " or session that is not loaded", + // 0x12 - TPM2_RC_REFERENCE_H2 + "the 3rd handle in the handle area references a transient object" + " or session that is not loaded", + // 0x13 - TPM2_RC_REFERENCE_H3 + "the 4th handle in the handle area references a transient object" + " or session that is not loaded", + // 0x14 - TPM2_RC_REFERENCE_H4 + "the 5th handle in the handle area references a transient object" + " or session that is not loaded", + // 0x15 - TPM2_RC_REFERENCE_H5 + "the 6th handle in the handle area references a transient object" + " or session that is not loaded", + // 0x16 - TPM2_RC_REFERENCE_H6 + "the 7th handle in the handle area references a transient object" + " or session that is not loaded", + // 0x17 - EMPTY, + // 0x18 - TPM2_RC_REFERENCE_S0 + "the 1st authorization session handle references a session that" + " is not loaded", + // 0x19 - TPM2_RC_REFERENCE_S1 + "the 2nd authorization session handle references a session that" + " is not loaded", + // 0x1A - TPM2_RC_REFERENCE_S2 + "the 3rd authorization session handle references a session that" + " is not loaded", + // 0x1B - TPM2_RC_REFERENCE_S3 + "the 4th authorization session handle references a session that" + " is not loaded", + // 0x1C - TPM2_RC_REFERENCE_S4 + "the 5th authorization session handle references a session that" + " is not loaded", + // 0x1D - TPM2_RC_REFERENCE_S5 + "the 6th authorization session handle references a session that" + " is not loaded", + // 0x1E - TPM2_RC_REFERENCE_S6 + "the 7th authorization session handle references a session that" + " is not loaded", + // 0x20 -TPM2_RC_NV_RATE + "the TPM is rate-limiting accesses to prevent wearout of NV", + // 0x21 - TPM2_RC_LOCKOUT + "authorizations for objects subject to DA protection are not" + " allowed at this time because the TPM is in DA lockout mode", + // 0x22 - TPM2_RC_RETRY + "the TPM was not able to start the command", + // 0x23 - TPM2_RC_NV_UNAVAILABLE + "the command may require writing of NV and NV is not current" + " accessible", + }; + + /* + * format 1 error codes start at 0, so + * no need to offset the error bits. + */ + static const char *fmt0_err_strs[] = { + // 0x0 - TPM2_RC_INITIALIZE + "TPM not initialized by TPM2_Startup or already initialized", + // 0x1 - TPM2_RC_FAILURE + "commands not being accepted because of a TPM failure", + // 0x2 - EMPTY + NULL, + // 0x3 - TPM2_RC_SEQUENCE + "improper use of a sequence handle", + // 0x4 - EMPTY + NULL, + // 0x5 - EMPTY + NULL, + // 0x6 - EMPTY + NULL, + // 0x7 - EMPTY + NULL, + // 0x8 - EMPTY + NULL, + // 0x9 - EMPTY + NULL, + // 0xA - EMPTY + NULL, + // 0xB - TPM2_RC_PRIVATE + "not currently used", + // 0xC - EMPTY + NULL, + // 0xD - EMPTY + NULL, + // 0xE - EMPTY + NULL, + // 0xF - EMPTY + NULL, + // 0x10 - EMPTY + NULL, + // 0x11 - EMPTY + NULL, + // 0x12 - EMPTY + NULL, + // 0x13 - EMPTY + NULL, + // 0x14 - EMPTY + NULL, + // 0x15 - EMPTY + NULL, + // 0x16 - EMPTY + NULL, + // 0x17 - EMPTY + NULL, + // 0x18 - EMPTY + NULL, + // 0x19 - TPM2_RC_HMAC + "not currently used", + // 0x1A - EMPTY + NULL, + // 0x1B - EMPTY + NULL, + // 0x1C - EMPTY + NULL, + // 0x1D - EMPTY + NULL, + // 0x1E - EMPTY + NULL, + // 0x1F - EMPTY + NULL, + // 0x20 - TPM2_RC_DISABLED + "the command is disabled", + // 0x21 - TPM2_RC_EXCLUSIVE + "command failed because audit sequence required exclusivity", + // 0x22 - EMPTY + NULL, + // 0x23 - EMPTY, + NULL, + // 0x24 - TPM2_RC_AUTH_TYPE + "authorization handle is not correct for command", + // 0x25 - TPM2_RC_AUTH_MISSING + "command requires an authorization session for handle and it is" + " not present", + // 0x26 - TPM2_RC_POLICY + "policy failure in math operation or an invalid authPolicy value", + // 0x27 - TPM2_RC_PCR + "PCR check fail", + // 0x28 - TPM2_RC_PCR_CHANGED + "PCR have changed since checked", + // 0x29 - EMPTY + NULL, + // 0x2A - EMPTY + NULL, + // 0x2B - EMPTY + NULL, + // 0x2C - EMPTY + NULL, + // 0x2D - TPM2_RC_UPGRADE + "TPM is in field upgrade mode unless called via" + " TPM2_FieldUpgradeData(), then it is not in field upgrade mode", + // 0x2E - TPM2_RC_TOO_MANY_CONTEXTS + "context ID counter is at maximum", + // 0x2F - TPM2_RC_AUTH_UNAVAILABLE + "authValue or authPolicy is not available for selected entity", + // 0x30 - TPM2_RC_REBOOT + "a _TPM_Init and Startup(CLEAR) is required before the TPM can" + " resume operation", + // 0x31 - TPM2_RC_UNBALANCED + "the protection algorithms (hash and symmetric) are not reasonably" + " balanced. The digest size of the hash must be larger than the key" + " size of the symmetric algorithm.", + // 0x32 - EMPTY + NULL, + // 0x33 - EMPTY + NULL, + // 0x34 - EMPTY + NULL, + // 0x35 - EMPTY + NULL, + // 0x36 - EMPTY + NULL, + // 0x37 - EMPTY + NULL, + // 0x38 - EMPTY + NULL, + // 0x39 - EMPTY + NULL, + // 0x3A - EMPTY + NULL, + // 0x3B - EMPTY + NULL, + // 0x3C - EMPTY + NULL, + // 0x3D - EMPTY + NULL, + // 0x3E - EMPTY + NULL, + // 0x3F - EMPTY + NULL, + // 0x40 - EMPTY + NULL, + // 0x41 - EMPTY + NULL, + // 0x42 - TPM2_RC_COMMAND_SIZE + "command commandSize value is inconsistent with contents of the" + " command buffer; either the size is not the same as the octets" + " loaded by the hardware interface layer or the value is not large" + " enough to hold a command header", + // 0x43 - TPM2_RC_COMMAND_CODE + "command code not supported", + // 0x44 - TPM2_RC_AUTHSIZE + "the value of authorizationSize is out of range or the number of" + " octets in the Authorization Area is greater than required", + // 0x45 - TPM2_RC_AUTH_CONTEXT + "use of an authorization session with a context command or another" + " command that cannot have an authorization session", + // 0x46 - TPM2_RC_NV_RANGE + "NV offset+size is out of range", + // 0x47 - TPM2_RC_NV_SIZE + "Requested allocation size is larger than allowed", + // 0x48 - TPM2_RC_NV_LOCKED + "NV access locked", + // 0x49 - TPM2_RC_NV_AUTHORIZATION + "NV access authorization fails in command actions", + // 0x4A - TPM2_RC_NV_UNINITIALIZED + "an NV Index is used before being initialized or the state saved" + " by TPM2_Shutdown(STATE) could not be restored", + // 0x4B - TPM2_RC_NV_SPACE + "insufficient space for NV allocation", + // 0x4C - TPM2_RC_NV_DEFINED + "NV Index or persistent object already defined", + // 0x4D - EMPTY + NULL, + // 0x4E - EMPTY + NULL, + // 0x4F - EMPTY + NULL, + // 0x50 - TPM2_RC_BAD_CONTEXT + "context in TPM2_ContextLoad() is not valid", + // 0x51 - TPM2_RC_CPHASH + "cpHash value already set or not correct for use", + // 0x52 - TPM2_RC_PARENT + "handle for parent is not a valid parent", + // 0x53 - TPM2_RC_NEEDS_TEST + "some function needs testing", + // 0x54 - TPM2_RC_NO_RESULT + "returned when an internal function cannot process a request due to" + " an unspecified problem. This code is usually related to invalid" + " parameters that are not properly filtered by the input" + " unmarshaling code", + // 0x55 - TPM2_RC_SENSITIVE + "the sensitive area did not unmarshal correctly after decryption", + }; + + static char buf[TSS2_ERR_LAYER_ERROR_STR_MAX + 1]; + + clearbuf(buf); + + char *e = tpm2_rc_fmt0_S_get(rc) ? "warn" : "error"; + char *v = tpm2_rc_tpm_fmt0_V_get(rc) ? "2.0" : "1.2"; + catbuf(buf, "%s(%s): ", e, v); + + UINT8 errnum = tpm2_rc_fmt0_error_get(rc); + /* We only have version 2.0 spec codes defined */ + if (tpm2_rc_tpm_fmt0_V_get(rc)) { + /* TCG specific error code */ + if (tpm2_rc_fmt0_T_get(rc)) { + catbuf(buf, "Vendor specific error: 0x%X", errnum); + return buf; + } + + /* is it a warning (version 2 error string) or is it a 1.2 error? */ + size_t len = + tpm2_rc_fmt0_S_get(rc) ? + ARRAY_LEN(fmt0_warn_strs) : ARRAY_LEN(fmt0_err_strs); + const char **selection = + tpm2_rc_fmt0_S_get(rc) ? fmt0_warn_strs : fmt0_err_strs; + if (errnum >= len) { + return NULL; + } + + const char *m = selection[errnum]; + if (!m) { + return NULL; + } + + catbuf(buf, "%s", m); + return buf; + } + + catbuf(buf, "%s", "unknown version 1.2 error code"); + + return buf; +} + +/** + * Retrieves the layer field from a TSS2_RC code. + * @param rc + * The rc to query the layer index of. + * @return + * The layer index. + */ +static inline UINT8 tss2_rc_layer_format_get(TSS2_RC rc) { + + return ((rc & (1 << 7)) >> 7); +} + +/** + * Handler for tpm2 error codes. ie codes + * coming from the tpm layer aka layer 0. + * @param rc + * The rc to decode. + * @return + * An error string. + */ +static const char *tpm2_ehandler(TSS2_RC rc) { + + bool is_fmt_1 = tss2_rc_layer_format_get(rc); + + return is_fmt_1 ? tpm2_err_handler_fmt1(rc) : tpm2_err_handler_fmt0(rc); +} + +/** + * The default system code handler. This handles codes + * from the RM (itself and simlated tpm responses), the marshaling + * library (mu), and the tcti layers. + * @param rc + * The rc to decode. + * @return + * An error string. + */ +static const char *sys_err_handler (TSS2_RC rc) { + UNUSED(rc); + + /* + * subtract 1 from the error number + * before indexing into this array. + * + * Commented offsets are for the corresponding + * error number *before* subtraction. Ie error + * number 4 is at array index 3. + */ + static const char *errors[] = { + // 1 - TSS2_BASE_RC_GENERAL_FAILURE + "Catch all for all errors not otherwise specified", + // 2 - TSS2_BASE_RC_NOT_IMPLEMENTED + "If called functionality isn't implemented", + // 3 - TSS2_BASE_RC_BAD_CONTEXT + "A context structure is bad", + // 4 - TSS2_BASE_RC_ABI_MISMATCH + "Passed in ABI version doesn't match called module's ABI version", + // 5 - TSS2_BASE_RC_BAD_REFERENCE + "A pointer is NULL that isn't allowed to be NULL.", + // 6 - TSS2_BASE_RC_INSUFFICIENT_BUFFER + "A buffer isn't large enough", + // 7 - TSS2_BASE_RC_BAD_SEQUENCE + "Function called in the wrong order", + // 8 - TSS2_BASE_RC_NO_CONNECTION + "Fails to connect to next lower layer", + // 9 - TSS2_BASE_RC_TRY_AGAIN + "Operation timed out; function must be called again to be completed", + // 10 - TSS2_BASE_RC_IO_ERROR + "IO failure", + // 11 - TSS2_BASE_RC_BAD_VALUE + "A parameter has a bad value", + // 12 - TSS2_BASE_RC_NOT_PERMITTED + "Operation not permitted.", + // 13 - TSS2_BASE_RC_INVALID_SESSIONS + "Session structures were sent, but command doesn't use them or doesn't" + " use the specified number of them", + // 14 - TSS2_BASE_RC_NO_DECRYPT_PARAM + "If function called that uses decrypt parameter, but command doesn't" + " support decrypt parameter.", + // 15 - TSS2_BASE_RC_NO_ENCRYPT_PARAM + "If function called that uses encrypt parameter, but command doesn't" + " support decrypt parameter.", + // 16 - TSS2_BASE_RC_BAD_SIZE + "If size of a parameter is incorrect", + // 17 - TSS2_BASE_RC_MALFORMED_RESPONSE + "Response is malformed", + // 18 - TSS2_BASE_RC_INSUFFICIENT_CONTEXT + "Context not large enough", + // 19 - TSS2_BASE_RC_INSUFFICIENT_RESPONSE + "Response is not long enough", + // 20 - TSS2_BASE_RC_INCOMPATIBLE_TCTI + "Unknown or unusable TCTI version", + // 21 - TSS2_BASE_RC_NOT_SUPPORTED + "Functionality not supported", + // 22 - TSS2_BASE_RC_BAD_TCTI_STRUCTURE + "TCTI context is bad" + }; + + return (rc - 1u < ARRAY_LEN(errors)) ? errors[rc - 1u] : NULL; +} + + +static struct { + const char *name; + tpm2_error_handler handler; +} layer_handler[TPM2_ERROR_TSS2_RC_LAYER_COUNT] = { + ADD_HANDLER("tpm" , tpm2_ehandler), + ADD_NULL_HANDLER, // layer 1 is unused + ADD_NULL_HANDLER, // layer 2 is unused + ADD_NULL_HANDLER, // layer 3 is unused + ADD_NULL_HANDLER, // layer 4 is unused + ADD_NULL_HANDLER, // layer 5 is unused + ADD_NULL_HANDLER, // layer 6 is the feature rc + ADD_HANDLER("fapi", NULL), // layer 7 is the esapi rc + ADD_HANDLER("sys", sys_err_handler), // layer 8 is the sys rc + ADD_HANDLER("mu", sys_err_handler), // layer 9 is the mu rc + // Defaults to the system handler + ADD_HANDLER("tcti", sys_err_handler), // layer 10 is the tcti rc + // Defaults to the system handler + ADD_HANDLER("rmt", tpm2_ehandler), // layer 11 is the resource manager TPM RC + // The RM usually duplicates TPM responses + // So just default the handler to tpm2. + ADD_HANDLER("rm", NULL), // layer 12 is the rm rc + ADD_HANDLER("drvr", NULL), // layer 13 is the driver rc +}; + +/** + * Determines if the layer allowed to be registered to. + * @param layer + * The layer to determine handler assignment eligibility of. + * @return + * True if it is reserved and thus non-assignable, false otherwise. + */ +static bool is_reserved_layer(UINT8 layer) { + return layer == 0; +} + +/** + * If a layer has no handler registered, default to this + * handler that prints the error number in hex. + * @param rc + * The rc to print the error number of. + * @return + * The string. + */ +static const char *unkown_layer_handler(TSS2_RC rc) { + UNUSED(rc); + + static char buf[32]; + + clearbuf(buf); + catbuf(buf, "0x%X", tpm2_error_get(rc)); + + return buf; +} + +/** + * Register or unregister a custom layer error handler. + * @param layer + * The layer in which to register a handler for. It is an error + * to register for the following reserved layers: + * - TSS2_TPM_RC_LAYER - layer 0 + * - TSS2_SYS_RC_LAYER - layer 8 + * - TSS2_MU_RC_LAYER - layer 9 + * - TSS2_TCTI_RC_LAYER - layer 10 + * @param name + * A friendly layer name. It is an error for the name to be of + * length 0 or greater than 4. + * @param handler + * The handler function to register or NULL to unregister. + * @return + * True on success or False on error. + */ +bool tpm2_error_set_handler(UINT8 layer, const char *name, + tpm2_error_handler handler) { + + /* don't allow setting reserved layers */ + if (is_reserved_layer(layer)) { + return false; + } + + /* + * if they are clearing the handler, name doesn't matter + * clear it too. + */ + if (!handler) { + name = NULL; + } + + /* Perform a zero and max-name length check if name is being set */ + if (name) { + size_t len = name ? strlen(name) : 0; + if (!len || len > TSS2_ERR_LAYER_NAME_MAX) + return false; + } + + layer_handler[layer].handler = handler; + layer_handler[layer].name = name; + + return true; +} + +const char * tpm2_error_str(TSS2_RC rc) { + + static char buf[TSS2_ERR_LAYER_NAME_MAX + TSS2_ERR_LAYER_ERROR_STR_MAX + 1]; + + clearbuf(buf); + + UINT8 layer = tss2_rc_layer_number_get(rc); + + tpm2_error_handler handler = layer_handler[layer].handler; + const char *lname = layer_handler[layer].name; + + if (lname) { + catbuf(buf, "%s:", lname); + } else { + catbuf(buf, "%u:", layer); + } + + handler = !handler ? unkown_layer_handler : handler; + + // Handlers only need the error bits. This way they don't + // need to concern themselves with masking off the layer + // bits or anything else. + UINT16 err_bits = tpm2_error_get(rc); + const char *e = err_bits ? handler(err_bits) : "success"; + if (e) { + catbuf(buf, "%s", e); + } else { + catbuf(buf, "0x%X", err_bits); + } + + return buf; +} diff --git a/TPM2-Plugin/lib/tpm2_hash.c b/TPM2-Plugin/lib/tpm2_hash.c new file mode 100644 index 0000000..ecf3a72 --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_hash.c @@ -0,0 +1,162 @@ +//**********************************************************************; +// 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 <errno.h> +#include <string.h> + +#include <sapi/tpm20.h> + +#include "log.h" +#include "files.h" +#include "tpm2_hash.h" +#include "tpm2_util.h" + +bool tpm2_hash_compute_data(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH halg, + TPMI_RH_HIERARCHY hierarchy, BYTE *buffer, UINT16 length, + TPM2B_DIGEST *result, TPMT_TK_HASHCHECK *validation) { + + FILE *mem = fmemopen(buffer, length, "rb"); + if (!mem) { + LOG_ERR("Error converting buffer to memory stream: %s", + strerror(errno)); + return false; + } + + return tpm2_hash_file(sapi_context, halg, hierarchy, mem, result, validation); +} + +bool tpm2_hash_file(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH halg, + TPMI_RH_HIERARCHY hierarchy, FILE *input, TPM2B_DIGEST *result, + TPMT_TK_HASHCHECK *validation) { + + TPM2B_AUTH nullAuth = TPM2B_EMPTY_INIT; + TPMI_DH_OBJECT sequenceHandle; + + TSS2L_SYS_AUTH_COMMAND cmdAuthArray = { 1, {{.sessionHandle = TPM2_RS_PW, + .nonce = TPM2B_EMPTY_INIT, .hmac = TPM2B_EMPTY_INIT, + .sessionAttributes = 0, }}}; + unsigned long file_size = 0; + + /* Suppress error reporting with NULL path */ + bool res = files_get_file_size(input, &file_size, NULL); + + /* If we can get the file size and its less than 1024, just do it in one hash invocation */ + if (res && file_size <= TPM2_MAX_DIGEST_BUFFER) { + + TPM2B_MAX_BUFFER buffer = { .size = file_size }; + + res = files_read_bytes(input, buffer.buffer, buffer.size); + if (!res) { + LOG_ERR("Error reading input file!"); + return false; + } + + TSS2_RC rval = TSS2_RETRY_EXP(Tss2_Sys_Hash(sapi_context, NULL, &buffer, halg, + hierarchy, result, validation, NULL)); + if (rval != TSS2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_Hash, rval); + return false; + } + + return true; + } + + /* + * Size is either unkown because the FILE * is a fifo, or it's too big + * to do in a single hash call. Based on the size figure out the chunks + * to loop over, if possible. This way we can call Complete with data. + */ + TSS2_RC rval = TSS2_RETRY_EXP(Tss2_Sys_HashSequenceStart(sapi_context, NULL, &nullAuth, + halg, &sequenceHandle, NULL)); + if (rval != TPM2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_HashSequenceStart, rval); + return rval; + } + + /* If we know the file size, we decrement the amount read and terminate the loop + * when 1 block is left, else we go till feof. + */ + size_t left = file_size; + bool use_left = !!res; + + TPM2B_MAX_BUFFER data; + + bool done = false; + while (!done) { + + size_t bytes_read = fread(data.buffer, 1, + BUFFER_SIZE(typeof(data), buffer), input); + if (ferror(input)) { + LOG_ERR("Error reading from input file"); + return false; + } + + data.size = bytes_read; + + /* if data was read, update the sequence */ + rval = TSS2_RETRY_EXP(Tss2_Sys_SequenceUpdate(sapi_context, sequenceHandle, + &cmdAuthArray, &data, NULL)); + if (rval != TPM2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_SequenceUpdate, rval); + return false; + } + + if (use_left) { + left -= bytes_read; + if (left <= TPM2_MAX_DIGEST_BUFFER) { + done = true; + continue; + } + } else if (feof(input)) { + done = true; + } + } /* end file read/hash update loop */ + + if (use_left) { + data.size = left; + bool res = files_read_bytes(input, data.buffer, left); + if (!res) { + LOG_ERR("Error reading from input file."); + return false; + } + } else { + data.size = 0; + } + + rval = TSS2_RETRY_EXP(Tss2_Sys_SequenceComplete(sapi_context, sequenceHandle, + &cmdAuthArray, &data, hierarchy, result, validation, + NULL)); + if (rval != TSS2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_SequenceComplete, rval); + return false; + } + + return true; +} diff --git a/TPM2-Plugin/lib/tpm2_plugin_api.c b/TPM2-Plugin/lib/tpm2_plugin_api.c new file mode 100644 index 0000000..adc8cf7 --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_plugin_api.c @@ -0,0 +1,176 @@ +//**********************************************************************; +// 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 <sapi/tpm20.h> +#include <stdbool.h> +#include <unistd.h> +#include "tpm2_plugin_api.h" +#include "log.h" +#include "tpm2_tcti_ldr.h" + + +const char *tcti_path="libtcti-device.so"; + +static void tcti_teardown (TSS2_TCTI_CONTEXT *tcti_context) +{ + + Tss2_Tcti_Finalize (tcti_context); + free (tcti_context); +} + +static void sapi_teardown (TSS2_SYS_CONTEXT *sapi_context) +{ + + if (sapi_context == NULL) + return; + Tss2_Sys_Finalize (sapi_context); + free (sapi_context); +} + +static void sapi_teardown_full (TSS2_SYS_CONTEXT *sapi_context) +{ + + TSS2_TCTI_CONTEXT *tcti_context = NULL; + TSS2_RC rc; + + rc = Tss2_Sys_GetTctiContext (sapi_context, &tcti_context); + if (rc != TPM2_RC_SUCCESS) + return; + sapi_teardown (sapi_context); + tcti_teardown (tcti_context); +} + +static TSS2_SYS_CONTEXT* sapi_ctx_init(TSS2_TCTI_CONTEXT *tcti_ctx) +{ + + TSS2_ABI_VERSION abi_version = { + .tssCreator = TSSWG_INTEROP, + .tssFamily = TSS_SAPI_FIRST_FAMILY, + .tssLevel = TSS_SAPI_FIRST_LEVEL, + .tssVersion = TSS_SAPI_FIRST_VERSION, + }; + + size_t size = Tss2_Sys_GetContextSize(0); + TSS2_SYS_CONTEXT *sapi_ctx = (TSS2_SYS_CONTEXT*) calloc(1, size); + if (sapi_ctx == NULL) { + LOG_ERR("Failed to allocate 0x%zx bytes for the SAPI context\n", + size); + return NULL; + } + + TSS2_RC rval = Tss2_Sys_Initialize(sapi_ctx, size, tcti_ctx, &abi_version); + if (rval != TPM2_RC_SUCCESS) { + LOG_PERR(Tss2_Sys_Initialize, rval); + free(sapi_ctx); + return NULL; + } + + return sapi_ctx; +} +int tpm2_rsa_sign_init( + unsigned long mechanish, + void *param, + size_t len, + void *ctx) +{ + printf("executing tpm2_rsa_sign_init in tpm2_plugin... \n"); + return 0; +} + +int tpm2_tool_sign(TSS2_SYS_CONTEXT *sapi_context) +{ + return 0; +} + +int tpm2_rsa_sign( + void *ctx, + unsigned char *msg, + int msg_len, + unsigned char *sig, + int *sig_len) +{ + int ret = 1; + TSS2_TCTI_CONTEXT *tcti; + tcti = tpm2_tcti_ldr_load(tcti_path, NULL); + if (!tcti) { + LOG_ERR("Could not load tcti, got: \"%s\"", tcti_path); + return -1; + } + + TSS2_SYS_CONTEXT *sapi_context = NULL; + if (tcti) { + sapi_context = sapi_ctx_init(tcti); + if (!sapi_context) { + goto free_tcti; + } + } + + ret = tpm2_tool_sign(sapi_context); + if (ret != 0) { + LOG_ERR("Unable to run tpm2_tool_sign"); + sapi_teardown_full(sapi_context); + +free_tcti: + tpm2_tcti_ldr_unload(); + return ret; +} +} + +int tpm2_rsa_create_object( + unsigned long appHandle, + //DhsmWPKRSAFormat* wpk, + void *wpk, + unsigned char* swk, + int swk_len, + unsigned char* iv, + int iv_len, + int tag_len, + void **cb_object) +{ + return 0; +} + +int tpm2_rsa_delete_object(void *cb_object) +{ + return 0; +} + +int tpm2_import_object(unsigned long appHandle, + unsigned char* tlvbuffer, + int buflen, + unsigned char* iv, + int iv_len, + unsigned char* tpm_pwd, + int tpm_pwd_len) + +{ + return 0; +} diff --git a/TPM2-Plugin/lib/tpm2_plugin_init.c b/TPM2-Plugin/lib/tpm2_plugin_init.c new file mode 100644 index 0000000..5ef0fce --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_plugin_init.c @@ -0,0 +1,77 @@ +//**********************************************************************; +// 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 <stdio.h> + +#include "plugin_register.h" + +#include "tpm2_plugin_api.h" + +int __plugin_init(char* configPath) +{ +// if tpm_plugin, do this + printf("Init module done for TPM plug-in mode ! \n"); +// if SGX_plugin, do this + + return 0; +} + +int __plugin_finialize() +{ +// if tpm_plugin, do this + printf("Finalize module done for SW mode ! \n"); +// if SGX_plugin, do this + + return 0; +} + +int __plugin_functions_mapping(plugin_register *plugin_fp) +{ + printf("%s(): Assigning Function pointers for TPM (dTPM or PTT) mode \n", __func__); + plugin_fp->cb_crypto_rsa_decrypt_init = NULL; + plugin_fp->cb_crypto_rsa_decrypt = NULL; + plugin_fp->cb_crypto_rsa_sign_init = &tpm2_rsa_sign_init; + plugin_fp->cb_crypto_rsa_sign = &tpm2_rsa_sign; + plugin_fp->cb_crypto_rsa_sign_update = NULL; + plugin_fp->cb_crypto_rsa_sign_final = NULL; + plugin_fp->cb_crypto_ecdsa_sign = NULL; + plugin_fp->cb_crypto_ecdsa_verify = NULL; + plugin_fp->cb_crypto_del_apphandle = NULL; + plugin_fp->cb_crypto_swk_getParentKey = NULL; + plugin_fp->cb_crypto_swk_import = &tpm2_import_object; + plugin_fp->cb_crypto_rsa_create_object = &tpm2_rsa_create_object; + plugin_fp->cb_crypto_rsa_delete_object = &tpm2_rsa_delete_object; + plugin_fp->cb_crypto_ecdsa_create_object = NULL; + plugin_fp->cb_crypto_ecdsa_delete_object = NULL; + + return 0; +} + diff --git a/TPM2-Plugin/lib/tpm2_tcti_ldr.c b/TPM2-Plugin/lib/tpm2_tcti_ldr.c new file mode 100644 index 0000000..9f25188 --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_tcti_ldr.c @@ -0,0 +1,124 @@ +//**********************************************************************; +// Copyright (c) 2018, 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. +// +// 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 <limits.h> +#include <stdlib.h> +#include <stdio.h> +#include <dlfcn.h> + +#include <sapi/tpm20.h> + +#include "log.h" +#include "tpm2_tcti_ldr.h" + +static void *handle; +static const TSS2_TCTI_INFO *info; + +void tpm2_tcti_ldr_unload(void) { + if (handle) { +#ifndef DISABLE_DLCLOSE + dlclose(handle); +#endif + handle = NULL; + info = NULL; + } +} + +const TSS2_TCTI_INFO *tpm2_tcti_ldr_getinfo(void) { + return info; +} + +TSS2_TCTI_CONTEXT *tpm2_tcti_ldr_load(const char *path, const char *opts) { + + TSS2_TCTI_CONTEXT *tcti_ctx = NULL; + + if (handle) { + LOG_ERR("Attempting to load multiple tcti's simultaneously is not supported!"); + return NULL; + } + + /* + * Try what they gave us, if it doesn't load up, try + * libtcti-xxx.so replacing xxx with what they gave us. + */ + handle = dlopen (path, RTLD_LAZY); + if (!handle) { + + char buf[PATH_MAX]; + size_t size = snprintf(buf, sizeof(buf), "libtcti-%s.so", path); + if (size >= sizeof(buf)) { + LOG_ERR("Truncated friendly name conversion, got: \"%s\", made: \"%s\"", + path, buf); + return NULL; + } + + handle = dlopen (buf, RTLD_LAZY); + if (!handle) { + LOG_ERR("Could not dlopen library: \"%s\"", buf); + return NULL; + } + } + + TSS2_TCTI_INFO_FUNC infofn = (TSS2_TCTI_INFO_FUNC)dlsym(handle, TSS2_TCTI_INFO_SYMBOL); + if (!infofn) { + LOG_ERR("Symbol \"%s\"not found in library: \"%s\"", + TSS2_TCTI_INFO_SYMBOL, path); + goto err; + } + + info = infofn(); + + TSS2_TCTI_INIT_FUNC init = info->init; + + size_t size; + TSS2_RC rc = init(NULL, &size, opts); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERR("tcti init setup routine failed for library: \"%s\"" + " options: \"%s\"", path, opts); + goto err; + } + + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc(1, size); + if (tcti_ctx == NULL) { + LOG_ERR("oom"); + goto err; + } + + rc = init(tcti_ctx, &size, opts); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERR("tcti init allocation routine failed for library: \"%s\"" + " options: \"%s\"", path, opts); + goto err; + } + + return tcti_ctx; + +err: + free(tcti_ctx); + dlclose(handle); + return NULL; +} diff --git a/TPM2-Plugin/lib/tpm2_util.c b/TPM2-Plugin/lib/tpm2_util.c new file mode 100644 index 0000000..7a42df7 --- /dev/null +++ b/TPM2-Plugin/lib/tpm2_util.c @@ -0,0 +1,392 @@ +//**********************************************************************; +// 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"); + } +} |