Skip to content

Commit f903e88

Browse files
committed
hw/uefi: add var-service-siglist.c
Functions to serialize and de-serialize EFI signature databases. This is needed to merge signature databases (happens in practice when appending dbx updates) and also to extract the certificates for pkcs7 signature verification. Signed-off-by: Gerd Hoffmann <[email protected]> Message-ID: <[email protected]>
1 parent 4ec89b0 commit f903e88

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

hw/uefi/var-service-siglist.c

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
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+
}

0 commit comments

Comments
 (0)