Home | History | Annotate | Line # | Download | only in efi
certs.c revision 1.2
      1 /* $NetBSD: certs.c,v 1.2 2025/02/25 20:23:19 rillig 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.2 2025/02/25 20:23:19 rillig 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((void *)&s->ToBeSignedHash, sizeof(s->ToBeSignedHash), "  ");
    224 	printf("%*sTimeOfRevocation: ", indent, "");
    225 	show_time(&s->TimeOfRevocation, indent);
    226 	return 0;
    227 }
    228 
    229 static int
    230 sigfn384(const void *vp, size_t sz, int indent)
    231 {
    232 	const struct {
    233 		uuid_t uuid;
    234 		EFI_SHA384_HASH		ToBeSignedHash;
    235 		EFI_TIME		TimeOfRevocation;
    236 	} __packed *s = vp;
    237 
    238 	assert(sizeof(*s) == sizeof(s->uuid) + sz);
    239 	printf("%*sOwner: ", indent, "");
    240 	uuid_printf(&s->uuid);
    241 	printf("\n");
    242 	show_data((void *)&s->ToBeSignedHash, sizeof(s->ToBeSignedHash), "  ");
    243 	printf("%*sTimeOfRevocation: ", indent, "");
    244 	show_time(&s->TimeOfRevocation, indent);
    245 	return 0;
    246 }
    247 
    248 static int
    249 sigfn512(const void *vp, size_t sz, int indent)
    250 {
    251 	const struct {
    252 		uuid_t uuid;
    253 		EFI_SHA512_HASH		ToBeSignedHash;
    254 		EFI_TIME		TimeOfRevocation;
    255 	} __packed *s = vp;
    256 
    257 	assert(sizeof(*s) == sizeof(s->uuid) + sz);
    258 	printf("%*sOwner: ", indent, "");
    259 	uuid_printf(&s->uuid);
    260 	printf("\n");
    261 	show_data((void *)&s->ToBeSignedHash, sizeof(s->ToBeSignedHash), "  ");
    262 	printf("%*sTimeOfRevocation: ", indent, "");
    263 	show_time(&s->TimeOfRevocation, indent);
    264 	return 0;
    265 }
    266 
    267 /************************************************************************/
    268 
    269 struct cert_tbl {
    270 	uuid_t guid;
    271 	const char *name;
    272 	int (*sigfn)(const void *, size_t, int);
    273 	size_t sigsz;
    274 };
    275 
    276 static int
    277 sortcmpfn(const void *a, const void *b)
    278 {
    279 	const struct cert_tbl *p = a;
    280 	const struct cert_tbl *q = b;
    281 
    282 	return memcmp(&p->guid, &q->guid, sizeof(p->guid));
    283 }
    284 
    285 static int
    286 srchcmpfn(const void *a, const void *b)
    287 {
    288 	const struct cert_tbl *q = b;
    289 
    290 	return memcmp(a, &q->guid, sizeof(q->guid));
    291 }
    292 
    293 static struct cert_tbl *
    294 get_cert_info(uuid_t *uuid)
    295 {
    296 	static bool init_done = false;
    297 	static struct cert_tbl tbl[] = {
    298 #define _X(c,f,s)	{ .guid = EFI_CERT_ ## c ## _GUID, .name = #c, \
    299  			  .sigfn = f, .sigsz = s, },
    300 		EFI_CERT_GUIDS
    301 #undef _X
    302 	};
    303 	struct cert_tbl *tp;
    304 
    305 	if (!init_done) {
    306 		qsort(tbl, __arraycount(tbl), sizeof(*tbl), sortcmpfn);
    307 		init_done = true;
    308 	}
    309 
    310 	tp = bsearch(uuid, tbl, __arraycount(tbl), sizeof(*tbl), srchcmpfn);
    311 	if (tp == NULL) {
    312 		printf("unknown owner GUID: ");
    313 		uuid_printf(uuid);
    314 		printf("\n");
    315 	}
    316 	return tp;
    317 }
    318 
    319 /************************************************************************/
    320 
    321 static inline const char *
    322 cert_info_name(struct cert_tbl *tp)
    323 {
    324 
    325 	return tp ? tp->name : EFI_CERT_GUID_UNKNOWN;
    326 }
    327 
    328 PUBLIC const char *
    329 get_cert_name(uuid_t *uuid)
    330 {
    331 
    332 	return cert_info_name(get_cert_info(uuid));
    333 }
    334 
    335 static struct cert_tbl *
    336 show_signature_list_header(EFI_SIGNATURE_LIST_t *lp, int indent)
    337 {
    338 	struct cert_tbl *tp;
    339 	const char *name;
    340 
    341 	tp = get_cert_info(&lp->SignatureType);
    342 	name = cert_info_name(tp);
    343 	printf("%*sSigType: %s\n", indent, "", name);
    344 	printf("%*sListSize: %d (0x%x)\n", indent, "",
    345 	    lp->SignatureListSize, lp->SignatureListSize);
    346 	printf("%*sHdrSize: %d (0x%x)\n", indent, "",
    347 	    lp->SignatureHeaderSize, lp->SignatureHeaderSize);
    348 	printf("%*sSigSize: %d (0x%x)\n", indent, "",
    349 	    lp->SignatureSize, lp->SignatureSize);
    350 
    351 	return tp;
    352 }
    353 
    354 static int
    355 parse_signature_list(const uint8_t *bp, size_t sz, int indent)
    356 {
    357 	union {
    358 		const uint8_t *bp;
    359 		EFI_SIGNATURE_LIST_t *lp;
    360 	} u;
    361 	struct cert_tbl *tp;
    362 	const uint8_t *endall, *endlist;
    363 
    364 	u.bp = bp;
    365 	endall = bp + sz;
    366 	while (u.bp < endall) {
    367 		tp = show_signature_list_header(u.lp, indent);
    368 
    369 		/*
    370 		 * XXX: all the documented cases seem to have no
    371 		 * signature header.
    372 		 */
    373 		if (u.lp->SignatureHeaderSize != 0) {
    374 			printf("expected zero SignatureHeaderSize: got %d\n",
    375 			    u.lp->SignatureHeaderSize);
    376 		}
    377 		assert(u.lp->SignatureHeaderSize == 0);
    378 
    379 		/*
    380 		 * Sanity check.
    381 		 */
    382 		if (tp && tp->sigsz && tp->sigsz != u.lp->SignatureSize) {
    383 			printf("expected signature size: %zu, got: %u\n",
    384 			    tp->sigsz, u.lp->SignatureSize);
    385 		}
    386 
    387 		endlist = u.bp + u.lp->SignatureListSize;
    388 		for (uint8_t *sp = u.lp->SignatureListBody
    389 			 + u.lp->SignatureHeaderSize;
    390 		     sp < endlist;
    391 		     sp += u.lp->SignatureSize) {
    392 			if (tp)
    393 				tp->sigfn(sp, u.lp->SignatureSize, 2);
    394 			else
    395 				sigfn0(sp, u.lp->SignatureSize, 2);
    396 		}
    397 
    398 		u.bp = endlist;
    399 	}
    400 	return 0;
    401 }
    402 
    403 PUBLIC int
    404 show_cert_data(efi_var_t *v, bool dbg)
    405 {
    406 	union {
    407 		const uint8_t *bp;
    408 		EFI_SIGNATURE_LIST_t *lp;
    409 	} u;
    410 	const uint8_t *end;
    411 	const char *name;
    412 
    413 	printf("%s: ", v->name);
    414 
    415 	u.bp = v->ev.data;
    416 	end = u.bp + v->ev.datasize;
    417 	for (;;) {
    418 		name = get_cert_name(&u.lp->SignatureType);
    419 
    420 		u.bp += u.lp->SignatureListSize;
    421 		if (u.bp < end)
    422 			printf("%s ", name);
    423 		else {
    424 			printf("%s\n", name);
    425 			break;
    426 		}
    427 	}
    428 
    429 	if (dbg)
    430 		parse_signature_list(v->ev.data, v->ev.datasize, 2);
    431 
    432 	return 0;
    433 }
    434