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