]> git.proxmox.com Git - efi-boot-shim.git/blob - MokManager.c
fix nit
[efi-boot-shim.git] / MokManager.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2
3 #include <efi.h>
4 #include <efilib.h>
5 #include <stdarg.h>
6 #include <Library/BaseCryptLib.h>
7 #include <openssl/x509.h>
8 #include <openssl/x509v3.h>
9 #include <openssl/asn1.h>
10 #include <openssl/bn.h>
11
12 #include "shim.h"
13
14 #include "hexdump.h"
15
16 #define PASSWORD_MAX 256
17 #define PASSWORD_MIN 1
18 #define SB_PASSWORD_LEN 16
19
20 #define NAME_LINE_MAX 70
21
22 #ifndef SHIM_VENDOR
23 #define SHIM_VENDOR L"Shim"
24 #endif
25
26 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
27 #define HASH_STRING L"Select a file to trust:\n\n"
28
29 #define CompareMemberGuid(x, y) CompareMem(x, y, sizeof(EFI_GUID))
30
31 typedef struct {
32 UINT32 MokSize;
33 UINT8 *Mok;
34 EFI_GUID Type;
35 } __attribute__ ((packed)) MokListNode;
36
37 typedef struct {
38 UINT32 MokSBState;
39 UINT32 PWLen;
40 CHAR16 Password[SB_PASSWORD_LEN];
41 } __attribute__ ((packed)) MokSBvar;
42
43 typedef struct {
44 UINT32 MokDBState;
45 UINT32 PWLen;
46 CHAR16 Password[SB_PASSWORD_LEN];
47 } __attribute__ ((packed)) MokDBvar;
48
49 typedef struct {
50 INT32 Timeout;
51 } __attribute__ ((packed)) MokTimeoutvar;
52
53 static EFI_STATUS get_sha1sum(void *Data, int DataSize, UINT8 * hash)
54 {
55 EFI_STATUS efi_status;
56 unsigned int ctxsize;
57 void *ctx = NULL;
58
59 ctxsize = Sha1GetContextSize();
60 ctx = AllocatePool(ctxsize);
61
62 if (!ctx) {
63 console_notify(L"Unable to allocate memory for hash context");
64 return EFI_OUT_OF_RESOURCES;
65 }
66
67 if (!Sha1Init(ctx)) {
68 console_notify(L"Unable to initialise hash");
69 efi_status = EFI_OUT_OF_RESOURCES;
70 goto done;
71 }
72
73 if (!(Sha1Update(ctx, Data, DataSize))) {
74 console_notify(L"Unable to generate hash");
75 efi_status = EFI_OUT_OF_RESOURCES;
76 goto done;
77 }
78
79 if (!(Sha1Final(ctx, hash))) {
80 console_notify(L"Unable to finalise hash");
81 efi_status = EFI_OUT_OF_RESOURCES;
82 goto done;
83 }
84
85 efi_status = EFI_SUCCESS;
86 done:
87 return efi_status;
88 }
89
90 static BOOLEAN is_sha2_hash(EFI_GUID Type)
91 {
92 if (CompareGuid(&Type, &EFI_CERT_SHA224_GUID) == 0)
93 return TRUE;
94 else if (CompareGuid(&Type, &EFI_CERT_SHA256_GUID) == 0)
95 return TRUE;
96 else if (CompareGuid(&Type, &EFI_CERT_SHA384_GUID) == 0)
97 return TRUE;
98 else if (CompareGuid(&Type, &EFI_CERT_SHA512_GUID) == 0)
99 return TRUE;
100
101 return FALSE;
102 }
103
104 static UINT32 sha_size(EFI_GUID Type)
105 {
106 if (CompareGuid(&Type, &EFI_CERT_SHA1_GUID) == 0)
107 return SHA1_DIGEST_SIZE;
108 else if (CompareGuid(&Type, &EFI_CERT_SHA224_GUID) == 0)
109 return SHA224_DIGEST_LENGTH;
110 else if (CompareGuid(&Type, &EFI_CERT_SHA256_GUID) == 0)
111 return SHA256_DIGEST_SIZE;
112 else if (CompareGuid(&Type, &EFI_CERT_SHA384_GUID) == 0)
113 return SHA384_DIGEST_LENGTH;
114 else if (CompareGuid(&Type, &EFI_CERT_SHA512_GUID) == 0)
115 return SHA512_DIGEST_LENGTH;
116
117 return 0;
118 }
119
120 static BOOLEAN is_valid_siglist(EFI_GUID Type, UINT32 SigSize)
121 {
122 UINT32 hash_sig_size;
123
124 if (CompareGuid (&Type, &X509_GUID) == 0 && SigSize != 0)
125 return TRUE;
126
127 if (!is_sha2_hash(Type))
128 return FALSE;
129
130 hash_sig_size = sha_size(Type) + sizeof(EFI_GUID);
131 if (SigSize != hash_sig_size)
132 return FALSE;
133
134 return TRUE;
135 }
136
137 static UINT32 count_keys(void *Data, UINTN DataSize)
138 {
139 EFI_SIGNATURE_LIST *CertList = Data;
140 UINTN dbsize = DataSize;
141 UINT32 MokNum = 0;
142 void *end = Data + DataSize;
143
144 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
145 /* Use ptr arithmetics to ensure bounded access. Do not allow 0
146 * SignatureListSize that will cause endless loop. */
147 if ((void *)(CertList + 1) > end
148 || CertList->SignatureListSize == 0) {
149 console_notify
150 (L"Invalid MOK detected! Ignoring MOK List.");
151 return 0;
152 }
153
154 if (CertList->SignatureListSize == 0 ||
155 CertList->SignatureListSize <= CertList->SignatureSize) {
156 console_errorbox(L"Corrupted signature list");
157 return 0;
158 }
159
160 if (!is_valid_siglist
161 (CertList->SignatureType, CertList->SignatureSize)) {
162 console_errorbox(L"Invalid signature list found");
163 return 0;
164 }
165
166 MokNum++;
167 dbsize -= CertList->SignatureListSize;
168 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
169 CertList->SignatureListSize);
170 }
171
172 return MokNum;
173 }
174
175 static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize)
176 {
177 MokListNode *list;
178 EFI_SIGNATURE_LIST *CertList = Data;
179 EFI_SIGNATURE_DATA *Cert;
180 UINTN dbsize = DataSize;
181 UINTN count = 0;
182 void *end = Data + DataSize;
183
184 list = AllocatePool(sizeof(MokListNode) * num);
185 if (!list) {
186 console_notify(L"Unable to allocate MOK list");
187 return NULL;
188 }
189
190 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
191 /* CertList out of bounds? */
192 if ((void *)(CertList + 1) > end
193 || CertList->SignatureListSize == 0) {
194 FreePool(list);
195 return NULL;
196 }
197
198 /* Omit the signature check here since we already did it
199 in count_keys() */
200
201 Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
202 sizeof(EFI_SIGNATURE_LIST) +
203 CertList->SignatureHeaderSize);
204 /* Cert out of bounds? */
205 if ((void *)(Cert + 1) > end
206 || CertList->SignatureSize <= sizeof(EFI_GUID)) {
207 FreePool(list);
208 return NULL;
209 }
210
211 list[count].Type = CertList->SignatureType;
212 if (CompareGuid (&CertList->SignatureType, &X509_GUID) == 0) {
213 list[count].MokSize = CertList->SignatureSize -
214 sizeof(EFI_GUID);
215 list[count].Mok = (void *)Cert->SignatureData;
216 } else {
217 list[count].MokSize = CertList->SignatureListSize -
218 sizeof(EFI_SIGNATURE_LIST);
219 list[count].Mok = (void *)Cert;
220 }
221
222 /* MOK out of bounds? */
223 if (list[count].MokSize > (unsigned long)end -
224 (unsigned long)list[count].Mok) {
225 FreePool(list);
226 return NULL;
227 }
228
229 count++;
230 dbsize -= CertList->SignatureListSize;
231 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
232 CertList->SignatureListSize);
233 }
234
235 return list;
236 }
237
238 typedef struct {
239 int nid;
240 CHAR16 *name;
241 } NidName;
242
243 static NidName nidname[] = {
244 {NID_commonName, L"CN"},
245 {NID_organizationName, L"O"},
246 {NID_countryName, L"C"},
247 {NID_stateOrProvinceName, L"ST"},
248 {NID_localityName, L"L"},
249 {-1, NULL}
250 };
251
252 static CHAR16 *get_x509_name(X509_NAME * X509Name)
253 {
254 CHAR16 name[NAME_LINE_MAX + 1];
255 CHAR16 part[NAME_LINE_MAX + 1];
256 char str[NAME_LINE_MAX];
257 int i, len, rest, first;
258
259 name[0] = '\0';
260 rest = NAME_LINE_MAX;
261 first = 1;
262 for (i = 0; nidname[i].name != NULL; i++) {
263 int add;
264 len = X509_NAME_get_text_by_NID(X509Name, nidname[i].nid,
265 str, NAME_LINE_MAX);
266 if (len <= 0)
267 continue;
268
269 if (first)
270 add = len + (int)StrLen(nidname[i].name) + 1;
271 else
272 add = len + (int)StrLen(nidname[i].name) + 3;
273
274 if (add > rest)
275 continue;
276
277 if (first) {
278 SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L"%s=%a",
279 nidname[i].name, str);
280 } else {
281 SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L", %s=%a",
282 nidname[i].name, str);
283 }
284 StrCat(name, part);
285 rest -= add;
286 first = 0;
287 }
288
289 if (rest >= 0 && rest < NAME_LINE_MAX)
290 return PoolPrint(L"%s", name);
291
292 return NULL;
293 }
294
295 static CHAR16 *get_x509_time(ASN1_TIME * time)
296 {
297 BIO *bio = BIO_new(BIO_s_mem());
298 char str[30];
299 int len;
300
301 ASN1_TIME_print(bio, time);
302 len = BIO_read(bio, str, 29);
303 if (len < 0)
304 len = 0;
305 str[len] = '\0';
306 BIO_free(bio);
307
308 return PoolPrint(L"%a", str);
309 }
310
311 static void show_x509_info(X509 * X509Cert, UINT8 * hash)
312 {
313 ASN1_INTEGER *serial;
314 BIGNUM *bnser;
315 unsigned char hexbuf[30];
316 X509_NAME *X509Name;
317 ASN1_TIME *time;
318 CHAR16 *issuer = NULL;
319 CHAR16 *subject = NULL;
320 CHAR16 *from = NULL;
321 CHAR16 *until = NULL;
322 EXTENDED_KEY_USAGE *extusage;
323 POOL_PRINT hash_string1;
324 POOL_PRINT hash_string2;
325 POOL_PRINT serial_string;
326 int fields = 0;
327 CHAR16 **text;
328 int i = 0;
329
330 ZeroMem(&hash_string1, sizeof(hash_string1));
331 ZeroMem(&hash_string2, sizeof(hash_string2));
332 ZeroMem(&serial_string, sizeof(serial_string));
333
334 serial = X509_get_serialNumber(X509Cert);
335 if (serial) {
336 int i, n;
337 bnser = ASN1_INTEGER_to_BN(serial, NULL);
338 n = BN_bn2bin(bnser, hexbuf);
339 for (i = 0; i < n; i++) {
340 CatPrint(&serial_string, L"%02x:", hexbuf[i]);
341 }
342 }
343
344 if (serial_string.str)
345 fields++;
346
347 X509Name = X509_get_issuer_name(X509Cert);
348 if (X509Name) {
349 issuer = get_x509_name(X509Name);
350 if (issuer)
351 fields++;
352 }
353
354 X509Name = X509_get_subject_name(X509Cert);
355 if (X509Name) {
356 subject = get_x509_name(X509Name);
357 if (subject)
358 fields++;
359 }
360
361 time = X509_get_notBefore(X509Cert);
362 if (time) {
363 from = get_x509_time(time);
364 if (from)
365 fields++;
366 }
367
368 time = X509_get_notAfter(X509Cert);
369 if (time) {
370 until = get_x509_time(time);
371 if (until)
372 fields++;
373 }
374
375 for (i = 0; i < 10; i++)
376 CatPrint(&hash_string1, L"%02x ", hash[i]);
377 for (i = 10; i < 20; i++)
378 CatPrint(&hash_string2, L"%02x ", hash[i]);
379
380 if (hash_string1.str)
381 fields++;
382
383 if (hash_string2.str)
384 fields++;
385
386 if (!fields)
387 return;
388
389 i = 0;
390
391 extusage = X509_get_ext_d2i(X509Cert, NID_ext_key_usage, NULL, NULL);
392 text = AllocateZeroPool(sizeof(CHAR16 *) *
393 (fields * 3 +
394 sk_ASN1_OBJECT_num(extusage) + 3));
395 if (extusage) {
396 int j = 0;
397
398 text[i++] = StrDuplicate(L"[Extended Key Usage]");
399
400 for (j = 0; j < sk_ASN1_OBJECT_num(extusage); j++) {
401 POOL_PRINT extkeyusage;
402 ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(extusage, j);
403 int buflen = 80;
404 char buf[buflen];
405
406 ZeroMem(&extkeyusage, sizeof(extkeyusage));
407
408 OBJ_obj2txt(buf, buflen, obj, 0);
409 CatPrint(&extkeyusage, L"OID: %a", buf);
410 text[i++] = StrDuplicate(extkeyusage.str);
411 FreePool(extkeyusage.str);
412 }
413 text[i++] = StrDuplicate(L"");
414 EXTENDED_KEY_USAGE_free(extusage);
415 }
416
417 if (serial_string.str) {
418 text[i++] = StrDuplicate(L"[Serial Number]");
419 text[i++] = serial_string.str;
420 text[i++] = StrDuplicate(L"");
421 }
422 if (issuer) {
423 text[i++] = StrDuplicate(L"[Issuer]");
424 text[i++] = issuer;
425 text[i++] = StrDuplicate(L"");
426 }
427 if (subject) {
428 text[i++] = StrDuplicate(L"[Subject]");
429 text[i++] = subject;
430 text[i++] = StrDuplicate(L"");
431 }
432 if (from) {
433 text[i++] = StrDuplicate(L"[Valid Not Before]");
434 text[i++] = from;
435 text[i++] = StrDuplicate(L"");
436 }
437 if (until) {
438 text[i++] = StrDuplicate(L"[Valid Not After]");
439 text[i++] = until;
440 text[i++] = StrDuplicate(L"");
441 }
442 if (hash_string1.str) {
443 text[i++] = StrDuplicate(L"[Fingerprint]");
444 text[i++] = hash_string1.str;
445 }
446 if (hash_string2.str) {
447 text[i++] = hash_string2.str;
448 text[i++] = StrDuplicate(L"");
449 }
450 text[i] = NULL;
451
452 console_print_box(text, -1);
453
454 for (i = 0; text[i] != NULL; i++)
455 FreePool(text[i]);
456
457 FreePool(text);
458 }
459
460 static void show_sha_digest(EFI_GUID Type, UINT8 * hash)
461 {
462 CHAR16 *text[5];
463 POOL_PRINT hash_string1;
464 POOL_PRINT hash_string2;
465 int i;
466 int length;
467
468 if (CompareGuid(&Type, &EFI_CERT_SHA1_GUID) == 0) {
469 length = SHA1_DIGEST_SIZE;
470 text[0] = L"SHA1 hash";
471 } else if (CompareGuid(&Type, &EFI_CERT_SHA224_GUID) == 0) {
472 length = SHA224_DIGEST_LENGTH;
473 text[0] = L"SHA224 hash";
474 } else if (CompareGuid(&Type, &EFI_CERT_SHA256_GUID) == 0) {
475 length = SHA256_DIGEST_SIZE;
476 text[0] = L"SHA256 hash";
477 } else if (CompareGuid(&Type, &EFI_CERT_SHA384_GUID) == 0) {
478 length = SHA384_DIGEST_LENGTH;
479 text[0] = L"SHA384 hash";
480 } else if (CompareGuid(&Type, &EFI_CERT_SHA512_GUID) == 0) {
481 length = SHA512_DIGEST_LENGTH;
482 text[0] = L"SHA512 hash";
483 } else {
484 return;
485 }
486
487 ZeroMem(&hash_string1, sizeof(hash_string1));
488 ZeroMem(&hash_string2, sizeof(hash_string2));
489
490 text[1] = L"";
491
492 for (i = 0; i < length / 2; i++)
493 CatPrint(&hash_string1, L"%02x ", hash[i]);
494 for (i = length / 2; i < length; i++)
495 CatPrint(&hash_string2, L"%02x ", hash[i]);
496
497 text[2] = hash_string1.str;
498 text[3] = hash_string2.str;
499 text[4] = NULL;
500
501 console_print_box(text, -1);
502
503 if (hash_string1.str)
504 FreePool(hash_string1.str);
505
506 if (hash_string2.str)
507 FreePool(hash_string2.str);
508 }
509
510 static void show_efi_hash(EFI_GUID Type, void *Mok, UINTN MokSize)
511 {
512 UINTN sig_size;
513 UINTN hash_num;
514 UINT8 *hash;
515 CHAR16 **menu_strings;
516 CHAR16 *selection[] = { L"[Hash List]", NULL };
517 UINTN key_num = 0;
518 UINTN i;
519
520 sig_size = sha_size(Type) + sizeof(EFI_GUID);
521 if ((MokSize % sig_size) != 0) {
522 console_errorbox(L"Corrupted Hash List");
523 return;
524 }
525 hash_num = MokSize / sig_size;
526
527 if (hash_num == 1) {
528 hash = (UINT8 *) Mok + sizeof(EFI_GUID);
529 show_sha_digest(Type, hash);
530 return;
531 }
532
533 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (hash_num + 2));
534 if (!menu_strings) {
535 console_errorbox(L"Out of Resources");
536 return;
537 }
538
539 for (i = 0; i < hash_num; i++) {
540 menu_strings[i] = PoolPrint(L"View hash %d", i);
541 }
542 menu_strings[i] = StrDuplicate(L"Back");
543 menu_strings[i + 1] = NULL;
544
545 while (key_num < hash_num) {
546 int rc;
547
548 key_num = rc = console_select(selection, menu_strings, key_num);
549 if (rc < 0 || key_num >= hash_num)
550 break;
551
552 hash = (UINT8 *) Mok + sig_size * key_num + sizeof(EFI_GUID);
553 show_sha_digest(Type, hash);
554 }
555
556 for (i = 0; menu_strings[i] != NULL; i++)
557 FreePool(menu_strings[i]);
558
559 FreePool(menu_strings);
560 }
561
562 static void show_mok_info(EFI_GUID Type, void *Mok, UINTN MokSize)
563 {
564 EFI_STATUS efi_status;
565
566 if (!Mok || MokSize == 0)
567 return;
568
569 if (CompareGuid (&Type, &X509_GUID) == 0) {
570 UINT8 hash[SHA1_DIGEST_SIZE];
571 X509 *X509Cert;
572
573 efi_status = get_sha1sum(Mok, MokSize, hash);
574 if (EFI_ERROR(efi_status)) {
575 console_notify(L"Failed to compute MOK fingerprint");
576 return;
577 }
578
579 if (X509ConstructCertificate(Mok, MokSize,
580 (UINT8 **) & X509Cert)
581 && X509Cert != NULL) {
582 show_x509_info(X509Cert, hash);
583 X509_free(X509Cert);
584 } else {
585 console_notify(L"Not a valid X509 certificate");
586 return;
587 }
588 } else if (is_sha2_hash(Type)) {
589 show_efi_hash(Type, Mok, MokSize);
590 }
591 }
592
593 static EFI_STATUS list_keys(void *KeyList, UINTN KeyListSize, CHAR16 * title)
594 {
595 UINTN MokNum = 0;
596 MokListNode *keys = NULL;
597 UINT32 key_num = 0;
598 CHAR16 **menu_strings;
599 CHAR16 *selection[] = { title, NULL };
600 unsigned int i;
601
602 if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
603 sizeof(EFI_SIGNATURE_DATA))) {
604 console_notify(L"No MOK keys found");
605 return EFI_NOT_FOUND;
606 }
607
608 MokNum = count_keys(KeyList, KeyListSize);
609 if (MokNum == 0) {
610 console_errorbox(L"Invalid key list");
611 return EFI_ABORTED;
612 }
613 keys = build_mok_list(MokNum, KeyList, KeyListSize);
614 if (!keys) {
615 console_errorbox(L"Failed to construct key list");
616 return EFI_ABORTED;
617 }
618
619 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (MokNum + 2));
620 if (!menu_strings)
621 return EFI_OUT_OF_RESOURCES;
622
623 for (i = 0; i < MokNum; i++) {
624 menu_strings[i] = PoolPrint(L"View key %d", i);
625 }
626 menu_strings[i] = StrDuplicate(L"Continue");
627
628 menu_strings[i + 1] = NULL;
629
630 while (key_num < MokNum) {
631 int rc;
632 rc = key_num = console_select(selection, menu_strings, key_num);
633
634 if (rc < 0 || key_num >= MokNum)
635 break;
636
637 show_mok_info(keys[key_num].Type, keys[key_num].Mok,
638 keys[key_num].MokSize);
639 }
640
641 for (i = 0; menu_strings[i] != NULL; i++)
642 FreePool(menu_strings[i]);
643 FreePool(menu_strings);
644 FreePool(keys);
645
646 return EFI_SUCCESS;
647 }
648
649 static EFI_STATUS get_line(UINT32 * length, CHAR16 * line, UINT32 line_max,
650 UINT8 show)
651 {
652 EFI_INPUT_KEY key;
653 EFI_STATUS efi_status;
654 unsigned int count = 0;
655
656 do {
657 efi_status = console_get_keystroke(&key);
658 if (EFI_ERROR(efi_status)) {
659 console_error(L"Failed to read the keystroke",
660 efi_status);
661 *length = 0;
662 return efi_status;
663 }
664
665 if ((count >= line_max &&
666 key.UnicodeChar != CHAR_BACKSPACE) ||
667 key.UnicodeChar == CHAR_NULL ||
668 key.UnicodeChar == CHAR_TAB ||
669 key.UnicodeChar == CHAR_LINEFEED ||
670 key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
671 continue;
672 }
673
674 if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
675 continue;
676 } else if (key.UnicodeChar == CHAR_BACKSPACE) {
677 if (show) {
678 console_print(L"\b");
679 }
680 line[--count] = '\0';
681 continue;
682 }
683
684 if (show) {
685 console_print(L"%c", key.UnicodeChar);
686 }
687
688 line[count++] = key.UnicodeChar;
689 } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
690 console_print(L"\n");
691
692 *length = count;
693
694 return EFI_SUCCESS;
695 }
696
697 static EFI_STATUS compute_pw_hash(void *Data, UINTN DataSize, UINT8 * password,
698 UINT32 pw_length, UINT8 * hash)
699 {
700 EFI_STATUS efi_status;
701 unsigned int ctxsize;
702 void *ctx = NULL;
703
704 ctxsize = Sha256GetContextSize();
705 ctx = AllocatePool(ctxsize);
706 if (!ctx) {
707 console_notify(L"Unable to allocate memory for hash context");
708 return EFI_OUT_OF_RESOURCES;
709 }
710
711 if (!Sha256Init(ctx)) {
712 console_notify(L"Unable to initialise hash");
713 efi_status = EFI_OUT_OF_RESOURCES;
714 goto done;
715 }
716
717 if (Data && DataSize) {
718 if (!(Sha256Update(ctx, Data, DataSize))) {
719 console_notify(L"Unable to generate hash");
720 efi_status = EFI_OUT_OF_RESOURCES;
721 goto done;
722 }
723 }
724
725 if (!(Sha256Update(ctx, password, pw_length))) {
726 console_notify(L"Unable to generate hash");
727 efi_status = EFI_OUT_OF_RESOURCES;
728 goto done;
729 }
730
731 if (!(Sha256Final(ctx, hash))) {
732 console_notify(L"Unable to finalise hash");
733 efi_status = EFI_OUT_OF_RESOURCES;
734 goto done;
735 }
736
737 efi_status = EFI_SUCCESS;
738 done:
739 return efi_status;
740 }
741
742 static INTN reset_system()
743 {
744 gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
745 console_notify(L"Failed to reboot\n");
746 return -1;
747 }
748
749 static UINT32 get_password(CHAR16 * prompt, CHAR16 * password, UINT32 max)
750 {
751 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
752 CHAR16 *str;
753 CHAR16 *message[2];
754 UINTN length;
755 UINT32 pw_length;
756
757 if (!prompt)
758 prompt = L"Password:";
759
760 console_save_and_set_mode(&SavedMode);
761
762 str = PoolPrint(L"%s ", prompt);
763 if (!str) {
764 console_errorbox(L"Failed to allocate prompt");
765 return 0;
766 }
767
768 message[0] = str;
769 message[1] = NULL;
770 length = StrLen(message[0]);
771 console_print_box_at(message, -1, -length - 4, -5, length + 4, 3, 0, 1);
772 get_line(&pw_length, password, max, 0);
773
774 console_restore_mode(&SavedMode);
775
776 FreePool(str);
777
778 return pw_length;
779 }
780
781 static EFI_STATUS match_password(PASSWORD_CRYPT * pw_crypt,
782 void *Data, UINTN DataSize,
783 UINT8 * auth, CHAR16 * prompt)
784 {
785 EFI_STATUS efi_status;
786 UINT8 hash[128];
787 UINT8 *auth_hash;
788 UINT32 auth_size;
789 CHAR16 password[PASSWORD_MAX];
790 UINT32 pw_length;
791 UINT8 fail_count = 0;
792 unsigned int i;
793
794 if (pw_crypt) {
795 auth_hash = pw_crypt->hash;
796 auth_size = get_hash_size(pw_crypt->method);
797 if (auth_size == 0)
798 return EFI_INVALID_PARAMETER;
799 } else if (auth) {
800 auth_hash = auth;
801 auth_size = SHA256_DIGEST_SIZE;
802 } else {
803 return EFI_INVALID_PARAMETER;
804 }
805
806 while (fail_count < 3) {
807 pw_length = get_password(prompt, password, PASSWORD_MAX);
808
809 if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) {
810 console_errorbox(L"Invalid password length");
811 fail_count++;
812 continue;
813 }
814
815 /*
816 * Compute password hash
817 */
818 if (pw_crypt) {
819 char pw_ascii[PASSWORD_MAX + 1];
820 for (i = 0; i < pw_length; i++)
821 pw_ascii[i] = (char)password[i];
822 pw_ascii[pw_length] = '\0';
823
824 efi_status = password_crypt(pw_ascii, pw_length,
825 pw_crypt, hash);
826 } else {
827 /*
828 * For backward compatibility
829 */
830 efi_status = compute_pw_hash(Data, DataSize,
831 (UINT8 *) password,
832 pw_length * sizeof(CHAR16),
833 hash);
834 }
835 if (EFI_ERROR(efi_status)) {
836 console_errorbox(L"Unable to generate password hash");
837 fail_count++;
838 continue;
839 }
840
841 if (CompareMem(auth_hash, hash, auth_size) != 0) {
842 console_errorbox(L"Password doesn't match");
843 fail_count++;
844 continue;
845 }
846
847 break;
848 }
849
850 if (fail_count >= 3)
851 return EFI_ACCESS_DENIED;
852
853 return EFI_SUCCESS;
854 }
855
856 static EFI_STATUS write_db(CHAR16 * db_name, void *MokNew, UINTN MokNewSize)
857 {
858 EFI_STATUS efi_status;
859 UINT32 attributes;
860 void *old_data = NULL;
861 void *new_data = NULL;
862 UINTN old_size;
863 UINTN new_size;
864
865 /* Do not use EFI_VARIABLE_APPEND_WRITE due to faulty firmwares.
866 * ref: https://github.com/rhboot/shim/issues/55
867 * https://github.com/rhboot/shim/issues/105 */
868
869 efi_status = get_variable_attr(db_name, (UINT8 **)&old_data, &old_size,
870 SHIM_LOCK_GUID, &attributes);
871 if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
872 return efi_status;
873 }
874
875 /* Check if the old db is compromised or not */
876 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
877 FreePool(old_data);
878 old_data = NULL;
879 old_size = 0;
880 }
881
882 new_size = old_size + MokNewSize;
883 new_data = AllocatePool(new_size);
884 if (new_data == NULL) {
885 efi_status = EFI_OUT_OF_RESOURCES;
886 goto out;
887 }
888
889 CopyMem(new_data, old_data, old_size);
890 CopyMem(new_data + old_size, MokNew, MokNewSize);
891
892 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
893 EFI_VARIABLE_NON_VOLATILE |
894 EFI_VARIABLE_BOOTSERVICE_ACCESS,
895 new_size, new_data);
896 out:
897 if (old_size > 0) {
898 FreePool(old_data);
899 }
900
901 if (new_data != NULL) {
902 FreePool(new_data);
903 }
904
905 return efi_status;
906 }
907
908 static EFI_STATUS store_keys(void *MokNew, UINTN MokNewSize, int authenticate,
909 BOOLEAN MokX)
910 {
911 EFI_STATUS efi_status;
912 CHAR16 *db_name;
913 CHAR16 *auth_name;
914 UINT8 auth[PASSWORD_CRYPT_SIZE];
915 UINTN auth_size = PASSWORD_CRYPT_SIZE;
916 UINT32 attributes;
917
918 if (MokX) {
919 db_name = L"MokListX";
920 auth_name = L"MokXAuth";
921 } else {
922 db_name = L"MokList";
923 auth_name = L"MokAuth";
924 }
925
926 if (authenticate) {
927 efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID,
928 &attributes, &auth_size, auth);
929 if (EFI_ERROR(efi_status) ||
930 (auth_size != SHA256_DIGEST_SIZE &&
931 auth_size != PASSWORD_CRYPT_SIZE)) {
932 if (MokX)
933 console_error(L"Failed to get MokXAuth",
934 efi_status);
935 else
936 console_error(L"Failed to get MokAuth",
937 efi_status);
938 return efi_status;
939 }
940
941 if (auth_size == PASSWORD_CRYPT_SIZE) {
942 efi_status = match_password((PASSWORD_CRYPT *) auth,
943 NULL, 0, NULL, NULL);
944 } else {
945 efi_status = match_password(NULL, MokNew, MokNewSize,
946 auth, NULL);
947 }
948 if (EFI_ERROR(efi_status))
949 return EFI_ACCESS_DENIED;
950 }
951
952 if (!MokNewSize) {
953 /* Delete MOK */
954 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
955 EFI_VARIABLE_NON_VOLATILE |
956 EFI_VARIABLE_BOOTSERVICE_ACCESS,
957 0, NULL);
958 } else {
959 /* Write new MOK */
960 efi_status = write_db(db_name, MokNew, MokNewSize);
961 }
962
963 if (EFI_ERROR(efi_status)) {
964 console_error(L"Failed to set variable", efi_status);
965 return efi_status;
966 }
967
968 return EFI_SUCCESS;
969 }
970
971 static EFI_STATUS mok_enrollment_prompt(void *MokNew, UINTN MokNewSize,
972 int auth, BOOLEAN MokX)
973 {
974 EFI_STATUS efi_status;
975 CHAR16 *enroll_p[] = { L"Enroll the key(s)?", NULL };
976 CHAR16 *title;
977
978 if (MokX)
979 title = L"[Enroll MOKX]";
980 else
981 title = L"[Enroll MOK]";
982
983 efi_status = list_keys(MokNew, MokNewSize, title);
984 if (EFI_ERROR(efi_status))
985 return efi_status;
986
987 if (console_yes_no(enroll_p) == 0)
988 return EFI_ABORTED;
989
990 efi_status = store_keys(MokNew, MokNewSize, auth, MokX);
991 if (EFI_ERROR(efi_status)) {
992 console_notify(L"Failed to enroll keys\n");
993 return efi_status;
994 }
995
996 if (auth) {
997 if (MokX) {
998 LibDeleteVariable(L"MokXNew", &SHIM_LOCK_GUID);
999 LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
1000 } else {
1001 LibDeleteVariable(L"MokNew", &SHIM_LOCK_GUID);
1002 LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
1003 }
1004 }
1005
1006 return EFI_SUCCESS;
1007 }
1008
1009 static EFI_STATUS mok_reset_prompt(BOOLEAN MokX)
1010 {
1011 EFI_STATUS efi_status;
1012 CHAR16 *prompt[] = { NULL, NULL };
1013
1014 ST->ConOut->ClearScreen(ST->ConOut);
1015
1016 if (MokX)
1017 prompt[0] = L"Erase all stored keys in MokListX?";
1018 else
1019 prompt[0] = L"Erase all stored keys in MokList?";
1020
1021 if (console_yes_no(prompt) == 0)
1022 return EFI_ABORTED;
1023
1024 efi_status = store_keys(NULL, 0, TRUE, MokX);
1025 if (EFI_ERROR(efi_status)) {
1026 console_notify(L"Failed to erase keys\n");
1027 return efi_status;
1028 }
1029
1030 if (MokX) {
1031 LibDeleteVariable(L"MokXNew", &SHIM_LOCK_GUID);
1032 LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
1033 LibDeleteVariable(L"MokListX", &SHIM_LOCK_GUID);
1034 } else {
1035 LibDeleteVariable(L"MokNew", &SHIM_LOCK_GUID);
1036 LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
1037 LibDeleteVariable(L"MokList", &SHIM_LOCK_GUID);
1038 }
1039
1040 return EFI_SUCCESS;
1041 }
1042
1043 static EFI_STATUS write_back_mok_list(MokListNode * list, INTN key_num,
1044 BOOLEAN MokX)
1045 {
1046 EFI_STATUS efi_status;
1047 EFI_SIGNATURE_LIST *CertList;
1048 EFI_SIGNATURE_DATA *CertData;
1049 EFI_GUID type;
1050 void *Data = NULL, *ptr;
1051 INTN DataSize = 0;
1052 int i;
1053 CHAR16 *db_name;
1054
1055 if (MokX)
1056 db_name = L"MokListX";
1057 else
1058 db_name = L"MokList";
1059
1060 dprint(L"Writing back %s (%d entries)\n", db_name, key_num);
1061 for (i = 0; i < key_num; i++) {
1062 if (list[i].Mok == NULL)
1063 continue;
1064
1065 DataSize += sizeof(EFI_SIGNATURE_LIST);
1066 type = list[i].Type; /* avoid -Werror=address-of-packed-member */
1067 if (CompareGuid(&type, &X509_GUID) == 0)
1068 DataSize += sizeof(EFI_GUID);
1069 DataSize += list[i].MokSize;
1070 }
1071 if (DataSize == 0) {
1072 dprint(L"DataSize = 0; deleting variable %s\n", db_name);
1073 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1074 EFI_VARIABLE_NON_VOLATILE |
1075 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1076 DataSize, Data);
1077 dprint(L"efi_status:%llu\n", efi_status);
1078 return EFI_SUCCESS;
1079 }
1080
1081 Data = AllocatePool(DataSize);
1082 if (Data == NULL)
1083 return EFI_OUT_OF_RESOURCES;
1084
1085 ptr = Data;
1086
1087 for (i = 0; i < key_num; i++) {
1088 if (list[i].Mok == NULL)
1089 continue;
1090
1091 CertList = (EFI_SIGNATURE_LIST *) ptr;
1092 CertData = (EFI_SIGNATURE_DATA *) (((uint8_t *) ptr) +
1093 sizeof(EFI_SIGNATURE_LIST));
1094
1095 CertList->SignatureType = list[i].Type;
1096 CertList->SignatureHeaderSize = 0;
1097
1098 if (CompareGuid(&(CertList->SignatureType), &X509_GUID) == 0) {
1099 CertList->SignatureListSize = list[i].MokSize +
1100 sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
1101 CertList->SignatureSize =
1102 list[i].MokSize + sizeof(EFI_GUID);
1103
1104 CertData->SignatureOwner = SHIM_LOCK_GUID;
1105 CopyMem(CertData->SignatureData, list[i].Mok,
1106 list[i].MokSize);
1107 } else {
1108 CertList->SignatureListSize = list[i].MokSize +
1109 sizeof(EFI_SIGNATURE_LIST);
1110 CertList->SignatureSize =
1111 sha_size(list[i].Type) + sizeof(EFI_GUID);
1112
1113 CopyMem(CertData, list[i].Mok, list[i].MokSize);
1114 }
1115 ptr = (uint8_t *) ptr + CertList->SignatureListSize;
1116 }
1117
1118 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1119 EFI_VARIABLE_NON_VOLATILE |
1120 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1121 DataSize, Data);
1122 if (Data)
1123 FreePool(Data);
1124
1125 if (EFI_ERROR(efi_status)) {
1126 console_error(L"Failed to set variable", efi_status);
1127 return efi_status;
1128 }
1129
1130 return EFI_SUCCESS;
1131 }
1132
1133 static void delete_cert(void *key, UINT32 key_size,
1134 MokListNode * mok, INTN mok_num)
1135 {
1136 EFI_GUID type;
1137 int i;
1138
1139 for (i = 0; i < mok_num; i++) {
1140 type = mok[i].Type; /* avoid -Werror=address-of-packed-member */
1141 if (CompareGuid(&type, &X509_GUID) != 0)
1142 continue;
1143
1144 if (mok[i].MokSize == key_size &&
1145 CompareMem(key, mok[i].Mok, key_size) == 0) {
1146 /* Remove the key */
1147 mok[i].Mok = NULL;
1148 mok[i].MokSize = 0;
1149 }
1150 }
1151 }
1152
1153 static int match_hash(UINT8 * hash, UINT32 hash_size, int start,
1154 void *hash_list, UINT32 list_num)
1155 {
1156 UINT8 *ptr;
1157 UINTN i;
1158
1159 ptr = hash_list + sizeof(EFI_GUID);
1160 for (i = start; i < list_num; i++) {
1161 if (CompareMem(hash, ptr, hash_size) == 0)
1162 return i;
1163 ptr += hash_size + sizeof(EFI_GUID);
1164 }
1165
1166 return -1;
1167 }
1168
1169 static void mem_move(void *dest, void *src, UINTN size)
1170 {
1171 UINT8 *d, *s;
1172 UINTN i;
1173
1174 d = (UINT8 *) dest;
1175 s = (UINT8 *) src;
1176 for (i = 0; i < size; i++)
1177 d[i] = s[i];
1178 }
1179
1180 static void delete_hash_in_list(EFI_GUID Type, UINT8 * hash, UINT32 hash_size,
1181 MokListNode * mok, INTN mok_num)
1182 {
1183 EFI_GUID type;
1184 UINT32 sig_size;
1185 UINT32 list_num;
1186 int i, del_ind;
1187 void *start, *end;
1188 UINT32 remain;
1189
1190 sig_size = hash_size + sizeof(EFI_GUID);
1191
1192 for (i = 0; i < mok_num; i++) {
1193 type = mok[i].Type; /* avoid -Werror=address-of-packed-member */
1194 if ((CompareGuid(&type, &Type) != 0) ||
1195 (mok[i].MokSize < sig_size))
1196 continue;
1197
1198 list_num = mok[i].MokSize / sig_size;
1199
1200 del_ind = match_hash(hash, hash_size, 0, mok[i].Mok, list_num);
1201 while (del_ind >= 0) {
1202 /* Remove the hash */
1203 if (sig_size == mok[i].MokSize) {
1204 mok[i].Mok = NULL;
1205 mok[i].MokSize = 0;
1206 break;
1207 }
1208
1209 start = mok[i].Mok + del_ind * sig_size;
1210 end = start + sig_size;
1211 remain = mok[i].MokSize - (del_ind + 1) * sig_size;
1212
1213 mem_move(start, end, remain);
1214 mok[i].MokSize -= sig_size;
1215 list_num--;
1216
1217 del_ind = match_hash(hash, hash_size, del_ind,
1218 mok[i].Mok, list_num);
1219 }
1220 }
1221 }
1222
1223 static void delete_hash_list(EFI_GUID Type, void *hash_list, UINT32 list_size,
1224 MokListNode * mok, INTN mok_num)
1225 {
1226 UINT32 hash_size;
1227 UINT32 hash_num;
1228 UINT32 sig_size;
1229 UINT8 *hash;
1230 UINT32 i;
1231
1232 hash_size = sha_size(Type);
1233 sig_size = hash_size + sizeof(EFI_GUID);
1234 if (list_size < sig_size)
1235 return;
1236
1237 hash_num = list_size / sig_size;
1238
1239 hash = hash_list + sizeof(EFI_GUID);
1240
1241 for (i = 0; i < hash_num; i++) {
1242 delete_hash_in_list(Type, hash, hash_size, mok, mok_num);
1243 hash += sig_size;
1244 }
1245 }
1246
1247 static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
1248 {
1249 EFI_STATUS efi_status;
1250 EFI_GUID type;
1251 CHAR16 *db_name;
1252 CHAR16 *auth_name;
1253 CHAR16 *err_strs[] = { NULL, NULL, NULL };
1254 UINT8 auth[PASSWORD_CRYPT_SIZE];
1255 UINTN auth_size = PASSWORD_CRYPT_SIZE;
1256 UINT32 attributes;
1257 UINT8 *MokListData = NULL;
1258 UINTN MokListDataSize = 0;
1259 MokListNode *mok = NULL, *del_key = NULL;
1260 INTN mok_num, del_num;
1261 int i;
1262
1263 if (MokX) {
1264 db_name = L"MokListX";
1265 auth_name = L"MokXDelAuth";
1266 } else {
1267 db_name = L"MokList";
1268 auth_name = L"MokDelAuth";
1269 }
1270
1271 efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID, &attributes,
1272 &auth_size, auth);
1273 if (EFI_ERROR(efi_status) ||
1274 (auth_size != SHA256_DIGEST_SIZE
1275 && auth_size != PASSWORD_CRYPT_SIZE)) {
1276 if (MokX)
1277 console_error(L"Failed to get MokXDelAuth", efi_status);
1278 else
1279 console_error(L"Failed to get MokDelAuth", efi_status);
1280 return efi_status;
1281 }
1282
1283 if (auth_size == PASSWORD_CRYPT_SIZE) {
1284 dprint(L"matching password with CRYPT");
1285 efi_status = match_password((PASSWORD_CRYPT *) auth, NULL, 0,
1286 NULL, NULL);
1287 dprint(L"match_password(0x%llx, NULL, 0, NULL, NULL) = %lu\n", auth, efi_status);
1288 } else {
1289 dprint(L"matching password as sha256sum");
1290 efi_status =
1291 match_password(NULL, MokDel, MokDelSize, auth, NULL);
1292 dprint(L"match_password(NULL, 0x%llx, %llu, 0x%llx, NULL) = %lu\n", MokDel, MokDelSize, auth, efi_status);
1293 }
1294 if (EFI_ERROR(efi_status))
1295 return EFI_ACCESS_DENIED;
1296
1297 efi_status = get_variable_attr(db_name, &MokListData, &MokListDataSize,
1298 SHIM_LOCK_GUID, &attributes);
1299 if (EFI_ERROR(efi_status)) {
1300 if (MokX)
1301 console_errorbox(L"Failed to retrieve MokListX");
1302 else
1303 console_errorbox(L"Failed to retrieve MokList");
1304 return EFI_ABORTED;
1305 } else if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
1306 if (MokX) {
1307 err_strs[0] = L"MokListX is compromised!";
1308 err_strs[1] = L"Erase all keys in MokListX!";
1309 } else {
1310 err_strs[0] = L"MokList is compromised!";
1311 err_strs[1] = L"Erase all keys in MokList!";
1312 }
1313 console_alertbox(err_strs);
1314 gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1315 EFI_VARIABLE_NON_VOLATILE |
1316 EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
1317 efi_status = EFI_ACCESS_DENIED;
1318 goto error;
1319 }
1320
1321 /* Nothing to do */
1322 if (!MokListData || MokListDataSize == 0)
1323 return EFI_SUCCESS;
1324
1325 /* Construct lists */
1326 mok_num = count_keys(MokListData, MokListDataSize);
1327 if (mok_num == 0) {
1328 if (MokX) {
1329 err_strs[0] = L"Failed to construct the key list of MokListX";
1330 err_strs[1] = L"Reset MokListX!";
1331 } else {
1332 err_strs[0] = L"Failed to construct the key list of MokList";
1333 err_strs[1] = L"Reset MokList!";
1334 }
1335 console_alertbox(err_strs);
1336 gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1337 EFI_VARIABLE_NON_VOLATILE |
1338 EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
1339 efi_status = EFI_ABORTED;
1340 goto error;
1341 }
1342 mok = build_mok_list(mok_num, MokListData, MokListDataSize);
1343 if (!mok) {
1344 console_errorbox(L"Failed to construct key list");
1345 efi_status = EFI_ABORTED;
1346 goto error;
1347 }
1348 del_num = count_keys(MokDel, MokDelSize);
1349 if (del_num == 0) {
1350 console_errorbox(L"Invalid key delete list");
1351 efi_status = EFI_ABORTED;
1352 goto error;
1353 }
1354 del_key = build_mok_list(del_num, MokDel, MokDelSize);
1355 if (!del_key) {
1356 console_errorbox(L"Failed to construct key list");
1357 efi_status = EFI_ABORTED;
1358 goto error;
1359 }
1360
1361 /* Search and destroy */
1362 dprint(L"deleting certs from %a\n", MokX ? "MokListX" : "MokList");
1363 for (i = 0; i < del_num; i++) {
1364 type = del_key[i].Type; /* avoid -Werror=address-of-packed-member */
1365 if (CompareGuid(&type, &X509_GUID) == 0) {
1366 dprint(L"deleting key %d (total %d):\n", i, mok_num);
1367 dhexdumpat(del_key[i].Mok, del_key[i].MokSize, 0);
1368 delete_cert(del_key[i].Mok, del_key[i].MokSize,
1369 mok, mok_num);
1370 } else if (is_sha2_hash(del_key[i].Type)) {
1371 dprint(L"deleting hash %d (total %d):\n", i, mok_num);
1372 dhexdumpat(del_key[i].Mok, del_key[i].MokSize, 0);
1373 delete_hash_list(del_key[i].Type, del_key[i].Mok,
1374 del_key[i].MokSize, mok, mok_num);
1375 }
1376 }
1377
1378 efi_status = write_back_mok_list(mok, mok_num, MokX);
1379
1380 error:
1381 if (MokListData)
1382 FreePool(MokListData);
1383 if (mok)
1384 FreePool(mok);
1385 if (del_key)
1386 FreePool(del_key);
1387
1388 return efi_status;
1389 }
1390
1391 static EFI_STATUS mok_deletion_prompt(void *MokDel, UINTN MokDelSize,
1392 BOOLEAN MokX)
1393 {
1394 EFI_STATUS efi_status;
1395 CHAR16 *delete_p[] = { L"Delete the key(s)?", NULL };
1396 CHAR16 *title;
1397
1398 if (MokX)
1399 title = L"[Delete MOKX]";
1400 else
1401 title = L"[Delete MOK]";
1402
1403 efi_status = list_keys(MokDel, MokDelSize, title);
1404 if (EFI_ERROR(efi_status))
1405 return efi_status;
1406
1407 if (console_yes_no(delete_p) == 0)
1408 return EFI_ABORTED;
1409
1410 efi_status = delete_keys(MokDel, MokDelSize, MokX);
1411 if (EFI_ERROR(efi_status)) {
1412 console_notify(L"Failed to delete keys");
1413 return efi_status;
1414 }
1415
1416 if (MokX) {
1417 LibDeleteVariable(L"MokXDel", &SHIM_LOCK_GUID);
1418 LibDeleteVariable(L"MokXDelAuth", &SHIM_LOCK_GUID);
1419 } else {
1420 LibDeleteVariable(L"MokDel", &SHIM_LOCK_GUID);
1421 LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
1422 }
1423
1424 if (MokDel)
1425 FreePool(MokDel);
1426
1427 return EFI_SUCCESS;
1428 }
1429
1430 static CHAR16 get_password_charater(CHAR16 * prompt)
1431 {
1432 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1433 EFI_STATUS efi_status;
1434 CHAR16 *message[2];
1435 CHAR16 character = 0;
1436 UINTN length;
1437 UINT32 pw_length;
1438
1439 if (!prompt)
1440 prompt = L"Password charater: ";
1441
1442 console_save_and_set_mode(&SavedMode);
1443
1444 message[0] = prompt;
1445 message[1] = NULL;
1446 length = StrLen(message[0]);
1447 console_print_box_at(message, -1, -length - 4, -5, length + 4, 3, 0, 1);
1448 efi_status = get_line(&pw_length, &character, 1, 0);
1449 if (EFI_ERROR(efi_status))
1450 character = 0;
1451
1452 console_restore_mode(&SavedMode);
1453
1454 return character;
1455 }
1456
1457 static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
1458 {
1459 EFI_STATUS efi_status;
1460 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1461 MokSBvar *var = MokSB;
1462 CHAR16 *message[4];
1463 CHAR16 pass1, pass2, pass3;
1464 CHAR16 *str;
1465 UINT8 fail_count = 0;
1466 UINT8 sbval = 1;
1467 UINT8 pos1, pos2, pos3;
1468 int ret;
1469 CHAR16 *disable_sb[] = { L"Disable Secure Boot", NULL };
1470 CHAR16 *enable_sb[] = { L"Enable Secure Boot", NULL };
1471
1472 if (MokSBSize != sizeof(MokSBvar)) {
1473 console_notify(L"Invalid MokSB variable contents");
1474 return EFI_INVALID_PARAMETER;
1475 }
1476
1477 ST->ConOut->ClearScreen(ST->ConOut);
1478
1479 message[0] = L"Change Secure Boot state";
1480 message[1] = NULL;
1481
1482 console_save_and_set_mode(&SavedMode);
1483 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1484 console_restore_mode(&SavedMode);
1485
1486 while (fail_count < 3) {
1487 RandomBytes(&pos1, sizeof(pos1));
1488 pos1 = (pos1 % var->PWLen);
1489
1490 do {
1491 RandomBytes(&pos2, sizeof(pos2));
1492 pos2 = (pos2 % var->PWLen);
1493 } while (pos2 == pos1);
1494
1495 do {
1496 RandomBytes(&pos3, sizeof(pos3));
1497 pos3 = (pos3 % var->PWLen);
1498 } while (pos3 == pos2 || pos3 == pos1);
1499
1500 str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1501 if (!str) {
1502 console_errorbox(L"Failed to allocate buffer");
1503 return EFI_OUT_OF_RESOURCES;
1504 }
1505 pass1 = get_password_charater(str);
1506 FreePool(str);
1507
1508 str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1509 if (!str) {
1510 console_errorbox(L"Failed to allocate buffer");
1511 return EFI_OUT_OF_RESOURCES;
1512 }
1513 pass2 = get_password_charater(str);
1514 FreePool(str);
1515
1516 str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1517 if (!str) {
1518 console_errorbox(L"Failed to allocate buffer");
1519 return EFI_OUT_OF_RESOURCES;
1520 }
1521 pass3 = get_password_charater(str);
1522 FreePool(str);
1523
1524 if (pass1 != var->Password[pos1] ||
1525 pass2 != var->Password[pos2] ||
1526 pass3 != var->Password[pos3]) {
1527 console_print(L"Invalid character\n");
1528 fail_count++;
1529 } else {
1530 break;
1531 }
1532 }
1533
1534 if (fail_count >= 3) {
1535 console_notify(L"Password limit reached");
1536 return EFI_ACCESS_DENIED;
1537 }
1538
1539 if (var->MokSBState == 0)
1540 ret = console_yes_no(disable_sb);
1541 else
1542 ret = console_yes_no(enable_sb);
1543
1544 if (ret == 0) {
1545 LibDeleteVariable(L"MokSB", &SHIM_LOCK_GUID);
1546 return EFI_ABORTED;
1547 }
1548
1549 if (var->MokSBState == 0) {
1550 efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
1551 EFI_VARIABLE_NON_VOLATILE |
1552 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1553 1, &sbval);
1554 if (EFI_ERROR(efi_status)) {
1555 console_notify(L"Failed to set Secure Boot state");
1556 return efi_status;
1557 }
1558 } else {
1559 efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
1560 EFI_VARIABLE_NON_VOLATILE |
1561 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1562 0, NULL);
1563 if (EFI_ERROR(efi_status)) {
1564 console_notify(L"Failed to delete Secure Boot state");
1565 return efi_status;
1566 }
1567 }
1568
1569 return EFI_SUCCESS;
1570 }
1571
1572 static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
1573 {
1574 EFI_STATUS efi_status;
1575 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1576 MokDBvar *var = MokDB;
1577 CHAR16 *message[4];
1578 CHAR16 pass1, pass2, pass3;
1579 CHAR16 *str;
1580 UINT8 fail_count = 0;
1581 UINT8 dbval = 1;
1582 UINT8 pos1, pos2, pos3;
1583 int ret;
1584 CHAR16 *ignore_db[] = { L"Ignore DB certs/hashes", NULL };
1585 CHAR16 *use_db[] = { L"Use DB certs/hashes", NULL };
1586
1587 if (MokDBSize != sizeof(MokDBvar)) {
1588 console_notify(L"Invalid MokDB variable contents");
1589 return EFI_INVALID_PARAMETER;
1590 }
1591
1592 ST->ConOut->ClearScreen(ST->ConOut);
1593
1594 message[0] = L"Change DB state";
1595 message[1] = NULL;
1596
1597 console_save_and_set_mode(&SavedMode);
1598 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1599 console_restore_mode(&SavedMode);
1600
1601 while (fail_count < 3) {
1602 RandomBytes(&pos1, sizeof(pos1));
1603 pos1 = (pos1 % var->PWLen);
1604
1605 do {
1606 RandomBytes(&pos2, sizeof(pos2));
1607 pos2 = (pos2 % var->PWLen);
1608 } while (pos2 == pos1);
1609
1610 do {
1611 RandomBytes(&pos3, sizeof(pos3));
1612 pos3 = (pos3 % var->PWLen);
1613 } while (pos3 == pos2 || pos3 == pos1);
1614
1615 str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1616 if (!str) {
1617 console_errorbox(L"Failed to allocate buffer");
1618 return EFI_OUT_OF_RESOURCES;
1619 }
1620 pass1 = get_password_charater(str);
1621 FreePool(str);
1622
1623 str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1624 if (!str) {
1625 console_errorbox(L"Failed to allocate buffer");
1626 return EFI_OUT_OF_RESOURCES;
1627 }
1628 pass2 = get_password_charater(str);
1629 FreePool(str);
1630
1631 str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1632 if (!str) {
1633 console_errorbox(L"Failed to allocate buffer");
1634 return EFI_OUT_OF_RESOURCES;
1635 }
1636 pass3 = get_password_charater(str);
1637 FreePool(str);
1638
1639 if (pass1 != var->Password[pos1] ||
1640 pass2 != var->Password[pos2] ||
1641 pass3 != var->Password[pos3]) {
1642 console_print(L"Invalid character\n");
1643 fail_count++;
1644 } else {
1645 break;
1646 }
1647 }
1648
1649 if (fail_count >= 3) {
1650 console_notify(L"Password limit reached");
1651 return EFI_ACCESS_DENIED;
1652 }
1653
1654 if (var->MokDBState == 0)
1655 ret = console_yes_no(ignore_db);
1656 else
1657 ret = console_yes_no(use_db);
1658
1659 if (ret == 0) {
1660 LibDeleteVariable(L"MokDB", &SHIM_LOCK_GUID);
1661 return EFI_ABORTED;
1662 }
1663
1664 if (var->MokDBState == 0) {
1665 efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
1666 EFI_VARIABLE_NON_VOLATILE |
1667 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1668 1, &dbval);
1669 if (EFI_ERROR(efi_status)) {
1670 console_notify(L"Failed to set DB state");
1671 return efi_status;
1672 }
1673 } else {
1674 efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
1675 EFI_VARIABLE_NON_VOLATILE |
1676 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1677 0, NULL);
1678 if (EFI_ERROR(efi_status)) {
1679 console_notify(L"Failed to delete DB state");
1680 return efi_status;
1681 }
1682 }
1683
1684 return EFI_SUCCESS;
1685 }
1686
1687 static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
1688 {
1689 EFI_STATUS efi_status;
1690 UINT8 hash[PASSWORD_CRYPT_SIZE];
1691 UINT8 clear = 0;
1692 CHAR16 *clear_p[] = { L"Clear MOK password?", NULL };
1693 CHAR16 *set_p[] = { L"Set MOK password?", NULL };
1694
1695 if (MokPWSize != SHA256_DIGEST_SIZE && MokPWSize != PASSWORD_CRYPT_SIZE) {
1696 console_notify(L"Invalid MokPW variable contents");
1697 return EFI_INVALID_PARAMETER;
1698 }
1699
1700 ST->ConOut->ClearScreen(ST->ConOut);
1701
1702 SetMem(hash, PASSWORD_CRYPT_SIZE, 0);
1703
1704 if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1705 if (CompareMem(MokPW, hash, PASSWORD_CRYPT_SIZE) == 0)
1706 clear = 1;
1707 } else {
1708 if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0)
1709 clear = 1;
1710 }
1711
1712 if (clear) {
1713 if (console_yes_no(clear_p) == 0)
1714 return EFI_ABORTED;
1715
1716 gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
1717 EFI_VARIABLE_NON_VOLATILE |
1718 EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
1719 goto mokpw_done;
1720 }
1721
1722 if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1723 efi_status = match_password((PASSWORD_CRYPT *) MokPW, NULL, 0,
1724 NULL, L"Confirm MOK passphrase: ");
1725 } else {
1726 efi_status = match_password(NULL, NULL, 0, MokPW,
1727 L"Confirm MOK passphrase: ");
1728 }
1729
1730 if (EFI_ERROR(efi_status)) {
1731 console_notify(L"Password limit reached");
1732 return efi_status;
1733 }
1734
1735 if (console_yes_no(set_p) == 0)
1736 return EFI_ABORTED;
1737
1738 efi_status = gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
1739 EFI_VARIABLE_NON_VOLATILE |
1740 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1741 MokPWSize, MokPW);
1742 if (EFI_ERROR(efi_status)) {
1743 console_notify(L"Failed to set MOK password");
1744 return efi_status;
1745 }
1746
1747 mokpw_done:
1748 LibDeleteVariable(L"MokPW", &SHIM_LOCK_GUID);
1749
1750 return EFI_SUCCESS;
1751 }
1752
1753 static BOOLEAN verify_certificate(UINT8 * cert, UINTN size)
1754 {
1755 X509 *X509Cert;
1756 UINTN length;
1757 if (!cert || size < 4)
1758 return FALSE;
1759
1760 /*
1761 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
1762 * the number of length bytes, and the number of value bytes.
1763 * The size of a x509 certificate is usually between 127 bytes
1764 * and 64KB. For convenience, assume the number of value bytes
1765 * is 2, i.e. the second byte is 0x82.
1766 */
1767 if (cert[0] != 0x30 || cert[1] != 0x82) {
1768 console_notify(L"Not a DER encoding X509 certificate");
1769 return FALSE;
1770 }
1771
1772 length = (cert[2] << 8 | cert[3]);
1773 if (length != (size - 4)) {
1774 console_notify(L"Invalid X509 certificate: Inconsistent size");
1775 return FALSE;
1776 }
1777
1778 if (!(X509ConstructCertificate(cert, size, (UINT8 **) & X509Cert)) ||
1779 X509Cert == NULL) {
1780 console_notify(L"Invalid X509 certificate");
1781 return FALSE;
1782 }
1783
1784 X509_free(X509Cert);
1785 return TRUE;
1786 }
1787
1788 static EFI_STATUS enroll_file(void *data, UINTN datasize, BOOLEAN hash)
1789 {
1790 EFI_STATUS efi_status = EFI_SUCCESS;
1791 EFI_SIGNATURE_LIST *CertList;
1792 EFI_SIGNATURE_DATA *CertData;
1793 UINTN mokbuffersize;
1794 void *mokbuffer = NULL;
1795
1796 if (hash) {
1797 UINT8 sha256[SHA256_DIGEST_SIZE];
1798 UINT8 sha1[SHA1_DIGEST_SIZE];
1799 SHIM_LOCK *shim_lock;
1800 PE_COFF_LOADER_IMAGE_CONTEXT context;
1801
1802 efi_status = LibLocateProtocol(&SHIM_LOCK_GUID,
1803 (VOID **) &shim_lock);
1804 if (EFI_ERROR(efi_status))
1805 goto out;
1806
1807 mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) +
1808 SHA256_DIGEST_SIZE;
1809
1810 mokbuffer = AllocatePool(mokbuffersize);
1811 if (!mokbuffer)
1812 goto out;
1813
1814 efi_status = shim_lock->Context(data, datasize, &context);
1815 if (EFI_ERROR(efi_status))
1816 goto out;
1817
1818 efi_status = shim_lock->Hash(data, datasize, &context, sha256,
1819 sha1);
1820 if (EFI_ERROR(efi_status))
1821 goto out;
1822
1823 CertList = mokbuffer;
1824 CertList->SignatureType = EFI_CERT_SHA256_GUID;
1825 CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE;
1826 CertData = (EFI_SIGNATURE_DATA *) (((UINT8 *) mokbuffer) +
1827 sizeof(EFI_SIGNATURE_LIST));
1828 CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
1829 } else {
1830 mokbuffersize = datasize + sizeof(EFI_SIGNATURE_LIST) +
1831 sizeof(EFI_GUID);
1832 mokbuffer = AllocatePool(mokbuffersize);
1833
1834 if (!mokbuffer)
1835 goto out;
1836
1837 CertList = mokbuffer;
1838 CertList->SignatureType = X509_GUID;
1839 CertList->SignatureSize = 16 + datasize;
1840
1841 memcpy(mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16, data,
1842 datasize);
1843
1844 CertData = (EFI_SIGNATURE_DATA *) (((UINT8 *) mokbuffer) +
1845 sizeof(EFI_SIGNATURE_LIST));
1846 }
1847
1848 CertList->SignatureListSize = mokbuffersize;
1849 CertList->SignatureHeaderSize = 0;
1850 CertData->SignatureOwner = SHIM_LOCK_GUID;
1851
1852 if (!hash) {
1853 if (!verify_certificate(CertData->SignatureData, datasize))
1854 goto out;
1855 }
1856
1857 efi_status = mok_enrollment_prompt(mokbuffer, mokbuffersize,
1858 FALSE, FALSE);
1859 out:
1860 if (mokbuffer)
1861 FreePool(mokbuffer);
1862
1863 return efi_status;
1864 }
1865
1866 static EFI_STATUS mok_hash_enroll(void)
1867 {
1868 EFI_STATUS efi_status;
1869 CHAR16 *file_name = NULL;
1870 EFI_HANDLE im = NULL;
1871 EFI_FILE *file = NULL;
1872 UINTN filesize;
1873 void *data;
1874 CHAR16 *selections[] = {
1875 L"Select Binary",
1876 L"",
1877 L"The Selected Binary will have its hash Enrolled",
1878 L"This means it will subsequently Boot with no prompting",
1879 L"Remember to make sure it is a genuine binary before enrolling its hash",
1880 NULL
1881 };
1882
1883 simple_file_selector(&im, selections, L"\\", L"", &file_name);
1884
1885 if (!file_name)
1886 return EFI_INVALID_PARAMETER;
1887
1888 efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1889 if (EFI_ERROR(efi_status)) {
1890 console_error(L"Unable to open file", efi_status);
1891 return efi_status;
1892 }
1893
1894 simple_file_read_all(file, &filesize, &data);
1895 file->Close(file);
1896 if (!filesize) {
1897 console_error(L"Unable to read file", efi_status);
1898 return EFI_BAD_BUFFER_SIZE;
1899 }
1900
1901 efi_status = enroll_file(data, filesize, TRUE);
1902 if (EFI_ERROR(efi_status))
1903 console_error(
1904 L"Hash failed (did you select a valid EFI binary?)",
1905 efi_status);
1906
1907 FreePool(data);
1908
1909 return efi_status;
1910 }
1911
1912 static CHAR16 *der_suffix[] = {
1913 L".cer",
1914 L".der",
1915 L".crt",
1916 NULL
1917 };
1918
1919 static BOOLEAN check_der_suffix(CHAR16 * file_name)
1920 {
1921 CHAR16 suffix[5];
1922 int i;
1923
1924 if (!file_name || StrLen(file_name) <= 4)
1925 return FALSE;
1926
1927 suffix[0] = '\0';
1928 StrnCat(suffix, file_name + StrLen(file_name) - 4, 4);
1929
1930 StrLwr(suffix);
1931 for (i = 0; der_suffix[i] != NULL; i++) {
1932 if (StrCmp(suffix, der_suffix[i]) == 0) {
1933 return TRUE;
1934 }
1935 }
1936
1937 return FALSE;
1938 }
1939
1940 static EFI_STATUS mok_key_enroll(void)
1941 {
1942 EFI_STATUS efi_status;
1943 CHAR16 *file_name = NULL;
1944 EFI_HANDLE im = NULL;
1945 EFI_FILE *file = NULL;
1946 UINTN filesize;
1947 void *data;
1948 CHAR16 *selections[] = {
1949 L"Select Key",
1950 L"",
1951 L"The selected key will be enrolled into the MOK database",
1952 L"This means any binaries signed with it will be run without prompting",
1953 L"Remember to make sure it is a genuine key before Enrolling it",
1954 NULL
1955 };
1956 CHAR16 *alert[] = {
1957 L"Unsupported Format",
1958 L"",
1959 L"Only DER encoded certificate (*.cer/der/crt) is supported",
1960 NULL
1961 };
1962
1963 simple_file_selector(&im, selections, L"\\", L"", &file_name);
1964
1965 if (!file_name)
1966 return EFI_INVALID_PARAMETER;
1967
1968 if (!check_der_suffix(file_name)) {
1969 console_alertbox(alert);
1970 return EFI_UNSUPPORTED;
1971 }
1972
1973 efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1974 if (EFI_ERROR(efi_status)) {
1975 console_error(L"Unable to open file", efi_status);
1976 return efi_status;
1977 }
1978
1979 simple_file_read_all(file, &filesize, &data);
1980 file->Close(file);
1981 if (!filesize) {
1982 console_error(L"Unable to read file", efi_status);
1983 return EFI_BAD_BUFFER_SIZE;
1984 }
1985
1986 efi_status = enroll_file(data, filesize, FALSE);
1987 FreePool(data);
1988
1989 return efi_status;
1990 }
1991
1992 static BOOLEAN verify_pw(BOOLEAN * protected)
1993 {
1994 EFI_STATUS efi_status;
1995 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1996 UINT8 pwhash[PASSWORD_CRYPT_SIZE];
1997 UINTN size = PASSWORD_CRYPT_SIZE;
1998 UINT32 attributes;
1999 CHAR16 *message[2];
2000
2001 *protected = FALSE;
2002
2003 efi_status = gRT->GetVariable(L"MokPWStore", &SHIM_LOCK_GUID, &attributes,
2004 &size, pwhash);
2005 /*
2006 * If anything can attack the password it could just set it to a
2007 * known value, so there's no safety advantage in failing to validate
2008 * purely because of a failure to read the variable
2009 */
2010 if (EFI_ERROR(efi_status) ||
2011 (size != SHA256_DIGEST_SIZE && size != PASSWORD_CRYPT_SIZE))
2012 return TRUE;
2013
2014 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
2015 return TRUE;
2016
2017 ST->ConOut->ClearScreen(ST->ConOut);
2018
2019 /* Draw the background */
2020 console_save_and_set_mode(&SavedMode);
2021 message[0] = PoolPrint(L"%s UEFI key management", SHIM_VENDOR);
2022 message[1] = NULL;
2023 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
2024 FreePool(message[0]);
2025 console_restore_mode(&SavedMode);
2026
2027 if (size == PASSWORD_CRYPT_SIZE) {
2028 efi_status = match_password((PASSWORD_CRYPT *) pwhash, NULL, 0,
2029 NULL, L"Enter MOK password:");
2030 } else {
2031 efi_status = match_password(NULL, NULL, 0, pwhash,
2032 L"Enter MOK password:");
2033 }
2034 if (EFI_ERROR(efi_status)) {
2035 console_notify(L"Password limit reached");
2036 return FALSE;
2037 }
2038
2039 *protected = TRUE;
2040
2041 return TRUE;
2042 }
2043
2044 static int draw_countdown()
2045 {
2046 CHAR16 *message = L"Press any key to perform MOK management";
2047 CHAR16 *title;
2048 void *MokTimeout = NULL;
2049 MokTimeoutvar *var;
2050 UINTN MokTimeoutSize = 0;
2051 int timeout = 10;
2052 EFI_STATUS efi_status;
2053
2054 efi_status = get_variable(L"MokTimeout", (UINT8 **) &MokTimeout,
2055 &MokTimeoutSize, SHIM_LOCK_GUID);
2056 if (!EFI_ERROR(efi_status)) {
2057 var = MokTimeout;
2058 timeout = (int)var->Timeout;
2059 FreePool(MokTimeout);
2060 LibDeleteVariable(L"MokTimeout", &SHIM_LOCK_GUID);
2061 }
2062
2063 if (timeout < 0)
2064 return timeout;
2065
2066 title = PoolPrint(L"%s UEFI key management", SHIM_VENDOR);
2067 timeout = console_countdown(title, message, timeout);
2068
2069 FreePool(title);
2070 return timeout;
2071 }
2072
2073 typedef enum {
2074 MOK_BOOT,
2075 MOK_RESET_MOK,
2076 MOK_RESET_MOKX,
2077 MOK_ENROLL_MOK,
2078 MOK_ENROLL_MOKX,
2079 MOK_DELETE_MOK,
2080 MOK_DELETE_MOKX,
2081 MOK_CHANGE_SB,
2082 MOK_SET_PW,
2083 MOK_CHANGE_DB,
2084 MOK_KEY_ENROLL,
2085 MOK_HASH_ENROLL
2086 } mok_menu_item;
2087
2088 static void free_menu(mok_menu_item * menu_item, CHAR16 ** menu_strings)
2089 {
2090 if (menu_strings)
2091 FreePool(menu_strings);
2092
2093 if (menu_item)
2094 FreePool(menu_item);
2095 }
2096
2097 static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
2098 void *MokNew, UINTN MokNewSize,
2099 void *MokDel, UINTN MokDelSize,
2100 void *MokSB, UINTN MokSBSize,
2101 void *MokPW, UINTN MokPWSize,
2102 void *MokDB, UINTN MokDBSize,
2103 void *MokXNew, UINTN MokXNewSize,
2104 void *MokXDel, UINTN MokXDelSize)
2105 {
2106 CHAR16 **menu_strings = NULL;
2107 mok_menu_item *menu_item = NULL;
2108 int choice = 0;
2109 int mok_changed = 0;
2110 EFI_STATUS efi_status;
2111 UINT8 auth[PASSWORD_CRYPT_SIZE];
2112 UINTN auth_size = PASSWORD_CRYPT_SIZE;
2113 UINT32 attributes;
2114 BOOLEAN protected;
2115 CHAR16 *mok_mgmt_p[] = { L"Perform MOK management", NULL };
2116 EFI_STATUS ret = EFI_SUCCESS;
2117
2118 if (verify_pw(&protected) == FALSE)
2119 return EFI_ACCESS_DENIED;
2120
2121 if (protected == FALSE && draw_countdown() == 0)
2122 goto out;
2123
2124 while (choice >= 0) {
2125 UINTN menucount = 3, i = 0;
2126 UINT32 MokAuth = 0;
2127 UINT32 MokDelAuth = 0;
2128 UINT32 MokXAuth = 0;
2129 UINT32 MokXDelAuth = 0;
2130
2131 efi_status = gRT->GetVariable(L"MokAuth", &SHIM_LOCK_GUID,
2132 &attributes, &auth_size, auth);
2133 if (!EFI_ERROR(efi_status) &&
2134 (auth_size == SHA256_DIGEST_SIZE ||
2135 auth_size == PASSWORD_CRYPT_SIZE))
2136 MokAuth = 1;
2137
2138 efi_status = gRT->GetVariable(L"MokDelAuth", &SHIM_LOCK_GUID,
2139 &attributes, &auth_size, auth);
2140 if (!EFI_ERROR(efi_status) &&
2141 (auth_size == SHA256_DIGEST_SIZE ||
2142 auth_size == PASSWORD_CRYPT_SIZE))
2143 MokDelAuth = 1;
2144
2145 efi_status = gRT->GetVariable(L"MokXAuth", &SHIM_LOCK_GUID,
2146 &attributes, &auth_size, auth);
2147 if (!EFI_ERROR(efi_status) &&
2148 (auth_size == SHA256_DIGEST_SIZE ||
2149 auth_size == PASSWORD_CRYPT_SIZE))
2150 MokXAuth = 1;
2151
2152 efi_status = gRT->GetVariable(L"MokXDelAuth", &SHIM_LOCK_GUID,
2153 &attributes, &auth_size, auth);
2154 if (!EFI_ERROR(efi_status) &&
2155 (auth_size == SHA256_DIGEST_SIZE ||
2156 auth_size == PASSWORD_CRYPT_SIZE))
2157 MokXDelAuth = 1;
2158
2159 if (MokNew || MokAuth)
2160 menucount++;
2161
2162 if (MokDel || MokDelAuth)
2163 menucount++;
2164
2165 if (MokXNew || MokXAuth)
2166 menucount++;
2167
2168 if (MokXDel || MokXDelAuth)
2169 menucount++;
2170
2171 if (MokSB)
2172 menucount++;
2173
2174 if (MokPW)
2175 menucount++;
2176
2177 if (MokDB)
2178 menucount++;
2179
2180 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) *
2181 (menucount + 1));
2182 if (!menu_strings)
2183 return EFI_OUT_OF_RESOURCES;
2184
2185 menu_item = AllocateZeroPool(sizeof(mok_menu_item) * menucount);
2186 if (!menu_item) {
2187 FreePool(menu_strings);
2188 return EFI_OUT_OF_RESOURCES;
2189 }
2190
2191 if (mok_changed)
2192 menu_strings[i] = L"Reboot";
2193 else
2194 menu_strings[i] = L"Continue boot";
2195 menu_item[i] = MOK_BOOT;
2196
2197 i++;
2198
2199 if (MokNew || MokAuth) {
2200 if (!MokNew) {
2201 menu_strings[i] = L"Reset MOK";
2202 menu_item[i] = MOK_RESET_MOK;
2203 } else {
2204 menu_strings[i] = L"Enroll MOK";
2205 menu_item[i] = MOK_ENROLL_MOK;
2206 }
2207 i++;
2208 }
2209
2210 if (MokDel || MokDelAuth) {
2211 menu_strings[i] = L"Delete MOK";
2212 menu_item[i] = MOK_DELETE_MOK;
2213 i++;
2214 }
2215
2216 if (MokXNew || MokXAuth) {
2217 if (!MokXNew) {
2218 menu_strings[i] = L"Reset MOKX";
2219 menu_item[i] = MOK_RESET_MOKX;
2220 } else {
2221 menu_strings[i] = L"Enroll MOKX";
2222 menu_item[i] = MOK_ENROLL_MOKX;
2223 }
2224 i++;
2225 }
2226
2227 if (MokXDel || MokXDelAuth) {
2228 menu_strings[i] = L"Delete MOKX";
2229 menu_item[i] = MOK_DELETE_MOKX;
2230 i++;
2231 }
2232
2233 if (MokSB) {
2234 menu_strings[i] = L"Change Secure Boot state";
2235 menu_item[i] = MOK_CHANGE_SB;
2236 i++;
2237 }
2238
2239 if (MokPW) {
2240 menu_strings[i] = L"Set MOK password";
2241 menu_item[i] = MOK_SET_PW;
2242 i++;
2243 }
2244
2245 if (MokDB) {
2246 menu_strings[i] = L"Change DB state";
2247 menu_item[i] = MOK_CHANGE_DB;
2248 i++;
2249 }
2250
2251 menu_strings[i] = L"Enroll key from disk";
2252 menu_item[i] = MOK_KEY_ENROLL;
2253 i++;
2254
2255 menu_strings[i] = L"Enroll hash from disk";
2256 menu_item[i] = MOK_HASH_ENROLL;
2257 i++;
2258
2259 menu_strings[i] = NULL;
2260
2261 choice = console_select(mok_mgmt_p, menu_strings, 0);
2262 if (choice < 0)
2263 goto out;
2264
2265 switch (menu_item[choice]) {
2266 case MOK_BOOT:
2267 goto out;
2268 case MOK_RESET_MOK:
2269 efi_status = mok_reset_prompt(FALSE);
2270 break;
2271 case MOK_ENROLL_MOK:
2272 if (!MokNew) {
2273 console_print(L"MokManager: internal error: %s",
2274 L"MokNew was !NULL but is now NULL\n");
2275 ret = EFI_ABORTED;
2276 goto out;
2277 }
2278 efi_status = mok_enrollment_prompt(MokNew, MokNewSize,
2279 TRUE, FALSE);
2280 if (!EFI_ERROR(efi_status))
2281 MokNew = NULL;
2282 break;
2283 case MOK_DELETE_MOK:
2284 if (!MokDel) {
2285 console_print(L"MokManager: internal error: %s",
2286 L"MokDel was !NULL but is now NULL\n");
2287 ret = EFI_ABORTED;
2288 goto out;
2289 }
2290 efi_status = mok_deletion_prompt(MokDel, MokDelSize,
2291 FALSE);
2292 if (!EFI_ERROR(efi_status))
2293 MokDel = NULL;
2294 break;
2295 case MOK_RESET_MOKX:
2296 efi_status = mok_reset_prompt(TRUE);
2297 break;
2298 case MOK_ENROLL_MOKX:
2299 if (!MokXNew) {
2300 console_print(L"MokManager: internal error: %s",
2301 L"MokXNew was !NULL but is now NULL\n");
2302 ret = EFI_ABORTED;
2303 goto out;
2304 }
2305 efi_status = mok_enrollment_prompt(MokXNew, MokXNewSize,
2306 TRUE, TRUE);
2307 if (!EFI_ERROR(efi_status))
2308 MokXNew = NULL;
2309 break;
2310 case MOK_DELETE_MOKX:
2311 if (!MokXDel) {
2312 console_print(L"MokManager: internal error: %s",
2313 L"MokXDel was !NULL but is now NULL\n");
2314 ret = EFI_ABORTED;
2315 goto out;
2316 }
2317 efi_status = mok_deletion_prompt(MokXDel, MokXDelSize,
2318 TRUE);
2319 if (!EFI_ERROR(efi_status))
2320 MokXDel = NULL;
2321 break;
2322 case MOK_CHANGE_SB:
2323 if (!MokSB) {
2324 console_print(L"MokManager: internal error: %s",
2325 L"MokSB was !NULL but is now NULL\n");
2326 ret = EFI_ABORTED;
2327 goto out;
2328 }
2329 efi_status = mok_sb_prompt(MokSB, MokSBSize);
2330 if (!EFI_ERROR(efi_status))
2331 MokSB = NULL;
2332 break;
2333 case MOK_SET_PW:
2334 if (!MokPW) {
2335 console_print(L"MokManager: internal error: %s",
2336 L"MokPW was !NULL but is now NULL\n");
2337 ret = EFI_ABORTED;
2338 goto out;
2339 }
2340 efi_status = mok_pw_prompt(MokPW, MokPWSize);
2341 if (!EFI_ERROR(efi_status))
2342 MokPW = NULL;
2343 break;
2344 case MOK_CHANGE_DB:
2345 if (!MokDB) {
2346 console_print(L"MokManager: internal error: %s",
2347 L"MokDB was !NULL but is now NULL\n");
2348 ret = EFI_ABORTED;
2349 goto out;
2350 }
2351 efi_status = mok_db_prompt(MokDB, MokDBSize);
2352 if (!EFI_ERROR(efi_status))
2353 MokDB = NULL;
2354 break;
2355 case MOK_KEY_ENROLL:
2356 efi_status = mok_key_enroll();
2357 break;
2358 case MOK_HASH_ENROLL:
2359 efi_status = mok_hash_enroll();
2360 break;
2361 }
2362
2363 if (!EFI_ERROR(efi_status))
2364 mok_changed = 1;
2365
2366 free_menu(menu_item, menu_strings);
2367 menu_item = NULL;
2368 menu_strings = NULL;
2369 }
2370
2371 out:
2372 free_menu(menu_item, menu_strings);
2373
2374 if (mok_changed)
2375 return reset_system();
2376
2377 console_reset();
2378
2379 return ret;
2380 }
2381
2382 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
2383 {
2384 UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
2385 UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0;
2386 void *MokNew = NULL;
2387 void *MokDel = NULL;
2388 void *MokSB = NULL;
2389 void *MokPW = NULL;
2390 void *MokDB = NULL;
2391 void *MokXNew = NULL;
2392 void *MokXDel = NULL;
2393 EFI_STATUS efi_status;
2394
2395 efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize,
2396 SHIM_LOCK_GUID);
2397 if (!EFI_ERROR(efi_status)) {
2398 efi_status = LibDeleteVariable(L"MokNew", &SHIM_LOCK_GUID);
2399 if (EFI_ERROR(efi_status))
2400 console_notify(L"Failed to delete MokNew");
2401 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2402 console_error(L"Could not retrieve MokNew", efi_status);
2403 }
2404
2405 efi_status = get_variable(L"MokDel", (UINT8 **) & MokDel, &MokDelSize,
2406 SHIM_LOCK_GUID);
2407 if (!EFI_ERROR(efi_status)) {
2408 efi_status = LibDeleteVariable(L"MokDel", &SHIM_LOCK_GUID);
2409 if (EFI_ERROR(efi_status))
2410 console_notify(L"Failed to delete MokDel");
2411 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2412 console_error(L"Could not retrieve MokDel", efi_status);
2413 }
2414
2415 efi_status = get_variable(L"MokSB", (UINT8 **) & MokSB, &MokSBSize,
2416 SHIM_LOCK_GUID);
2417 if (!EFI_ERROR(efi_status)) {
2418 efi_status = LibDeleteVariable(L"MokSB", &SHIM_LOCK_GUID);
2419 if (EFI_ERROR(efi_status))
2420 console_notify(L"Failed to delete MokSB");
2421 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2422 console_error(L"Could not retrieve MokSB", efi_status);
2423 }
2424
2425 efi_status = get_variable(L"MokPW", (UINT8 **) & MokPW, &MokPWSize,
2426 SHIM_LOCK_GUID);
2427 if (!EFI_ERROR(efi_status)) {
2428 efi_status = LibDeleteVariable(L"MokPW", &SHIM_LOCK_GUID);
2429 if (EFI_ERROR(efi_status))
2430 console_notify(L"Failed to delete MokPW");
2431 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2432 console_error(L"Could not retrieve MokPW", efi_status);
2433 }
2434
2435 efi_status = get_variable(L"MokDB", (UINT8 **) & MokDB, &MokDBSize,
2436 SHIM_LOCK_GUID);
2437 if (!EFI_ERROR(efi_status)) {
2438 efi_status = LibDeleteVariable(L"MokDB", &SHIM_LOCK_GUID);
2439 if (EFI_ERROR(efi_status))
2440 console_notify(L"Failed to delete MokDB");
2441 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2442 console_error(L"Could not retrieve MokDB", efi_status);
2443 }
2444
2445 efi_status = get_variable(L"MokXNew", (UINT8 **) & MokXNew,
2446 &MokXNewSize, SHIM_LOCK_GUID);
2447 if (!EFI_ERROR(efi_status)) {
2448 efi_status = LibDeleteVariable(L"MokXNew", &SHIM_LOCK_GUID);
2449 if (EFI_ERROR(efi_status))
2450 console_notify(L"Failed to delete MokXNew");
2451 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2452 console_error(L"Could not retrieve MokXNew", efi_status);
2453 }
2454
2455 efi_status = get_variable(L"MokXDel", (UINT8 **) & MokXDel,
2456 &MokXDelSize, SHIM_LOCK_GUID);
2457 if (!EFI_ERROR(efi_status)) {
2458 efi_status = LibDeleteVariable(L"MokXDel", &SHIM_LOCK_GUID);
2459 if (EFI_ERROR(efi_status))
2460 console_notify(L"Failed to delete MokXDel");
2461 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2462 console_error(L"Could not retrieve MokXDel", efi_status);
2463 }
2464
2465 enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
2466 MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize,
2467 MokXNew, MokXNewSize, MokXDel, MokXDelSize);
2468
2469 if (MokNew)
2470 FreePool(MokNew);
2471
2472 if (MokDel)
2473 FreePool(MokDel);
2474
2475 if (MokSB)
2476 FreePool(MokSB);
2477
2478 if (MokPW)
2479 FreePool(MokPW);
2480
2481 if (MokDB)
2482 FreePool(MokDB);
2483
2484 if (MokXNew)
2485 FreePool(MokXNew);
2486
2487 if (MokXDel)
2488 FreePool(MokXDel);
2489
2490 LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
2491 LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
2492 LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
2493 LibDeleteVariable(L"MokXDelAuth", &SHIM_LOCK_GUID);
2494
2495 return EFI_SUCCESS;
2496 }
2497
2498 static EFI_STATUS setup_rand(void)
2499 {
2500 EFI_TIME time;
2501 EFI_STATUS efi_status;
2502 UINT64 seed;
2503 BOOLEAN status;
2504
2505 efi_status = gRT->GetTime(&time, NULL);
2506 if (EFI_ERROR(efi_status))
2507 return efi_status;
2508
2509 seed = ((UINT64) time.Year << 48) | ((UINT64) time.Month << 40) |
2510 ((UINT64) time.Day << 32) | ((UINT64) time.Hour << 24) |
2511 ((UINT64) time.Minute << 16) | ((UINT64) time.Second << 8) |
2512 ((UINT64) time.Daylight);
2513
2514 status = RandomSeed((UINT8 *) & seed, sizeof(seed));
2515 if (!status)
2516 return EFI_ABORTED;
2517
2518 return EFI_SUCCESS;
2519 }
2520
2521 EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * systab)
2522 {
2523 EFI_STATUS efi_status;
2524
2525 InitializeLib(image_handle, systab);
2526
2527 setup_verbosity();
2528 setup_rand();
2529
2530 console_mode_handle();
2531
2532 efi_status = check_mok_request(image_handle);
2533
2534 console_fini();
2535 return efi_status;
2536 }