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