Home | History | Annotate | Line # | Download | only in efi
      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