xref: /qemu/hw/uefi/var-service-siglist.c (revision 50aa3d0984d8a4a9c39d34e2f81e8a70674462e4)
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