aboutsummaryrefslogtreecommitdiffstats
path: root/TPM2-Plugin/lib/tpm2_hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'TPM2-Plugin/lib/tpm2_hash.c')
-rw-r--r--TPM2-Plugin/lib/tpm2_hash.c162
1 files changed, 162 insertions, 0 deletions
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;
+}