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