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