aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/imalib.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/libstb/tss2/ibmtpm20tss/utils/imalib.c')
-rw-r--r--roms/skiboot/libstb/tss2/ibmtpm20tss/utils/imalib.c1832
1 files changed, 1832 insertions, 0 deletions
diff --git a/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/imalib.c b/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/imalib.c
new file mode 100644
index 000000000..06373c50b
--- /dev/null
+++ b/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/imalib.c
@@ -0,0 +1,1832 @@
+/********************************************************************************/
+/* */
+/* IMA Routines */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* */
+/* (c) Copyright IBM Corporation 2016 - 2019. */
+/* */
+/* All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions are */
+/* met: */
+/* */
+/* Redistributions of source code must retain the above copyright notice, */
+/* this list of conditions and the following disclaimer. */
+/* */
+/* 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. */
+/* */
+/* Neither the names of the IBM 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. */
+/********************************************************************************/
+
+/* imalib is a set of utility functions to handle IMA (Integrity Measurement Architecture) event
+ logs.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#ifdef TPM_POSIX
+#include <arpa/inet.h>
+#endif
+
+#ifdef TPM_WINDOWS
+#include <winsock2.h>
+#endif
+
+#include <openssl/x509.h>
+#include <openssl/bio.h>
+
+#include <ibmtss/TPM_Types.h>
+#include <ibmtss/tsscryptoh.h>
+#include <ibmtss/tssmarshal.h>
+#include <ibmtss/tssprint.h>
+#include <ibmtss/tsserror.h>
+
+#include "imalib.h"
+
+#define IMA_PARSE_FUNCTIONS_MAX 128
+
+static uint32_t IMA_Uint32_Convert(const uint8_t *stream,
+ int littleEndian);
+static uint32_t IMA_Strn2cpy(char *dest, const uint8_t *src,
+ size_t destLength, size_t srcLength);
+static void IMA_Event_ParseName(ImaEvent *imaEvent);
+
+static uint32_t IMA_TemplateData_ReadFile(ImaEvent *imaEvent,
+ int *endOfFile,
+ FILE *inFile,
+ int littleEndian);
+static uint32_t IMA_TemplateDataIma_ReadFile(ImaEvent *imaEvent,
+ int *endOfFile,
+ FILE *inFile,
+ int littleEndian);
+
+/* callback to parse a template data field */
+
+typedef uint32_t (*TemplateDataParseFunction_t)(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_TemplateName_Parse(TemplateDataParseFunction_t templateDataParseFunctions[],
+ size_t templateDataParseFunctionsSize,
+ ImaEvent *imaEvent);
+static uint32_t
+IMA_TemplateName_ParseCustom(TemplateDataParseFunction_t templateDataParseFunctions[],
+ size_t templateDataParseFunctionsSize,
+ ImaEvent *imaEvent);
+static uint32_t IMA_ParseD(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_ParseDNG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_ParseNNG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_ParseSIG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_ParseDMODSIG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_ParseMODSIG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+static uint32_t IMA_ParseBUF(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian);
+
+extern int tssUtilsVerbose;
+
+/* IMA_Event_Init() initializes the ImaEvent structure so that IMA_Event_Free() is safe.
+
+ */
+
+void IMA_Event_Init(ImaEvent *imaEvent)
+{
+ if (imaEvent != NULL) {
+ imaEvent->nameInt = IMA_UNSUPPORTED;
+ imaEvent->template_data = NULL;
+ }
+ return;
+}
+
+/* IMA_Event_Free() frees any memory allocated for the ImaEvent structure.
+
+ */
+
+void IMA_Event_Free(ImaEvent *imaEvent)
+{
+ if (imaEvent != NULL) {
+ free(imaEvent->template_data);
+ imaEvent->template_data = NULL;
+ }
+ return;
+}
+
+/* IMA_Event_Trace() traces the ImaEvent structure.
+
+ If traceTemplate is FALSE, template data is not traced. This handles the case where template
+ data is not unmarshaled.
+
+*/
+
+void IMA_Event_Trace(ImaEvent *imaEvent, int traceTemplate)
+{
+ printf("IMA_Event_Trace: PCR index %u\n", imaEvent->pcrIndex);
+ TSS_PrintAll("IMA_Event_Trace: hash",
+ imaEvent->digest, sizeof(((ImaEvent *)NULL)->digest));
+
+ printf("IMA_Event_Trace: name length %u\n", imaEvent->name_len);
+ printf("IMA_Event_Trace: name %s\n", imaEvent->name);
+ printf("IMA_Event_Trace: name integer %u\n", imaEvent->nameInt);
+ printf("IMA_Event_Trace: template data length %u\n", imaEvent->template_data_len);
+ /* in some use cases, the template_data field is not populated. In those cases, do not trace
+ it. */
+ if (traceTemplate) {
+ TSS_PrintAll("IMA_Event_Trace: template data",
+ imaEvent->template_data, imaEvent->template_data_len);
+ }
+ return;
+}
+
+/* IMA_Event_ParseName() parses the Template Name and sets the nameInt field */
+
+static void IMA_Event_ParseName(ImaEvent *imaEvent)
+{
+ if (strcmp(imaEvent->name, "ima-ng") == 0) {
+ imaEvent->nameInt = IMA_FORMAT_IMA_NG;
+ }
+ else if (strcmp(imaEvent->name, "ima-sig") == 0) {
+ imaEvent->nameInt = IMA_FORMAT_IMA_SIG;
+ }
+ else if (strcmp(imaEvent->name, "ima") == 0) {
+ imaEvent->nameInt = IMA_FORMAT_IMA;
+ }
+ else if (strcmp(imaEvent->name, "ima-modsig") == 0) {
+ imaEvent->nameInt = IMA_FORMAT_MODSIG;
+ }
+ else if (strcmp(imaEvent->name, "ima-buf") == 0) {
+ imaEvent->nameInt = IMA_FORMAT_BUF;
+ }
+ /* the template data parser currently supports only these formats. */
+ else {
+ imaEvent->nameInt = IMA_UNSUPPORTED;
+ }
+ return;
+}
+
+void IMA_TemplateData_Init(ImaTemplateData *imaTemplateData)
+{
+ imaTemplateData->imaTemplateDNG.hashLength = 0;
+ imaTemplateData->imaTemplateDNG.fileDataHashLength = 0;
+ imaTemplateData->imaTemplateNNG.fileNameLength = 0;
+ imaTemplateData->imaTemplateNNG.fileName[0] = '\0';
+ imaTemplateData->imaTemplateSIG.sigLength = 0;
+ imaTemplateData->imaTemplateSIG.sigHeaderLength = 0;
+ imaTemplateData->imaTemplateSIG.signatureSize = 0;
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashLength = 0;
+ imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength = 0;
+ imaTemplateData->imaTemplateMODSIG.modSigLength = 0;
+ imaTemplateData->imaTemplateBUF.bufLength = 0;
+ return;
+}
+
+/* IMA_TemplateData_Trace() traces the ImaTemplateData structure.
+
+ nameInt maps to the template name.
+
+*/
+
+void IMA_TemplateData_Trace(ImaTemplateData *imaTemplateData,
+ unsigned int nameInt)
+{
+ nameInt = nameInt; /* obsolete now that custom templates are supported */
+ /* d-ng */
+ printf("IMA_TemplateData_Trace: DNG hashLength %u\n", imaTemplateData->imaTemplateDNG.hashLength);
+ printf("IMA_TemplateData_Trace: DNG hashAlg %s\n", imaTemplateData->imaTemplateDNG.hashAlg);
+ TSS_PrintAll("IMA_Template_Trace: DNG file data hash",
+ imaTemplateData->imaTemplateDNG.fileDataHash,
+ imaTemplateData->imaTemplateDNG.fileDataHashLength);
+ /* n-ng */
+ printf("IMA_TemplateData_Trace: NNG fileNameLength %u\n",
+ imaTemplateData->imaTemplateNNG.fileNameLength);
+ if (imaTemplateData->imaTemplateNNG.fileNameLength > 0) {
+ printf("IMA_TemplateData_Trace: NNG fileName %s\n", imaTemplateData->imaTemplateNNG.fileName);
+ }
+ /* sig */
+ printf("IMA_TemplateData_Trace: SIG sigLength %u\n", imaTemplateData->imaTemplateSIG.sigLength);
+ if (imaTemplateData->imaTemplateSIG.sigLength != 0) {
+ TSS_PrintAll("IMA_TemplateData_Trace: sigHeader",
+ imaTemplateData->imaTemplateSIG.sigHeader,
+ imaTemplateData->imaTemplateSIG.sigHeaderLength);
+ printf("IMA_TemplateData_Trace: SIG signatureSize %u\n",
+ imaTemplateData->imaTemplateSIG.signatureSize);
+ TSS_PrintAll("IMA_TemplateData_Trace: SIG signature",
+ imaTemplateData->imaTemplateSIG.signature,
+ imaTemplateData->imaTemplateSIG.signatureSize);
+ }
+ /* d-modsig */
+ printf("IMA_TemplateData_Trace: DMODSIG dModSigHashLength %u\n",
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashLength);
+ if (imaTemplateData->imaTemplateDMODSIG.dModSigHashLength != 0) {
+ printf("IMA_TemplateData_Trace: DMODSIG dModSigHashAlg %s\n",
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg);
+ TSS_PrintAll("IMA_Template_Trace: DMODSIG file data hash",
+ imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHash,
+ imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength);
+ }
+ /* modsig */
+ printf("IMA_TemplateData_Trace: MODSIG modSigLength %u\n",
+ imaTemplateData->imaTemplateMODSIG.modSigLength);
+ if (imaTemplateData->imaTemplateMODSIG.modSigLength != 0) {
+ TSS_PrintAll("IMA_TemplateData_Trace: MODSIG modSigData",
+ imaTemplateData->imaTemplateMODSIG.modSigData,
+ imaTemplateData->imaTemplateMODSIG.modSigLength);
+#ifndef TPM_TSS_MBEDTLS
+ {
+ PKCS7 *pkcs7 = NULL;
+ unsigned char *tmpData = NULL;
+ /* tmp pointer because d2i moves the pointer */
+ tmpData = imaTemplateData->imaTemplateMODSIG.modSigData;
+ pkcs7 = d2i_PKCS7(NULL, /* freed @1 */
+ (const unsigned char **)&tmpData,
+ imaTemplateData->imaTemplateMODSIG.modSigLength);
+ if (pkcs7 != NULL) {
+ BIO *bio = NULL;
+ bio = BIO_new_fd(fileno(stdout), BIO_NOCLOSE); /* freed @2 */
+ if (bio != NULL) {
+ PKCS7_print_ctx(bio, pkcs7, 4, NULL);
+ BIO_free(bio); /* @2 */
+ }
+ else {
+ printf("IMA_TemplateData_Trace: MODSIG Could not create BIO for PKCS7\n");
+ }
+ PKCS7_free(pkcs7); /* @1 */
+ }
+ else {
+ printf("IMA_TemplateData_Trace: MODSIG Could not trace modSigData as PKCS7\n");
+ }
+ }
+#endif /* TPM_TSS_MBEDTLS */
+ }
+ /* buf */
+ printf("IMA_TemplateData_Trace: BUF bufLength %u\n", imaTemplateData->imaTemplateBUF.bufLength);
+ if (imaTemplateData->imaTemplateBUF.bufLength != 0) {
+ TSS_PrintAll("IMA_TemplateData_Trace: BUF bufData",
+ imaTemplateData->imaTemplateBUF.bufData, imaTemplateData->imaTemplateBUF.bufLength);
+#ifndef TPM_TSS_MBEDTLS
+ if ((strcmp((const char *)imaTemplateData->imaTemplateNNG.fileName, ".builtin_trusted_keys") == 0) ||
+ (strcmp((const char *)imaTemplateData->imaTemplateNNG.fileName, ".ima") == 0)) {
+ {
+ X509 *x509 = NULL;
+ unsigned char *tmpData = NULL;
+ /* tmp pointer because d2i moves the pointer */
+ tmpData = imaTemplateData->imaTemplateBUF.bufData;
+ x509 = d2i_X509(NULL, /* freed @1 */
+ (const unsigned char **)&tmpData,
+ imaTemplateData->imaTemplateBUF.bufLength);
+ if (x509 != NULL) {
+ X509_print_fp(stdout, x509);
+ X509_free(x509); /* @1 */
+ }
+ else {
+ printf("IMA_TemplateData_Trace: BUF Could not trace bufData as X509\n");
+ }
+ }
+
+ }
+#endif /* TPM_TSS_MBEDTLS */
+ }
+ return;
+}
+
+/* IMA_Event_ReadFile() reads one IMA event from a file.
+
+ It currently supports these template formats: ima, ima-ng, ima-sig.
+
+ This is typically used at the client, reading from the pseudofile.
+*/
+
+uint32_t IMA_Event_ReadFile(ImaEvent *imaEvent, /* freed by caller */
+ int *endOfFile,
+ FILE *inFile,
+ int littleEndian)
+{
+ int rc = 0;
+ size_t readSize;
+ *endOfFile = FALSE;
+
+ imaEvent->template_data = NULL; /* for free */
+
+ /* read the IMA PCR index */
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(&(imaEvent->pcrIndex),
+ sizeof(((ImaEvent *)NULL)->pcrIndex), 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_Event_ReadFile: could not read pcrIndex, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ /* PCR index endian convert */
+ if ((rc == 0) && !(*endOfFile)) {
+ imaEvent->pcrIndex = IMA_Uint32_Convert((uint8_t *)&imaEvent->pcrIndex, littleEndian);
+ /* range check the PCR index */
+ if (imaEvent->pcrIndex >= IMPLEMENTATION_PCR) {
+ printf("ERROR: IMA_Event_ReadFile: PCR index %u %08x out of range\n",
+ imaEvent->pcrIndex, imaEvent->pcrIndex);
+ rc = TSS_RC_BAD_PROPERTY_VALUE;
+ }
+ }
+ /* read the IMA digest, this is hard coded to SHA-1 */
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(&(imaEvent->digest),
+ sizeof(((ImaEvent *)NULL)->digest), 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_Event_ReadFile: could not read digest, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ /* read the IMA name length */
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(&(imaEvent->name_len),
+ sizeof(((ImaEvent *)NULL)->name_len), 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_Event_ReadFile: could not read name_len, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ imaEvent->name_len = IMA_Uint32_Convert((uint8_t *)&imaEvent->name_len, littleEndian);
+ }
+ /* bounds check the name length, leave a byte for the nul terminator */
+ if ((rc == 0) && !(*endOfFile)) {
+ if (imaEvent->name_len > (sizeof(((ImaEvent *)NULL)->name)) -1) {
+ printf("ERROR: IMA_Event_ReadFile: template name length too big: %u\n",
+ imaEvent->name_len);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ /* read the template name */
+ if ((rc == 0) && !(*endOfFile)) {
+ /* nul terminate first */
+ memset(imaEvent->name, 0, sizeof(((ImaEvent *)NULL)->name));
+ readSize = fread(&(imaEvent->name),
+ imaEvent->name_len, 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_Event_ReadFile: could not read template name, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ /* record the template name as an int */
+ if ((rc == 0) && !(*endOfFile)) {
+ IMA_Event_ParseName(imaEvent);
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ if (imaEvent->nameInt != IMA_FORMAT_IMA) { /* standard format */
+ rc = IMA_TemplateData_ReadFile(imaEvent, endOfFile, inFile, littleEndian);
+ }
+ else { /* unique 'ima' format */
+ rc = IMA_TemplateDataIma_ReadFile(imaEvent, endOfFile, inFile, littleEndian);
+ }
+ }
+ return rc;
+}
+
+/* IMA_TemplateData_ReadFile() reads the template data as a pure array. It handles the normal case
+ of template data length plus template data.
+*/
+
+static uint32_t IMA_TemplateData_ReadFile(ImaEvent *imaEvent, /* freed by caller */
+ int *endOfFile,
+ FILE *inFile,
+ int littleEndian)
+{
+ int rc = 0;
+ size_t readSize;
+
+ /* read template data length */
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(&(imaEvent->template_data_len),
+ sizeof(((ImaEvent *)NULL)->template_data_len ), 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_TemplateData_ReadFile: could not read template_data_len, "
+ " returned %lu\n", (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ imaEvent->template_data_len =
+ IMA_Uint32_Convert((uint8_t *)&imaEvent->template_data_len,
+ littleEndian);
+ }
+ /* bounds check the template data length */
+ if ((rc == 0) && !(*endOfFile)) {
+ if (imaEvent->template_data_len > TCG_TEMPLATE_DATA_LEN_MAX) {
+ printf("ERROR: IMA_TemplateData_ReadFile: template data length too big: %u\n",
+ imaEvent->template_data_len);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ imaEvent->template_data = malloc(imaEvent->template_data_len);
+ if (imaEvent->template_data == NULL) {
+ printf("ERROR: IMA_TemplateData_ReadFile: "
+ "could not allocate template data, size %u\n",
+ imaEvent->template_data_len);
+ rc = TSS_RC_OUT_OF_MEMORY;
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(imaEvent->template_data,
+ imaEvent->template_data_len, 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_Event_ReadFile: could not read template_data, "
+ "returned %lu\n", (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ return rc;
+}
+
+/* IMA_TemplateDataIma_ReadFile() reads the template data. It handles the special case of the
+ template name 'ima', which does not have a template data length. 'ima' has a 20 byte file data
+ hash, a 4 byte file name length, and a file name.
+*/
+
+static uint32_t IMA_TemplateDataIma_ReadFile(ImaEvent *imaEvent, /* freed by caller */
+ int *endOfFile,
+ FILE *inFile,
+ int littleEndian)
+{
+ int rc = 0;
+ size_t readSize;
+ uint8_t fileDataHash[SHA1_DIGEST_SIZE]; /* IMA hard coded to SHA-1 */
+ uint32_t fileNameLengthIbo; /* ima log byte order */
+ uint32_t fileNameLength; /* host byte order */
+
+ /* read the fileDataHash digest, this is hard coded to SHA-1 */
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(&fileDataHash,
+ sizeof(fileDataHash), 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_TemplateDataIma_ReadFile: "
+ "could not read fileDataHash, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ /* read the IMA name length */
+ if ((rc == 0) && !(*endOfFile)) {
+ readSize = fread(&fileNameLengthIbo,
+ sizeof(fileNameLength), 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_TemplateDataIma_ReadFile: "
+ "could not read fileNameLength, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ fileNameLength = IMA_Uint32_Convert((uint8_t *)&fileNameLengthIbo, littleEndian);
+ /* should check for addition overflowing a uint32_t */
+ if (fileNameLength > (0xffffffff - (uint32_t)(sizeof(fileDataHash) + sizeof(fileNameLength)))) {
+ printf("ERROR: IMA_TemplateDataIma_ReadFile: file name length too big: %u\n",
+ fileNameLength);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ /* addition is safe because of above check */
+ imaEvent->template_data_len = sizeof(fileDataHash) + sizeof(fileNameLength) + fileNameLength;
+ }
+ /* bounds check the template data length */
+ if ((rc == 0) && !(*endOfFile)) {
+ if (imaEvent->template_data_len > TCG_TEMPLATE_DATA_LEN_MAX) {
+ printf("ERROR: IMA_TemplateDataIma_ReadFile: template data length too big: %u\n",
+ imaEvent->template_data_len);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ if ((rc == 0) && !(*endOfFile)) {
+ imaEvent->template_data = malloc(imaEvent->template_data_len);
+ if (imaEvent->template_data == NULL) {
+ printf("ERROR: IMA_TemplateData_ReadFile: "
+ "could not allocate template data, size %u\n",
+ imaEvent->template_data_len);
+ rc = TSS_RC_OUT_OF_MEMORY;
+ }
+ }
+ /* copy results to template_data */
+ if ((rc == 0) && !(*endOfFile)) {
+ /* copy file data hash */
+ memcpy(imaEvent->template_data, fileDataHash, sizeof(fileDataHash));
+ /* copy file name length */
+ memcpy(imaEvent->template_data + sizeof(fileDataHash),
+ &fileNameLength, sizeof(fileNameLength));
+ /* read and copy the file name */
+ readSize = fread(imaEvent->template_data + sizeof(fileDataHash) + sizeof(fileNameLength),
+ fileNameLength, 1, inFile);
+ if (readSize != 1) {
+ if (feof(inFile)) {
+ *endOfFile = TRUE;
+ }
+ else {
+ printf("ERROR: IMA_TemplateDataIma_ReadFile: "
+ "could not read fileNameLength, returned %lu\n",
+ (unsigned long)readSize);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ return rc;
+}
+
+/* IMA_Event_ReadBuffer() reads one IMA event from a buffer.
+
+ This is typically used at the server, reading from a client connection.
+
+ Although the raw IMA event log 'ima' template does not have a template data length, this function
+ at the server assumes it has been inserted by the client.
+
+ If getTemplate is TRUE, the template data is copied to a malloced imaEvent->template_data. If
+ FALSE, template data is skipped. FALSE is used for the first pass, where the template data is not
+ needed until the hash is validated.
+
+*/
+
+uint32_t IMA_Event_ReadBuffer(ImaEvent *imaEvent, /* freed by caller */
+ size_t *length,
+ uint8_t **buffer,
+ int *endOfBuffer,
+ int littleEndian,
+ int getTemplate)
+{
+ int rc = 0;
+
+ imaEvent->template_data = NULL; /* for free */
+ if (*length == 0) {
+ *endOfBuffer = 1;
+ }
+ else {
+ /* read the IMA pcr index */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_Event_ReadBuffer: buffer too small for PCR index\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaEvent->pcrIndex = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* sanity check the PCR index */
+ if (rc == 0) {
+ if (imaEvent->pcrIndex != IMA_PCR) {
+ printf("ERROR: IMA_Event_ReadBuffer: PCR index %u not PCR %u\n",
+ IMA_PCR, imaEvent->pcrIndex);
+ rc = TSS_RC_BAD_PROPERTY_VALUE;
+ }
+ }
+ /* read the IMA digest, this is hard coded to SHA-1 */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(((ImaEvent *)NULL)->digest)) {
+ printf("ERROR: IMA_Event_ReadBuffer: buffer too small for IMA digest\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaEvent->digest), *buffer, sizeof(((ImaEvent *)NULL)->digest));
+ *buffer += sizeof(((ImaEvent *)NULL)->digest);
+ *length -= sizeof(((ImaEvent *)NULL)->digest);
+ }
+ }
+ /* read the IMA name length */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_Event_ReadBuffer: "
+ "buffer too small for IMA template name length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaEvent->name_len = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* read the template name */
+ if (rc == 0) {
+ /* bounds check the name length */
+ if (imaEvent->name_len > TCG_EVENT_NAME_LEN_MAX) {
+ printf("ERROR: IMA_Event_ReadBuffer: Error, template name length too big: %u\n",
+ imaEvent->name_len);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else if (*length < imaEvent->name_len) {
+ printf("ERROR: IMA_Event_ReadBuffer: buffer too small for template name\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ /* nul terminate first */
+ memset(imaEvent->name, 0, sizeof(((ImaEvent *)NULL)->name));
+ memcpy(&(imaEvent->name), *buffer, imaEvent->name_len);
+ *buffer += imaEvent->name_len;
+ *length -= imaEvent->name_len;
+ }
+ }
+ /* record the template name as an int */
+ if (rc == 0) {
+ IMA_Event_ParseName(imaEvent);
+ }
+ /* read the template data length */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_Event_ReadBuffer: buffer too small for template data length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaEvent->template_data_len = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* allocate for the template data */
+ if (rc == 0) {
+ if (getTemplate) {
+ /* bounds check the template data length */
+ if (imaEvent->template_data_len > TCG_TEMPLATE_DATA_LEN_MAX) {
+ printf("ERROR: IMA_Event_ReadBuffer: template data length too big: %u\n",
+ imaEvent->template_data_len);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else if (*length < imaEvent->template_data_len) {
+ printf("ERROR: IMA_Event_ReadBuffer: buffer too small for template data\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ if (rc == 0) {
+ imaEvent->template_data = malloc(imaEvent->template_data_len);
+ if (imaEvent->template_data == NULL) {
+ printf("ERROR: IMA_Event_ReadBuffer: "
+ "could not allocate template data, size %u\n",
+ imaEvent->template_data_len);
+ rc = TSS_RC_OUT_OF_MEMORY;
+ }
+ }
+ if (rc == 0) {
+ memcpy(imaEvent->template_data, *buffer, imaEvent->template_data_len);
+ }
+ }
+ }
+ /* move the buffer even if getTemplate is false */
+ if (rc == 0) {
+ *buffer += imaEvent->template_data_len;
+ *length -= imaEvent->template_data_len;
+ }
+ }
+ }
+ return rc;
+}
+
+/* IMA_TemplateName_Parse() parses the template name and registers the template data callbacks */
+
+static uint32_t IMA_TemplateName_Parse(TemplateDataParseFunction_t templateDataParseFunctions[],
+ size_t templateDataParseFunctionsSize,
+ ImaEvent *imaEvent)
+{
+ uint32_t rc = 0;
+ size_t i;
+
+ /* initialize all the function pointers to NULL */
+ for (i = 0 ; (rc == 0) && (i < templateDataParseFunctionsSize) ; i++) {
+ templateDataParseFunctions[i] = NULL;
+ }
+ /* parse the name into the callback structure */
+ if (rc == 0) {
+ switch (imaEvent->nameInt) {
+ /* these are the pre-defined formats */
+ case IMA_FORMAT_IMA_NG:
+ /* d-ng | n-ng */
+ templateDataParseFunctions[0] = (TemplateDataParseFunction_t)IMA_ParseDNG;
+ templateDataParseFunctions[1] = (TemplateDataParseFunction_t)IMA_ParseNNG;
+ break;
+ case IMA_FORMAT_IMA_SIG:
+ /* d-ng | n-ng | sig */
+ templateDataParseFunctions[0] = (TemplateDataParseFunction_t)IMA_ParseDNG;
+ templateDataParseFunctions[1] = (TemplateDataParseFunction_t)IMA_ParseNNG;
+ templateDataParseFunctions[2] = (TemplateDataParseFunction_t)IMA_ParseSIG;
+ break;
+ case IMA_FORMAT_IMA:
+ templateDataParseFunctions[0] = (TemplateDataParseFunction_t)IMA_ParseD;
+ templateDataParseFunctions[1] = (TemplateDataParseFunction_t)IMA_ParseNNG;
+ break;
+ case IMA_FORMAT_MODSIG:
+ /* d-ng | n-ng | sig | d-modsig | modsig */
+ templateDataParseFunctions[0] = (TemplateDataParseFunction_t)IMA_ParseDNG;
+ templateDataParseFunctions[1] = (TemplateDataParseFunction_t)IMA_ParseNNG;
+ templateDataParseFunctions[2] = (TemplateDataParseFunction_t)IMA_ParseSIG;
+ templateDataParseFunctions[3] = (TemplateDataParseFunction_t)IMA_ParseDMODSIG;
+ templateDataParseFunctions[4] = (TemplateDataParseFunction_t)IMA_ParseMODSIG;
+ break;
+ case IMA_FORMAT_BUF:
+ /* d-ng | n-ng | buf */
+ templateDataParseFunctions[0] = (TemplateDataParseFunction_t)IMA_ParseDNG;
+ templateDataParseFunctions[1] = (TemplateDataParseFunction_t)IMA_ParseNNG;
+ templateDataParseFunctions[2] = (TemplateDataParseFunction_t)IMA_ParseBUF;
+ break;
+ /* these are potentially the custom templates */
+ default:
+ rc = IMA_TemplateName_ParseCustom(templateDataParseFunctions,
+ templateDataParseFunctionsSize,
+ imaEvent);
+ }
+ }
+ return rc;
+}
+
+/* the mapping between a format string and the template data parse function */
+
+typedef struct {
+ const char *formatString;
+ TemplateDataParseFunction_t parseFunction;
+} ImaFormatMap;
+
+static ImaFormatMap imaFormatMap[] = {
+ {"d", (TemplateDataParseFunction_t)IMA_ParseD},
+ {"n", (TemplateDataParseFunction_t)IMA_ParseNNG},
+ {"d-ng", (TemplateDataParseFunction_t)IMA_ParseDNG},
+ {"n-ng", (TemplateDataParseFunction_t)IMA_ParseNNG},
+ {"sig", (TemplateDataParseFunction_t)IMA_ParseSIG},
+ {"d-modsig", (TemplateDataParseFunction_t)IMA_ParseDMODSIG},
+ {"modsig", (TemplateDataParseFunction_t)IMA_ParseMODSIG},
+ {"buf", (TemplateDataParseFunction_t)IMA_ParseBUF}
+};
+
+static uint32_t
+IMA_TemplateName_ParseCustom(TemplateDataParseFunction_t templateDataParseFunctions[],
+ size_t templateDataParseFunctionsSize,
+ ImaEvent *imaEvent)
+{
+ uint32_t rc = 0;
+ size_t i; /* index into templateDataParseFunctions table */
+ size_t j; /* index into imaFormatMap table */
+ char *startName;
+ char *endName;
+ char templateName[TCG_EVENT_NAME_LEN_MAX + 1]; /* one | separated item with nul */
+
+ /* parse the custom templates */
+ strcpy(templateName, imaEvent->name); /* modify'able */
+ startName = templateName;
+
+ for (i = 0 ; (rc == 0) && (i < templateDataParseFunctionsSize) ; i++) {
+ endName = strchr(startName, '|');
+ if (endName != NULL) { /* found a | character */
+ *endName = '\0'; /* nul terminate the next format string */
+ }
+ printf("item %lu : %s\n", (unsigned long)i, startName);
+ /* search the table for the format string */
+ for (j = 0 ; j < (sizeof(imaFormatMap) / sizeof(ImaFormatMap)) ; j++) {
+ int irc;
+ irc = strcmp(startName, imaFormatMap[j].formatString);
+ if (irc == 0) {
+ templateDataParseFunctions[i] = imaFormatMap[j].parseFunction;
+ }
+ }
+ /* if no format string found */
+ if (templateDataParseFunctions[i] == NULL) {
+ printf("ERROR: IMA_TemplateName_ParseCustom: unknown format string %s\n",
+ startName);
+ rc = TSS_RC_BAD_PROPERTY_VALUE;
+ }
+ /* if found an item, move the pointer */
+ if (rc == 0) {
+ startName = endName + 1;
+ }
+ if (endName == NULL) { /* no | character, last entry */
+ break;
+ }
+ }
+ return rc;
+}
+
+/*
+ template data callbacks
+*/
+
+/* IMA_ParseD() parses a d : digest (no length or algorithm) */
+
+static uint32_t IMA_ParseD(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+ littleEndian = littleEndian; /* unised */
+ /* fileDataHash */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < SHA1_DIGEST_SIZE) {
+ printf("ERROR: IMA_ParseD: buffer too small for file data hash\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateDNG.fileDataHashLength = SHA1_DIGEST_SIZE;
+ memcpy(&(imaTemplateData->imaTemplateDNG.fileDataHash), *buffer, SHA1_DIGEST_SIZE);
+ *buffer += SHA1_DIGEST_SIZE;
+ *length -= SHA1_DIGEST_SIZE;
+ }
+ }
+ return rc;
+}
+
+/* IMA_ParseDNG parses a d-ng : hash length + hash algorithm string + digest
+
+ The digest is a file data hash.
+ */
+
+static uint32_t IMA_ParseDNG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+ size_t hashAlgSize;
+ /* read the hash length, algorithm + hash */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_ParseDNG: buffer too small for hash length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateDNG.hashLength = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* read the hash algorithm, nul terminated string */
+ if (rc == 0) {
+ /* NUL terminate first */
+ memset(imaTemplateData->imaTemplateDNG.hashAlg, 0,
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateDNG.hashAlg));
+ rc = IMA_Strn2cpy(imaTemplateData->imaTemplateDNG.hashAlg, *buffer,
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateDNG.hashAlg), /* destLength */
+ imaTemplateData->imaTemplateDNG.hashLength); /* srcLength */
+ if (rc != 0) {
+ printf("ERROR: IMA_ParseDNG: buffer too small for hash algorithm\n"
+ "\tor hash algorithm exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ hashAlgSize = strlen(imaTemplateData->imaTemplateDNG.hashAlg) + 1;
+ *buffer += hashAlgSize;
+ *length -= hashAlgSize;
+ }
+ }
+ /* fileDataHashLength */
+ if (rc == 0) {
+ if (strcmp(imaTemplateData->imaTemplateDNG.hashAlg, "sha1:") == 0) {
+ imaTemplateData->imaTemplateDNG.fileDataHashLength = SHA1_DIGEST_SIZE;
+ imaTemplateData->imaTemplateDNG.hashAlgId = TPM_ALG_SHA1;
+ }
+ else if (strcmp(imaTemplateData->imaTemplateDNG.hashAlg, "sha256:") == 0) {
+ imaTemplateData->imaTemplateDNG.fileDataHashLength = SHA256_DIGEST_SIZE;
+ imaTemplateData->imaTemplateDNG.hashAlgId = TPM_ALG_SHA256;
+ }
+ else {
+ printf("ERROR: IMA_ParseDNG: Unknown file data hash algorithm: %s\n",
+ imaTemplateData->imaTemplateDNG.hashAlg);
+ rc = TSS_RC_BAD_HASH_ALGORITHM;
+ }
+ }
+ /* consistency check hashLength vs contents */
+ if (rc == 0) {
+ if ((hashAlgSize + imaTemplateData->imaTemplateDNG.fileDataHashLength) !=
+ imaTemplateData->imaTemplateDNG.hashLength) {
+ printf("ERROR: IMA_ParseDNG: "
+ "hashLength %u inconsistent with hashAlgSize %lu and fileDataHashLength %u\n",
+ imaTemplateData->imaTemplateDNG.hashLength, (unsigned long)hashAlgSize,
+ imaTemplateData->imaTemplateDNG.fileDataHashLength);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ /* fileDataHash */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateDNG.fileDataHashLength) {
+ printf("ERROR: IMA_ParseDNG: buffer too small for file data hash\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else if (imaTemplateData->imaTemplateDNG.fileDataHashLength >
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateDNG.fileDataHash)) {
+ printf("ERROR: IMA_ParseDNG: "
+ "file data hash length exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateDNG.fileDataHash), *buffer,
+ imaTemplateData->imaTemplateDNG.fileDataHashLength);
+ *buffer += imaTemplateData->imaTemplateDNG.fileDataHashLength;
+ *length -= imaTemplateData->imaTemplateDNG.fileDataHashLength;
+ /* FIXME remove */
+ TSS_PrintAll("IMA_ParseDNG: file data hash",
+ imaTemplateData->imaTemplateDNG.fileDataHash,
+ imaTemplateData->imaTemplateDNG.fileDataHashLength);
+ }
+ }
+ return rc;
+}
+
+/* IMA_ParseNNG() parses a n-ng : length + filename */
+
+static uint32_t IMA_ParseNNG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+ /* fileNameLength (length includes the nul terminator) */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_ParseNNG: buffer too small for file name length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateNNG.fileNameLength = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* fileName */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateNNG.fileNameLength) {
+ printf("ERROR: IMA_ParseNNG: buffer too small for file name\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ /* leave one byte for the nul terminator */
+ else if (imaTemplateData->imaTemplateNNG.fileNameLength >
+ (sizeof(imaTemplateData->imaTemplateNNG.fileName)-1)) {
+ printf("ERROR: IMA_ParseNNG: file name length exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateNNG.fileName), *buffer,
+ imaTemplateData->imaTemplateNNG.fileNameLength);
+ /* ima template does not nul terminate the file name */
+ imaTemplateData->imaTemplateNNG.fileName[imaTemplateData->imaTemplateNNG.fileNameLength] = '\0';
+ *buffer += imaTemplateData->imaTemplateNNG.fileNameLength;
+ *length -= imaTemplateData->imaTemplateNNG.fileNameLength;
+ }
+ }
+ return rc;
+}
+
+/* IMA_ParseSIG() parses a sig : signature header + signature */
+
+static uint32_t IMA_ParseSIG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+ /* sigLength */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_ParseSIG: "
+ "buffer too small for signature length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateSIG.sigLength = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ /* FIXME remove */
+ printf("IMA_ParseSIG: sigLength %u\n", imaTemplateData->imaTemplateSIG.sigLength);
+ }
+ }
+ /* sigHeader - only parsed if its length is not zero */
+ if (imaTemplateData->imaTemplateSIG.sigLength != 0) {
+ if (rc == 0) {
+ imaTemplateData->imaTemplateSIG.sigHeaderLength =
+ sizeof((ImaTemplateData *)NULL)->imaTemplateSIG.sigHeader;
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateSIG.sigHeaderLength) {
+ printf("ERROR: IMA_ParseSIG: "
+ "buffer too small for signature header\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateSIG.sigHeader), *buffer,
+ imaTemplateData->imaTemplateSIG.sigHeaderLength);
+ *buffer += imaTemplateData->imaTemplateSIG.sigHeaderLength;
+ *length -= imaTemplateData->imaTemplateSIG.sigHeaderLength;
+ }
+ }
+ /* get signature length from last two bytes */
+ if (rc == 0) {
+ /* magic number for offset: type(1) version(1) hash alg (1) pubkey id (4) */
+ imaTemplateData->imaTemplateSIG.signatureSize =
+ ntohs(*(uint16_t *)(imaTemplateData->imaTemplateSIG.sigHeader + 7));
+ }
+ /* consistency check signature header contents */
+ if (rc == 0) {
+ int goodHashAlgo = (((imaTemplateData->imaTemplateSIG.sigHeader[2] == HASH_ALGO_SHA1) &&
+ (imaTemplateData->imaTemplateDNG.hashAlgId == TPM_ALG_SHA1)) ||
+ ((imaTemplateData->imaTemplateSIG.sigHeader[2] == HASH_ALGO_SHA256) &&
+ (imaTemplateData->imaTemplateDNG.hashAlgId == TPM_ALG_SHA256)));
+ int goodSigSize = ((imaTemplateData->imaTemplateSIG.signatureSize == 128) ||
+ (imaTemplateData->imaTemplateSIG.signatureSize == 256));
+ /* xattr type */
+ if (
+ (imaTemplateData->imaTemplateSIG.sigHeader[0] != EVM_IMA_XATTR_DIGSIG) || /* [0] type */
+ (imaTemplateData->imaTemplateSIG.sigHeader[1] != 2) || /* [1] version */
+ !goodHashAlgo || /* [2] hash algorithm */
+ /* [3]-[6] are the public key fingerprint. Any value is legal. */
+ !goodSigSize /* [7][8] sig size */
+ ) {
+ printf("ERROR: IMA_ParseSIG: invalid sigHeader\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ /* signature */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateSIG.signatureSize) {
+ printf("ERROR: IMA_ParseSIG: "
+ "buffer too small for signature \n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ /* sanity check the signatureSize against the sigLength */
+ else if (imaTemplateData->imaTemplateSIG.sigLength !=
+ (sizeof((ImaTemplateData *)NULL)->imaTemplateSIG.sigHeader +
+ imaTemplateData->imaTemplateSIG.signatureSize)) {
+ printf("ERROR: IMA_ParseSIG: "
+ "sigLength inconsistent with signatureSize\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateSIG.signature), *buffer,
+ imaTemplateData->imaTemplateSIG.signatureSize);
+ *buffer += imaTemplateData->imaTemplateSIG.signatureSize;
+ *length -= imaTemplateData->imaTemplateSIG.signatureSize;
+ /* FIXME remove */
+ TSS_PrintAll("IMA_ParseSIG: file data hash",
+ imaTemplateData->imaTemplateSIG.signature,
+ imaTemplateData->imaTemplateSIG.signatureSize);
+
+ }
+ }
+ }
+ return rc;
+}
+
+/* IMA_ParseDMODSIG parses a d-ng : hash length + hash algorithm string + digest
+
+ The digest is a file data hash omitting the appended modsig signature.
+
+ NOTE: This is currently thre same as IMA_ParseDNG but may have different processing in the
+ future.
+*/
+
+static uint32_t IMA_ParseDMODSIG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+ size_t hashAlgSize;
+
+ /* read the hash length, algorithm + hash */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_ParseDMODSIG: buffer too small for hash length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashLength = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* FIXME is zero length an error? */
+ if (imaTemplateData->imaTemplateDMODSIG.dModSigHashLength != 0) {
+
+ /* read the hash algorithm, nul terminated string */
+ if (rc == 0) {
+ /* NUL terminate first */
+ memset(imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg, 0,
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateDMODSIG.dModSigHashAlgId));
+ rc = IMA_Strn2cpy(imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg, *buffer,
+ /* destLength */
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateDMODSIG.dModSigHashAlg),
+ /* srcLength */
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashLength);
+ if (rc != 0) {
+ printf("ERROR: IMA_ParseDMODSIG: buffer too small for hash algorithm\n"
+ "\tor hash algorithm exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ hashAlgSize = strlen(imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg) + 1;
+ *buffer += hashAlgSize;
+ *length -= hashAlgSize;
+ }
+ }
+ /* dModSigFileDataHashLength */
+ if (rc == 0) {
+ if (strcmp(imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg, "sha1:") == 0) {
+ imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength = SHA1_DIGEST_SIZE;
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashAlgId = TPM_ALG_SHA1;
+ }
+ else if (strcmp(imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg, "sha256:") == 0) {
+ imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength = SHA256_DIGEST_SIZE;
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashAlgId = TPM_ALG_SHA256;
+ }
+ else {
+ printf("ERROR: IMA_ParseDMODSIG: Unknown file data hash algorithm: %s\n",
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashAlg);
+ rc = TSS_RC_BAD_HASH_ALGORITHM;
+ }
+ }
+ /* consistency check dModSigFileDataHashLength vs contents */
+ if (rc == 0) {
+ if ((hashAlgSize + imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength) !=
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashLength) {
+ printf("ERROR: IMA_ParseDMODSIG: "
+ "dModSigFileDataHashLength %u inconsistent with hashAlgSize %lu "
+ "and dModSigFileDataHashLength %u\n",
+ imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength,
+ (unsigned long)hashAlgSize,
+ imaTemplateData->imaTemplateDMODSIG.dModSigHashLength);
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ /* dModSigFileDataHashLength */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength ) {
+ printf("ERROR: IMA_ParseDMODSIG: buffer too small for file data hash\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else if (imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength >
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateDMODSIG.dModSigFileDataHash)) {
+ printf("ERROR: IMA_ParseDMODSIG: "
+ "file data hash length exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHash),
+ *buffer, imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength);
+ *buffer += imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength ;
+ *length -= imaTemplateData->imaTemplateDMODSIG.dModSigFileDataHashLength ;
+ }
+ }
+ }
+ return rc;
+}
+
+/* IMA_ParseMODSIG parses a modsig : 4 byte length + DER encoded CMS document, RFC 5652 */
+
+static uint32_t IMA_ParseMODSIG(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+
+ /* read the length */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_ParseMODSIG: buffer too small for length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateMODSIG.modSigLength = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* read the DER */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateMODSIG.modSigLength) {
+ printf("ERROR: IMA_ParseMODSIG: buffer too small for modSig data\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else if (imaTemplateData->imaTemplateMODSIG.modSigLength >
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateMODSIG.modSigData)) {
+ printf("ERROR: IMA_ParseMODSIG: "
+ "modSigData length exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateMODSIG.modSigData), *buffer,
+ imaTemplateData->imaTemplateMODSIG.modSigLength);
+ *buffer += imaTemplateData->imaTemplateMODSIG.modSigLength;
+ *length -= imaTemplateData->imaTemplateMODSIG.modSigLength;
+ }
+ }
+ return rc;
+}
+
+/* IMA_ParseBUF parses a modsig : 4 byte length + DER encoded CMS document, RFC 5652 */
+
+static uint32_t IMA_ParseBUF(ImaTemplateData *imaTemplateData,
+ uint8_t **buffer,
+ size_t *length,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+
+ /* FIXME factor reading a 4 byte length plus data stream */
+ /* read the length */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < sizeof(uint32_t)) {
+ printf("ERROR: IMA_ParseBUF: buffer too small for length\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ imaTemplateData->imaTemplateBUF.bufLength = IMA_Uint32_Convert(*buffer, littleEndian);
+ *buffer += sizeof(uint32_t);
+ *length -= sizeof(uint32_t);
+ }
+ }
+ /* read the DER */
+ if (rc == 0) {
+ /* bounds check the length */
+ if (*length < imaTemplateData->imaTemplateBUF.bufLength) {
+ printf("ERROR: IMA_ParseBUF: buffer too small for buf data\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else if (imaTemplateData->imaTemplateBUF.bufLength >
+ sizeof(((ImaTemplateData *)NULL)->imaTemplateBUF.bufData)) {
+ printf("ERROR: IMA_ParseBUF: "
+ "bufData length exceeds maximum size\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ else {
+ memcpy(&(imaTemplateData->imaTemplateBUF.bufData), *buffer,
+ imaTemplateData->imaTemplateBUF.bufLength);
+ *buffer += imaTemplateData->imaTemplateBUF.bufLength;
+ *length -= imaTemplateData->imaTemplateBUF.bufLength;
+ }
+ }
+ return rc;
+}
+
+/* IMA_TemplateData_ReadBuffer() unmarshals the template data fields from the template data byte
+ array.
+
+*/
+
+uint32_t IMA_TemplateData_ReadBuffer(ImaTemplateData *imaTemplateData,
+ ImaEvent *imaEvent,
+ int littleEndian)
+{
+ uint32_t rc = 0;
+ size_t length = imaEvent->template_data_len;
+ uint8_t *buffer = imaEvent->template_data;
+ TemplateDataParseFunction_t templateDataParseFunctions[IMA_PARSE_FUNCTIONS_MAX];
+ size_t i;
+
+ /* initialize all fields, since not all fields are included in all templates */
+ if (rc == 0) {
+ IMA_TemplateData_Init(imaTemplateData);
+ }
+ if (rc == 0) {
+ rc = IMA_TemplateName_Parse(templateDataParseFunctions, IMA_PARSE_FUNCTIONS_MAX,
+ imaEvent);
+ }
+ for (i = 0 ; (rc == 0) && (templateDataParseFunctions[i] != NULL) ; i++) {
+ rc = templateDataParseFunctions[i](imaTemplateData, &buffer, &length, littleEndian);
+ }
+ /* length should now be zero */
+ if (rc == 0) {
+ if (length != 0) {
+ printf("ERROR: IMA_TemplateData_ReadBuffer: "
+ "buffer too large (bytes remaining after unmarshaling)\n");
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ return rc;
+}
+
+/* IMA_Event_Write() writes an event line to a binary file outFile.
+
+ The write is always big endian, network byte order.
+*/
+
+uint32_t IMA_Event_Write(ImaEvent *imaEvent,
+ FILE *outFile)
+{
+ int rc = 0;
+ size_t writeSize;
+ uint32_t nbo32; /* network byte order */
+
+ if (rc == 0) {
+ /* do the endian conversion */
+ nbo32 = htonl(imaEvent->pcrIndex);
+ /* write the IMA pcr index */
+ writeSize = fwrite(&nbo32, sizeof(uint32_t), 1, outFile);
+ if (writeSize != 1) {
+ printf("ERROR: IMA_Event_Write: could not write pcrIndex, returned %lu\n",
+ (unsigned long)writeSize);
+ rc = TSS_RC_FILE_WRITE;
+ }
+ }
+ /* write the IMA digest, name length */
+ if (rc == 0) {
+ writeSize = fwrite(&(imaEvent->digest), sizeof(((ImaEvent *)NULL)->digest), 1, outFile);
+ if (writeSize != 1) {
+ printf("ERROR: IMA_Event_Write: could not write digest, returned %lu\n",
+ (unsigned long)writeSize);
+ rc = TSS_RC_FILE_WRITE;
+ }
+ }
+ /* write the IMA name length */
+ if (rc == 0) {
+ /* do the endian conversion */
+ nbo32 = htonl(imaEvent->name_len);
+ /* write the IMA name length */
+ writeSize = fwrite(&nbo32, sizeof(uint32_t), 1, outFile);
+ if (writeSize != 1) {
+ printf("ERROR: IMA_Event_Write: could not write name length, returned %lu\n",
+ (unsigned long)writeSize);
+ rc = TSS_RC_FILE_WRITE;
+ }
+ }
+ /* write the name */
+ if (rc == 0) {
+ writeSize = fwrite(&(imaEvent->name), imaEvent->name_len, 1, outFile);
+ if (writeSize != 1) {
+ printf("ERROR: IMA_Event_Write: could not write name, returned %lu\n",
+ (unsigned long)writeSize);
+ rc = TSS_RC_FILE_WRITE;
+ }
+ }
+ /* write the template data length */
+ if (rc == 0) {
+ /* do the endian conversion */
+ nbo32 = htonl(imaEvent->template_data_len);
+ /* write the IMA template data length */
+ writeSize = fwrite(&nbo32, sizeof(uint32_t), 1, outFile);
+ if (writeSize != 1) {
+ printf("ERROR: IMA_Event_Write: could not template data length , returned %lu\n",
+ (unsigned long)writeSize);
+ rc = TSS_RC_FILE_WRITE;
+ }
+ }
+ /* write the template data */
+ if (rc == 0) {
+ writeSize = fwrite(&(imaEvent->template_data), imaEvent->template_data_len, 1, outFile);
+ if (writeSize != 1) {
+ printf("ERROR: IMA_Event_Write: could not write template data, returned %lu\n",
+ (unsigned long)writeSize);
+ rc = TSS_RC_FILE_WRITE;
+ }
+ }
+ return rc;
+}
+
+/* IMA_Extend() extends the event into the imaPcr.
+
+ An IMA quirk is that, if the event is all zero, all ones is extended into the SHA-1 bank. Since
+ the SHA-256 bank currently gets the SHA-1 value zero extended, it will get 20 ff's and 12 00's.
+
+ halg indicates whether to calculate the digest for the SHA-1 or SHA-256 PCR bank. The IMA event
+ log itself is always SHA-1.
+
+ This function assumes that the same hash algorithm / PCR bank is used for all calls.
+*/
+
+uint32_t IMA_Extend(TPMT_HA *imapcr,
+ ImaEvent *imaEvent,
+ TPMI_ALG_HASH hashAlg)
+{
+ uint32_t rc = 0;
+ uint16_t digestSize;
+ uint16_t zeroPad;
+ int notAllZero;
+ unsigned char zeroDigest[SHA256_DIGEST_SIZE];
+ unsigned char oneDigest[SHA256_DIGEST_SIZE];
+
+ /* FIXME sanity check TPM_IMA_PCR imaEvent->pcrIndex */
+
+ /* extend based on the previous IMA PCR value */
+ if (rc == 0) {
+ memset(zeroDigest, 0, SHA256_DIGEST_SIZE);
+ memset(oneDigest, 0xff, SHA256_DIGEST_SIZE);
+ if (hashAlg == TPM_ALG_SHA1) {
+ digestSize = SHA1_DIGEST_SIZE;
+ zeroPad = 0;
+ }
+ else if (hashAlg == TPM_ALG_SHA256) {
+ digestSize = SHA256_DIGEST_SIZE;
+ /* pad the SHA-1 event with zeros for the SHA-256 bank */
+ zeroPad = SHA256_DIGEST_SIZE - SHA1_DIGEST_SIZE;
+ }
+ else {
+ printf("ERROR: IMA_Extend: Unsupported hash algorithm: %04x\n", hashAlg);
+ rc = TSS_RC_BAD_HASH_ALGORITHM;
+ }
+ }
+ if (rc == 0) {
+ notAllZero = memcmp(imaEvent->digest, zeroDigest, SHA1_DIGEST_SIZE);
+ imapcr->hashAlg = hashAlg;
+#if 1
+ TSS_PrintAll("IMA_Extend: Start PCR", (uint8_t *)&imapcr->digest, digestSize);
+ TSS_PrintAll("IMA_Extend: SHA-256 Pad", zeroDigest, zeroPad);
+#endif
+ if (notAllZero) {
+ TSS_PrintAll("IMA_Extend: Extend", (uint8_t *)&imaEvent->digest, SHA1_DIGEST_SIZE);
+ rc = TSS_Hash_Generate(imapcr,
+ digestSize, (uint8_t *)&imapcr->digest,
+ SHA1_DIGEST_SIZE, &imaEvent->digest,
+ /* SHA-1 PCR extend gets zero padded */
+ zeroPad, zeroDigest,
+ 0, NULL);
+#if 1
+ TSS_PrintAll("IMA_Extend: notAllZero End PCR",
+ (uint8_t *)&imapcr->digest, digestSize);
+#endif
+ }
+ /* IMA has a quirk where, when it places all all zero digest into the measurement log, it
+ extends all ones into IMA PCR */
+ else {
+ TSS_PrintAll("IMA_Extend: Extend", (uint8_t *)oneDigest, SHA1_DIGEST_SIZE);
+ rc = TSS_Hash_Generate(imapcr,
+ digestSize, (uint8_t *)&imapcr->digest,
+ SHA1_DIGEST_SIZE, oneDigest,
+ /* SHA-1 gets zero padded */
+ zeroPad, zeroDigest,
+ 0, NULL);
+#if 1
+ TSS_PrintAll("IMA_Extend: allZero End PCR",
+ (uint8_t *)&imapcr->digest, digestSize);
+#endif
+ }
+ }
+ if (rc != 0) {
+ printf("ERROR: IMA_Extend: could not extend imapcr, rc %08x\n", rc);
+ }
+ return rc;
+}
+
+/* IMA_VerifyImaDigest() verifies the IMA digest against the hash of the template data.
+
+ This handles the SHA-1 IMA event log.
+*/
+
+uint32_t IMA_VerifyImaDigest(uint32_t *badEvent, /* TRUE if hash does not match */
+ ImaEvent *imaEvent, /* the current IMA event being processed */
+ int eventNum) /* the current IMA event number being processed */
+{
+ uint32_t rc = 0;
+ int irc;
+ TPMT_HA calculatedImaDigest;
+
+ /* calculate the hash of the template data */
+ if (rc == 0) {
+ calculatedImaDigest.hashAlg = TPM_ALG_SHA1;
+ /* standard case, hash of entire template data */
+ if (imaEvent->nameInt != IMA_FORMAT_IMA) {
+ rc = TSS_Hash_Generate(&calculatedImaDigest,
+ imaEvent->template_data_len, imaEvent->template_data,
+ 0, NULL);
+ }
+ /* special case of "ima" template, hash of File Data Hash || File Name padded with zeros to
+ 256 bytes */
+ else {
+ ImaTemplateData imaTemplateData;
+ int zeroPadLength;
+ uint8_t zeroPad[256];
+ if (rc == 0) {
+ rc = IMA_TemplateData_ReadBuffer(&imaTemplateData,
+ imaEvent,
+ TRUE); /* FIXME littleEndian */
+ }
+ if (rc == 0) {
+ if (imaTemplateData.imaTemplateNNG.fileNameLength > sizeof(zeroPad)) {
+ printf("ERROR: IMA_VerifyImaDigest: ima template file name length %lu > %lu\n",
+ (unsigned long)imaTemplateData.imaTemplateNNG.fileNameLength,
+ (unsigned long)sizeof(zeroPad));
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ }
+ if (rc == 0) {
+ memset(zeroPad, 0, sizeof(zeroPad));
+ /* subtract safe after above length check */
+ zeroPadLength = sizeof(zeroPad) - imaTemplateData.imaTemplateNNG.fileNameLength;
+ }
+ if (rc == 0) {
+ rc = TSS_Hash_Generate(&calculatedImaDigest,
+ SHA1_DIGEST_SIZE, &imaTemplateData.imaTemplateDNG.fileDataHash,
+ imaTemplateData.imaTemplateNNG.fileNameLength,
+ &imaTemplateData.imaTemplateNNG.fileName,
+ zeroPadLength, zeroPad,
+ 0, NULL);
+ }
+ }
+ }
+ /* compare the calculated hash to the event digest received from the client */
+ if (rc == 0) {
+ if (tssUtilsVerbose) TSS_PrintAll("IMA_VerifyImaDigest: Received IMA digest",
+ imaEvent->digest, SHA1_DIGEST_SIZE);
+ if (tssUtilsVerbose) TSS_PrintAll("IMA_VerifyImaDigest: Calculated IMA digest",
+ (uint8_t *)&calculatedImaDigest.digest, SHA1_DIGEST_SIZE);
+
+ irc = memcmp(imaEvent->digest, &calculatedImaDigest.digest, SHA1_DIGEST_SIZE);
+ if (irc == 0) {
+ if (tssUtilsVerbose) printf("IMA_VerifyImaDigest: IMA digest verified, event %u\n", eventNum);
+ *badEvent = FALSE;
+ }
+ else {
+ printf("ERROR: IMA_VerifyImaDigest: IMA digest did not verify, event %u\n",
+ eventNum);
+ *badEvent = TRUE;
+ }
+ }
+ return rc;
+}
+
+/* IMA_Uint32_Convert() converts a uint8_t (from an input stream) to host byte order
+ */
+
+static uint32_t IMA_Uint32_Convert(const uint8_t *stream,
+ int littleEndian)
+{
+ uint32_t out = 0;
+
+ /* little endian input */
+ if (littleEndian) {
+ out = (stream[0] << 0) |
+ (stream[1] << 8) |
+ (stream[2] << 16) |
+ (stream[3] << 24);
+ }
+ /* big endian input */
+ else {
+ out = (stream[0] << 24) |
+ (stream[1] << 16) |
+ (stream[2] << 8) |
+ (stream[3] << 0);
+ }
+ return out;
+}
+
+/* IMA_Strn2cpy() copies src to dest, including a NUL terminator
+
+ It checks that src is nul terminated within srcLength bytes.
+ It checks that src fits into dest within destLength bytes
+
+ Returns error if either the src is not nul terminated or will not fit in dest.
+*/
+
+static uint32_t IMA_Strn2cpy(char *dest, const uint8_t *src,
+ size_t destLength, size_t srcLength)
+{
+ uint32_t rc = 0;
+ int done = 0;
+
+ while ((destLength > 0) && (srcLength > 0)) {
+ *dest = *src;
+ if (*dest == '\0') {
+ done = 1;
+ break;
+ }
+ else {
+ dest++;
+ src++;
+ destLength--;
+ srcLength--;
+ }
+ }
+ if (!done) {
+ rc = TSS_RC_INSUFFICIENT_BUFFER;
+ }
+ return rc;
+}
+
+/* IMA_Event_Marshal() marshals an ImaEvent structure */
+
+TPM_RC IMA_Event_Marshal(ImaEvent *source,
+ uint16_t *written, uint8_t **buffer, uint32_t *size)
+{
+ TPM_RC rc = 0;
+
+ if (rc == 0) {
+ rc = TSS_UINT32_Marshalu(&source->pcrIndex, written, buffer, size);
+ }
+ if (rc == 0) {
+ rc = TSS_Array_Marshalu(source->digest, SHA1_DIGEST_SIZE, written, buffer, size);
+ }
+ if (rc == 0) {
+ rc = TSS_UINT32_Marshalu(&source->name_len, written, buffer, size);
+ }
+ if (rc == 0) {
+ rc = TSS_Array_Marshalu((uint8_t *)source->name, source->name_len, written, buffer, size);
+ }
+ if (rc == 0) {
+ rc = TSS_UINT32_Marshalu(&source->template_data_len, written, buffer, size);
+ }
+ if (rc == 0) {
+ rc = TSS_Array_Marshalu(source->template_data, source->template_data_len,
+ written, buffer, size);
+ }
+ return rc;
+}
+
+/* IMA_Event_PcrExtend() extends PCR digests with the digest from the ImaEvent event log
+ entry.
+
+ Bank 0 is SHA-1. Bank 1 is SHA-256.
+
+ The function supports all PCRs, even though the PCRs are limited in practice.
+
+*/
+
+uint32_t IMA_Event_PcrExtend(TPMT_HA pcrs[IMA_PCR_BANKS][IMPLEMENTATION_PCR],
+ ImaEvent *imaEvent)
+{
+ TPM_RC rc = 0;
+ uint8_t eventData[SHA256_DIGEST_SIZE];
+
+ /* validate PCR number */
+ if (rc == 0) {
+ if (imaEvent->pcrIndex >= IMPLEMENTATION_PCR) {
+ printf("ERROR: IMA_Event_PcrExtend: PCR number %u %08x out of range\n",
+ imaEvent->pcrIndex, imaEvent->pcrIndex);
+ rc = TSS_RC_BAD_PROPERTY;
+ }
+ }
+ /* process each event hash algorithm */
+ if (rc == 0) {
+ unsigned char zeroDigest[SHA1_DIGEST_SIZE];
+ int notAllZero;
+ memset(zeroDigest, 0, SHA1_DIGEST_SIZE);
+ notAllZero = memcmp(imaEvent->digest, zeroDigest, SHA1_DIGEST_SIZE);
+ /* for the SHA-256 zero extend */
+ memset(eventData, 0, SHA256_DIGEST_SIZE);
+
+ /* IMA has a quirk where some measurements store a zero digest in the event log, but
+ extend ones into PCR 10 */
+ if (notAllZero) {
+ memcpy(eventData, imaEvent->digest, SHA1_DIGEST_SIZE);
+ }
+ else {
+ memset(eventData, 0xff, SHA1_DIGEST_SIZE);
+ }
+ }
+ /* SHA-1 */
+ if (rc == 0) {
+ rc = TSS_Hash_Generate(&pcrs[0][imaEvent->pcrIndex],
+ SHA1_DIGEST_SIZE,
+ (uint8_t *)&pcrs[0][imaEvent->pcrIndex].digest,
+ SHA1_DIGEST_SIZE,
+ eventData,
+ 0, NULL);
+ }
+ /* SHA-256 */
+ if (rc == 0) {
+ rc = TSS_Hash_Generate(&pcrs[1][imaEvent->pcrIndex],
+ SHA256_DIGEST_SIZE,
+ (uint8_t *)&pcrs[1][imaEvent->pcrIndex].digest,
+ SHA256_DIGEST_SIZE,
+ eventData,
+ 0, NULL);
+ }
+ return rc;
+}
+
+#if 0
+/* IMA_Event_ToString() converts the ImaEvent structure to a hexascii string, big endian. */
+
+uint32_t IMA_Event_ToString(char **eventString, /* freed by caller */
+ ImaEvent *imaEvent)
+{
+ int rc = 0;
+ size_t length;
+
+ /* calculate size of string, from ImaEvent structure */
+ if (rc == 0) {
+ length = ((sizeof(uint32_t) + SHA1_DIGEST_SIZE + sizeof(uint32_t) +
+ TCG_EVENT_NAME_LEN_MAX + 1 + sizeof(uint32_t) +
+ imaEvent->template_data_len) * 2) + 1;
+ }
+ if (rc == 0) {
+ *eventString = malloc(length);
+ if (*eventString == NULL) {
+ printf("ERROR: IMA_Event_ToString: error allocating %lu bytes\n", length);
+ rc = TSS_RC_OUT_OF_MEMORY;
+ }
+ }
+ if (rc == 0) {
+ memset(*eventString, '\0', length);
+ char *p = *eventString;
+
+ sprintf(p, "%08lx", (long unsigned int)imaEvent->pcrIndex);
+ p += sizeof(uint32_t)* 2;
+
+ Array_Print(p, NULL, imaEvent->digest, SHA1_DIGEST_SIZE);
+ p += SHA1_DIGEST_SIZE * 2;
+
+ sprintf(p, "%08lx", (long unsigned int)imaEvent->name_len);
+ p += sizeof(uint32_t) * 2;
+
+ Array_Print(p, NULL, FALSE, (uint8_t *)imaEvent->name, imaEvent->name_len);
+ p += imaEvent->name_len * 2;
+
+ sprintf(p, "%08lx", (long unsigned int)imaEvent->template_data_len);
+ p += sizeof(uint32_t) * 2;
+
+ Array_Print(p, NULL, FALSE, imaEvent->template_data, imaEvent->template_data_len);
+ p += imaEvent->template_data_len * 2;
+ /* printf("IMA_Event_ToString: result\n:%s:\n", *eventString); */
+ }
+ return rc;
+}
+
+#endif
+