163d2a5c7SDorjoy Chowdhury /* 263d2a5c7SDorjoy Chowdhury * EIF (Enclave Image Format) related helpers 363d2a5c7SDorjoy Chowdhury * 463d2a5c7SDorjoy Chowdhury * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com> 563d2a5c7SDorjoy Chowdhury * 663d2a5c7SDorjoy Chowdhury * This work is licensed under the terms of the GNU GPL, version 2 or 763d2a5c7SDorjoy Chowdhury * (at your option) any later version. See the COPYING file in the 863d2a5c7SDorjoy Chowdhury * top-level directory. 963d2a5c7SDorjoy Chowdhury */ 1063d2a5c7SDorjoy Chowdhury 1163d2a5c7SDorjoy Chowdhury #include "qemu/osdep.h" 1263d2a5c7SDorjoy Chowdhury #include "qemu/bswap.h" 1363d2a5c7SDorjoy Chowdhury #include "qapi/error.h" 1463d2a5c7SDorjoy Chowdhury #include "crypto/hash.h" 1563d2a5c7SDorjoy Chowdhury #include "crypto/x509-utils.h" 1663d2a5c7SDorjoy Chowdhury #include <zlib.h> /* for crc32 */ 1763d2a5c7SDorjoy Chowdhury #include <cbor.h> 1863d2a5c7SDorjoy Chowdhury 1963d2a5c7SDorjoy Chowdhury #include "hw/core/eif.h" 2063d2a5c7SDorjoy Chowdhury 2163d2a5c7SDorjoy Chowdhury #define MAX_SECTIONS 32 2263d2a5c7SDorjoy Chowdhury 2363d2a5c7SDorjoy Chowdhury /* members are ordered according to field order in .eif file */ 2463d2a5c7SDorjoy Chowdhury typedef struct EifHeader { 2563d2a5c7SDorjoy Chowdhury uint8_t magic[4]; /* must be .eif in ascii i.e., [46, 101, 105, 102] */ 2663d2a5c7SDorjoy Chowdhury uint16_t version; 2763d2a5c7SDorjoy Chowdhury uint16_t flags; 2863d2a5c7SDorjoy Chowdhury uint64_t default_memory; 2963d2a5c7SDorjoy Chowdhury uint64_t default_cpus; 3063d2a5c7SDorjoy Chowdhury uint16_t reserved; 3163d2a5c7SDorjoy Chowdhury uint16_t section_cnt; 3263d2a5c7SDorjoy Chowdhury uint64_t section_offsets[MAX_SECTIONS]; 3363d2a5c7SDorjoy Chowdhury uint64_t section_sizes[MAX_SECTIONS]; 3463d2a5c7SDorjoy Chowdhury uint32_t unused; 3563d2a5c7SDorjoy Chowdhury uint32_t eif_crc32; 3663d2a5c7SDorjoy Chowdhury } QEMU_PACKED EifHeader; 3763d2a5c7SDorjoy Chowdhury 3863d2a5c7SDorjoy Chowdhury /* members are ordered according to field order in .eif file */ 3963d2a5c7SDorjoy Chowdhury typedef struct EifSectionHeader { 4063d2a5c7SDorjoy Chowdhury /* 4163d2a5c7SDorjoy Chowdhury * 0 = invalid, 1 = kernel, 2 = cmdline, 3 = ramdisk, 4 = signature, 4263d2a5c7SDorjoy Chowdhury * 5 = metadata 4363d2a5c7SDorjoy Chowdhury */ 4463d2a5c7SDorjoy Chowdhury uint16_t section_type; 4563d2a5c7SDorjoy Chowdhury uint16_t flags; 4663d2a5c7SDorjoy Chowdhury uint64_t section_size; 4763d2a5c7SDorjoy Chowdhury } QEMU_PACKED EifSectionHeader; 4863d2a5c7SDorjoy Chowdhury 4963d2a5c7SDorjoy Chowdhury enum EifSectionTypes { 5063d2a5c7SDorjoy Chowdhury EIF_SECTION_INVALID = 0, 5163d2a5c7SDorjoy Chowdhury EIF_SECTION_KERNEL = 1, 5263d2a5c7SDorjoy Chowdhury EIF_SECTION_CMDLINE = 2, 5363d2a5c7SDorjoy Chowdhury EIF_SECTION_RAMDISK = 3, 5463d2a5c7SDorjoy Chowdhury EIF_SECTION_SIGNATURE = 4, 5563d2a5c7SDorjoy Chowdhury EIF_SECTION_METADATA = 5, 5663d2a5c7SDorjoy Chowdhury EIF_SECTION_MAX = 6, 5763d2a5c7SDorjoy Chowdhury }; 5863d2a5c7SDorjoy Chowdhury 5963d2a5c7SDorjoy Chowdhury static const char *section_type_to_string(uint16_t type) 6063d2a5c7SDorjoy Chowdhury { 6163d2a5c7SDorjoy Chowdhury const char *str; 6263d2a5c7SDorjoy Chowdhury switch (type) { 6363d2a5c7SDorjoy Chowdhury case EIF_SECTION_INVALID: 6463d2a5c7SDorjoy Chowdhury str = "invalid"; 6563d2a5c7SDorjoy Chowdhury break; 6663d2a5c7SDorjoy Chowdhury case EIF_SECTION_KERNEL: 6763d2a5c7SDorjoy Chowdhury str = "kernel"; 6863d2a5c7SDorjoy Chowdhury break; 6963d2a5c7SDorjoy Chowdhury case EIF_SECTION_CMDLINE: 7063d2a5c7SDorjoy Chowdhury str = "cmdline"; 7163d2a5c7SDorjoy Chowdhury break; 7263d2a5c7SDorjoy Chowdhury case EIF_SECTION_RAMDISK: 7363d2a5c7SDorjoy Chowdhury str = "ramdisk"; 7463d2a5c7SDorjoy Chowdhury break; 7563d2a5c7SDorjoy Chowdhury case EIF_SECTION_SIGNATURE: 7663d2a5c7SDorjoy Chowdhury str = "signature"; 7763d2a5c7SDorjoy Chowdhury break; 7863d2a5c7SDorjoy Chowdhury case EIF_SECTION_METADATA: 7963d2a5c7SDorjoy Chowdhury str = "metadata"; 8063d2a5c7SDorjoy Chowdhury break; 8163d2a5c7SDorjoy Chowdhury default: 8263d2a5c7SDorjoy Chowdhury str = "unknown"; 8363d2a5c7SDorjoy Chowdhury break; 8463d2a5c7SDorjoy Chowdhury } 8563d2a5c7SDorjoy Chowdhury 8663d2a5c7SDorjoy Chowdhury return str; 8763d2a5c7SDorjoy Chowdhury } 8863d2a5c7SDorjoy Chowdhury 8963d2a5c7SDorjoy Chowdhury static bool read_eif_header(FILE *f, EifHeader *header, uint32_t *crc, 9063d2a5c7SDorjoy Chowdhury Error **errp) 9163d2a5c7SDorjoy Chowdhury { 9263d2a5c7SDorjoy Chowdhury size_t got; 9363d2a5c7SDorjoy Chowdhury size_t header_size = sizeof(*header); 9463d2a5c7SDorjoy Chowdhury 9563d2a5c7SDorjoy Chowdhury got = fread(header, 1, header_size, f); 9663d2a5c7SDorjoy Chowdhury if (got != header_size) { 9763d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF header"); 9863d2a5c7SDorjoy Chowdhury return false; 9963d2a5c7SDorjoy Chowdhury } 10063d2a5c7SDorjoy Chowdhury 10163d2a5c7SDorjoy Chowdhury if (memcmp(header->magic, ".eif", 4) != 0) { 10263d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. Magic mismatch."); 10363d2a5c7SDorjoy Chowdhury return false; 10463d2a5c7SDorjoy Chowdhury } 10563d2a5c7SDorjoy Chowdhury 10663d2a5c7SDorjoy Chowdhury /* Exclude header->eif_crc32 field from CRC calculation */ 10763d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, (uint8_t *)header, header_size - 4); 10863d2a5c7SDorjoy Chowdhury 10963d2a5c7SDorjoy Chowdhury header->version = be16_to_cpu(header->version); 11063d2a5c7SDorjoy Chowdhury header->flags = be16_to_cpu(header->flags); 11163d2a5c7SDorjoy Chowdhury header->default_memory = be64_to_cpu(header->default_memory); 11263d2a5c7SDorjoy Chowdhury header->default_cpus = be64_to_cpu(header->default_cpus); 11363d2a5c7SDorjoy Chowdhury header->reserved = be16_to_cpu(header->reserved); 11463d2a5c7SDorjoy Chowdhury header->section_cnt = be16_to_cpu(header->section_cnt); 11563d2a5c7SDorjoy Chowdhury 11663d2a5c7SDorjoy Chowdhury for (int i = 0; i < MAX_SECTIONS; ++i) { 11763d2a5c7SDorjoy Chowdhury header->section_offsets[i] = be64_to_cpu(header->section_offsets[i]); 11863d2a5c7SDorjoy Chowdhury } 11963d2a5c7SDorjoy Chowdhury 12063d2a5c7SDorjoy Chowdhury for (int i = 0; i < MAX_SECTIONS; ++i) { 12163d2a5c7SDorjoy Chowdhury header->section_sizes[i] = be64_to_cpu(header->section_sizes[i]); 12263d2a5c7SDorjoy Chowdhury } 12363d2a5c7SDorjoy Chowdhury 12463d2a5c7SDorjoy Chowdhury header->unused = be32_to_cpu(header->unused); 12563d2a5c7SDorjoy Chowdhury header->eif_crc32 = be32_to_cpu(header->eif_crc32); 12663d2a5c7SDorjoy Chowdhury return true; 12763d2a5c7SDorjoy Chowdhury } 12863d2a5c7SDorjoy Chowdhury 12963d2a5c7SDorjoy Chowdhury static bool read_eif_section_header(FILE *f, EifSectionHeader *section_header, 13063d2a5c7SDorjoy Chowdhury uint32_t *crc, Error **errp) 13163d2a5c7SDorjoy Chowdhury { 13263d2a5c7SDorjoy Chowdhury size_t got; 13363d2a5c7SDorjoy Chowdhury size_t section_header_size = sizeof(*section_header); 13463d2a5c7SDorjoy Chowdhury 13563d2a5c7SDorjoy Chowdhury got = fread(section_header, 1, section_header_size, f); 13663d2a5c7SDorjoy Chowdhury if (got != section_header_size) { 13763d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF section header"); 13863d2a5c7SDorjoy Chowdhury return false; 13963d2a5c7SDorjoy Chowdhury } 14063d2a5c7SDorjoy Chowdhury 14163d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, (uint8_t *)section_header, section_header_size); 14263d2a5c7SDorjoy Chowdhury 14363d2a5c7SDorjoy Chowdhury section_header->section_type = be16_to_cpu(section_header->section_type); 14463d2a5c7SDorjoy Chowdhury section_header->flags = be16_to_cpu(section_header->flags); 14563d2a5c7SDorjoy Chowdhury section_header->section_size = be64_to_cpu(section_header->section_size); 14663d2a5c7SDorjoy Chowdhury return true; 14763d2a5c7SDorjoy Chowdhury } 14863d2a5c7SDorjoy Chowdhury 14963d2a5c7SDorjoy Chowdhury /* 15063d2a5c7SDorjoy Chowdhury * Upon success, the caller is responsible for unlinking and freeing *tmp_path. 15163d2a5c7SDorjoy Chowdhury */ 15263d2a5c7SDorjoy Chowdhury static bool get_tmp_file(const char *template, char **tmp_path, Error **errp) 15363d2a5c7SDorjoy Chowdhury { 15463d2a5c7SDorjoy Chowdhury int tmp_fd; 15563d2a5c7SDorjoy Chowdhury 15663d2a5c7SDorjoy Chowdhury *tmp_path = NULL; 15763d2a5c7SDorjoy Chowdhury tmp_fd = g_file_open_tmp(template, tmp_path, NULL); 15863d2a5c7SDorjoy Chowdhury if (tmp_fd < 0 || *tmp_path == NULL) { 15963d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to create temporary file for template %s", 16063d2a5c7SDorjoy Chowdhury template); 16163d2a5c7SDorjoy Chowdhury return false; 16263d2a5c7SDorjoy Chowdhury } 16363d2a5c7SDorjoy Chowdhury 16463d2a5c7SDorjoy Chowdhury close(tmp_fd); 16563d2a5c7SDorjoy Chowdhury return true; 16663d2a5c7SDorjoy Chowdhury } 16763d2a5c7SDorjoy Chowdhury 16863d2a5c7SDorjoy Chowdhury static void safe_fclose(FILE *f) 16963d2a5c7SDorjoy Chowdhury { 17063d2a5c7SDorjoy Chowdhury if (f) { 17163d2a5c7SDorjoy Chowdhury fclose(f); 17263d2a5c7SDorjoy Chowdhury } 17363d2a5c7SDorjoy Chowdhury } 17463d2a5c7SDorjoy Chowdhury 17563d2a5c7SDorjoy Chowdhury static void safe_unlink(char *f) 17663d2a5c7SDorjoy Chowdhury { 17763d2a5c7SDorjoy Chowdhury if (f) { 17863d2a5c7SDorjoy Chowdhury unlink(f); 17963d2a5c7SDorjoy Chowdhury } 18063d2a5c7SDorjoy Chowdhury } 18163d2a5c7SDorjoy Chowdhury 18263d2a5c7SDorjoy Chowdhury /* 18363d2a5c7SDorjoy Chowdhury * Upon success, the caller is reponsible for unlinking and freeing *kernel_path 18463d2a5c7SDorjoy Chowdhury */ 18563d2a5c7SDorjoy Chowdhury static bool read_eif_kernel(FILE *f, uint64_t size, char **kernel_path, 18663d2a5c7SDorjoy Chowdhury uint8_t *kernel, uint32_t *crc, Error **errp) 18763d2a5c7SDorjoy Chowdhury { 18863d2a5c7SDorjoy Chowdhury size_t got; 18963d2a5c7SDorjoy Chowdhury FILE *tmp_file = NULL; 19063d2a5c7SDorjoy Chowdhury 19163d2a5c7SDorjoy Chowdhury *kernel_path = NULL; 19263d2a5c7SDorjoy Chowdhury if (!get_tmp_file("eif-kernel-XXXXXX", kernel_path, errp)) { 19363d2a5c7SDorjoy Chowdhury goto cleanup; 19463d2a5c7SDorjoy Chowdhury } 19563d2a5c7SDorjoy Chowdhury 19663d2a5c7SDorjoy Chowdhury tmp_file = fopen(*kernel_path, "wb"); 19763d2a5c7SDorjoy Chowdhury if (tmp_file == NULL) { 19863d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open temporary file %s", 19963d2a5c7SDorjoy Chowdhury *kernel_path); 20063d2a5c7SDorjoy Chowdhury goto cleanup; 20163d2a5c7SDorjoy Chowdhury } 20263d2a5c7SDorjoy Chowdhury 20363d2a5c7SDorjoy Chowdhury got = fread(kernel, 1, size, f); 20463d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 20563d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF kernel section data"); 20663d2a5c7SDorjoy Chowdhury goto cleanup; 20763d2a5c7SDorjoy Chowdhury } 20863d2a5c7SDorjoy Chowdhury 20963d2a5c7SDorjoy Chowdhury got = fwrite(kernel, 1, size, tmp_file); 21063d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 21163d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to write EIF kernel section data to temporary" 21263d2a5c7SDorjoy Chowdhury " file"); 21363d2a5c7SDorjoy Chowdhury goto cleanup; 21463d2a5c7SDorjoy Chowdhury } 21563d2a5c7SDorjoy Chowdhury 21663d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, kernel, size); 21763d2a5c7SDorjoy Chowdhury fclose(tmp_file); 21863d2a5c7SDorjoy Chowdhury 21963d2a5c7SDorjoy Chowdhury return true; 22063d2a5c7SDorjoy Chowdhury 22163d2a5c7SDorjoy Chowdhury cleanup: 22263d2a5c7SDorjoy Chowdhury safe_fclose(tmp_file); 22363d2a5c7SDorjoy Chowdhury 22463d2a5c7SDorjoy Chowdhury safe_unlink(*kernel_path); 22563d2a5c7SDorjoy Chowdhury g_free(*kernel_path); 22663d2a5c7SDorjoy Chowdhury *kernel_path = NULL; 22763d2a5c7SDorjoy Chowdhury 22863d2a5c7SDorjoy Chowdhury return false; 22963d2a5c7SDorjoy Chowdhury } 23063d2a5c7SDorjoy Chowdhury 23163d2a5c7SDorjoy Chowdhury static bool read_eif_cmdline(FILE *f, uint64_t size, char *cmdline, 23263d2a5c7SDorjoy Chowdhury uint32_t *crc, Error **errp) 23363d2a5c7SDorjoy Chowdhury { 23463d2a5c7SDorjoy Chowdhury size_t got = fread(cmdline, 1, size, f); 23563d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 23663d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF cmdline section data"); 23763d2a5c7SDorjoy Chowdhury return false; 23863d2a5c7SDorjoy Chowdhury } 23963d2a5c7SDorjoy Chowdhury 24063d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, (uint8_t *)cmdline, size); 24163d2a5c7SDorjoy Chowdhury return true; 24263d2a5c7SDorjoy Chowdhury } 24363d2a5c7SDorjoy Chowdhury 24463d2a5c7SDorjoy Chowdhury static bool read_eif_ramdisk(FILE *eif, FILE *initrd, uint64_t size, 24563d2a5c7SDorjoy Chowdhury uint8_t *ramdisk, uint32_t *crc, Error **errp) 24663d2a5c7SDorjoy Chowdhury { 24763d2a5c7SDorjoy Chowdhury size_t got; 24863d2a5c7SDorjoy Chowdhury 24963d2a5c7SDorjoy Chowdhury got = fread(ramdisk, 1, size, eif); 25063d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 25163d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF ramdisk section data"); 25263d2a5c7SDorjoy Chowdhury return false; 25363d2a5c7SDorjoy Chowdhury } 25463d2a5c7SDorjoy Chowdhury 25563d2a5c7SDorjoy Chowdhury got = fwrite(ramdisk, 1, size, initrd); 25663d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 25763d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to write EIF ramdisk data to temporary file"); 25863d2a5c7SDorjoy Chowdhury return false; 25963d2a5c7SDorjoy Chowdhury } 26063d2a5c7SDorjoy Chowdhury 26163d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, ramdisk, size); 26263d2a5c7SDorjoy Chowdhury return true; 26363d2a5c7SDorjoy Chowdhury } 26463d2a5c7SDorjoy Chowdhury 26563d2a5c7SDorjoy Chowdhury static bool get_signature_fingerprint_sha384(FILE *eif, uint64_t size, 26663d2a5c7SDorjoy Chowdhury uint8_t *sha384, 26763d2a5c7SDorjoy Chowdhury uint32_t *crc, 26863d2a5c7SDorjoy Chowdhury Error **errp) 26963d2a5c7SDorjoy Chowdhury { 27063d2a5c7SDorjoy Chowdhury size_t got; 27163d2a5c7SDorjoy Chowdhury g_autofree uint8_t *sig = NULL; 27263d2a5c7SDorjoy Chowdhury g_autofree uint8_t *cert = NULL; 27363d2a5c7SDorjoy Chowdhury cbor_item_t *item = NULL; 27463d2a5c7SDorjoy Chowdhury cbor_item_t *pcr0 = NULL; 27563d2a5c7SDorjoy Chowdhury size_t len; 27663d2a5c7SDorjoy Chowdhury size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384; 27763d2a5c7SDorjoy Chowdhury struct cbor_pair *pair; 27863d2a5c7SDorjoy Chowdhury struct cbor_load_result result; 27963d2a5c7SDorjoy Chowdhury bool ret = false; 28063d2a5c7SDorjoy Chowdhury 28163d2a5c7SDorjoy Chowdhury sig = g_malloc(size); 28263d2a5c7SDorjoy Chowdhury got = fread(sig, 1, size, eif); 28363d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 28463d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF signature section data"); 28563d2a5c7SDorjoy Chowdhury goto cleanup; 28663d2a5c7SDorjoy Chowdhury } 28763d2a5c7SDorjoy Chowdhury 28863d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, sig, size); 28963d2a5c7SDorjoy Chowdhury 29063d2a5c7SDorjoy Chowdhury item = cbor_load(sig, size, &result); 29163d2a5c7SDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 29263d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to load signature section data as CBOR"); 29363d2a5c7SDorjoy Chowdhury goto cleanup; 29463d2a5c7SDorjoy Chowdhury } 29563d2a5c7SDorjoy Chowdhury if (!cbor_isa_array(item) || cbor_array_size(item) < 1) { 29663d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 29763d2a5c7SDorjoy Chowdhury goto cleanup; 29863d2a5c7SDorjoy Chowdhury } 29963d2a5c7SDorjoy Chowdhury pcr0 = cbor_array_get(item, 0); 30063d2a5c7SDorjoy Chowdhury if (!pcr0) { 30163d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to get PCR0 signature"); 30263d2a5c7SDorjoy Chowdhury goto cleanup; 30363d2a5c7SDorjoy Chowdhury } 30463d2a5c7SDorjoy Chowdhury if (!cbor_isa_map(pcr0) || cbor_map_size(pcr0) != 2) { 30563d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 30663d2a5c7SDorjoy Chowdhury goto cleanup; 30763d2a5c7SDorjoy Chowdhury } 30863d2a5c7SDorjoy Chowdhury pair = cbor_map_handle(pcr0); 30963d2a5c7SDorjoy Chowdhury if (!cbor_isa_string(pair->key) || cbor_string_length(pair->key) != 19 || 31063d2a5c7SDorjoy Chowdhury memcmp(cbor_string_handle(pair->key), "signing_certificate", 19) != 0) { 31163d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signautre CBOR"); 31263d2a5c7SDorjoy Chowdhury goto cleanup; 31363d2a5c7SDorjoy Chowdhury } 31463d2a5c7SDorjoy Chowdhury if (!cbor_isa_array(pair->value)) { 31563d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 31663d2a5c7SDorjoy Chowdhury goto cleanup; 31763d2a5c7SDorjoy Chowdhury } 31863d2a5c7SDorjoy Chowdhury len = cbor_array_size(pair->value); 31963d2a5c7SDorjoy Chowdhury if (len == 0) { 32063d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 32163d2a5c7SDorjoy Chowdhury goto cleanup; 32263d2a5c7SDorjoy Chowdhury } 32363d2a5c7SDorjoy Chowdhury cert = g_malloc(len); 32463d2a5c7SDorjoy Chowdhury for (int i = 0; i < len; ++i) { 32563d2a5c7SDorjoy Chowdhury cbor_item_t *tmp = cbor_array_get(pair->value, i); 32663d2a5c7SDorjoy Chowdhury if (!tmp) { 32763d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 32863d2a5c7SDorjoy Chowdhury goto cleanup; 32963d2a5c7SDorjoy Chowdhury } 33063d2a5c7SDorjoy Chowdhury if (!cbor_isa_uint(tmp) || cbor_int_get_width(tmp) != CBOR_INT_8) { 33163d2a5c7SDorjoy Chowdhury cbor_decref(&tmp); 33263d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 33363d2a5c7SDorjoy Chowdhury goto cleanup; 33463d2a5c7SDorjoy Chowdhury } 33563d2a5c7SDorjoy Chowdhury cert[i] = cbor_get_uint8(tmp); 33663d2a5c7SDorjoy Chowdhury cbor_decref(&tmp); 33763d2a5c7SDorjoy Chowdhury } 33863d2a5c7SDorjoy Chowdhury 33963d2a5c7SDorjoy Chowdhury if (qcrypto_get_x509_cert_fingerprint(cert, len, QCRYPTO_HASH_ALGO_SHA384, 34063d2a5c7SDorjoy Chowdhury sha384, &hash_len, errp)) { 34163d2a5c7SDorjoy Chowdhury goto cleanup; 34263d2a5c7SDorjoy Chowdhury } 34363d2a5c7SDorjoy Chowdhury 34463d2a5c7SDorjoy Chowdhury ret = true; 34563d2a5c7SDorjoy Chowdhury 34663d2a5c7SDorjoy Chowdhury cleanup: 34763d2a5c7SDorjoy Chowdhury if (pcr0) { 34863d2a5c7SDorjoy Chowdhury cbor_decref(&pcr0); 34963d2a5c7SDorjoy Chowdhury } 35063d2a5c7SDorjoy Chowdhury if (item) { 35163d2a5c7SDorjoy Chowdhury cbor_decref(&item); 35263d2a5c7SDorjoy Chowdhury } 35363d2a5c7SDorjoy Chowdhury return ret; 35463d2a5c7SDorjoy Chowdhury } 35563d2a5c7SDorjoy Chowdhury 35663d2a5c7SDorjoy Chowdhury /* Expects file to have offset 0 before this function is called */ 35763d2a5c7SDorjoy Chowdhury static long get_file_size(FILE *f, Error **errp) 35863d2a5c7SDorjoy Chowdhury { 35963d2a5c7SDorjoy Chowdhury long size; 36063d2a5c7SDorjoy Chowdhury 36163d2a5c7SDorjoy Chowdhury if (fseek(f, 0, SEEK_END) != 0) { 36263d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to seek to the end of file"); 36363d2a5c7SDorjoy Chowdhury return -1; 36463d2a5c7SDorjoy Chowdhury } 36563d2a5c7SDorjoy Chowdhury 36663d2a5c7SDorjoy Chowdhury size = ftell(f); 36763d2a5c7SDorjoy Chowdhury if (size == -1) { 36863d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to get offset"); 36963d2a5c7SDorjoy Chowdhury return -1; 37063d2a5c7SDorjoy Chowdhury } 37163d2a5c7SDorjoy Chowdhury 37263d2a5c7SDorjoy Chowdhury if (fseek(f, 0, SEEK_SET) != 0) { 37363d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to seek back to the start"); 37463d2a5c7SDorjoy Chowdhury return -1; 37563d2a5c7SDorjoy Chowdhury } 37663d2a5c7SDorjoy Chowdhury 37763d2a5c7SDorjoy Chowdhury return size; 37863d2a5c7SDorjoy Chowdhury } 37963d2a5c7SDorjoy Chowdhury 38063d2a5c7SDorjoy Chowdhury static bool get_SHA384_digest(GList *list, uint8_t *digest, Error **errp) 38163d2a5c7SDorjoy Chowdhury { 38263d2a5c7SDorjoy Chowdhury size_t digest_len = QCRYPTO_HASH_DIGEST_LEN_SHA384; 38363d2a5c7SDorjoy Chowdhury size_t list_len = g_list_length(list); 38463d2a5c7SDorjoy Chowdhury struct iovec *iovec_list = g_new0(struct iovec, list_len); 38563d2a5c7SDorjoy Chowdhury bool ret = true; 38663d2a5c7SDorjoy Chowdhury GList *l; 38763d2a5c7SDorjoy Chowdhury int i; 38863d2a5c7SDorjoy Chowdhury 38963d2a5c7SDorjoy Chowdhury for (i = 0, l = list; l != NULL; l = l->next, i++) { 39063d2a5c7SDorjoy Chowdhury iovec_list[i] = *(struct iovec *) l->data; 39163d2a5c7SDorjoy Chowdhury } 39263d2a5c7SDorjoy Chowdhury 39363d2a5c7SDorjoy Chowdhury if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA384, iovec_list, list_len, 39463d2a5c7SDorjoy Chowdhury &digest, &digest_len, errp) < 0) { 39563d2a5c7SDorjoy Chowdhury ret = false; 39663d2a5c7SDorjoy Chowdhury } 39763d2a5c7SDorjoy Chowdhury 39863d2a5c7SDorjoy Chowdhury g_free(iovec_list); 39963d2a5c7SDorjoy Chowdhury return ret; 40063d2a5c7SDorjoy Chowdhury } 40163d2a5c7SDorjoy Chowdhury 40263d2a5c7SDorjoy Chowdhury static void free_iovec(struct iovec *iov) 40363d2a5c7SDorjoy Chowdhury { 40463d2a5c7SDorjoy Chowdhury if (iov) { 40563d2a5c7SDorjoy Chowdhury g_free(iov->iov_base); 40663d2a5c7SDorjoy Chowdhury g_free(iov); 40763d2a5c7SDorjoy Chowdhury } 40863d2a5c7SDorjoy Chowdhury } 40963d2a5c7SDorjoy Chowdhury 41063d2a5c7SDorjoy Chowdhury /* 41163d2a5c7SDorjoy Chowdhury * Upon success, the caller is reponsible for unlinking and freeing 41263d2a5c7SDorjoy Chowdhury * *kernel_path, *initrd_path and freeing *cmdline. 41363d2a5c7SDorjoy Chowdhury */ 41463d2a5c7SDorjoy Chowdhury bool read_eif_file(const char *eif_path, const char *machine_initrd, 41563d2a5c7SDorjoy Chowdhury char **kernel_path, char **initrd_path, char **cmdline, 41663d2a5c7SDorjoy Chowdhury uint8_t *image_sha384, uint8_t *bootstrap_sha384, 41763d2a5c7SDorjoy Chowdhury uint8_t *app_sha384, uint8_t *fingerprint_sha384, 41863d2a5c7SDorjoy Chowdhury bool *signature_found, Error **errp) 41963d2a5c7SDorjoy Chowdhury { 42063d2a5c7SDorjoy Chowdhury FILE *f = NULL; 42163d2a5c7SDorjoy Chowdhury FILE *machine_initrd_f = NULL; 42263d2a5c7SDorjoy Chowdhury FILE *initrd_path_f = NULL; 42363d2a5c7SDorjoy Chowdhury long machine_initrd_size; 42463d2a5c7SDorjoy Chowdhury uint32_t crc = 0; 42563d2a5c7SDorjoy Chowdhury EifHeader eif_header; 42663d2a5c7SDorjoy Chowdhury bool seen_sections[EIF_SECTION_MAX] = {false}; 42763d2a5c7SDorjoy Chowdhury /* kernel + ramdisks + cmdline sha384 hash */ 42863d2a5c7SDorjoy Chowdhury GList *iov_PCR0 = NULL; 42963d2a5c7SDorjoy Chowdhury /* kernel + boot ramdisk + cmdline sha384 hash */ 43063d2a5c7SDorjoy Chowdhury GList *iov_PCR1 = NULL; 43163d2a5c7SDorjoy Chowdhury /* application ramdisk(s) hash */ 43263d2a5c7SDorjoy Chowdhury GList *iov_PCR2 = NULL; 43363d2a5c7SDorjoy Chowdhury uint8_t *ptr = NULL; 43463d2a5c7SDorjoy Chowdhury struct iovec *iov_ptr = NULL; 43563d2a5c7SDorjoy Chowdhury 43663d2a5c7SDorjoy Chowdhury *signature_found = false; 43763d2a5c7SDorjoy Chowdhury *kernel_path = *initrd_path = *cmdline = NULL; 43863d2a5c7SDorjoy Chowdhury 43963d2a5c7SDorjoy Chowdhury f = fopen(eif_path, "rb"); 44063d2a5c7SDorjoy Chowdhury if (f == NULL) { 44163d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open %s", eif_path); 44263d2a5c7SDorjoy Chowdhury goto cleanup; 44363d2a5c7SDorjoy Chowdhury } 44463d2a5c7SDorjoy Chowdhury 44563d2a5c7SDorjoy Chowdhury if (!read_eif_header(f, &eif_header, &crc, errp)) { 44663d2a5c7SDorjoy Chowdhury goto cleanup; 44763d2a5c7SDorjoy Chowdhury } 44863d2a5c7SDorjoy Chowdhury 44963d2a5c7SDorjoy Chowdhury if (eif_header.version < 4) { 45063d2a5c7SDorjoy Chowdhury error_setg(errp, "Expected EIF version 4 or greater"); 45163d2a5c7SDorjoy Chowdhury goto cleanup; 45263d2a5c7SDorjoy Chowdhury } 45363d2a5c7SDorjoy Chowdhury 45463d2a5c7SDorjoy Chowdhury if (eif_header.flags != 0) { 45563d2a5c7SDorjoy Chowdhury error_setg(errp, "Expected EIF flags to be 0"); 45663d2a5c7SDorjoy Chowdhury goto cleanup; 45763d2a5c7SDorjoy Chowdhury } 45863d2a5c7SDorjoy Chowdhury 45963d2a5c7SDorjoy Chowdhury if (eif_header.section_cnt > MAX_SECTIONS) { 46063d2a5c7SDorjoy Chowdhury error_setg(errp, "EIF header section count must not be greater than " 46163d2a5c7SDorjoy Chowdhury "%d but found %d", MAX_SECTIONS, eif_header.section_cnt); 46263d2a5c7SDorjoy Chowdhury goto cleanup; 46363d2a5c7SDorjoy Chowdhury } 46463d2a5c7SDorjoy Chowdhury 46563d2a5c7SDorjoy Chowdhury for (int i = 0; i < eif_header.section_cnt; ++i) { 46663d2a5c7SDorjoy Chowdhury EifSectionHeader hdr; 46763d2a5c7SDorjoy Chowdhury uint16_t section_type; 46863d2a5c7SDorjoy Chowdhury 469*619d1447SPaolo Bonzini if (eif_header.section_offsets[i] > OFF_MAX) { 470*619d1447SPaolo Bonzini error_setg(errp, "Invalid EIF image. Section offset out of bounds"); 471*619d1447SPaolo Bonzini goto cleanup; 472*619d1447SPaolo Bonzini } 47363d2a5c7SDorjoy Chowdhury if (fseek(f, eif_header.section_offsets[i], SEEK_SET) != 0) { 47463d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to offset to %" PRIu64 " in EIF file", 47563d2a5c7SDorjoy Chowdhury eif_header.section_offsets[i]); 47663d2a5c7SDorjoy Chowdhury goto cleanup; 47763d2a5c7SDorjoy Chowdhury } 47863d2a5c7SDorjoy Chowdhury 47963d2a5c7SDorjoy Chowdhury if (!read_eif_section_header(f, &hdr, &crc, errp)) { 48063d2a5c7SDorjoy Chowdhury goto cleanup; 48163d2a5c7SDorjoy Chowdhury } 48263d2a5c7SDorjoy Chowdhury 48363d2a5c7SDorjoy Chowdhury if (hdr.flags != 0) { 48463d2a5c7SDorjoy Chowdhury error_setg(errp, "Expected EIF section header flags to be 0"); 48563d2a5c7SDorjoy Chowdhury goto cleanup; 48663d2a5c7SDorjoy Chowdhury } 48763d2a5c7SDorjoy Chowdhury 48863d2a5c7SDorjoy Chowdhury if (eif_header.section_sizes[i] != hdr.section_size) { 48963d2a5c7SDorjoy Chowdhury error_setg(errp, "EIF section size mismatch between header and " 49063d2a5c7SDorjoy Chowdhury "section header: header %" PRIu64 ", section header %" PRIu64, 49163d2a5c7SDorjoy Chowdhury eif_header.section_sizes[i], 49263d2a5c7SDorjoy Chowdhury hdr.section_size); 49363d2a5c7SDorjoy Chowdhury goto cleanup; 49463d2a5c7SDorjoy Chowdhury } 49563d2a5c7SDorjoy Chowdhury 49663d2a5c7SDorjoy Chowdhury section_type = hdr.section_type; 49763d2a5c7SDorjoy Chowdhury 49863d2a5c7SDorjoy Chowdhury switch (section_type) { 49963d2a5c7SDorjoy Chowdhury case EIF_SECTION_KERNEL: 50063d2a5c7SDorjoy Chowdhury if (seen_sections[EIF_SECTION_KERNEL]) { 50163d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. More than 1 kernel " 50263d2a5c7SDorjoy Chowdhury "section"); 50363d2a5c7SDorjoy Chowdhury goto cleanup; 50463d2a5c7SDorjoy Chowdhury } 50563d2a5c7SDorjoy Chowdhury 50663d2a5c7SDorjoy Chowdhury ptr = g_malloc(hdr.section_size); 50763d2a5c7SDorjoy Chowdhury 50863d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 50963d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = ptr; 51063d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = hdr.section_size; 51163d2a5c7SDorjoy Chowdhury 51263d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 51363d2a5c7SDorjoy Chowdhury iov_PCR1 = g_list_append(iov_PCR1, iov_ptr); 51463d2a5c7SDorjoy Chowdhury 51563d2a5c7SDorjoy Chowdhury if (!read_eif_kernel(f, hdr.section_size, kernel_path, ptr, &crc, 51663d2a5c7SDorjoy Chowdhury errp)) { 51763d2a5c7SDorjoy Chowdhury goto cleanup; 51863d2a5c7SDorjoy Chowdhury } 51963d2a5c7SDorjoy Chowdhury 52063d2a5c7SDorjoy Chowdhury break; 52163d2a5c7SDorjoy Chowdhury case EIF_SECTION_CMDLINE: 52263d2a5c7SDorjoy Chowdhury { 52363d2a5c7SDorjoy Chowdhury uint64_t size; 52463d2a5c7SDorjoy Chowdhury uint8_t *cmdline_copy; 52563d2a5c7SDorjoy Chowdhury if (seen_sections[EIF_SECTION_CMDLINE]) { 52663d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. More than 1 cmdline " 52763d2a5c7SDorjoy Chowdhury "section"); 52863d2a5c7SDorjoy Chowdhury goto cleanup; 52963d2a5c7SDorjoy Chowdhury } 53063d2a5c7SDorjoy Chowdhury size = hdr.section_size; 53163d2a5c7SDorjoy Chowdhury *cmdline = g_malloc(size + 1); 53263d2a5c7SDorjoy Chowdhury if (!read_eif_cmdline(f, size, *cmdline, &crc, errp)) { 53363d2a5c7SDorjoy Chowdhury goto cleanup; 53463d2a5c7SDorjoy Chowdhury } 53563d2a5c7SDorjoy Chowdhury (*cmdline)[size] = '\0'; 53663d2a5c7SDorjoy Chowdhury 53763d2a5c7SDorjoy Chowdhury /* 53863d2a5c7SDorjoy Chowdhury * We make a copy of '*cmdline' for putting it in iovecs so that 53963d2a5c7SDorjoy Chowdhury * we can easily free all the iovec entries later as we cannot 54063d2a5c7SDorjoy Chowdhury * free '*cmdline' which is used by the caller. 54163d2a5c7SDorjoy Chowdhury */ 54263d2a5c7SDorjoy Chowdhury cmdline_copy = g_memdup2(*cmdline, size); 54363d2a5c7SDorjoy Chowdhury 54463d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 54563d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = cmdline_copy; 54663d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = size; 54763d2a5c7SDorjoy Chowdhury 54863d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 54963d2a5c7SDorjoy Chowdhury iov_PCR1 = g_list_append(iov_PCR1, iov_ptr); 55063d2a5c7SDorjoy Chowdhury break; 55163d2a5c7SDorjoy Chowdhury } 55263d2a5c7SDorjoy Chowdhury case EIF_SECTION_RAMDISK: 55363d2a5c7SDorjoy Chowdhury { 55463d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_RAMDISK]) { 55563d2a5c7SDorjoy Chowdhury /* 55663d2a5c7SDorjoy Chowdhury * If this is the first time we are seeing a ramdisk section, 55763d2a5c7SDorjoy Chowdhury * we need to create the initrd temporary file. 55863d2a5c7SDorjoy Chowdhury */ 55963d2a5c7SDorjoy Chowdhury if (!get_tmp_file("eif-initrd-XXXXXX", initrd_path, errp)) { 56063d2a5c7SDorjoy Chowdhury goto cleanup; 56163d2a5c7SDorjoy Chowdhury } 56263d2a5c7SDorjoy Chowdhury initrd_path_f = fopen(*initrd_path, "wb"); 56363d2a5c7SDorjoy Chowdhury if (initrd_path_f == NULL) { 56463d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open file %s", 56563d2a5c7SDorjoy Chowdhury *initrd_path); 56663d2a5c7SDorjoy Chowdhury goto cleanup; 56763d2a5c7SDorjoy Chowdhury } 56863d2a5c7SDorjoy Chowdhury } 56963d2a5c7SDorjoy Chowdhury 57063d2a5c7SDorjoy Chowdhury ptr = g_malloc(hdr.section_size); 57163d2a5c7SDorjoy Chowdhury 57263d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 57363d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = ptr; 57463d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = hdr.section_size; 57563d2a5c7SDorjoy Chowdhury 57663d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 57763d2a5c7SDorjoy Chowdhury /* 57863d2a5c7SDorjoy Chowdhury * If it's the first ramdisk, we need to hash it into bootstrap 57963d2a5c7SDorjoy Chowdhury * i.e., iov_PCR1, otherwise we need to hash it into app i.e., 58063d2a5c7SDorjoy Chowdhury * iov_PCR2. 58163d2a5c7SDorjoy Chowdhury */ 58263d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_RAMDISK]) { 58363d2a5c7SDorjoy Chowdhury iov_PCR1 = g_list_append(iov_PCR1, iov_ptr); 58463d2a5c7SDorjoy Chowdhury } else { 58563d2a5c7SDorjoy Chowdhury iov_PCR2 = g_list_append(iov_PCR2, iov_ptr); 58663d2a5c7SDorjoy Chowdhury } 58763d2a5c7SDorjoy Chowdhury 58863d2a5c7SDorjoy Chowdhury if (!read_eif_ramdisk(f, initrd_path_f, hdr.section_size, ptr, 58963d2a5c7SDorjoy Chowdhury &crc, errp)) { 59063d2a5c7SDorjoy Chowdhury goto cleanup; 59163d2a5c7SDorjoy Chowdhury } 59263d2a5c7SDorjoy Chowdhury 59363d2a5c7SDorjoy Chowdhury break; 59463d2a5c7SDorjoy Chowdhury } 59563d2a5c7SDorjoy Chowdhury case EIF_SECTION_SIGNATURE: 59663d2a5c7SDorjoy Chowdhury *signature_found = true; 59763d2a5c7SDorjoy Chowdhury if (!get_signature_fingerprint_sha384(f, hdr.section_size, 59863d2a5c7SDorjoy Chowdhury fingerprint_sha384, &crc, 59963d2a5c7SDorjoy Chowdhury errp)) { 60063d2a5c7SDorjoy Chowdhury goto cleanup; 60163d2a5c7SDorjoy Chowdhury } 60263d2a5c7SDorjoy Chowdhury break; 60363d2a5c7SDorjoy Chowdhury default: 60463d2a5c7SDorjoy Chowdhury /* other sections including invalid or unknown sections */ 60563d2a5c7SDorjoy Chowdhury { 60663d2a5c7SDorjoy Chowdhury uint8_t *buf; 60763d2a5c7SDorjoy Chowdhury size_t got; 60863d2a5c7SDorjoy Chowdhury uint64_t size = hdr.section_size; 60963d2a5c7SDorjoy Chowdhury buf = g_malloc(size); 61063d2a5c7SDorjoy Chowdhury got = fread(buf, 1, size, f); 61163d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 61263d2a5c7SDorjoy Chowdhury g_free(buf); 61363d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF %s section data", 61463d2a5c7SDorjoy Chowdhury section_type_to_string(section_type)); 61563d2a5c7SDorjoy Chowdhury goto cleanup; 61663d2a5c7SDorjoy Chowdhury } 61763d2a5c7SDorjoy Chowdhury crc = crc32(crc, buf, size); 61863d2a5c7SDorjoy Chowdhury g_free(buf); 61963d2a5c7SDorjoy Chowdhury break; 62063d2a5c7SDorjoy Chowdhury } 62163d2a5c7SDorjoy Chowdhury } 62263d2a5c7SDorjoy Chowdhury 62363d2a5c7SDorjoy Chowdhury if (section_type < EIF_SECTION_MAX) { 62463d2a5c7SDorjoy Chowdhury seen_sections[section_type] = true; 62563d2a5c7SDorjoy Chowdhury } 62663d2a5c7SDorjoy Chowdhury } 62763d2a5c7SDorjoy Chowdhury 62863d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_KERNEL]) { 62963d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. No kernel section."); 63063d2a5c7SDorjoy Chowdhury goto cleanup; 63163d2a5c7SDorjoy Chowdhury } 63263d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_CMDLINE]) { 63363d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. No cmdline section."); 63463d2a5c7SDorjoy Chowdhury goto cleanup; 63563d2a5c7SDorjoy Chowdhury } 63663d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_RAMDISK]) { 63763d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. No ramdisk section."); 63863d2a5c7SDorjoy Chowdhury goto cleanup; 63963d2a5c7SDorjoy Chowdhury } 64063d2a5c7SDorjoy Chowdhury 64163d2a5c7SDorjoy Chowdhury if (eif_header.eif_crc32 != crc) { 64263d2a5c7SDorjoy Chowdhury error_setg(errp, "CRC mismatch. Expected %u but header has %u.", 64363d2a5c7SDorjoy Chowdhury crc, eif_header.eif_crc32); 64463d2a5c7SDorjoy Chowdhury goto cleanup; 64563d2a5c7SDorjoy Chowdhury } 64663d2a5c7SDorjoy Chowdhury 64763d2a5c7SDorjoy Chowdhury /* 64863d2a5c7SDorjoy Chowdhury * Let's append the initrd file from "-initrd" option if any. Although 64963d2a5c7SDorjoy Chowdhury * we pass the crc pointer to read_eif_ramdisk, it is not useful anymore. 65063d2a5c7SDorjoy Chowdhury * We have already done the crc mismatch check above this code. 65163d2a5c7SDorjoy Chowdhury */ 65263d2a5c7SDorjoy Chowdhury if (machine_initrd) { 65363d2a5c7SDorjoy Chowdhury machine_initrd_f = fopen(machine_initrd, "rb"); 65463d2a5c7SDorjoy Chowdhury if (machine_initrd_f == NULL) { 65563d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open initrd file %s", 65663d2a5c7SDorjoy Chowdhury machine_initrd); 65763d2a5c7SDorjoy Chowdhury goto cleanup; 65863d2a5c7SDorjoy Chowdhury } 65963d2a5c7SDorjoy Chowdhury 66063d2a5c7SDorjoy Chowdhury machine_initrd_size = get_file_size(machine_initrd_f, errp); 66163d2a5c7SDorjoy Chowdhury if (machine_initrd_size == -1) { 66263d2a5c7SDorjoy Chowdhury goto cleanup; 66363d2a5c7SDorjoy Chowdhury } 66463d2a5c7SDorjoy Chowdhury 66563d2a5c7SDorjoy Chowdhury ptr = g_malloc(machine_initrd_size); 66663d2a5c7SDorjoy Chowdhury 66763d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 66863d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = ptr; 66963d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = machine_initrd_size; 67063d2a5c7SDorjoy Chowdhury 67163d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 67263d2a5c7SDorjoy Chowdhury iov_PCR2 = g_list_append(iov_PCR2, iov_ptr); 67363d2a5c7SDorjoy Chowdhury 67463d2a5c7SDorjoy Chowdhury if (!read_eif_ramdisk(machine_initrd_f, initrd_path_f, 67563d2a5c7SDorjoy Chowdhury machine_initrd_size, ptr, &crc, errp)) { 67663d2a5c7SDorjoy Chowdhury goto cleanup; 67763d2a5c7SDorjoy Chowdhury } 67863d2a5c7SDorjoy Chowdhury } 67963d2a5c7SDorjoy Chowdhury 68063d2a5c7SDorjoy Chowdhury if (!get_SHA384_digest(iov_PCR0, image_sha384, errp)) { 68163d2a5c7SDorjoy Chowdhury goto cleanup; 68263d2a5c7SDorjoy Chowdhury } 68363d2a5c7SDorjoy Chowdhury if (!get_SHA384_digest(iov_PCR1, bootstrap_sha384, errp)) { 68463d2a5c7SDorjoy Chowdhury goto cleanup; 68563d2a5c7SDorjoy Chowdhury } 68663d2a5c7SDorjoy Chowdhury if (!get_SHA384_digest(iov_PCR2, app_sha384, errp)) { 68763d2a5c7SDorjoy Chowdhury goto cleanup; 68863d2a5c7SDorjoy Chowdhury } 68963d2a5c7SDorjoy Chowdhury 69063d2a5c7SDorjoy Chowdhury /* 69163d2a5c7SDorjoy Chowdhury * We only need to free iov_PCR0 entries because iov_PCR1 and 69263d2a5c7SDorjoy Chowdhury * iov_PCR2 iovec entries are subsets of iov_PCR0 iovec entries. 69363d2a5c7SDorjoy Chowdhury */ 69463d2a5c7SDorjoy Chowdhury g_list_free_full(iov_PCR0, (GDestroyNotify) free_iovec); 69563d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR1); 69663d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR2); 69763d2a5c7SDorjoy Chowdhury fclose(f); 69863d2a5c7SDorjoy Chowdhury fclose(initrd_path_f); 69963d2a5c7SDorjoy Chowdhury safe_fclose(machine_initrd_f); 70063d2a5c7SDorjoy Chowdhury return true; 70163d2a5c7SDorjoy Chowdhury 70263d2a5c7SDorjoy Chowdhury cleanup: 70363d2a5c7SDorjoy Chowdhury g_list_free_full(iov_PCR0, (GDestroyNotify) free_iovec); 70463d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR1); 70563d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR2); 70663d2a5c7SDorjoy Chowdhury 70763d2a5c7SDorjoy Chowdhury safe_fclose(f); 70863d2a5c7SDorjoy Chowdhury safe_fclose(initrd_path_f); 70963d2a5c7SDorjoy Chowdhury safe_fclose(machine_initrd_f); 71063d2a5c7SDorjoy Chowdhury 71163d2a5c7SDorjoy Chowdhury safe_unlink(*kernel_path); 71263d2a5c7SDorjoy Chowdhury g_free(*kernel_path); 71363d2a5c7SDorjoy Chowdhury *kernel_path = NULL; 71463d2a5c7SDorjoy Chowdhury 71563d2a5c7SDorjoy Chowdhury safe_unlink(*initrd_path); 71663d2a5c7SDorjoy Chowdhury g_free(*initrd_path); 71763d2a5c7SDorjoy Chowdhury *initrd_path = NULL; 71863d2a5c7SDorjoy Chowdhury 71963d2a5c7SDorjoy Chowdhury g_free(*cmdline); 72063d2a5c7SDorjoy Chowdhury *cmdline = NULL; 72163d2a5c7SDorjoy Chowdhury 72263d2a5c7SDorjoy Chowdhury return false; 72363d2a5c7SDorjoy Chowdhury } 724