certs.c revision 1.2 1 1.2 rillig /* $NetBSD: certs.c,v 1.2 2025/02/25 20:23:19 rillig Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Redistribution and use in source and binary forms, with or without
5 1.1 christos * modification, are permitted provided that the following conditions
6 1.1 christos * are met:
7 1.1 christos * 1. Redistributions of source code must retain the above copyright
8 1.1 christos * notice, this list of conditions and the following disclaimer.
9 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
10 1.1 christos * notice, this list of conditions and the following disclaimer in the
11 1.1 christos * documentation and/or other materials provided with the distribution.
12 1.1 christos *
13 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 1.1 christos * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 1.1 christos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 1.1 christos * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 1.1 christos * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 1.1 christos * SUCH DAMAGE.
24 1.1 christos */
25 1.1 christos
26 1.1 christos #include <sys/cdefs.h>
27 1.1 christos #ifndef lint
28 1.2 rillig __RCSID("$NetBSD: certs.c,v 1.2 2025/02/25 20:23:19 rillig Exp $");
29 1.1 christos #endif /* not lint */
30 1.1 christos
31 1.1 christos #include <assert.h>
32 1.1 christos #include <stdbool.h>
33 1.1 christos #include <stdio.h>
34 1.1 christos #include <stdlib.h>
35 1.1 christos #include <sys/efiio.h>
36 1.1 christos
37 1.1 christos #include "efiio.h"
38 1.1 christos #include "defs.h"
39 1.1 christos #include "certs.h"
40 1.1 christos
41 1.1 christos /*
42 1.1 christos * See UEFI spec section 32.4
43 1.1 christos */
44 1.1 christos
45 1.1 christos #define EFI_CERT_SHA256_GUID \
46 1.2 rillig {0xc1c41626,0x504c,0x4092,0xac,0xa9,\
47 1.2 rillig {0x41,0xf9,0x36,0x93,0x43,0x28}}
48 1.1 christos
49 1.1 christos #define EFI_CERT_RSA2048_GUID \
50 1.2 rillig {0x3c5766e8,0x269c,0x4e34,0xaa,0x14,\
51 1.2 rillig {0xed,0x77,0x6e,0x85,0xb3,0xb6}}
52 1.1 christos
53 1.1 christos #define EFI_CERT_RSA2048_SHA256_GUID \
54 1.2 rillig {0xe2b36190,0x879b,0x4a3d,0xad,0x8d,\
55 1.2 rillig {0xf2,0xe7,0xbb,0xa3,0x27,0x84}}
56 1.1 christos
57 1.1 christos #define EFI_CERT_SHA1_GUID \
58 1.2 rillig {0x826ca512,0xcf10,0x4ac9,0xb1,0x87,\
59 1.2 rillig {0xbe,0x01,0x49,0x66,0x31,0xbd}}
60 1.1 christos
61 1.1 christos #define EFI_CERT_RSA2048_SHA1_GUID \
62 1.2 rillig {0x67f8444f,0x8743,0x48f1,0xa3,0x28,\
63 1.2 rillig {0x1e,0xaa,0xb8,0x73,0x60,0x80}}
64 1.1 christos
65 1.1 christos #define EFI_CERT_X509_GUID \
66 1.2 rillig {0xa5c059a1,0x94e4,0x4aa7,0x87,0xb5,\
67 1.2 rillig {0xab,0x15,0x5c,0x2b,0xf0,0x72}}
68 1.1 christos
69 1.1 christos #define EFI_CERT_SHA224_GUID \
70 1.2 rillig {0x0b6e5233,0xa65c,0x44c9,0x94,0x07,\
71 1.2 rillig {0xd9,0xab,0x83,0xbf,0xc8,0xbd}}
72 1.1 christos
73 1.1 christos #define EFI_CERT_SHA384_GUID \
74 1.2 rillig {0xff3e5307,0x9fd0,0x48c9,0x85,0xf1,\
75 1.2 rillig {0x8a,0xd5,0x6c,0x70,0x1e,0x01}}
76 1.1 christos
77 1.1 christos #define EFI_CERT_SHA512_GUID \
78 1.2 rillig {0x093e0fae,0xa6c4,0x4f50,0x9f,0x1b,\
79 1.2 rillig {0xd4,0x1e,0x2b,0x89,0xc1,0x9a}}
80 1.1 christos
81 1.1 christos #define EFI_CERT_X509_SHA256_GUID \
82 1.2 rillig {0x3bd2a492,0x96c0,0x4079,0xb4,0x20,\
83 1.2 rillig {0xfc,0xf9,0x8e,0xf1,0x03,0xed}}
84 1.1 christos
85 1.1 christos #define EFI_CERT_X509_SHA384_GUID \
86 1.2 rillig {0x7076876e,0x80c2,0x4ee6,0xaa,0xd2,\
87 1.2 rillig {0x28,0xb3,0x49,0xa6,0x86,0x5b}}
88 1.1 christos
89 1.1 christos #define EFI_CERT_X509_SHA512_GUID \
90 1.2 rillig {0x446dbf63,0x2502,0x4cda,0xbc,0xfa,\
91 1.2 rillig {0x24,0x65,0xd2,0xb0,0xfe,0x9d}}
92 1.1 christos
93 1.1 christos #define EFI_CERT_EXTERNAL_MANAGEMENT_GUID \
94 1.2 rillig {0x452e8ced,0xdfff,0x4b8c,0xae,0x01,\
95 1.2 rillig {0x51,0x18,0x86,0x2e,0x68,0x2c}}
96 1.1 christos
97 1.1 christos #define EFI_CERT_GUIDS \
98 1.1 christos _X(SHA256, sigfn0, 16 + 32) \
99 1.1 christos _X(RSA2048, sigfn0, 16 + 256) \
100 1.1 christos _X(RSA2048_SHA256, sigfn0, 16 + 256) \
101 1.1 christos _X(SHA1, sigfn0, 16 + 20) \
102 1.1 christos _X(RSA2048_SHA1, sigfn0, 16 + 256) \
103 1.1 christos _X(X509, sigfn0, 0) \
104 1.1 christos _X(SHA224, sigfn0, 16 + 28) \
105 1.1 christos _X(SHA384, sigfn0, 16 + 48) \
106 1.1 christos _X(SHA512, sigfn0, 16 + 64) \
107 1.1 christos _X(X509_SHA256, sigfn256, 16 + 48) \
108 1.1 christos _X(X509_SHA384, sigfn384, 16 + 64) \
109 1.1 christos _X(X509_SHA512, sigfn512, 16 + 80) \
110 1.1 christos _X(EXTERNAL_MANAGEMENT, sigfn1, 16 + 1)
111 1.1 christos
112 1.1 christos #define EFI_CERT_GUID_UNKNOWN "unknown"
113 1.1 christos
114 1.1 christos /************************************************************************/
115 1.1 christos
116 1.1 christos typedef uint8_t EFI_SHA256_HASH[32];
117 1.1 christos typedef uint8_t EFI_SHA384_HASH[48];
118 1.1 christos typedef uint8_t EFI_SHA512_HASH[64];
119 1.1 christos
120 1.1 christos typedef struct EFI_SIGNATURE_DAT {
121 1.1 christos uuid_t SignatureOwner;
122 1.1 christos uint8_t SignatureData[];
123 1.1 christos } __packed EFI_SIGNATURE_DATA_t;
124 1.1 christos
125 1.1 christos typedef struct EFI_SIGNATURE_LIST {
126 1.1 christos uuid_t SignatureType;
127 1.1 christos uint32_t SignatureListSize;
128 1.1 christos uint32_t SignatureHeaderSize;
129 1.1 christos uint32_t SignatureSize;
130 1.1 christos uint8_t SignatureListBody[];
131 1.1 christos // uint8_t SignatureHeader[SignatureHeaderSize];
132 1.1 christos // EFI_SIGNATURE_DATA Signatures[][SignatureSize];
133 1.1 christos } __packed EFI_SIGNATURE_LIST_t;
134 1.1 christos
135 1.1 christos typedef struct {
136 1.1 christos uint16_t Year; // 1900 - 9999
137 1.1 christos uint8_t Month; // 1 - 12
138 1.1 christos uint8_t Day; // 1 - 31
139 1.1 christos uint8_t Hour; // 0 - 23
140 1.1 christos uint8_t Minute; // 0 - 59
141 1.1 christos uint8_t Second; // 0 - 59
142 1.1 christos uint8_t Pad1;
143 1.1 christos uint32_t Nanosecond; // 0 - 999,999,999
144 1.1 christos int16_t TimeZone; // -1440 to 1440 or 2047 (0x7ff)
145 1.1 christos #define EFI_UNSPECIFIED_TIMEZONE 0x07FF
146 1.1 christos uint8_t Daylight;
147 1.1 christos #define EFI_TIME_ADJUST_DAYLIGHT 0x01
148 1.1 christos #define EFI_TIME_IN_DAYLIGHT 0x02
149 1.1 christos uint8_t Pad2;
150 1.1 christos } __packed EFI_TIME;
151 1.1 christos
152 1.1 christos /************************************************************************/
153 1.1 christos
154 1.1 christos static char *
155 1.1 christos show_time(const EFI_TIME *et, int indent)
156 1.1 christos {
157 1.1 christos /*
158 1.1 christos * XXX: Deal with the Daylight flags!
159 1.1 christos */
160 1.1 christos printf("%*s%u.%u.%u %u:%u:%u.%u",
161 1.1 christos indent, "",
162 1.1 christos et->Year,
163 1.1 christos et->Month,
164 1.1 christos et->Day,
165 1.1 christos et->Hour,
166 1.1 christos et->Minute,
167 1.1 christos et->Second,
168 1.1 christos et->Nanosecond);
169 1.1 christos if (et->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
170 1.1 christos printf(" (%d)", et->TimeZone);
171 1.1 christos }
172 1.1 christos printf("\n");
173 1.1 christos
174 1.1 christos return NULL;
175 1.1 christos }
176 1.1 christos
177 1.1 christos /************************************************************************/
178 1.1 christos
179 1.1 christos static int
180 1.1 christos sigfn0(const void *vp, size_t sz, int indent)
181 1.1 christos {
182 1.1 christos const struct {
183 1.1 christos uuid_t uuid;
184 1.1 christos uint8_t data[];
185 1.1 christos } __packed *s = vp;
186 1.1 christos
187 1.1 christos printf("%*sOwner: ", indent, "");
188 1.1 christos uuid_printf(&s->uuid);
189 1.1 christos printf("\n");
190 1.1 christos show_data(s->data, sz, " ");
191 1.1 christos return 0;
192 1.1 christos }
193 1.1 christos
194 1.1 christos static int
195 1.1 christos sigfn1(const void *vp, size_t sz, int indent)
196 1.1 christos {
197 1.1 christos const struct {
198 1.1 christos uuid_t uuid;
199 1.1 christos uint8_t zero;
200 1.1 christos } __packed *s = vp;
201 1.1 christos
202 1.1 christos assert(sizeof(*s) == sizeof(s->uuid) + sz);
203 1.1 christos printf("%*sOwner: ", indent, "");
204 1.1 christos uuid_printf(&s->uuid);
205 1.1 christos printf("\n");
206 1.1 christos printf("%*szero: 0x%02x\n", indent, "", s->zero);
207 1.1 christos return 0;
208 1.1 christos }
209 1.1 christos
210 1.1 christos static int
211 1.1 christos sigfn256(const void *vp, size_t sz, int indent)
212 1.1 christos {
213 1.1 christos const struct {
214 1.1 christos uuid_t uuid;
215 1.1 christos EFI_SHA256_HASH ToBeSignedHash;
216 1.1 christos EFI_TIME TimeOfRevocation;
217 1.1 christos } __packed *s = vp;
218 1.1 christos
219 1.1 christos assert(sizeof(*s) == sizeof(s->uuid) + sz);
220 1.1 christos printf("%*sOwner: ", indent, "");
221 1.1 christos uuid_printf(&s->uuid);
222 1.1 christos printf("\n");
223 1.1 christos show_data((void *)&s->ToBeSignedHash, sizeof(s->ToBeSignedHash), " ");
224 1.1 christos printf("%*sTimeOfRevocation: ", indent, "");
225 1.1 christos show_time(&s->TimeOfRevocation, indent);
226 1.1 christos return 0;
227 1.1 christos }
228 1.1 christos
229 1.1 christos static int
230 1.1 christos sigfn384(const void *vp, size_t sz, int indent)
231 1.1 christos {
232 1.1 christos const struct {
233 1.1 christos uuid_t uuid;
234 1.1 christos EFI_SHA384_HASH ToBeSignedHash;
235 1.1 christos EFI_TIME TimeOfRevocation;
236 1.1 christos } __packed *s = vp;
237 1.1 christos
238 1.1 christos assert(sizeof(*s) == sizeof(s->uuid) + sz);
239 1.1 christos printf("%*sOwner: ", indent, "");
240 1.1 christos uuid_printf(&s->uuid);
241 1.1 christos printf("\n");
242 1.1 christos show_data((void *)&s->ToBeSignedHash, sizeof(s->ToBeSignedHash), " ");
243 1.1 christos printf("%*sTimeOfRevocation: ", indent, "");
244 1.1 christos show_time(&s->TimeOfRevocation, indent);
245 1.1 christos return 0;
246 1.1 christos }
247 1.1 christos
248 1.1 christos static int
249 1.1 christos sigfn512(const void *vp, size_t sz, int indent)
250 1.1 christos {
251 1.1 christos const struct {
252 1.1 christos uuid_t uuid;
253 1.1 christos EFI_SHA512_HASH ToBeSignedHash;
254 1.1 christos EFI_TIME TimeOfRevocation;
255 1.1 christos } __packed *s = vp;
256 1.1 christos
257 1.1 christos assert(sizeof(*s) == sizeof(s->uuid) + sz);
258 1.1 christos printf("%*sOwner: ", indent, "");
259 1.1 christos uuid_printf(&s->uuid);
260 1.1 christos printf("\n");
261 1.1 christos show_data((void *)&s->ToBeSignedHash, sizeof(s->ToBeSignedHash), " ");
262 1.1 christos printf("%*sTimeOfRevocation: ", indent, "");
263 1.1 christos show_time(&s->TimeOfRevocation, indent);
264 1.1 christos return 0;
265 1.1 christos }
266 1.1 christos
267 1.1 christos /************************************************************************/
268 1.1 christos
269 1.1 christos struct cert_tbl {
270 1.1 christos uuid_t guid;
271 1.1 christos const char *name;
272 1.1 christos int (*sigfn)(const void *, size_t, int);
273 1.1 christos size_t sigsz;
274 1.1 christos };
275 1.1 christos
276 1.1 christos static int
277 1.1 christos sortcmpfn(const void *a, const void *b)
278 1.1 christos {
279 1.1 christos const struct cert_tbl *p = a;
280 1.1 christos const struct cert_tbl *q = b;
281 1.1 christos
282 1.1 christos return memcmp(&p->guid, &q->guid, sizeof(p->guid));
283 1.1 christos }
284 1.1 christos
285 1.1 christos static int
286 1.1 christos srchcmpfn(const void *a, const void *b)
287 1.1 christos {
288 1.1 christos const struct cert_tbl *q = b;
289 1.1 christos
290 1.1 christos return memcmp(a, &q->guid, sizeof(q->guid));
291 1.1 christos }
292 1.1 christos
293 1.1 christos static struct cert_tbl *
294 1.1 christos get_cert_info(uuid_t *uuid)
295 1.1 christos {
296 1.1 christos static bool init_done = false;
297 1.1 christos static struct cert_tbl tbl[] = {
298 1.1 christos #define _X(c,f,s) { .guid = EFI_CERT_ ## c ## _GUID, .name = #c, \
299 1.1 christos .sigfn = f, .sigsz = s, },
300 1.1 christos EFI_CERT_GUIDS
301 1.1 christos #undef _X
302 1.1 christos };
303 1.1 christos struct cert_tbl *tp;
304 1.1 christos
305 1.1 christos if (!init_done) {
306 1.1 christos qsort(tbl, __arraycount(tbl), sizeof(*tbl), sortcmpfn);
307 1.1 christos init_done = true;
308 1.1 christos }
309 1.1 christos
310 1.1 christos tp = bsearch(uuid, tbl, __arraycount(tbl), sizeof(*tbl), srchcmpfn);
311 1.1 christos if (tp == NULL) {
312 1.1 christos printf("unknown owner GUID: ");
313 1.1 christos uuid_printf(uuid);
314 1.1 christos printf("\n");
315 1.1 christos }
316 1.1 christos return tp;
317 1.1 christos }
318 1.1 christos
319 1.1 christos /************************************************************************/
320 1.1 christos
321 1.1 christos static inline const char *
322 1.1 christos cert_info_name(struct cert_tbl *tp)
323 1.1 christos {
324 1.1 christos
325 1.1 christos return tp ? tp->name : EFI_CERT_GUID_UNKNOWN;
326 1.1 christos }
327 1.1 christos
328 1.1 christos PUBLIC const char *
329 1.1 christos get_cert_name(uuid_t *uuid)
330 1.1 christos {
331 1.1 christos
332 1.1 christos return cert_info_name(get_cert_info(uuid));
333 1.1 christos }
334 1.1 christos
335 1.1 christos static struct cert_tbl *
336 1.1 christos show_signature_list_header(EFI_SIGNATURE_LIST_t *lp, int indent)
337 1.1 christos {
338 1.1 christos struct cert_tbl *tp;
339 1.1 christos const char *name;
340 1.1 christos
341 1.1 christos tp = get_cert_info(&lp->SignatureType);
342 1.1 christos name = cert_info_name(tp);
343 1.1 christos printf("%*sSigType: %s\n", indent, "", name);
344 1.1 christos printf("%*sListSize: %d (0x%x)\n", indent, "",
345 1.1 christos lp->SignatureListSize, lp->SignatureListSize);
346 1.1 christos printf("%*sHdrSize: %d (0x%x)\n", indent, "",
347 1.1 christos lp->SignatureHeaderSize, lp->SignatureHeaderSize);
348 1.1 christos printf("%*sSigSize: %d (0x%x)\n", indent, "",
349 1.1 christos lp->SignatureSize, lp->SignatureSize);
350 1.1 christos
351 1.1 christos return tp;
352 1.1 christos }
353 1.1 christos
354 1.1 christos static int
355 1.1 christos parse_signature_list(const uint8_t *bp, size_t sz, int indent)
356 1.1 christos {
357 1.1 christos union {
358 1.1 christos const uint8_t *bp;
359 1.1 christos EFI_SIGNATURE_LIST_t *lp;
360 1.1 christos } u;
361 1.1 christos struct cert_tbl *tp;
362 1.1 christos const uint8_t *endall, *endlist;
363 1.1 christos
364 1.1 christos u.bp = bp;
365 1.1 christos endall = bp + sz;
366 1.1 christos while (u.bp < endall) {
367 1.1 christos tp = show_signature_list_header(u.lp, indent);
368 1.1 christos
369 1.1 christos /*
370 1.1 christos * XXX: all the documented cases seem to have no
371 1.1 christos * signature header.
372 1.1 christos */
373 1.1 christos if (u.lp->SignatureHeaderSize != 0) {
374 1.1 christos printf("expected zero SignatureHeaderSize: got %d\n",
375 1.1 christos u.lp->SignatureHeaderSize);
376 1.1 christos }
377 1.1 christos assert(u.lp->SignatureHeaderSize == 0);
378 1.1 christos
379 1.1 christos /*
380 1.1 christos * Sanity check.
381 1.1 christos */
382 1.1 christos if (tp && tp->sigsz && tp->sigsz != u.lp->SignatureSize) {
383 1.1 christos printf("expected signature size: %zu, got: %u\n",
384 1.1 christos tp->sigsz, u.lp->SignatureSize);
385 1.1 christos }
386 1.1 christos
387 1.1 christos endlist = u.bp + u.lp->SignatureListSize;
388 1.1 christos for (uint8_t *sp = u.lp->SignatureListBody
389 1.1 christos + u.lp->SignatureHeaderSize;
390 1.1 christos sp < endlist;
391 1.1 christos sp += u.lp->SignatureSize) {
392 1.1 christos if (tp)
393 1.1 christos tp->sigfn(sp, u.lp->SignatureSize, 2);
394 1.1 christos else
395 1.1 christos sigfn0(sp, u.lp->SignatureSize, 2);
396 1.1 christos }
397 1.1 christos
398 1.1 christos u.bp = endlist;
399 1.1 christos }
400 1.1 christos return 0;
401 1.1 christos }
402 1.1 christos
403 1.1 christos PUBLIC int
404 1.1 christos show_cert_data(efi_var_t *v, bool dbg)
405 1.1 christos {
406 1.1 christos union {
407 1.1 christos const uint8_t *bp;
408 1.1 christos EFI_SIGNATURE_LIST_t *lp;
409 1.1 christos } u;
410 1.1 christos const uint8_t *end;
411 1.1 christos const char *name;
412 1.1 christos
413 1.1 christos printf("%s: ", v->name);
414 1.1 christos
415 1.1 christos u.bp = v->ev.data;
416 1.1 christos end = u.bp + v->ev.datasize;
417 1.1 christos for (;;) {
418 1.1 christos name = get_cert_name(&u.lp->SignatureType);
419 1.1 christos
420 1.1 christos u.bp += u.lp->SignatureListSize;
421 1.1 christos if (u.bp < end)
422 1.1 christos printf("%s ", name);
423 1.1 christos else {
424 1.1 christos printf("%s\n", name);
425 1.1 christos break;
426 1.1 christos }
427 1.1 christos }
428 1.1 christos
429 1.1 christos if (dbg)
430 1.1 christos parse_signature_list(v->ev.data, v->ev.datasize, 2);
431 1.1 christos
432 1.1 christos return 0;
433 1.1 christos }
434