1*63d2a5c7SDorjoy Chowdhury /* 2*63d2a5c7SDorjoy Chowdhury * EIF (Enclave Image Format) related helpers 3*63d2a5c7SDorjoy Chowdhury * 4*63d2a5c7SDorjoy Chowdhury * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com> 5*63d2a5c7SDorjoy Chowdhury * 6*63d2a5c7SDorjoy Chowdhury * This work is licensed under the terms of the GNU GPL, version 2 or 7*63d2a5c7SDorjoy Chowdhury * (at your option) any later version. See the COPYING file in the 8*63d2a5c7SDorjoy Chowdhury * top-level directory. 9*63d2a5c7SDorjoy Chowdhury */ 10*63d2a5c7SDorjoy Chowdhury 11*63d2a5c7SDorjoy Chowdhury #include "qemu/osdep.h" 12*63d2a5c7SDorjoy Chowdhury #include "qemu/bswap.h" 13*63d2a5c7SDorjoy Chowdhury #include "qapi/error.h" 14*63d2a5c7SDorjoy Chowdhury #include "crypto/hash.h" 15*63d2a5c7SDorjoy Chowdhury #include "crypto/x509-utils.h" 16*63d2a5c7SDorjoy Chowdhury #include <zlib.h> /* for crc32 */ 17*63d2a5c7SDorjoy Chowdhury #include <cbor.h> 18*63d2a5c7SDorjoy Chowdhury 19*63d2a5c7SDorjoy Chowdhury #include "hw/core/eif.h" 20*63d2a5c7SDorjoy Chowdhury 21*63d2a5c7SDorjoy Chowdhury #define MAX_SECTIONS 32 22*63d2a5c7SDorjoy Chowdhury 23*63d2a5c7SDorjoy Chowdhury /* members are ordered according to field order in .eif file */ 24*63d2a5c7SDorjoy Chowdhury typedef struct EifHeader { 25*63d2a5c7SDorjoy Chowdhury uint8_t magic[4]; /* must be .eif in ascii i.e., [46, 101, 105, 102] */ 26*63d2a5c7SDorjoy Chowdhury uint16_t version; 27*63d2a5c7SDorjoy Chowdhury uint16_t flags; 28*63d2a5c7SDorjoy Chowdhury uint64_t default_memory; 29*63d2a5c7SDorjoy Chowdhury uint64_t default_cpus; 30*63d2a5c7SDorjoy Chowdhury uint16_t reserved; 31*63d2a5c7SDorjoy Chowdhury uint16_t section_cnt; 32*63d2a5c7SDorjoy Chowdhury uint64_t section_offsets[MAX_SECTIONS]; 33*63d2a5c7SDorjoy Chowdhury uint64_t section_sizes[MAX_SECTIONS]; 34*63d2a5c7SDorjoy Chowdhury uint32_t unused; 35*63d2a5c7SDorjoy Chowdhury uint32_t eif_crc32; 36*63d2a5c7SDorjoy Chowdhury } QEMU_PACKED EifHeader; 37*63d2a5c7SDorjoy Chowdhury 38*63d2a5c7SDorjoy Chowdhury /* members are ordered according to field order in .eif file */ 39*63d2a5c7SDorjoy Chowdhury typedef struct EifSectionHeader { 40*63d2a5c7SDorjoy Chowdhury /* 41*63d2a5c7SDorjoy Chowdhury * 0 = invalid, 1 = kernel, 2 = cmdline, 3 = ramdisk, 4 = signature, 42*63d2a5c7SDorjoy Chowdhury * 5 = metadata 43*63d2a5c7SDorjoy Chowdhury */ 44*63d2a5c7SDorjoy Chowdhury uint16_t section_type; 45*63d2a5c7SDorjoy Chowdhury uint16_t flags; 46*63d2a5c7SDorjoy Chowdhury uint64_t section_size; 47*63d2a5c7SDorjoy Chowdhury } QEMU_PACKED EifSectionHeader; 48*63d2a5c7SDorjoy Chowdhury 49*63d2a5c7SDorjoy Chowdhury enum EifSectionTypes { 50*63d2a5c7SDorjoy Chowdhury EIF_SECTION_INVALID = 0, 51*63d2a5c7SDorjoy Chowdhury EIF_SECTION_KERNEL = 1, 52*63d2a5c7SDorjoy Chowdhury EIF_SECTION_CMDLINE = 2, 53*63d2a5c7SDorjoy Chowdhury EIF_SECTION_RAMDISK = 3, 54*63d2a5c7SDorjoy Chowdhury EIF_SECTION_SIGNATURE = 4, 55*63d2a5c7SDorjoy Chowdhury EIF_SECTION_METADATA = 5, 56*63d2a5c7SDorjoy Chowdhury EIF_SECTION_MAX = 6, 57*63d2a5c7SDorjoy Chowdhury }; 58*63d2a5c7SDorjoy Chowdhury 59*63d2a5c7SDorjoy Chowdhury static const char *section_type_to_string(uint16_t type) 60*63d2a5c7SDorjoy Chowdhury { 61*63d2a5c7SDorjoy Chowdhury const char *str; 62*63d2a5c7SDorjoy Chowdhury switch (type) { 63*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_INVALID: 64*63d2a5c7SDorjoy Chowdhury str = "invalid"; 65*63d2a5c7SDorjoy Chowdhury break; 66*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_KERNEL: 67*63d2a5c7SDorjoy Chowdhury str = "kernel"; 68*63d2a5c7SDorjoy Chowdhury break; 69*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_CMDLINE: 70*63d2a5c7SDorjoy Chowdhury str = "cmdline"; 71*63d2a5c7SDorjoy Chowdhury break; 72*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_RAMDISK: 73*63d2a5c7SDorjoy Chowdhury str = "ramdisk"; 74*63d2a5c7SDorjoy Chowdhury break; 75*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_SIGNATURE: 76*63d2a5c7SDorjoy Chowdhury str = "signature"; 77*63d2a5c7SDorjoy Chowdhury break; 78*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_METADATA: 79*63d2a5c7SDorjoy Chowdhury str = "metadata"; 80*63d2a5c7SDorjoy Chowdhury break; 81*63d2a5c7SDorjoy Chowdhury default: 82*63d2a5c7SDorjoy Chowdhury str = "unknown"; 83*63d2a5c7SDorjoy Chowdhury break; 84*63d2a5c7SDorjoy Chowdhury } 85*63d2a5c7SDorjoy Chowdhury 86*63d2a5c7SDorjoy Chowdhury return str; 87*63d2a5c7SDorjoy Chowdhury } 88*63d2a5c7SDorjoy Chowdhury 89*63d2a5c7SDorjoy Chowdhury static bool read_eif_header(FILE *f, EifHeader *header, uint32_t *crc, 90*63d2a5c7SDorjoy Chowdhury Error **errp) 91*63d2a5c7SDorjoy Chowdhury { 92*63d2a5c7SDorjoy Chowdhury size_t got; 93*63d2a5c7SDorjoy Chowdhury size_t header_size = sizeof(*header); 94*63d2a5c7SDorjoy Chowdhury 95*63d2a5c7SDorjoy Chowdhury got = fread(header, 1, header_size, f); 96*63d2a5c7SDorjoy Chowdhury if (got != header_size) { 97*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF header"); 98*63d2a5c7SDorjoy Chowdhury return false; 99*63d2a5c7SDorjoy Chowdhury } 100*63d2a5c7SDorjoy Chowdhury 101*63d2a5c7SDorjoy Chowdhury if (memcmp(header->magic, ".eif", 4) != 0) { 102*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. Magic mismatch."); 103*63d2a5c7SDorjoy Chowdhury return false; 104*63d2a5c7SDorjoy Chowdhury } 105*63d2a5c7SDorjoy Chowdhury 106*63d2a5c7SDorjoy Chowdhury /* Exclude header->eif_crc32 field from CRC calculation */ 107*63d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, (uint8_t *)header, header_size - 4); 108*63d2a5c7SDorjoy Chowdhury 109*63d2a5c7SDorjoy Chowdhury header->version = be16_to_cpu(header->version); 110*63d2a5c7SDorjoy Chowdhury header->flags = be16_to_cpu(header->flags); 111*63d2a5c7SDorjoy Chowdhury header->default_memory = be64_to_cpu(header->default_memory); 112*63d2a5c7SDorjoy Chowdhury header->default_cpus = be64_to_cpu(header->default_cpus); 113*63d2a5c7SDorjoy Chowdhury header->reserved = be16_to_cpu(header->reserved); 114*63d2a5c7SDorjoy Chowdhury header->section_cnt = be16_to_cpu(header->section_cnt); 115*63d2a5c7SDorjoy Chowdhury 116*63d2a5c7SDorjoy Chowdhury for (int i = 0; i < MAX_SECTIONS; ++i) { 117*63d2a5c7SDorjoy Chowdhury header->section_offsets[i] = be64_to_cpu(header->section_offsets[i]); 118*63d2a5c7SDorjoy Chowdhury } 119*63d2a5c7SDorjoy Chowdhury 120*63d2a5c7SDorjoy Chowdhury for (int i = 0; i < MAX_SECTIONS; ++i) { 121*63d2a5c7SDorjoy Chowdhury header->section_sizes[i] = be64_to_cpu(header->section_sizes[i]); 122*63d2a5c7SDorjoy Chowdhury } 123*63d2a5c7SDorjoy Chowdhury 124*63d2a5c7SDorjoy Chowdhury header->unused = be32_to_cpu(header->unused); 125*63d2a5c7SDorjoy Chowdhury header->eif_crc32 = be32_to_cpu(header->eif_crc32); 126*63d2a5c7SDorjoy Chowdhury return true; 127*63d2a5c7SDorjoy Chowdhury } 128*63d2a5c7SDorjoy Chowdhury 129*63d2a5c7SDorjoy Chowdhury static bool read_eif_section_header(FILE *f, EifSectionHeader *section_header, 130*63d2a5c7SDorjoy Chowdhury uint32_t *crc, Error **errp) 131*63d2a5c7SDorjoy Chowdhury { 132*63d2a5c7SDorjoy Chowdhury size_t got; 133*63d2a5c7SDorjoy Chowdhury size_t section_header_size = sizeof(*section_header); 134*63d2a5c7SDorjoy Chowdhury 135*63d2a5c7SDorjoy Chowdhury got = fread(section_header, 1, section_header_size, f); 136*63d2a5c7SDorjoy Chowdhury if (got != section_header_size) { 137*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF section header"); 138*63d2a5c7SDorjoy Chowdhury return false; 139*63d2a5c7SDorjoy Chowdhury } 140*63d2a5c7SDorjoy Chowdhury 141*63d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, (uint8_t *)section_header, section_header_size); 142*63d2a5c7SDorjoy Chowdhury 143*63d2a5c7SDorjoy Chowdhury section_header->section_type = be16_to_cpu(section_header->section_type); 144*63d2a5c7SDorjoy Chowdhury section_header->flags = be16_to_cpu(section_header->flags); 145*63d2a5c7SDorjoy Chowdhury section_header->section_size = be64_to_cpu(section_header->section_size); 146*63d2a5c7SDorjoy Chowdhury return true; 147*63d2a5c7SDorjoy Chowdhury } 148*63d2a5c7SDorjoy Chowdhury 149*63d2a5c7SDorjoy Chowdhury /* 150*63d2a5c7SDorjoy Chowdhury * Upon success, the caller is responsible for unlinking and freeing *tmp_path. 151*63d2a5c7SDorjoy Chowdhury */ 152*63d2a5c7SDorjoy Chowdhury static bool get_tmp_file(const char *template, char **tmp_path, Error **errp) 153*63d2a5c7SDorjoy Chowdhury { 154*63d2a5c7SDorjoy Chowdhury int tmp_fd; 155*63d2a5c7SDorjoy Chowdhury 156*63d2a5c7SDorjoy Chowdhury *tmp_path = NULL; 157*63d2a5c7SDorjoy Chowdhury tmp_fd = g_file_open_tmp(template, tmp_path, NULL); 158*63d2a5c7SDorjoy Chowdhury if (tmp_fd < 0 || *tmp_path == NULL) { 159*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to create temporary file for template %s", 160*63d2a5c7SDorjoy Chowdhury template); 161*63d2a5c7SDorjoy Chowdhury return false; 162*63d2a5c7SDorjoy Chowdhury } 163*63d2a5c7SDorjoy Chowdhury 164*63d2a5c7SDorjoy Chowdhury close(tmp_fd); 165*63d2a5c7SDorjoy Chowdhury return true; 166*63d2a5c7SDorjoy Chowdhury } 167*63d2a5c7SDorjoy Chowdhury 168*63d2a5c7SDorjoy Chowdhury static void safe_fclose(FILE *f) 169*63d2a5c7SDorjoy Chowdhury { 170*63d2a5c7SDorjoy Chowdhury if (f) { 171*63d2a5c7SDorjoy Chowdhury fclose(f); 172*63d2a5c7SDorjoy Chowdhury } 173*63d2a5c7SDorjoy Chowdhury } 174*63d2a5c7SDorjoy Chowdhury 175*63d2a5c7SDorjoy Chowdhury static void safe_unlink(char *f) 176*63d2a5c7SDorjoy Chowdhury { 177*63d2a5c7SDorjoy Chowdhury if (f) { 178*63d2a5c7SDorjoy Chowdhury unlink(f); 179*63d2a5c7SDorjoy Chowdhury } 180*63d2a5c7SDorjoy Chowdhury } 181*63d2a5c7SDorjoy Chowdhury 182*63d2a5c7SDorjoy Chowdhury /* 183*63d2a5c7SDorjoy Chowdhury * Upon success, the caller is reponsible for unlinking and freeing *kernel_path 184*63d2a5c7SDorjoy Chowdhury */ 185*63d2a5c7SDorjoy Chowdhury static bool read_eif_kernel(FILE *f, uint64_t size, char **kernel_path, 186*63d2a5c7SDorjoy Chowdhury uint8_t *kernel, uint32_t *crc, Error **errp) 187*63d2a5c7SDorjoy Chowdhury { 188*63d2a5c7SDorjoy Chowdhury size_t got; 189*63d2a5c7SDorjoy Chowdhury FILE *tmp_file = NULL; 190*63d2a5c7SDorjoy Chowdhury 191*63d2a5c7SDorjoy Chowdhury *kernel_path = NULL; 192*63d2a5c7SDorjoy Chowdhury if (!get_tmp_file("eif-kernel-XXXXXX", kernel_path, errp)) { 193*63d2a5c7SDorjoy Chowdhury goto cleanup; 194*63d2a5c7SDorjoy Chowdhury } 195*63d2a5c7SDorjoy Chowdhury 196*63d2a5c7SDorjoy Chowdhury tmp_file = fopen(*kernel_path, "wb"); 197*63d2a5c7SDorjoy Chowdhury if (tmp_file == NULL) { 198*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open temporary file %s", 199*63d2a5c7SDorjoy Chowdhury *kernel_path); 200*63d2a5c7SDorjoy Chowdhury goto cleanup; 201*63d2a5c7SDorjoy Chowdhury } 202*63d2a5c7SDorjoy Chowdhury 203*63d2a5c7SDorjoy Chowdhury got = fread(kernel, 1, size, f); 204*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 205*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF kernel section data"); 206*63d2a5c7SDorjoy Chowdhury goto cleanup; 207*63d2a5c7SDorjoy Chowdhury } 208*63d2a5c7SDorjoy Chowdhury 209*63d2a5c7SDorjoy Chowdhury got = fwrite(kernel, 1, size, tmp_file); 210*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 211*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to write EIF kernel section data to temporary" 212*63d2a5c7SDorjoy Chowdhury " file"); 213*63d2a5c7SDorjoy Chowdhury goto cleanup; 214*63d2a5c7SDorjoy Chowdhury } 215*63d2a5c7SDorjoy Chowdhury 216*63d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, kernel, size); 217*63d2a5c7SDorjoy Chowdhury fclose(tmp_file); 218*63d2a5c7SDorjoy Chowdhury 219*63d2a5c7SDorjoy Chowdhury return true; 220*63d2a5c7SDorjoy Chowdhury 221*63d2a5c7SDorjoy Chowdhury cleanup: 222*63d2a5c7SDorjoy Chowdhury safe_fclose(tmp_file); 223*63d2a5c7SDorjoy Chowdhury 224*63d2a5c7SDorjoy Chowdhury safe_unlink(*kernel_path); 225*63d2a5c7SDorjoy Chowdhury g_free(*kernel_path); 226*63d2a5c7SDorjoy Chowdhury *kernel_path = NULL; 227*63d2a5c7SDorjoy Chowdhury 228*63d2a5c7SDorjoy Chowdhury return false; 229*63d2a5c7SDorjoy Chowdhury } 230*63d2a5c7SDorjoy Chowdhury 231*63d2a5c7SDorjoy Chowdhury static bool read_eif_cmdline(FILE *f, uint64_t size, char *cmdline, 232*63d2a5c7SDorjoy Chowdhury uint32_t *crc, Error **errp) 233*63d2a5c7SDorjoy Chowdhury { 234*63d2a5c7SDorjoy Chowdhury size_t got = fread(cmdline, 1, size, f); 235*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 236*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF cmdline section data"); 237*63d2a5c7SDorjoy Chowdhury return false; 238*63d2a5c7SDorjoy Chowdhury } 239*63d2a5c7SDorjoy Chowdhury 240*63d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, (uint8_t *)cmdline, size); 241*63d2a5c7SDorjoy Chowdhury return true; 242*63d2a5c7SDorjoy Chowdhury } 243*63d2a5c7SDorjoy Chowdhury 244*63d2a5c7SDorjoy Chowdhury static bool read_eif_ramdisk(FILE *eif, FILE *initrd, uint64_t size, 245*63d2a5c7SDorjoy Chowdhury uint8_t *ramdisk, uint32_t *crc, Error **errp) 246*63d2a5c7SDorjoy Chowdhury { 247*63d2a5c7SDorjoy Chowdhury size_t got; 248*63d2a5c7SDorjoy Chowdhury 249*63d2a5c7SDorjoy Chowdhury got = fread(ramdisk, 1, size, eif); 250*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 251*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF ramdisk section data"); 252*63d2a5c7SDorjoy Chowdhury return false; 253*63d2a5c7SDorjoy Chowdhury } 254*63d2a5c7SDorjoy Chowdhury 255*63d2a5c7SDorjoy Chowdhury got = fwrite(ramdisk, 1, size, initrd); 256*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 257*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to write EIF ramdisk data to temporary file"); 258*63d2a5c7SDorjoy Chowdhury return false; 259*63d2a5c7SDorjoy Chowdhury } 260*63d2a5c7SDorjoy Chowdhury 261*63d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, ramdisk, size); 262*63d2a5c7SDorjoy Chowdhury return true; 263*63d2a5c7SDorjoy Chowdhury } 264*63d2a5c7SDorjoy Chowdhury 265*63d2a5c7SDorjoy Chowdhury static bool get_signature_fingerprint_sha384(FILE *eif, uint64_t size, 266*63d2a5c7SDorjoy Chowdhury uint8_t *sha384, 267*63d2a5c7SDorjoy Chowdhury uint32_t *crc, 268*63d2a5c7SDorjoy Chowdhury Error **errp) 269*63d2a5c7SDorjoy Chowdhury { 270*63d2a5c7SDorjoy Chowdhury size_t got; 271*63d2a5c7SDorjoy Chowdhury g_autofree uint8_t *sig = NULL; 272*63d2a5c7SDorjoy Chowdhury g_autofree uint8_t *cert = NULL; 273*63d2a5c7SDorjoy Chowdhury cbor_item_t *item = NULL; 274*63d2a5c7SDorjoy Chowdhury cbor_item_t *pcr0 = NULL; 275*63d2a5c7SDorjoy Chowdhury size_t len; 276*63d2a5c7SDorjoy Chowdhury size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384; 277*63d2a5c7SDorjoy Chowdhury struct cbor_pair *pair; 278*63d2a5c7SDorjoy Chowdhury struct cbor_load_result result; 279*63d2a5c7SDorjoy Chowdhury bool ret = false; 280*63d2a5c7SDorjoy Chowdhury 281*63d2a5c7SDorjoy Chowdhury sig = g_malloc(size); 282*63d2a5c7SDorjoy Chowdhury got = fread(sig, 1, size, eif); 283*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 284*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF signature section data"); 285*63d2a5c7SDorjoy Chowdhury goto cleanup; 286*63d2a5c7SDorjoy Chowdhury } 287*63d2a5c7SDorjoy Chowdhury 288*63d2a5c7SDorjoy Chowdhury *crc = crc32(*crc, sig, size); 289*63d2a5c7SDorjoy Chowdhury 290*63d2a5c7SDorjoy Chowdhury item = cbor_load(sig, size, &result); 291*63d2a5c7SDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 292*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to load signature section data as CBOR"); 293*63d2a5c7SDorjoy Chowdhury goto cleanup; 294*63d2a5c7SDorjoy Chowdhury } 295*63d2a5c7SDorjoy Chowdhury if (!cbor_isa_array(item) || cbor_array_size(item) < 1) { 296*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 297*63d2a5c7SDorjoy Chowdhury goto cleanup; 298*63d2a5c7SDorjoy Chowdhury } 299*63d2a5c7SDorjoy Chowdhury pcr0 = cbor_array_get(item, 0); 300*63d2a5c7SDorjoy Chowdhury if (!pcr0) { 301*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to get PCR0 signature"); 302*63d2a5c7SDorjoy Chowdhury goto cleanup; 303*63d2a5c7SDorjoy Chowdhury } 304*63d2a5c7SDorjoy Chowdhury if (!cbor_isa_map(pcr0) || cbor_map_size(pcr0) != 2) { 305*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 306*63d2a5c7SDorjoy Chowdhury goto cleanup; 307*63d2a5c7SDorjoy Chowdhury } 308*63d2a5c7SDorjoy Chowdhury pair = cbor_map_handle(pcr0); 309*63d2a5c7SDorjoy Chowdhury if (!cbor_isa_string(pair->key) || cbor_string_length(pair->key) != 19 || 310*63d2a5c7SDorjoy Chowdhury memcmp(cbor_string_handle(pair->key), "signing_certificate", 19) != 0) { 311*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signautre CBOR"); 312*63d2a5c7SDorjoy Chowdhury goto cleanup; 313*63d2a5c7SDorjoy Chowdhury } 314*63d2a5c7SDorjoy Chowdhury if (!cbor_isa_array(pair->value)) { 315*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 316*63d2a5c7SDorjoy Chowdhury goto cleanup; 317*63d2a5c7SDorjoy Chowdhury } 318*63d2a5c7SDorjoy Chowdhury len = cbor_array_size(pair->value); 319*63d2a5c7SDorjoy Chowdhury if (len == 0) { 320*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 321*63d2a5c7SDorjoy Chowdhury goto cleanup; 322*63d2a5c7SDorjoy Chowdhury } 323*63d2a5c7SDorjoy Chowdhury cert = g_malloc(len); 324*63d2a5c7SDorjoy Chowdhury for (int i = 0; i < len; ++i) { 325*63d2a5c7SDorjoy Chowdhury cbor_item_t *tmp = cbor_array_get(pair->value, i); 326*63d2a5c7SDorjoy Chowdhury if (!tmp) { 327*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 328*63d2a5c7SDorjoy Chowdhury goto cleanup; 329*63d2a5c7SDorjoy Chowdhury } 330*63d2a5c7SDorjoy Chowdhury if (!cbor_isa_uint(tmp) || cbor_int_get_width(tmp) != CBOR_INT_8) { 331*63d2a5c7SDorjoy Chowdhury cbor_decref(&tmp); 332*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid signature CBOR"); 333*63d2a5c7SDorjoy Chowdhury goto cleanup; 334*63d2a5c7SDorjoy Chowdhury } 335*63d2a5c7SDorjoy Chowdhury cert[i] = cbor_get_uint8(tmp); 336*63d2a5c7SDorjoy Chowdhury cbor_decref(&tmp); 337*63d2a5c7SDorjoy Chowdhury } 338*63d2a5c7SDorjoy Chowdhury 339*63d2a5c7SDorjoy Chowdhury if (qcrypto_get_x509_cert_fingerprint(cert, len, QCRYPTO_HASH_ALGO_SHA384, 340*63d2a5c7SDorjoy Chowdhury sha384, &hash_len, errp)) { 341*63d2a5c7SDorjoy Chowdhury goto cleanup; 342*63d2a5c7SDorjoy Chowdhury } 343*63d2a5c7SDorjoy Chowdhury 344*63d2a5c7SDorjoy Chowdhury ret = true; 345*63d2a5c7SDorjoy Chowdhury 346*63d2a5c7SDorjoy Chowdhury cleanup: 347*63d2a5c7SDorjoy Chowdhury if (pcr0) { 348*63d2a5c7SDorjoy Chowdhury cbor_decref(&pcr0); 349*63d2a5c7SDorjoy Chowdhury } 350*63d2a5c7SDorjoy Chowdhury if (item) { 351*63d2a5c7SDorjoy Chowdhury cbor_decref(&item); 352*63d2a5c7SDorjoy Chowdhury } 353*63d2a5c7SDorjoy Chowdhury return ret; 354*63d2a5c7SDorjoy Chowdhury } 355*63d2a5c7SDorjoy Chowdhury 356*63d2a5c7SDorjoy Chowdhury /* Expects file to have offset 0 before this function is called */ 357*63d2a5c7SDorjoy Chowdhury static long get_file_size(FILE *f, Error **errp) 358*63d2a5c7SDorjoy Chowdhury { 359*63d2a5c7SDorjoy Chowdhury long size; 360*63d2a5c7SDorjoy Chowdhury 361*63d2a5c7SDorjoy Chowdhury if (fseek(f, 0, SEEK_END) != 0) { 362*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to seek to the end of file"); 363*63d2a5c7SDorjoy Chowdhury return -1; 364*63d2a5c7SDorjoy Chowdhury } 365*63d2a5c7SDorjoy Chowdhury 366*63d2a5c7SDorjoy Chowdhury size = ftell(f); 367*63d2a5c7SDorjoy Chowdhury if (size == -1) { 368*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to get offset"); 369*63d2a5c7SDorjoy Chowdhury return -1; 370*63d2a5c7SDorjoy Chowdhury } 371*63d2a5c7SDorjoy Chowdhury 372*63d2a5c7SDorjoy Chowdhury if (fseek(f, 0, SEEK_SET) != 0) { 373*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to seek back to the start"); 374*63d2a5c7SDorjoy Chowdhury return -1; 375*63d2a5c7SDorjoy Chowdhury } 376*63d2a5c7SDorjoy Chowdhury 377*63d2a5c7SDorjoy Chowdhury return size; 378*63d2a5c7SDorjoy Chowdhury } 379*63d2a5c7SDorjoy Chowdhury 380*63d2a5c7SDorjoy Chowdhury static bool get_SHA384_digest(GList *list, uint8_t *digest, Error **errp) 381*63d2a5c7SDorjoy Chowdhury { 382*63d2a5c7SDorjoy Chowdhury size_t digest_len = QCRYPTO_HASH_DIGEST_LEN_SHA384; 383*63d2a5c7SDorjoy Chowdhury size_t list_len = g_list_length(list); 384*63d2a5c7SDorjoy Chowdhury struct iovec *iovec_list = g_new0(struct iovec, list_len); 385*63d2a5c7SDorjoy Chowdhury bool ret = true; 386*63d2a5c7SDorjoy Chowdhury GList *l; 387*63d2a5c7SDorjoy Chowdhury int i; 388*63d2a5c7SDorjoy Chowdhury 389*63d2a5c7SDorjoy Chowdhury for (i = 0, l = list; l != NULL; l = l->next, i++) { 390*63d2a5c7SDorjoy Chowdhury iovec_list[i] = *(struct iovec *) l->data; 391*63d2a5c7SDorjoy Chowdhury } 392*63d2a5c7SDorjoy Chowdhury 393*63d2a5c7SDorjoy Chowdhury if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA384, iovec_list, list_len, 394*63d2a5c7SDorjoy Chowdhury &digest, &digest_len, errp) < 0) { 395*63d2a5c7SDorjoy Chowdhury ret = false; 396*63d2a5c7SDorjoy Chowdhury } 397*63d2a5c7SDorjoy Chowdhury 398*63d2a5c7SDorjoy Chowdhury g_free(iovec_list); 399*63d2a5c7SDorjoy Chowdhury return ret; 400*63d2a5c7SDorjoy Chowdhury } 401*63d2a5c7SDorjoy Chowdhury 402*63d2a5c7SDorjoy Chowdhury static void free_iovec(struct iovec *iov) 403*63d2a5c7SDorjoy Chowdhury { 404*63d2a5c7SDorjoy Chowdhury if (iov) { 405*63d2a5c7SDorjoy Chowdhury g_free(iov->iov_base); 406*63d2a5c7SDorjoy Chowdhury g_free(iov); 407*63d2a5c7SDorjoy Chowdhury } 408*63d2a5c7SDorjoy Chowdhury } 409*63d2a5c7SDorjoy Chowdhury 410*63d2a5c7SDorjoy Chowdhury /* 411*63d2a5c7SDorjoy Chowdhury * Upon success, the caller is reponsible for unlinking and freeing 412*63d2a5c7SDorjoy Chowdhury * *kernel_path, *initrd_path and freeing *cmdline. 413*63d2a5c7SDorjoy Chowdhury */ 414*63d2a5c7SDorjoy Chowdhury bool read_eif_file(const char *eif_path, const char *machine_initrd, 415*63d2a5c7SDorjoy Chowdhury char **kernel_path, char **initrd_path, char **cmdline, 416*63d2a5c7SDorjoy Chowdhury uint8_t *image_sha384, uint8_t *bootstrap_sha384, 417*63d2a5c7SDorjoy Chowdhury uint8_t *app_sha384, uint8_t *fingerprint_sha384, 418*63d2a5c7SDorjoy Chowdhury bool *signature_found, Error **errp) 419*63d2a5c7SDorjoy Chowdhury { 420*63d2a5c7SDorjoy Chowdhury FILE *f = NULL; 421*63d2a5c7SDorjoy Chowdhury FILE *machine_initrd_f = NULL; 422*63d2a5c7SDorjoy Chowdhury FILE *initrd_path_f = NULL; 423*63d2a5c7SDorjoy Chowdhury long machine_initrd_size; 424*63d2a5c7SDorjoy Chowdhury uint32_t crc = 0; 425*63d2a5c7SDorjoy Chowdhury EifHeader eif_header; 426*63d2a5c7SDorjoy Chowdhury bool seen_sections[EIF_SECTION_MAX] = {false}; 427*63d2a5c7SDorjoy Chowdhury /* kernel + ramdisks + cmdline sha384 hash */ 428*63d2a5c7SDorjoy Chowdhury GList *iov_PCR0 = NULL; 429*63d2a5c7SDorjoy Chowdhury /* kernel + boot ramdisk + cmdline sha384 hash */ 430*63d2a5c7SDorjoy Chowdhury GList *iov_PCR1 = NULL; 431*63d2a5c7SDorjoy Chowdhury /* application ramdisk(s) hash */ 432*63d2a5c7SDorjoy Chowdhury GList *iov_PCR2 = NULL; 433*63d2a5c7SDorjoy Chowdhury uint8_t *ptr = NULL; 434*63d2a5c7SDorjoy Chowdhury struct iovec *iov_ptr = NULL; 435*63d2a5c7SDorjoy Chowdhury 436*63d2a5c7SDorjoy Chowdhury *signature_found = false; 437*63d2a5c7SDorjoy Chowdhury *kernel_path = *initrd_path = *cmdline = NULL; 438*63d2a5c7SDorjoy Chowdhury 439*63d2a5c7SDorjoy Chowdhury f = fopen(eif_path, "rb"); 440*63d2a5c7SDorjoy Chowdhury if (f == NULL) { 441*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open %s", eif_path); 442*63d2a5c7SDorjoy Chowdhury goto cleanup; 443*63d2a5c7SDorjoy Chowdhury } 444*63d2a5c7SDorjoy Chowdhury 445*63d2a5c7SDorjoy Chowdhury if (!read_eif_header(f, &eif_header, &crc, errp)) { 446*63d2a5c7SDorjoy Chowdhury goto cleanup; 447*63d2a5c7SDorjoy Chowdhury } 448*63d2a5c7SDorjoy Chowdhury 449*63d2a5c7SDorjoy Chowdhury if (eif_header.version < 4) { 450*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Expected EIF version 4 or greater"); 451*63d2a5c7SDorjoy Chowdhury goto cleanup; 452*63d2a5c7SDorjoy Chowdhury } 453*63d2a5c7SDorjoy Chowdhury 454*63d2a5c7SDorjoy Chowdhury if (eif_header.flags != 0) { 455*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Expected EIF flags to be 0"); 456*63d2a5c7SDorjoy Chowdhury goto cleanup; 457*63d2a5c7SDorjoy Chowdhury } 458*63d2a5c7SDorjoy Chowdhury 459*63d2a5c7SDorjoy Chowdhury if (eif_header.section_cnt > MAX_SECTIONS) { 460*63d2a5c7SDorjoy Chowdhury error_setg(errp, "EIF header section count must not be greater than " 461*63d2a5c7SDorjoy Chowdhury "%d but found %d", MAX_SECTIONS, eif_header.section_cnt); 462*63d2a5c7SDorjoy Chowdhury goto cleanup; 463*63d2a5c7SDorjoy Chowdhury } 464*63d2a5c7SDorjoy Chowdhury 465*63d2a5c7SDorjoy Chowdhury for (int i = 0; i < eif_header.section_cnt; ++i) { 466*63d2a5c7SDorjoy Chowdhury EifSectionHeader hdr; 467*63d2a5c7SDorjoy Chowdhury uint16_t section_type; 468*63d2a5c7SDorjoy Chowdhury 469*63d2a5c7SDorjoy Chowdhury if (fseek(f, eif_header.section_offsets[i], SEEK_SET) != 0) { 470*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to offset to %" PRIu64 " in EIF file", 471*63d2a5c7SDorjoy Chowdhury eif_header.section_offsets[i]); 472*63d2a5c7SDorjoy Chowdhury goto cleanup; 473*63d2a5c7SDorjoy Chowdhury } 474*63d2a5c7SDorjoy Chowdhury 475*63d2a5c7SDorjoy Chowdhury if (!read_eif_section_header(f, &hdr, &crc, errp)) { 476*63d2a5c7SDorjoy Chowdhury goto cleanup; 477*63d2a5c7SDorjoy Chowdhury } 478*63d2a5c7SDorjoy Chowdhury 479*63d2a5c7SDorjoy Chowdhury if (hdr.flags != 0) { 480*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Expected EIF section header flags to be 0"); 481*63d2a5c7SDorjoy Chowdhury goto cleanup; 482*63d2a5c7SDorjoy Chowdhury } 483*63d2a5c7SDorjoy Chowdhury 484*63d2a5c7SDorjoy Chowdhury if (eif_header.section_sizes[i] != hdr.section_size) { 485*63d2a5c7SDorjoy Chowdhury error_setg(errp, "EIF section size mismatch between header and " 486*63d2a5c7SDorjoy Chowdhury "section header: header %" PRIu64 ", section header %" PRIu64, 487*63d2a5c7SDorjoy Chowdhury eif_header.section_sizes[i], 488*63d2a5c7SDorjoy Chowdhury hdr.section_size); 489*63d2a5c7SDorjoy Chowdhury goto cleanup; 490*63d2a5c7SDorjoy Chowdhury } 491*63d2a5c7SDorjoy Chowdhury 492*63d2a5c7SDorjoy Chowdhury section_type = hdr.section_type; 493*63d2a5c7SDorjoy Chowdhury 494*63d2a5c7SDorjoy Chowdhury switch (section_type) { 495*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_KERNEL: 496*63d2a5c7SDorjoy Chowdhury if (seen_sections[EIF_SECTION_KERNEL]) { 497*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. More than 1 kernel " 498*63d2a5c7SDorjoy Chowdhury "section"); 499*63d2a5c7SDorjoy Chowdhury goto cleanup; 500*63d2a5c7SDorjoy Chowdhury } 501*63d2a5c7SDorjoy Chowdhury 502*63d2a5c7SDorjoy Chowdhury ptr = g_malloc(hdr.section_size); 503*63d2a5c7SDorjoy Chowdhury 504*63d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 505*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = ptr; 506*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = hdr.section_size; 507*63d2a5c7SDorjoy Chowdhury 508*63d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 509*63d2a5c7SDorjoy Chowdhury iov_PCR1 = g_list_append(iov_PCR1, iov_ptr); 510*63d2a5c7SDorjoy Chowdhury 511*63d2a5c7SDorjoy Chowdhury if (!read_eif_kernel(f, hdr.section_size, kernel_path, ptr, &crc, 512*63d2a5c7SDorjoy Chowdhury errp)) { 513*63d2a5c7SDorjoy Chowdhury goto cleanup; 514*63d2a5c7SDorjoy Chowdhury } 515*63d2a5c7SDorjoy Chowdhury 516*63d2a5c7SDorjoy Chowdhury break; 517*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_CMDLINE: 518*63d2a5c7SDorjoy Chowdhury { 519*63d2a5c7SDorjoy Chowdhury uint64_t size; 520*63d2a5c7SDorjoy Chowdhury uint8_t *cmdline_copy; 521*63d2a5c7SDorjoy Chowdhury if (seen_sections[EIF_SECTION_CMDLINE]) { 522*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. More than 1 cmdline " 523*63d2a5c7SDorjoy Chowdhury "section"); 524*63d2a5c7SDorjoy Chowdhury goto cleanup; 525*63d2a5c7SDorjoy Chowdhury } 526*63d2a5c7SDorjoy Chowdhury size = hdr.section_size; 527*63d2a5c7SDorjoy Chowdhury *cmdline = g_malloc(size + 1); 528*63d2a5c7SDorjoy Chowdhury if (!read_eif_cmdline(f, size, *cmdline, &crc, errp)) { 529*63d2a5c7SDorjoy Chowdhury goto cleanup; 530*63d2a5c7SDorjoy Chowdhury } 531*63d2a5c7SDorjoy Chowdhury (*cmdline)[size] = '\0'; 532*63d2a5c7SDorjoy Chowdhury 533*63d2a5c7SDorjoy Chowdhury /* 534*63d2a5c7SDorjoy Chowdhury * We make a copy of '*cmdline' for putting it in iovecs so that 535*63d2a5c7SDorjoy Chowdhury * we can easily free all the iovec entries later as we cannot 536*63d2a5c7SDorjoy Chowdhury * free '*cmdline' which is used by the caller. 537*63d2a5c7SDorjoy Chowdhury */ 538*63d2a5c7SDorjoy Chowdhury cmdline_copy = g_memdup2(*cmdline, size); 539*63d2a5c7SDorjoy Chowdhury 540*63d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 541*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = cmdline_copy; 542*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = size; 543*63d2a5c7SDorjoy Chowdhury 544*63d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 545*63d2a5c7SDorjoy Chowdhury iov_PCR1 = g_list_append(iov_PCR1, iov_ptr); 546*63d2a5c7SDorjoy Chowdhury break; 547*63d2a5c7SDorjoy Chowdhury } 548*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_RAMDISK: 549*63d2a5c7SDorjoy Chowdhury { 550*63d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_RAMDISK]) { 551*63d2a5c7SDorjoy Chowdhury /* 552*63d2a5c7SDorjoy Chowdhury * If this is the first time we are seeing a ramdisk section, 553*63d2a5c7SDorjoy Chowdhury * we need to create the initrd temporary file. 554*63d2a5c7SDorjoy Chowdhury */ 555*63d2a5c7SDorjoy Chowdhury if (!get_tmp_file("eif-initrd-XXXXXX", initrd_path, errp)) { 556*63d2a5c7SDorjoy Chowdhury goto cleanup; 557*63d2a5c7SDorjoy Chowdhury } 558*63d2a5c7SDorjoy Chowdhury initrd_path_f = fopen(*initrd_path, "wb"); 559*63d2a5c7SDorjoy Chowdhury if (initrd_path_f == NULL) { 560*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open file %s", 561*63d2a5c7SDorjoy Chowdhury *initrd_path); 562*63d2a5c7SDorjoy Chowdhury goto cleanup; 563*63d2a5c7SDorjoy Chowdhury } 564*63d2a5c7SDorjoy Chowdhury } 565*63d2a5c7SDorjoy Chowdhury 566*63d2a5c7SDorjoy Chowdhury ptr = g_malloc(hdr.section_size); 567*63d2a5c7SDorjoy Chowdhury 568*63d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 569*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = ptr; 570*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = hdr.section_size; 571*63d2a5c7SDorjoy Chowdhury 572*63d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 573*63d2a5c7SDorjoy Chowdhury /* 574*63d2a5c7SDorjoy Chowdhury * If it's the first ramdisk, we need to hash it into bootstrap 575*63d2a5c7SDorjoy Chowdhury * i.e., iov_PCR1, otherwise we need to hash it into app i.e., 576*63d2a5c7SDorjoy Chowdhury * iov_PCR2. 577*63d2a5c7SDorjoy Chowdhury */ 578*63d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_RAMDISK]) { 579*63d2a5c7SDorjoy Chowdhury iov_PCR1 = g_list_append(iov_PCR1, iov_ptr); 580*63d2a5c7SDorjoy Chowdhury } else { 581*63d2a5c7SDorjoy Chowdhury iov_PCR2 = g_list_append(iov_PCR2, iov_ptr); 582*63d2a5c7SDorjoy Chowdhury } 583*63d2a5c7SDorjoy Chowdhury 584*63d2a5c7SDorjoy Chowdhury if (!read_eif_ramdisk(f, initrd_path_f, hdr.section_size, ptr, 585*63d2a5c7SDorjoy Chowdhury &crc, errp)) { 586*63d2a5c7SDorjoy Chowdhury goto cleanup; 587*63d2a5c7SDorjoy Chowdhury } 588*63d2a5c7SDorjoy Chowdhury 589*63d2a5c7SDorjoy Chowdhury break; 590*63d2a5c7SDorjoy Chowdhury } 591*63d2a5c7SDorjoy Chowdhury case EIF_SECTION_SIGNATURE: 592*63d2a5c7SDorjoy Chowdhury *signature_found = true; 593*63d2a5c7SDorjoy Chowdhury if (!get_signature_fingerprint_sha384(f, hdr.section_size, 594*63d2a5c7SDorjoy Chowdhury fingerprint_sha384, &crc, 595*63d2a5c7SDorjoy Chowdhury errp)) { 596*63d2a5c7SDorjoy Chowdhury goto cleanup; 597*63d2a5c7SDorjoy Chowdhury } 598*63d2a5c7SDorjoy Chowdhury break; 599*63d2a5c7SDorjoy Chowdhury default: 600*63d2a5c7SDorjoy Chowdhury /* other sections including invalid or unknown sections */ 601*63d2a5c7SDorjoy Chowdhury { 602*63d2a5c7SDorjoy Chowdhury uint8_t *buf; 603*63d2a5c7SDorjoy Chowdhury size_t got; 604*63d2a5c7SDorjoy Chowdhury uint64_t size = hdr.section_size; 605*63d2a5c7SDorjoy Chowdhury buf = g_malloc(size); 606*63d2a5c7SDorjoy Chowdhury got = fread(buf, 1, size, f); 607*63d2a5c7SDorjoy Chowdhury if ((uint64_t) got != size) { 608*63d2a5c7SDorjoy Chowdhury g_free(buf); 609*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Failed to read EIF %s section data", 610*63d2a5c7SDorjoy Chowdhury section_type_to_string(section_type)); 611*63d2a5c7SDorjoy Chowdhury goto cleanup; 612*63d2a5c7SDorjoy Chowdhury } 613*63d2a5c7SDorjoy Chowdhury crc = crc32(crc, buf, size); 614*63d2a5c7SDorjoy Chowdhury g_free(buf); 615*63d2a5c7SDorjoy Chowdhury break; 616*63d2a5c7SDorjoy Chowdhury } 617*63d2a5c7SDorjoy Chowdhury } 618*63d2a5c7SDorjoy Chowdhury 619*63d2a5c7SDorjoy Chowdhury if (section_type < EIF_SECTION_MAX) { 620*63d2a5c7SDorjoy Chowdhury seen_sections[section_type] = true; 621*63d2a5c7SDorjoy Chowdhury } 622*63d2a5c7SDorjoy Chowdhury } 623*63d2a5c7SDorjoy Chowdhury 624*63d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_KERNEL]) { 625*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. No kernel section."); 626*63d2a5c7SDorjoy Chowdhury goto cleanup; 627*63d2a5c7SDorjoy Chowdhury } 628*63d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_CMDLINE]) { 629*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. No cmdline section."); 630*63d2a5c7SDorjoy Chowdhury goto cleanup; 631*63d2a5c7SDorjoy Chowdhury } 632*63d2a5c7SDorjoy Chowdhury if (!seen_sections[EIF_SECTION_RAMDISK]) { 633*63d2a5c7SDorjoy Chowdhury error_setg(errp, "Invalid EIF image. No ramdisk section."); 634*63d2a5c7SDorjoy Chowdhury goto cleanup; 635*63d2a5c7SDorjoy Chowdhury } 636*63d2a5c7SDorjoy Chowdhury 637*63d2a5c7SDorjoy Chowdhury if (eif_header.eif_crc32 != crc) { 638*63d2a5c7SDorjoy Chowdhury error_setg(errp, "CRC mismatch. Expected %u but header has %u.", 639*63d2a5c7SDorjoy Chowdhury crc, eif_header.eif_crc32); 640*63d2a5c7SDorjoy Chowdhury goto cleanup; 641*63d2a5c7SDorjoy Chowdhury } 642*63d2a5c7SDorjoy Chowdhury 643*63d2a5c7SDorjoy Chowdhury /* 644*63d2a5c7SDorjoy Chowdhury * Let's append the initrd file from "-initrd" option if any. Although 645*63d2a5c7SDorjoy Chowdhury * we pass the crc pointer to read_eif_ramdisk, it is not useful anymore. 646*63d2a5c7SDorjoy Chowdhury * We have already done the crc mismatch check above this code. 647*63d2a5c7SDorjoy Chowdhury */ 648*63d2a5c7SDorjoy Chowdhury if (machine_initrd) { 649*63d2a5c7SDorjoy Chowdhury machine_initrd_f = fopen(machine_initrd, "rb"); 650*63d2a5c7SDorjoy Chowdhury if (machine_initrd_f == NULL) { 651*63d2a5c7SDorjoy Chowdhury error_setg_errno(errp, errno, "Failed to open initrd file %s", 652*63d2a5c7SDorjoy Chowdhury machine_initrd); 653*63d2a5c7SDorjoy Chowdhury goto cleanup; 654*63d2a5c7SDorjoy Chowdhury } 655*63d2a5c7SDorjoy Chowdhury 656*63d2a5c7SDorjoy Chowdhury machine_initrd_size = get_file_size(machine_initrd_f, errp); 657*63d2a5c7SDorjoy Chowdhury if (machine_initrd_size == -1) { 658*63d2a5c7SDorjoy Chowdhury goto cleanup; 659*63d2a5c7SDorjoy Chowdhury } 660*63d2a5c7SDorjoy Chowdhury 661*63d2a5c7SDorjoy Chowdhury ptr = g_malloc(machine_initrd_size); 662*63d2a5c7SDorjoy Chowdhury 663*63d2a5c7SDorjoy Chowdhury iov_ptr = g_malloc(sizeof(struct iovec)); 664*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_base = ptr; 665*63d2a5c7SDorjoy Chowdhury iov_ptr->iov_len = machine_initrd_size; 666*63d2a5c7SDorjoy Chowdhury 667*63d2a5c7SDorjoy Chowdhury iov_PCR0 = g_list_append(iov_PCR0, iov_ptr); 668*63d2a5c7SDorjoy Chowdhury iov_PCR2 = g_list_append(iov_PCR2, iov_ptr); 669*63d2a5c7SDorjoy Chowdhury 670*63d2a5c7SDorjoy Chowdhury if (!read_eif_ramdisk(machine_initrd_f, initrd_path_f, 671*63d2a5c7SDorjoy Chowdhury machine_initrd_size, ptr, &crc, errp)) { 672*63d2a5c7SDorjoy Chowdhury goto cleanup; 673*63d2a5c7SDorjoy Chowdhury } 674*63d2a5c7SDorjoy Chowdhury } 675*63d2a5c7SDorjoy Chowdhury 676*63d2a5c7SDorjoy Chowdhury if (!get_SHA384_digest(iov_PCR0, image_sha384, errp)) { 677*63d2a5c7SDorjoy Chowdhury goto cleanup; 678*63d2a5c7SDorjoy Chowdhury } 679*63d2a5c7SDorjoy Chowdhury if (!get_SHA384_digest(iov_PCR1, bootstrap_sha384, errp)) { 680*63d2a5c7SDorjoy Chowdhury goto cleanup; 681*63d2a5c7SDorjoy Chowdhury } 682*63d2a5c7SDorjoy Chowdhury if (!get_SHA384_digest(iov_PCR2, app_sha384, errp)) { 683*63d2a5c7SDorjoy Chowdhury goto cleanup; 684*63d2a5c7SDorjoy Chowdhury } 685*63d2a5c7SDorjoy Chowdhury 686*63d2a5c7SDorjoy Chowdhury /* 687*63d2a5c7SDorjoy Chowdhury * We only need to free iov_PCR0 entries because iov_PCR1 and 688*63d2a5c7SDorjoy Chowdhury * iov_PCR2 iovec entries are subsets of iov_PCR0 iovec entries. 689*63d2a5c7SDorjoy Chowdhury */ 690*63d2a5c7SDorjoy Chowdhury g_list_free_full(iov_PCR0, (GDestroyNotify) free_iovec); 691*63d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR1); 692*63d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR2); 693*63d2a5c7SDorjoy Chowdhury fclose(f); 694*63d2a5c7SDorjoy Chowdhury fclose(initrd_path_f); 695*63d2a5c7SDorjoy Chowdhury safe_fclose(machine_initrd_f); 696*63d2a5c7SDorjoy Chowdhury return true; 697*63d2a5c7SDorjoy Chowdhury 698*63d2a5c7SDorjoy Chowdhury cleanup: 699*63d2a5c7SDorjoy Chowdhury g_list_free_full(iov_PCR0, (GDestroyNotify) free_iovec); 700*63d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR1); 701*63d2a5c7SDorjoy Chowdhury g_list_free(iov_PCR2); 702*63d2a5c7SDorjoy Chowdhury 703*63d2a5c7SDorjoy Chowdhury safe_fclose(f); 704*63d2a5c7SDorjoy Chowdhury safe_fclose(initrd_path_f); 705*63d2a5c7SDorjoy Chowdhury safe_fclose(machine_initrd_f); 706*63d2a5c7SDorjoy Chowdhury 707*63d2a5c7SDorjoy Chowdhury safe_unlink(*kernel_path); 708*63d2a5c7SDorjoy Chowdhury g_free(*kernel_path); 709*63d2a5c7SDorjoy Chowdhury *kernel_path = NULL; 710*63d2a5c7SDorjoy Chowdhury 711*63d2a5c7SDorjoy Chowdhury safe_unlink(*initrd_path); 712*63d2a5c7SDorjoy Chowdhury g_free(*initrd_path); 713*63d2a5c7SDorjoy Chowdhury *initrd_path = NULL; 714*63d2a5c7SDorjoy Chowdhury 715*63d2a5c7SDorjoy Chowdhury g_free(*cmdline); 716*63d2a5c7SDorjoy Chowdhury *cmdline = NULL; 717*63d2a5c7SDorjoy Chowdhury 718*63d2a5c7SDorjoy Chowdhury return false; 719*63d2a5c7SDorjoy Chowdhury } 720