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