<commit_before>#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uchar.h>
#include <regex.h>

#include <tss2/tss2_tpm2_types.h>

#include "log.h"
#include "efi_event.h"
#include "tpm2_alg_util.h"
#include "tpm2_eventlog.h"
#include "tpm2_eventlog_yaml.h"
#include "tpm2_tool.h"
#include "tpm2_tool_output.h"

char const *eventtype_to_string (UINT32 event_type) {

    switch (event_type) {
    case EV_PREBOOT_CERT:
        return "EV_PREBOOT_CERT";
    case EV_POST_CODE:
        return "EV_POST_CODE";
    case EV_UNUSED:
        return "EV_UNUSED";
    case EV_NO_ACTION:
        return "EV_NO_ACTION";
    case EV_SEPARATOR:
        return "EV_SEPARATOR";
    case EV_ACTION:
        return "EV_ACTION";
    case EV_EVENT_TAG:
        return "EV_EVENT_TAG";
    case EV_S_CRTM_CONTENTS:
        return "EV_S_CRTM_CONTENTS";
    case EV_S_CRTM_VERSION:
        return "EV_S_CRTM_VERSION";
    case EV_CPU_MICROCODE:
        return "EV_CPU_MICROCODE";
    case EV_PLATFORM_CONFIG_FLAGS:
        return "EV_PLATFORM_CONFIG_FLAGS";
    case EV_TABLE_OF_DEVICES:
        return "EV_TABLE_OF_DEVICES";
    case EV_COMPACT_HASH:
        return "EV_COMPACT_HASH";
    case EV_IPL:
        return "EV_IPL";
    case EV_IPL_PARTITION_DATA:
        return "EV_IPL_PARTITION_DATA";
    case EV_NONHOST_CODE:
        return "EV_NONHOST_CODE";
    case EV_NONHOST_CONFIG:
        return "EV_NONHOST_CONFIG";
    case EV_NONHOST_INFO:
        return "EV_NONHOST_INFO";
    case EV_OMIT_BOOT_DEVICE_EVENTS:
        return "EV_OMIT_BOOT_DEVICE_EVENTS";
    case EV_EFI_VARIABLE_DRIVER_CONFIG:
        return "EV_EFI_VARIABLE_DRIVER_CONFIG";
    case EV_EFI_VARIABLE_BOOT:
        return "EV_EFI_VARIABLE_BOOT";
    case EV_EFI_BOOT_SERVICES_APPLICATION:
        return "EV_EFI_BOOT_SERVICES_APPLICATION";
    case EV_EFI_BOOT_SERVICES_DRIVER:
        return "EV_EFI_BOOT_SERVICES_DRIVER";
    case EV_EFI_RUNTIME_SERVICES_DRIVER:
        return "EV_EFI_RUNTIME_SERVICES_DRIVER";
    case EV_EFI_GPT_EVENT:
        return "EV_EFI_GPT_EVENT";
    case EV_EFI_ACTION:
        return "EV_EFI_ACTION";
    case EV_EFI_PLATFORM_FIRMWARE_BLOB:
        return "EV_EFI_PLATFORM_FIRMWARE_BLOB";
    case EV_EFI_HANDOFF_TABLES:
        return "EV_EFI_HANDOFF_TABLES";
    case EV_EFI_VARIABLE_AUTHORITY:
        return "EV_EFI_VARIABLE_AUTHORITY";
    default:
        return "Unknown event type";
    }
}
void bytes_to_str(uint8_t const *buf, size_t size, char *dest, size_t dest_size) {

    size_t i, j;

    for(i = 0, j = 0; i < size && j < dest_size - 2; ++i, j+=2) {
        sprintf(&dest[j], "%02x", buf[i]);
    }
    dest[j] = '\0';
}
void yaml_event2hdr(TCG_EVENT_HEADER2 const *eventhdr, size_t size) {

    (void)size;

    tpm2_tool_output("  PCRIndex: %d\n"
                     "  EventType: %s\n"
                     "  DigestCount: %d\n",
                     eventhdr->PCRIndex,
                     eventtype_to_string(eventhdr->EventType),
                     eventhdr->DigestCount);

    return;
}
void yaml_sha1_log_eventhdr(TCG_EVENT const *eventhdr, size_t size) {

    (void)size;

    tpm2_tool_output("  PCRIndex: %d\n"
                     "  EventType: %s\n",
                     eventhdr->pcrIndex,
                     eventtype_to_string(eventhdr->eventType));

    return;
}
/* converting byte buffer to hex string requires 2x, plus 1 for '\0' */
#define BYTES_TO_HEX_STRING_SIZE(byte_count) ((byte_count) * 2 + 1)
#define DIGEST_HEX_STRING_MAX BYTES_TO_HEX_STRING_SIZE(TPM2_MAX_DIGEST_BUFFER)
bool yaml_digest2(TCG_DIGEST2 const *digest, size_t size) {

    char hexstr[DIGEST_HEX_STRING_MAX] = { 0, };
    bytes_to_str(digest->Digest, size, hexstr, sizeof(hexstr));

    tpm2_tool_output("  - AlgorithmId: %s\n"
                     "    Digest: \"%s\"\n",
                     tpm2_alg_util_algtostr(digest->AlgorithmId, tpm2_alg_util_flags_hash),
                     hexstr);

    return true;
}
char *yaml_uefi_var_unicodename(UEFI_VARIABLE_DATA *data) {

    int ret = 0;
    mbstate_t st;

    memset(&st, '\0', sizeof(st));

    char *mbstr = calloc(data->UnicodeNameLength + 1, MB_CUR_MAX);
    char *tmp = mbstr;
    if (mbstr == NULL) {
        LOG_ERR("failed to allocate data: %s\n", strerror(errno));
        return NULL;
    }

    for(size_t i = 0; i < data->UnicodeNameLength; ++i, tmp += ret) {
        ret = c16rtomb(tmp, data->UnicodeName[i], &st);
        if (ret < 0) {
            LOG_ERR("c16rtomb failed: %s", strerror(errno));
            free(mbstr);
            return NULL;
        }
    }
    return mbstr;
}
#define VAR_DATA_HEX_SIZE(data) BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength)
static bool yaml_uefi_var_data(UEFI_VARIABLE_DATA *data) {

    if (data->VariableDataLength == 0) {
        return true;
    }

    char *var_data = calloc (1, VAR_DATA_HEX_SIZE(data));
    uint8_t *variable_data = (uint8_t*)&data->UnicodeName[
        data->UnicodeNameLength];
    if (var_data == NULL) {
        LOG_ERR("failled to allocate data: %s\n", strerror(errno));
        return false;
    }
    bytes_to_str(variable_data, data->VariableDataLength, var_data,
                 VAR_DATA_HEX_SIZE(data));

    tpm2_tool_output("    VariableData: \"%s\"\n", var_data);
    free(var_data);

    return true;
}
/*
 * TCG PC Client FPF section 2.3.4.1 and 9.4.1:
 * Usage of the event type EV_POST_CODE:
 * - If a combined event is measured, the event field SHOULD
 * be the string "POST CODE" in all caps. ...
 * - Embedded SMM code and the code that sets it up SHOULD use
 * the string "SMM CODE" in all caps...
 * - BIS code (excluding the BIS Certificate) should use event
 * field string of "BIS CODE" in all caps. ...
 * - ACPI flash data prior to any modifications ... should use
 * event field string of "ACPI DATA" in all caps.
 *
 * Section 9.2.5 also says "...Below is the definition of the
 * UEFI_PLATFORM_FIRMWARE_BLOB structure that the CRTM MUST put
 * into the Event Log entry TCG_PCR_EVENT2.event[1] field for
 * event types EV_POST_CODE, EV_S_CRTM_CONTENTS, and
 * EV_EFI_PLATFORM_FIRMWARE_BLOB."
 */

static bool yaml_uefi_post_code(const TCG_EVENT2* const event) {
    const size_t len = event->EventSize;

    /* if length is 16, we treat it as EV_EFI_PLATFORM_FIRMWARE_BLOB */
    if (len == 16) {
        const UEFI_PLATFORM_FIRMWARE_BLOB * const blob = \
            (const UEFI_PLATFORM_FIRMWARE_BLOB*) event->Event;
        tpm2_tool_output("  Event:\n"
                         "    BlobBase: 0x%" PRIx64 "\n"
                         "    BlobLength: 0x%" PRIx64 "\n",
                         blob->BlobBase,
                         blob->BlobLength);
    } else { // otherwise, we treat it as an ASCII string
        const char* const data = (const char *) event->Event;
        tpm2_tool_output("  Event: |-\n"
                         "    %.*s\n", (int) len, data);

    }
    return true;
}
/*
 * TCG PC Client FPF section 9.2.6
 * The tpm2_eventlog module validates the event structure but nothing within
 * the event data buffer so we must do that here.
 */
static bool yaml_uefi_var(UEFI_VARIABLE_DATA *data, size_t size, UINT32 type,
                          uint32_t eventlog_version) {

    char uuidstr[37] = { 0 };
    size_t start = 0;

    if (size < sizeof(*data)) {
        LOG_ERR("EventSize is too small\n");
        return false;
    }

    uuid_unparse_lower(data->VariableName, uuidstr);

    tpm2_tool_output("  Event:\n"
                     "    VariableName: %s\n"
                     "    UnicodeNameLength: %"PRIu64"\n"
                     "    VariableDataLength: %" PRIu64 "\n",
                     uuidstr, data->UnicodeNameLength,
                     data->VariableDataLength);

    start += sizeof(*data);
    if (start + data->UnicodeNameLength*2 > size) {
        LOG_ERR("EventSize is too small\n");
        return false;
    }

    char *ret = yaml_uefi_var_unicodename(data);
    if (!ret) {
        return false;
    }
    tpm2_tool_output("    UnicodeName: %s\n", ret);

    start += data->UnicodeNameLength*2;
    /* Try to parse as much as we can without fail-stop. Bugs in firmware, shim,
     * grub could produce inconsistent metadata. As long as it is not preventing
     * us from parsing the data, we try to continue while giving a warning
     * message.
     */
    if (start + data->VariableDataLength > size) {
        LOG_ERR("EventSize is inconsistent with actual data\n");
    }

    if (eventlog_version == 2) {
        /* PK, KEK, db, and dbx are reserved variables names used to store platform
         * keys, key exchange keys, database keys, and blacklisted database keys,
         * respectively.
         */
        if (type == EV_EFI_VARIABLE_DRIVER_CONFIG) {
            if ((strlen(ret) == 2 && strncmp(ret, "PK", 2) == 0) ||
                (strlen(ret) == 3 && strncmp(ret, "KEK", 3) == 0) ||
                (strlen(ret) == 2 && strncmp(ret, "db", 2) == 0) ||
                (strlen(ret) == 3 && strncmp(ret, "dbx", 3) == 0)) {

                free(ret);
                tpm2_tool_output("    VariableData:\n");
                uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
                    data->UnicodeNameLength];
                /* iterate through each EFI_SIGNATURE_LIST */
                while (start < size) {
                    EFI_SIGNATURE_LIST *slist = (EFI_SIGNATURE_LIST *)variable_data;
                    if (start + sizeof(*slist) > size) {
                        LOG_ERR("EventSize is inconsistent with actual data\n");
                        break;
                    }

                    if (slist->SignatureSize < 16) {
                        LOG_ERR("SignatureSize is too small\n");
                        break;
                    }

                    uuid_unparse_lower(slist->SignatureType, uuidstr);
                    tpm2_tool_output("    - SignatureType: %s\n"
                                     "      SignatureListSize: %" PRIu32 "\n"
                                     "      SignatureHeaderSize: %" PRIu32 "\n"
                                     "      SignatureSize: %" PRIu32 "\n"
                                     "      Keys:\n",
                                     uuidstr, slist->SignatureListSize,
                                     slist->SignatureHeaderSize,
                                     slist->SignatureSize);

                    start += (sizeof(*slist) + slist->SignatureHeaderSize);
                    if (start + slist->SignatureSize > size) {
                        LOG_ERR("EventSize is inconsistent with actual data\n");
                        break;
                    }

                    int signature_size = slist->SignatureListSize -
                        sizeof(*slist) - slist->SignatureHeaderSize;
                    if (signature_size < 0 || signature_size % slist->SignatureSize != 0) {
                        LOG_ERR("Malformed EFI_SIGNATURE_LIST\n");
                        break;
                    }

                    uint8_t *signature = (uint8_t *)slist +
                        sizeof(*slist) + slist->SignatureHeaderSize;
                    int signatures = signature_size / slist->SignatureSize;
                    /* iterate through each EFI_SIGNATURE on the list */
                    int i;
                    for (i = 0; i < signatures; i++) {
                        EFI_SIGNATURE_DATA *s = (EFI_SIGNATURE_DATA *)signature;
                        char *sdata = calloc (1,
                            BYTES_TO_HEX_STRING_SIZE(slist->SignatureSize-16));
                        if (sdata == NULL) {
                            LOG_ERR("Failled to allocate data: %s\n", strerror(errno));
                            return false;
                        }
                        bytes_to_str(s->SignatureData, slist->SignatureSize-16,
                            sdata, BYTES_TO_HEX_STRING_SIZE(slist->SignatureSize-16));
                        uuid_unparse_lower(s->SignatureOwner, uuidstr);
                        tpm2_tool_output("      - SignatureOwner: %s\n"
                                         "        SignatureData: %s\n",
                                         uuidstr, sdata);
                        free(sdata);

                        signature += slist->SignatureSize;
                        start += slist->SignatureSize;
                        if (start > size) {
                            LOG_ERR("Malformed EFI_SIGNATURE_DATA\n");
                            break;
                        }
                    }
                    variable_data += slist->SignatureListSize;
                }
                return true;
            } else if ((strlen(ret) == 10 && strncmp(ret, "SecureBoot", 10) == 0)) {
                free(ret);
                tpm2_tool_output("    VariableData:\n"
                                 "      Enabled: ");
                if (data->VariableDataLength == 0) {
                    tpm2_tool_output("'No'\n");
                } else if (data->VariableDataLength > 1) {
                    LOG_ERR("SecureBoot value length %" PRIu64 " is unexpectedly > 1\n",
                            data->VariableDataLength);
                    return false;
                } else {
                    uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
                        data->UnicodeNameLength];
                    if (*variable_data == 0) {
                        tpm2_tool_output("'No'\n");
                    } else {
                        tpm2_tool_output("'Yes'\n");
                    }
                }
                return true;
            }
            /* Other variables will be printed as a hex string */
        } else if (type == EV_EFI_VARIABLE_AUTHORITY) {
            free(ret);
            tpm2_tool_output("    VariableData:\n");
            
            EFI_SIGNATURE_DATA *s= (EFI_SIGNATURE_DATA *)&data->UnicodeName[
                data->UnicodeNameLength];
            char *sdata = calloc (1,
                BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength - 16));
            if (sdata == NULL) {
                LOG_ERR("Failled to allocate data: %s\n", strerror(errno));
                return false;
            }
            bytes_to_str(s->SignatureData, data->VariableDataLength - 16,
                sdata, BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength - 16));
            uuid_unparse_lower(s->SignatureOwner, uuidstr);
            tpm2_tool_output("    - SignatureOwner: %s\n"
                             "      SignatureData: %s\n",
                             uuidstr, sdata);
            free(sdata);
            return true;
        } else if (type == EV_EFI_VARIABLE_BOOT) {
            if ((strlen(ret) == 9 && strncmp(ret, "BootOrder", 9) == 0)) {
                free(ret);
                tpm2_tool_output("    VariableData:\n");
                
                if (data->VariableDataLength % 2 != 0) {
                    LOG_ERR("BootOrder value length %" PRIu64 " is not divisible by 2\n",
                            data->VariableDataLength);
                    return false;
                }

                uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
                    data->UnicodeNameLength];
                for (uint64_t i = 0; i < data->VariableDataLength / 2; i++) {
                    tpm2_tool_output("    - Boot%04x\n", *((uint16_t*)variable_data + i));
                }
                return true;
            }

            regex_t regex;
            int r;

            r = regcomp(&regex, "^Boot[0-9a-fA-F]\\{4\\}$", 0);
            if (r != 0) {
                free(ret);
                LOG_ERR("regcomp() returned %d\n", r);
                return false;
            }

            r = regexec(&regex, ret, 0, NULL, 0);
            if (r == 0) {
                free(ret);
                tpm2_tool_output("    VariableData:\n"
                                 "      Enabled: ");
                EFI_LOAD_OPTION *loadopt = (EFI_LOAD_OPTION*)&data->UnicodeName[
                    data->UnicodeNameLength];

                if (loadopt->Attributes & 1) {
                    tpm2_tool_output("'Yes'\n");
                } else {
                    tpm2_tool_output("'No'\n");
                }

                tpm2_tool_output("      FilePathListLength: %" PRIu16 "\n",
                    loadopt->FilePathListLength);

                tpm2_tool_output("      Description: \"");
                int i;
                for (i = 0; (wchar_t)loadopt->Description[i] != 0; i++) {<commit_msg>avoid using regex<commit_after>#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uchar.h>

#include <tss2/tss2_tpm2_types.h>

#include "log.h"
#include "efi_event.h"
#include "tpm2_alg_util.h"
#include "tpm2_eventlog.h"
#include "tpm2_eventlog_yaml.h"
#include "tpm2_tool.h"
#include "tpm2_tool_output.h"

char const *eventtype_to_string (UINT32 event_type) {

    switch (event_type) {
    case EV_PREBOOT_CERT:
        return "EV_PREBOOT_CERT";
    case EV_POST_CODE:
        return "EV_POST_CODE";
    case EV_UNUSED:
        return "EV_UNUSED";
    case EV_NO_ACTION:
        return "EV_NO_ACTION";
    case EV_SEPARATOR:
        return "EV_SEPARATOR";
    case EV_ACTION:
        return "EV_ACTION";
    case EV_EVENT_TAG:
        return "EV_EVENT_TAG";
    case EV_S_CRTM_CONTENTS:
        return "EV_S_CRTM_CONTENTS";
    case EV_S_CRTM_VERSION:
        return "EV_S_CRTM_VERSION";
    case EV_CPU_MICROCODE:
        return "EV_CPU_MICROCODE";
    case EV_PLATFORM_CONFIG_FLAGS:
        return "EV_PLATFORM_CONFIG_FLAGS";
    case EV_TABLE_OF_DEVICES:
        return "EV_TABLE_OF_DEVICES";
    case EV_COMPACT_HASH:
        return "EV_COMPACT_HASH";
    case EV_IPL:
        return "EV_IPL";
    case EV_IPL_PARTITION_DATA:
        return "EV_IPL_PARTITION_DATA";
    case EV_NONHOST_CODE:
        return "EV_NONHOST_CODE";
    case EV_NONHOST_CONFIG:
        return "EV_NONHOST_CONFIG";
    case EV_NONHOST_INFO:
        return "EV_NONHOST_INFO";
    case EV_OMIT_BOOT_DEVICE_EVENTS:
        return "EV_OMIT_BOOT_DEVICE_EVENTS";
    case EV_EFI_VARIABLE_DRIVER_CONFIG:
        return "EV_EFI_VARIABLE_DRIVER_CONFIG";
    case EV_EFI_VARIABLE_BOOT:
        return "EV_EFI_VARIABLE_BOOT";
    case EV_EFI_BOOT_SERVICES_APPLICATION:
        return "EV_EFI_BOOT_SERVICES_APPLICATION";
    case EV_EFI_BOOT_SERVICES_DRIVER:
        return "EV_EFI_BOOT_SERVICES_DRIVER";
    case EV_EFI_RUNTIME_SERVICES_DRIVER:
        return "EV_EFI_RUNTIME_SERVICES_DRIVER";
    case EV_EFI_GPT_EVENT:
        return "EV_EFI_GPT_EVENT";
    case EV_EFI_ACTION:
        return "EV_EFI_ACTION";
    case EV_EFI_PLATFORM_FIRMWARE_BLOB:
        return "EV_EFI_PLATFORM_FIRMWARE_BLOB";
    case EV_EFI_HANDOFF_TABLES:
        return "EV_EFI_HANDOFF_TABLES";
    case EV_EFI_VARIABLE_AUTHORITY:
        return "EV_EFI_VARIABLE_AUTHORITY";
    default:
        return "Unknown event type";
    }
}
void bytes_to_str(uint8_t const *buf, size_t size, char *dest, size_t dest_size) {

    size_t i, j;

    for(i = 0, j = 0; i < size && j < dest_size - 2; ++i, j+=2) {
        sprintf(&dest[j], "%02x", buf[i]);
    }
    dest[j] = '\0';
}
void yaml_event2hdr(TCG_EVENT_HEADER2 const *eventhdr, size_t size) {

    (void)size;

    tpm2_tool_output("  PCRIndex: %d\n"
                     "  EventType: %s\n"
                     "  DigestCount: %d\n",
                     eventhdr->PCRIndex,
                     eventtype_to_string(eventhdr->EventType),
                     eventhdr->DigestCount);

    return;
}
void yaml_sha1_log_eventhdr(TCG_EVENT const *eventhdr, size_t size) {

    (void)size;

    tpm2_tool_output("  PCRIndex: %d\n"
                     "  EventType: %s\n",
                     eventhdr->pcrIndex,
                     eventtype_to_string(eventhdr->eventType));

    return;
}
/* converting byte buffer to hex string requires 2x, plus 1 for '\0' */
#define BYTES_TO_HEX_STRING_SIZE(byte_count) ((byte_count) * 2 + 1)
#define DIGEST_HEX_STRING_MAX BYTES_TO_HEX_STRING_SIZE(TPM2_MAX_DIGEST_BUFFER)
bool yaml_digest2(TCG_DIGEST2 const *digest, size_t size) {

    char hexstr[DIGEST_HEX_STRING_MAX] = { 0, };
    bytes_to_str(digest->Digest, size, hexstr, sizeof(hexstr));

    tpm2_tool_output("  - AlgorithmId: %s\n"
                     "    Digest: \"%s\"\n",
                     tpm2_alg_util_algtostr(digest->AlgorithmId, tpm2_alg_util_flags_hash),
                     hexstr);

    return true;
}
char *yaml_uefi_var_unicodename(UEFI_VARIABLE_DATA *data) {

    int ret = 0;
    mbstate_t st;

    memset(&st, '\0', sizeof(st));

    char *mbstr = calloc(data->UnicodeNameLength + 1, MB_CUR_MAX);
    char *tmp = mbstr;
    if (mbstr == NULL) {
        LOG_ERR("failed to allocate data: %s\n", strerror(errno));
        return NULL;
    }

    for(size_t i = 0; i < data->UnicodeNameLength; ++i, tmp += ret) {
        ret = c16rtomb(tmp, data->UnicodeName[i], &st);
        if (ret < 0) {
            LOG_ERR("c16rtomb failed: %s", strerror(errno));
            free(mbstr);
            return NULL;
        }
    }
    return mbstr;
}
#define VAR_DATA_HEX_SIZE(data) BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength)
static bool yaml_uefi_var_data(UEFI_VARIABLE_DATA *data) {

    if (data->VariableDataLength == 0) {
        return true;
    }

    char *var_data = calloc (1, VAR_DATA_HEX_SIZE(data));
    uint8_t *variable_data = (uint8_t*)&data->UnicodeName[
        data->UnicodeNameLength];
    if (var_data == NULL) {
        LOG_ERR("failled to allocate data: %s\n", strerror(errno));
        return false;
    }
    bytes_to_str(variable_data, data->VariableDataLength, var_data,
                 VAR_DATA_HEX_SIZE(data));

    tpm2_tool_output("    VariableData: \"%s\"\n", var_data);
    free(var_data);

    return true;
}
/*
 * TCG PC Client FPF section 2.3.4.1 and 9.4.1:
 * Usage of the event type EV_POST_CODE:
 * - If a combined event is measured, the event field SHOULD
 * be the string "POST CODE" in all caps. ...
 * - Embedded SMM code and the code that sets it up SHOULD use
 * the string "SMM CODE" in all caps...
 * - BIS code (excluding the BIS Certificate) should use event
 * field string of "BIS CODE" in all caps. ...
 * - ACPI flash data prior to any modifications ... should use
 * event field string of "ACPI DATA" in all caps.
 *
 * Section 9.2.5 also says "...Below is the definition of the
 * UEFI_PLATFORM_FIRMWARE_BLOB structure that the CRTM MUST put
 * into the Event Log entry TCG_PCR_EVENT2.event[1] field for
 * event types EV_POST_CODE, EV_S_CRTM_CONTENTS, and
 * EV_EFI_PLATFORM_FIRMWARE_BLOB."
 */

static bool yaml_uefi_post_code(const TCG_EVENT2* const event) {
    const size_t len = event->EventSize;

    /* if length is 16, we treat it as EV_EFI_PLATFORM_FIRMWARE_BLOB */
    if (len == 16) {
        const UEFI_PLATFORM_FIRMWARE_BLOB * const blob = \
            (const UEFI_PLATFORM_FIRMWARE_BLOB*) event->Event;
        tpm2_tool_output("  Event:\n"
                         "    BlobBase: 0x%" PRIx64 "\n"
                         "    BlobLength: 0x%" PRIx64 "\n",
                         blob->BlobBase,
                         blob->BlobLength);
    } else { // otherwise, we treat it as an ASCII string
        const char* const data = (const char *) event->Event;
        tpm2_tool_output("  Event: |-\n"
                         "    %.*s\n", (int) len, data);

    }
    return true;
}
/*
 * TCG PC Client FPF section 9.2.6
 * The tpm2_eventlog module validates the event structure but nothing within
 * the event data buffer so we must do that here.
 */
static bool yaml_uefi_var(UEFI_VARIABLE_DATA *data, size_t size, UINT32 type,
                          uint32_t eventlog_version) {

    char uuidstr[37] = { 0 };
    size_t start = 0;

    if (size < sizeof(*data)) {
        LOG_ERR("EventSize is too small\n");
        return false;
    }

    uuid_unparse_lower(data->VariableName, uuidstr);

    tpm2_tool_output("  Event:\n"
                     "    VariableName: %s\n"
                     "    UnicodeNameLength: %"PRIu64"\n"
                     "    VariableDataLength: %" PRIu64 "\n",
                     uuidstr, data->UnicodeNameLength,
                     data->VariableDataLength);

    start += sizeof(*data);
    if (start + data->UnicodeNameLength*2 > size) {
        LOG_ERR("EventSize is too small\n");
        return false;
    }

    char *ret = yaml_uefi_var_unicodename(data);
    if (!ret) {
        return false;
    }
    tpm2_tool_output("    UnicodeName: %s\n", ret);

    start += data->UnicodeNameLength*2;
    /* Try to parse as much as we can without fail-stop. Bugs in firmware, shim,
     * grub could produce inconsistent metadata. As long as it is not preventing
     * us from parsing the data, we try to continue while giving a warning
     * message.
     */
    if (start + data->VariableDataLength > size) {
        LOG_ERR("EventSize is inconsistent with actual data\n");
    }

    if (eventlog_version == 2) {
        /* PK, KEK, db, and dbx are reserved variables names used to store platform
         * keys, key exchange keys, database keys, and blacklisted database keys,
         * respectively.
         */
        if (type == EV_EFI_VARIABLE_DRIVER_CONFIG) {
            if ((strlen(ret) == 2 && strncmp(ret, "PK", 2) == 0) ||
                (strlen(ret) == 3 && strncmp(ret, "KEK", 3) == 0) ||
                (strlen(ret) == 2 && strncmp(ret, "db", 2) == 0) ||
                (strlen(ret) == 3 && strncmp(ret, "dbx", 3) == 0)) {

                free(ret);
                tpm2_tool_output("    VariableData:\n");
                uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
                    data->UnicodeNameLength];
                /* iterate through each EFI_SIGNATURE_LIST */
                while (start < size) {
                    EFI_SIGNATURE_LIST *slist = (EFI_SIGNATURE_LIST *)variable_data;
                    if (start + sizeof(*slist) > size) {
                        LOG_ERR("EventSize is inconsistent with actual data\n");
                        break;
                    }

                    if (slist->SignatureSize < 16) {
                        LOG_ERR("SignatureSize is too small\n");
                        break;
                    }

                    uuid_unparse_lower(slist->SignatureType, uuidstr);
                    tpm2_tool_output("    - SignatureType: %s\n"
                                     "      SignatureListSize: %" PRIu32 "\n"
                                     "      SignatureHeaderSize: %" PRIu32 "\n"
                                     "      SignatureSize: %" PRIu32 "\n"
                                     "      Keys:\n",
                                     uuidstr, slist->SignatureListSize,
                                     slist->SignatureHeaderSize,
                                     slist->SignatureSize);

                    start += (sizeof(*slist) + slist->SignatureHeaderSize);
                    if (start + slist->SignatureSize > size) {
                        LOG_ERR("EventSize is inconsistent with actual data\n");
                        break;
                    }

                    int signature_size = slist->SignatureListSize -
                        sizeof(*slist) - slist->SignatureHeaderSize;
                    if (signature_size < 0 || signature_size % slist->SignatureSize != 0) {
                        LOG_ERR("Malformed EFI_SIGNATURE_LIST\n");
                        break;
                    }

                    uint8_t *signature = (uint8_t *)slist +
                        sizeof(*slist) + slist->SignatureHeaderSize;
                    int signatures = signature_size / slist->SignatureSize;
                    /* iterate through each EFI_SIGNATURE on the list */
                    int i;
                    for (i = 0; i < signatures; i++) {
                        EFI_SIGNATURE_DATA *s = (EFI_SIGNATURE_DATA *)signature;
                        char *sdata = calloc (1,
                            BYTES_TO_HEX_STRING_SIZE(slist->SignatureSize-16));
                        if (sdata == NULL) {
                            LOG_ERR("Failled to allocate data: %s\n", strerror(errno));
                            return false;
                        }
                        bytes_to_str(s->SignatureData, slist->SignatureSize-16,
                            sdata, BYTES_TO_HEX_STRING_SIZE(slist->SignatureSize-16));
                        uuid_unparse_lower(s->SignatureOwner, uuidstr);
                        tpm2_tool_output("      - SignatureOwner: %s\n"
                                         "        SignatureData: %s\n",
                                         uuidstr, sdata);
                        free(sdata);

                        signature += slist->SignatureSize;
                        start += slist->SignatureSize;
                        if (start > size) {
                            LOG_ERR("Malformed EFI_SIGNATURE_DATA\n");
                            break;
                        }
                    }
                    variable_data += slist->SignatureListSize;
                }
                return true;
            } else if ((strlen(ret) == 10 && strncmp(ret, "SecureBoot", 10) == 0)) {
                free(ret);
                tpm2_tool_output("    VariableData:\n"
                                 "      Enabled: ");
                if (data->VariableDataLength == 0) {
                    tpm2_tool_output("'No'\n");
                } else if (data->VariableDataLength > 1) {
                    LOG_ERR("SecureBoot value length %" PRIu64 " is unexpectedly > 1\n",
                            data->VariableDataLength);
                    return false;
                } else {
                    uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
                        data->UnicodeNameLength];
                    if (*variable_data == 0) {
                        tpm2_tool_output("'No'\n");
                    } else {
                        tpm2_tool_output("'Yes'\n");
                    }
                }
                return true;
            }
            /* Other variables will be printed as a hex string */
        } else if (type == EV_EFI_VARIABLE_AUTHORITY) {
            free(ret);
            tpm2_tool_output("    VariableData:\n");
            
            EFI_SIGNATURE_DATA *s= (EFI_SIGNATURE_DATA *)&data->UnicodeName[
                data->UnicodeNameLength];
            char *sdata = calloc (1,
                BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength - 16));
            if (sdata == NULL) {
                LOG_ERR("Failled to allocate data: %s\n", strerror(errno));
                return false;
            }
            bytes_to_str(s->SignatureData, data->VariableDataLength - 16,
                sdata, BYTES_TO_HEX_STRING_SIZE(data->VariableDataLength - 16));
            uuid_unparse_lower(s->SignatureOwner, uuidstr);
            tpm2_tool_output("    - SignatureOwner: %s\n"
                             "      SignatureData: %s\n",
                             uuidstr, sdata);
            free(sdata);
            return true;
        } else if (type == EV_EFI_VARIABLE_BOOT) {
            if ((strlen(ret) == 9 && strncmp(ret, "BootOrder", 9) == 0)) {
                free(ret);
                tpm2_tool_output("    VariableData:\n");
                
                if (data->VariableDataLength % 2 != 0) {
                    LOG_ERR("BootOrder value length %" PRIu64 " is not divisible by 2\n",
                            data->VariableDataLength);
                    return false;
                }

                uint8_t *variable_data = (uint8_t *)&data->UnicodeName[
                    data->UnicodeNameLength];
                for (uint64_t i = 0; i < data->VariableDataLength / 2; i++) {
                    tpm2_tool_output("    - Boot%04x\n", *((uint16_t*)variable_data + i));
                }
                return true;
            }

            /* Test for regex "^Boot[0-9a-fA-F]\\{4\\}$" */
            if (strlen(ret) == 8 && strncmp(ret, "Boot", 4) == 0 &&
                isxdigit((int)ret[4]) && isxdigit((int)ret[5]) &&
                isxdigit((int)ret[6]) && isxdigit((int)ret[7])) {

                free(ret);
                tpm2_tool_output("    VariableData:\n"
                                 "      Enabled: ");
                EFI_LOAD_OPTION *loadopt = (EFI_LOAD_OPTION*)&data->UnicodeName[
                    data->UnicodeNameLength];

                if (loadopt->Attributes & 1) {
                    tpm2_tool_output("'Yes'\n");
                } else {
                    tpm2_tool_output("'No'\n");
                }

                tpm2_tool_output("      FilePathListLength: %" PRIu16 "\n",
                    loadopt->FilePathListLength);

                tpm2_tool_output("      Description: \"");
                int i;
                for (i = 0; (wchar_t)loadopt->Description[i] != 0; i++) {
{'fraction_non_alphanumeric': 0.1059267078871965, 'fraction_numerical': 0.011883577137686624, 'mean_word_length': 1.6781906300484652, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 173, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4193384', 'n_tokens_mistral': 10732, 'n_tokens_neox': 10138, 'n_words': 2192}