diff options
30 files changed, 5608 insertions, 0 deletions
diff --git a/TPM2-Plugin/Makefile.am b/TPM2-Plugin/Makefile.am new file mode 100644 index 0000000..e932e6e --- /dev/null +++ b/TPM2-Plugin/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = lib src +ACLOCAL_AMFLAGS = -I m4 diff --git a/TPM2-Plugin/README b/TPM2-Plugin/README.md index e6ed31a..e80adc3 100644 --- a/TPM2-Plugin/README +++ b/TPM2-Plugin/README.md @@ -3,3 +3,15 @@ This is TPM2-Plugin to gererate asymetric key pairs from TPM2.0 module and save them in SoftHSM Token object folder in encryped fasion. The private part of keys can only be used for signing when it is loaded in TPM module. +### Build + +./bootstrap +./configure --prefix test + +### Installation +make install + +###Uninstall + +make clean +make distclean diff --git a/TPM2-Plugin/bootstrap b/TPM2-Plugin/bootstrap new file mode 100755 index 0000000..2a09c33 --- /dev/null +++ b/TPM2-Plugin/bootstrap @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +#autoreconf --install --sym + +AUTORECONF=${AUTORECONF:-autoreconf} + +${AUTORECONF} --install --sym + diff --git a/TPM2-Plugin/configure.ac b/TPM2-Plugin/configure.ac new file mode 100644 index 0000000..90f6902 --- /dev/null +++ b/TPM2-Plugin/configure.ac @@ -0,0 +1,15 @@ +AC_INIT([tpm2-plugin], [1.0], [ning.sun@intel.com]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([foreign -Wall -Werror]) +#Version info for the library +VERSION_INFO="1:0:0" +AC_SUBST(VERSION_INFO) + + +AM_PROG_AR +LT_INIT +AC_PROG_CC +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile lib/Makefile src/Makefile]) +AC_OUTPUT 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"); + } +} diff --git a/TPM2-Plugin/src/Makefile.am b/TPM2-Plugin/src/Makefile.am new file mode 100644 index 0000000..8cbcd68 --- /dev/null +++ b/TPM2-Plugin/src/Makefile.am @@ -0,0 +1,4 @@ +AM_CPPFLAGS = -I$(srcdir)/../lib/include +bin_PROGRAMS = tpm2_plugin +tpm2_plugin_SOURCES = main.c +tpm2_plugin_LDADD = ../lib/libtpm2-plugin.la diff --git a/TPM2-Plugin/src/main.c b/TPM2-Plugin/src/main.c new file mode 100644 index 0000000..69bb29f --- /dev/null +++ b/TPM2-Plugin/src/main.c @@ -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. +//**********************************************************************; + +#include <stdio.h> +#include "tpm2_plugin_api.h" + +void main(void) +{ + unsigned long mechanish =1; + void *param = NULL; + size_t len = 100; + void *ctx = NULL; + + printf("test app calling tpm2_rsa_sign_init in tpm2_plugin \n"); + + tpm2_rsa_sign_init(mechanish, param, len, ctx); + + printf("tpm2_rsa_sign_init was returned from tpm2_plugin, test app will exit... \n"); + +} |