1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * 4 * uefi vars device - parse and generate efi signature databases 5 */ 6 7 #include "qemu/osdep.h" 8 #include "qemu/error-report.h" 9 #include "system/dma.h" 10 11 #include "hw/uefi/var-service.h" 12 13 /* 14 * Add x509 certificate to list (with duplicate check). 15 */ 16 static void uefi_vars_siglist_add_x509(uefi_vars_siglist *siglist, 17 QemuUUID *owner, 18 void *data, uint64_t size) 19 { 20 uefi_vars_cert *c; 21 22 QTAILQ_FOREACH(c, &siglist->x509, next) { 23 if (c->size != size) { 24 continue; 25 } 26 if (memcmp(c->data, data, size) != 0) { 27 continue; 28 } 29 return; 30 } 31 32 c = g_malloc(sizeof(*c) + size); 33 c->owner = *owner; 34 c->size = size; 35 memcpy(c->data, data, size); 36 QTAILQ_INSERT_TAIL(&siglist->x509, c, next); 37 } 38 39 /* 40 * Add sha256 hash to list (with duplicate check). 41 */ 42 static void uefi_vars_siglist_add_sha256(uefi_vars_siglist *siglist, 43 QemuUUID *owner, 44 void *data) 45 { 46 uefi_vars_hash *h; 47 48 QTAILQ_FOREACH(h, &siglist->sha256, next) { 49 if (memcmp(h->data, data, 32) != 0) { 50 continue; 51 } 52 return; 53 } 54 55 h = g_malloc(sizeof(*h) + 32); 56 h->owner = *owner; 57 memcpy(h->data, data, 32); 58 QTAILQ_INSERT_TAIL(&siglist->sha256, h, next); 59 } 60 61 void uefi_vars_siglist_init(uefi_vars_siglist *siglist) 62 { 63 memset(siglist, 0, sizeof(*siglist)); 64 QTAILQ_INIT(&siglist->x509); 65 QTAILQ_INIT(&siglist->sha256); 66 } 67 68 void uefi_vars_siglist_free(uefi_vars_siglist *siglist) 69 { 70 uefi_vars_cert *c, *cs; 71 uefi_vars_hash *h, *hs; 72 73 QTAILQ_FOREACH_SAFE(c, &siglist->x509, next, cs) { 74 QTAILQ_REMOVE(&siglist->x509, c, next); 75 g_free(c); 76 } 77 QTAILQ_FOREACH_SAFE(h, &siglist->sha256, next, hs) { 78 QTAILQ_REMOVE(&siglist->sha256, h, next); 79 g_free(h); 80 } 81 } 82 83 /* 84 * Parse UEFI signature list. 85 */ 86 void uefi_vars_siglist_parse(uefi_vars_siglist *siglist, 87 void *data, uint64_t size) 88 { 89 efi_siglist *efilist; 90 uint64_t start; 91 92 while (size) { 93 if (size < sizeof(*efilist)) { 94 break; 95 } 96 efilist = data; 97 if (size < efilist->siglist_size) { 98 break; 99 } 100 101 if (uadd64_overflow(sizeof(*efilist), efilist->header_size, &start)) { 102 break; 103 } 104 if (efilist->sig_size <= sizeof(QemuUUID)) { 105 break; 106 } 107 108 if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertX509Guid)) { 109 if (start + efilist->sig_size != efilist->siglist_size) { 110 break; 111 } 112 uefi_vars_siglist_add_x509(siglist, 113 (QemuUUID *)(data + start), 114 data + start + sizeof(QemuUUID), 115 efilist->sig_size - sizeof(QemuUUID)); 116 117 } else if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertSha256Guid)) { 118 if (efilist->sig_size != sizeof(QemuUUID) + 32) { 119 break; 120 } 121 if (start + efilist->sig_size > efilist->siglist_size) { 122 break; 123 } 124 while (start <= efilist->siglist_size - efilist->sig_size) { 125 uefi_vars_siglist_add_sha256(siglist, 126 (QemuUUID *)(data + start), 127 data + start + sizeof(QemuUUID)); 128 start += efilist->sig_size; 129 } 130 131 } else { 132 QemuUUID be = qemu_uuid_bswap(efilist->guid_type); 133 char *str_uuid = qemu_uuid_unparse_strdup(&be); 134 warn_report("%s: unknown type (%s)", __func__, str_uuid); 135 g_free(str_uuid); 136 } 137 138 data += efilist->siglist_size; 139 size -= efilist->siglist_size; 140 } 141 } 142 143 uint64_t uefi_vars_siglist_blob_size(uefi_vars_siglist *siglist) 144 { 145 uefi_vars_cert *c; 146 uefi_vars_hash *h; 147 uint64_t size = 0; 148 149 QTAILQ_FOREACH(c, &siglist->x509, next) { 150 size += sizeof(efi_siglist) + sizeof(QemuUUID) + c->size; 151 } 152 153 if (!QTAILQ_EMPTY(&siglist->sha256)) { 154 size += sizeof(efi_siglist); 155 QTAILQ_FOREACH(h, &siglist->sha256, next) { 156 size += sizeof(QemuUUID) + 32; 157 } 158 } 159 160 return size; 161 } 162 163 /* 164 * Generate UEFI signature list. 165 */ 166 void uefi_vars_siglist_blob_generate(uefi_vars_siglist *siglist, 167 void *data, uint64_t size) 168 { 169 uefi_vars_cert *c; 170 uefi_vars_hash *h; 171 efi_siglist *efilist; 172 uint64_t pos = 0, start; 173 uint32_t i; 174 175 QTAILQ_FOREACH(c, &siglist->x509, next) { 176 efilist = data + pos; 177 efilist->guid_type = EfiCertX509Guid; 178 efilist->sig_size = sizeof(QemuUUID) + c->size; 179 efilist->header_size = 0; 180 181 start = pos + sizeof(efi_siglist); 182 memcpy(data + start, 183 &c->owner, sizeof(QemuUUID)); 184 memcpy(data + start + sizeof(QemuUUID), 185 c->data, c->size); 186 187 efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size; 188 pos += efilist->siglist_size; 189 } 190 191 if (!QTAILQ_EMPTY(&siglist->sha256)) { 192 efilist = data + pos; 193 efilist->guid_type = EfiCertSha256Guid; 194 efilist->sig_size = sizeof(QemuUUID) + 32; 195 efilist->header_size = 0; 196 197 i = 0; 198 start = pos + sizeof(efi_siglist); 199 QTAILQ_FOREACH(h, &siglist->sha256, next) { 200 memcpy(data + start + efilist->sig_size * i, 201 &h->owner, sizeof(QemuUUID)); 202 memcpy(data + start + efilist->sig_size * i + sizeof(QemuUUID), 203 h->data, 32); 204 i++; 205 } 206 207 efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size * i; 208 pos += efilist->siglist_size; 209 } 210 211 assert(pos == size); 212 } 213