]> git.proxmox.com Git - efi-boot-shim.git/blob - MokManager.c
Add timeout support
[efi-boot-shim.git] / MokManager.c
1 #include <efi.h>
2 #include <efilib.h>
3 #include <Library/BaseCryptLib.h>
4 #include <openssl/x509.h>
5 #include "shim.h"
6
7 #define PASSWORD_MAX 16
8 #define PASSWORD_MIN 8
9
10 struct menu_item {
11 CHAR16 *text;
12 INTN (* callback)(void *data, void *data2);
13 void *data;
14 void *data2;
15 UINTN colour;
16 };
17
18 typedef struct {
19 UINT32 MokSize;
20 UINT8 *Mok;
21 } __attribute__ ((packed)) MokListNode;
22
23 static EFI_INPUT_KEY get_keystroke (void)
24 {
25 EFI_INPUT_KEY key;
26 UINTN EventIndex;
27
28 uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey,
29 &EventIndex);
30 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key);
31
32 return key;
33 }
34
35 static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash)
36 {
37 EFI_STATUS status;
38 unsigned int ctxsize;
39 void *ctx = NULL;
40
41 ctxsize = Sha1GetContextSize();
42 ctx = AllocatePool(ctxsize);
43
44 if (!ctx) {
45 Print(L"Unable to allocate memory for hash context\n");
46 return EFI_OUT_OF_RESOURCES;
47 }
48
49 if (!Sha1Init(ctx)) {
50 Print(L"Unable to initialise hash\n");
51 status = EFI_OUT_OF_RESOURCES;
52 goto done;
53 }
54
55 if (!(Sha1Update(ctx, Data, DataSize))) {
56 Print(L"Unable to generate hash\n");
57 status = EFI_OUT_OF_RESOURCES;
58 goto done;
59 }
60
61 if (!(Sha1Final(ctx, hash))) {
62 Print(L"Unable to finalise hash\n");
63 status = EFI_OUT_OF_RESOURCES;
64 goto done;
65 }
66
67 status = EFI_SUCCESS;
68 done:
69 return status;
70 }
71
72 static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
73 MokListNode *list;
74 INT64 remain = DataSize;
75 int i;
76 void *ptr;
77
78 if (DataSize < sizeof(UINT32))
79 return NULL;
80
81 list = AllocatePool(sizeof(MokListNode) * num);
82
83 if (!list) {
84 Print(L"Unable to allocate MOK list\n");
85 return NULL;
86 }
87
88 ptr = Data;
89 for (i = 0; i < num; i++) {
90 CopyMem(&list[i].MokSize, ptr, sizeof(UINT32));
91 remain -= sizeof(UINT32) + list[i].MokSize;
92
93 if (remain < 0) {
94 Print(L"the list was corrupted\n");
95 FreePool(list);
96 return NULL;
97 }
98
99 ptr += sizeof(UINT32);
100 list[i].Mok = ptr;
101 ptr += list[i].MokSize;
102 }
103
104 return list;
105 }
106
107 static void print_x509_name (X509_NAME *X509Name, CHAR16 *name)
108 {
109 char *str;
110
111 str = X509_NAME_oneline(X509Name, NULL, 0);
112 if (str) {
113 Print(L" %s:\n %a\n", name, str);
114 OPENSSL_free(str);
115 }
116 }
117
118 static const char *mon[12]= {
119 "Jan","Feb","Mar","Apr","May","Jun",
120 "Jul","Aug","Sep","Oct","Nov","Dec"
121 };
122
123 static void print_x509_GENERALIZEDTIME_time (ASN1_TIME *time, CHAR16 *time_string)
124 {
125 char *v;
126 int gmt = 0;
127 int i;
128 int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0;
129 char *f = NULL;
130 int f_len = 0;
131
132 i=time->length;
133 v=(char *)time->data;
134
135 if (i < 12)
136 goto error;
137
138 if (v[i-1] == 'Z')
139 gmt=1;
140
141 for (i=0; i<12; i++) {
142 if ((v[i] > '9') || (v[i] < '0'))
143 goto error;
144 }
145
146 y = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0');
147 M = (v[4]-'0')*10+(v[5]-'0');
148
149 if ((M > 12) || (M < 1))
150 goto error;
151
152 d = (v[6]-'0')*10+(v[7]-'0');
153 h = (v[8]-'0')*10+(v[9]-'0');
154 m = (v[10]-'0')*10+(v[11]-'0');
155
156 if (time->length >= 14 &&
157 (v[12] >= '0') && (v[12] <= '9') &&
158 (v[13] >= '0') && (v[13] <= '9')) {
159 s = (v[12]-'0')*10+(v[13]-'0');
160 /* Check for fractions of seconds. */
161 if (time->length >= 15 && v[14] == '.') {
162 int l = time->length;
163 f = &v[14]; /* The decimal point. */
164 f_len = 1;
165 while (14 + f_len < l && f[f_len] >= '0' &&
166 f[f_len] <= '9')
167 ++f_len;
168 }
169 }
170
171 SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d%.*a %d%a",
172 mon[M-1], d, h, m, s, f_len, f, y, (gmt)?" GMT":"");
173 error:
174 return;
175 }
176
177 static void print_x509_UTCTIME_time (ASN1_TIME *time, CHAR16 *time_string)
178 {
179 char *v;
180 int gmt=0;
181 int i;
182 int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0;
183
184 i=time->length;
185 v=(char *)time->data;
186
187 if (i < 10)
188 goto error;
189
190 if (v[i-1] == 'Z')
191 gmt=1;
192
193 for (i=0; i<10; i++)
194 if ((v[i] > '9') || (v[i] < '0'))
195 goto error;
196
197 y = (v[0]-'0')*10+(v[1]-'0');
198
199 if (y < 50)
200 y+=100;
201
202 M = (v[2]-'0')*10+(v[3]-'0');
203
204 if ((M > 12) || (M < 1))
205 goto error;
206
207 d = (v[4]-'0')*10+(v[5]-'0');
208 h = (v[6]-'0')*10+(v[7]-'0');
209 m = (v[8]-'0')*10+(v[9]-'0');
210
211 if (time->length >=12 &&
212 (v[10] >= '0') && (v[10] <= '9') &&
213 (v[11] >= '0') && (v[11] <= '9'))
214 s = (v[10]-'0')*10+(v[11]-'0');
215
216 SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d %d%a",
217 mon[M-1], d, h, m, s, y+1900, (gmt)?" GMT":"");
218 error:
219 return;
220 }
221
222 static void print_x509_time (ASN1_TIME *time, CHAR16 *name)
223 {
224 CHAR16 time_string[30];
225
226 if (time->type == V_ASN1_UTCTIME) {
227 print_x509_UTCTIME_time(time, time_string);
228 } else if (time->type == V_ASN1_GENERALIZEDTIME) {
229 print_x509_GENERALIZEDTIME_time(time, time_string);
230 } else {
231 time_string[0] = '\0';
232 }
233
234 Print(L" %s:\n %s\n", name, time_string);
235 }
236
237 static void show_x509_info (X509 *X509Cert)
238 {
239 ASN1_INTEGER *serial;
240 BIGNUM *bnser;
241 unsigned char hexbuf[30];
242 X509_NAME *X509Name;
243 ASN1_TIME *time;
244
245 serial = X509_get_serialNumber(X509Cert);
246 if (serial) {
247 int i, n;
248 bnser = ASN1_INTEGER_to_BN(serial, NULL);
249 n = BN_bn2bin(bnser, hexbuf);
250 Print(L" Serial Number:\n ");
251 for (i = 0; i < n-1; i++) {
252 Print(L"%02x:", hexbuf[i]);
253 }
254 Print(L"%02x\n", hexbuf[n-1]);
255 }
256
257 X509Name = X509_get_issuer_name(X509Cert);
258 if (X509Name) {
259 print_x509_name(X509Name, L"Issuer");
260 }
261
262 X509Name = X509_get_subject_name(X509Cert);
263 if (X509Name) {
264 print_x509_name(X509Name, L"Subject");
265 }
266
267 time = X509_get_notBefore(X509Cert);
268 if (time) {
269 print_x509_time(time, L"Validity from");
270 }
271
272 time = X509_get_notAfter(X509Cert);
273 if (time) {
274 print_x509_time(time, L"Validity till");
275 }
276 }
277
278 static void show_mok_info (void *Mok, UINTN MokSize)
279 {
280 EFI_STATUS efi_status;
281 UINT8 hash[SHA1_DIGEST_SIZE];
282 unsigned int i;
283 X509 *X509Cert;
284
285 if (!Mok || MokSize == 0)
286 return;
287
288 if (X509ConstructCertificate(Mok, MokSize, (UINT8 **) &X509Cert) &&
289 X509Cert != NULL) {
290 show_x509_info(X509Cert);
291 X509_free(X509Cert);
292 } else {
293 Print(L" Not a valid X509 certificate: %x\n\n",
294 ((UINT32 *)Mok)[0]);
295 return;
296 }
297
298 efi_status = get_sha1sum(Mok, MokSize, hash);
299
300 if (efi_status != EFI_SUCCESS) {
301 Print(L"Failed to compute MOK fingerprint\n");
302 return;
303 }
304
305 Print(L" Fingerprint (SHA1):\n ");
306 for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
307 Print(L" %02x", hash[i]);
308 if (i % 10 == 9)
309 Print(L"\n ");
310 }
311 Print(L"\n");
312 }
313
314 static INTN get_number ()
315 {
316 EFI_INPUT_KEY input_key;
317 CHAR16 input[10];
318 int count = 0;
319
320 do {
321 input_key = get_keystroke();
322
323 if ((input_key.UnicodeChar < '0' ||
324 input_key.UnicodeChar > '9' ||
325 count >= 10) &&
326 input_key.UnicodeChar != CHAR_BACKSPACE) {
327 continue;
328 }
329
330 if (count == 0 && input_key.UnicodeChar == CHAR_BACKSPACE)
331 continue;
332
333 Print(L"%c", input_key.UnicodeChar);
334
335 if (input_key.UnicodeChar == CHAR_BACKSPACE) {
336 input[--count] = '\0';
337 continue;
338 }
339
340 input[count++] = input_key.UnicodeChar;
341 } while (input_key.UnicodeChar != CHAR_CARRIAGE_RETURN);
342
343 if (count == 0)
344 return -1;
345
346 input[count] = '\0';
347
348 return (INTN)Atoi(input);
349 }
350
351 static UINT8 list_keys (void *MokNew, UINTN MokNewSize)
352 {
353 UINT32 MokNum;
354 MokListNode *keys = NULL;
355 INTN key_num = 0;
356 UINT8 initial = 1;
357
358 CopyMem(&MokNum, MokNew, sizeof(UINT32));
359 if (MokNum == 0) {
360 Print(L"No key exists\n");
361 return 0;
362 }
363
364 keys = build_mok_list(MokNum,
365 (void *)MokNew + sizeof(UINT32),
366 MokNewSize - sizeof(UINT32));
367
368 if (!keys) {
369 Print(L"Failed to construct key list in MokNew\n");
370 return 0;
371 }
372
373 do {
374 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
375 Print(L"Input the key number to show the details of the key or\n"
376 L"type \'0\' to continue\n\n");
377 Print(L"%d key(s) in the new key list\n\n", MokNum);
378
379 if (key_num > MokNum) {
380 Print(L"[Key %d]\n", key_num);
381 Print(L"No such key\n\n");
382 } else if (initial != 1 && key_num > 0){
383 Print(L"[Key %d]\n", key_num);
384 show_mok_info(keys[key_num-1].Mok, keys[key_num-1].MokSize);
385 }
386
387 Print(L"Key Number: ");
388
389 key_num = get_number();
390
391 Print(L"\n\n");
392
393 if (key_num == -1)
394 continue;
395
396 initial = 0;
397 } while (key_num != 0);
398
399 FreePool(keys);
400
401 return 1;
402 }
403
404 static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show)
405 {
406 EFI_INPUT_KEY key;
407 int count = 0;
408
409 do {
410 key = get_keystroke();
411
412 if ((count >= line_max &&
413 key.UnicodeChar != CHAR_BACKSPACE) ||
414 key.UnicodeChar == CHAR_NULL ||
415 key.UnicodeChar == CHAR_TAB ||
416 key.UnicodeChar == CHAR_LINEFEED ||
417 key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
418 continue;
419 }
420
421 if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
422 continue;
423 } else if (key.UnicodeChar == CHAR_BACKSPACE) {
424 if (show) {
425 Print(L"\b");
426 }
427 line[--count] = '\0';
428 continue;
429 }
430
431 if (show) {
432 Print(L"%c", key.UnicodeChar);
433 }
434
435 line[count++] = key.UnicodeChar;
436 } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
437 Print(L"\n");
438
439 *length = count;
440
441 return 1;
442 }
443
444 static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *password,
445 UINT32 pw_length, UINT8 *hash)
446 {
447 EFI_STATUS status;
448 unsigned int ctxsize;
449 void *ctx = NULL;
450
451 ctxsize = Sha256GetContextSize();
452 ctx = AllocatePool(ctxsize);
453
454 if (!ctx) {
455 Print(L"Unable to allocate memory for hash context\n");
456 return EFI_OUT_OF_RESOURCES;
457 }
458
459 if (!Sha256Init(ctx)) {
460 Print(L"Unable to initialise hash\n");
461 status = EFI_OUT_OF_RESOURCES;
462 goto done;
463 }
464
465 if (!(Sha256Update(ctx, MokNew, MokNewSize))) {
466 Print(L"Unable to generate hash\n");
467 status = EFI_OUT_OF_RESOURCES;
468 goto done;
469 }
470
471 if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) {
472 Print(L"Unable to generate hash\n");
473 status = EFI_OUT_OF_RESOURCES;
474 goto done;
475 }
476
477 if (!(Sha256Final(ctx, hash))) {
478 Print(L"Unable to finalise hash\n");
479 status = EFI_OUT_OF_RESOURCES;
480 goto done;
481 }
482
483 status = EFI_SUCCESS;
484 done:
485 return status;
486 }
487
488 static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
489 {
490 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
491 EFI_STATUS efi_status;
492 UINT8 hash[SHA256_DIGEST_SIZE];
493 UINT8 auth[SHA256_DIGEST_SIZE];
494 UINTN auth_size;
495 UINT32 attributes;
496 CHAR16 password[PASSWORD_MAX];
497 UINT32 pw_length;
498 UINT8 fail_count = 0;
499
500 if (authenticate) {
501 auth_size = SHA256_DIGEST_SIZE;
502 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
503 &shim_lock_guid,
504 &attributes, &auth_size, auth);
505
506
507 if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
508 Print(L"Failed to get MokAuth %d\n", efi_status);
509 return efi_status;
510 }
511
512 while (fail_count < 3) {
513 Print(L"Password(%d-%d characters): ",
514 PASSWORD_MIN, PASSWORD_MAX);
515 get_line(&pw_length, password, PASSWORD_MAX, 0);
516
517 if (pw_length < 8) {
518 Print(L"At least %d characters for the password\n",
519 PASSWORD_MIN);
520 }
521
522 efi_status = compute_pw_hash(MokNew, MokNewSize, password,
523 pw_length, hash);
524
525 if (efi_status != EFI_SUCCESS) {
526 return efi_status;
527 }
528
529 if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) {
530 Print(L"Password doesn't match\n");
531 fail_count++;
532 } else {
533 break;
534 }
535 }
536
537 if (fail_count >= 3)
538 return EFI_ACCESS_DENIED;
539 }
540
541 /* Write new MOK */
542 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
543 &shim_lock_guid,
544 EFI_VARIABLE_NON_VOLATILE
545 | EFI_VARIABLE_BOOTSERVICE_ACCESS,
546 MokNewSize, MokNew);
547 if (efi_status != EFI_SUCCESS) {
548 Print(L"Failed to set variable %d\n", efi_status);
549 return efi_status;
550 }
551
552 return EFI_SUCCESS;
553 }
554
555 static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
556 CHAR16 line[1];
557 UINT32 length;
558 EFI_STATUS efi_status;
559
560 do {
561 if (!list_keys(MokNew, MokNewSize)) {
562 return 0;
563 }
564
565 Print(L"Enroll the key(s)? (y/n): ");
566
567 get_line (&length, line, 1, 1);
568
569 if (line[0] == 'Y' || line[0] == 'y') {
570 efi_status = store_keys(MokNew, MokNewSize, auth);
571
572 if (efi_status != EFI_SUCCESS) {
573 Print(L"Failed to enroll keys\n");
574 return -1;
575 }
576 return 0;
577 }
578 } while (line[0] != 'N' && line[0] != 'n');
579 return -1;
580 }
581
582 static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2) {
583 return mok_enrollment_prompt(MokNew, (UINTN)data2, TRUE);
584 }
585
586 static INTN mok_deletion_prompt (void *MokNew, void *data2) {
587 CHAR16 line[1];
588 UINT32 length;
589 EFI_STATUS efi_status;
590
591 Print(L"Erase all stored keys? (y/N): ");
592
593 get_line (&length, line, 1, 1);
594
595 if (line[0] == 'Y' || line[0] == 'y') {
596 efi_status = store_keys(MokNew, sizeof(UINT32), TRUE);
597
598 if (efi_status != EFI_SUCCESS) {
599 Print(L"Failed to erase keys\n");
600 return -1;
601 }
602 }
603
604 return 0;
605 }
606
607 static void draw_menu (struct menu_item *items, UINTN count) {
608 UINTN i;
609
610 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
611
612 for (i = 0; i < count; i++) {
613 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
614 items[i].colour | EFI_BACKGROUND_BLACK);
615 Print(L" %s\n", items[i].text);
616 }
617
618 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0);
619 uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
620 }
621
622 static void free_menu (struct menu_item *items, UINTN count) {
623 UINTN i;
624
625 #if 0
626 for (i=0; i<count; i++) {
627 if (items[i].text)
628 FreePool(items[i].text);
629 }
630
631 FreePool(items);
632 #endif
633 }
634
635 static void run_menu (struct menu_item *items, UINTN count, UINTN timeout) {
636 UINTN index, pos = 0, wait = 0;
637 EFI_INPUT_KEY key;
638 EFI_STATUS status;
639
640 if (timeout)
641 wait = 10000000;
642
643 while (1) {
644 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
645
646 draw_menu (items, count);
647
648 uefi_call_wrapper(ST->ConOut->SetAttribute, 2,
649 ST->ConOut,
650 EFI_WHITE | EFI_BACKGROUND_BLACK);
651
652 if (timeout) {
653 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3,
654 ST->ConOut, 0, count + 1);
655 if (timeout > 1)
656 Print(L"Booting in %d seconds\n", timeout);
657 else
658 Print(L"Booting in %d second\n", timeout);
659 }
660
661 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut,
662 0, pos);
663 status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait);
664
665 if (status == EFI_TIMEOUT) {
666 timeout--;
667 if (!timeout) {
668 free_menu(items, count);
669 return;
670 }
671 continue;
672 }
673
674 wait = 0;
675 timeout = 0;
676
677 uefi_call_wrapper(BS->WaitForEvent, 3, 1,
678 &ST->ConIn->WaitForKey, &index);
679 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
680 &key);
681
682 switch(key.ScanCode) {
683 case SCAN_UP:
684 if (pos == 0)
685 continue;
686 pos--;
687 continue;
688 break;
689 case SCAN_DOWN:
690 if (pos == (count - 1))
691 continue;
692 pos++;
693 continue;
694 break;
695 }
696
697 switch(key.UnicodeChar) {
698 case CHAR_LINEFEED:
699 case CHAR_CARRIAGE_RETURN:
700 if (items[pos].callback == NULL) {
701 free_menu(items, count);
702 return;
703 }
704
705 items[pos].callback(items[pos].data, items[pos].data2);
706 draw_menu (items, count);
707 pos = 0;
708 break;
709 }
710 }
711 }
712
713 static INTN file_callback (void *data, void *data2) {
714 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
715 EFI_FILE_INFO *buffer = NULL;
716 UINTN buffersize = 0, readsize;
717 EFI_STATUS status;
718 EFI_FILE *file;
719 CHAR16 *filename = data;
720 EFI_FILE *parent = data2;
721 EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
722 void *mokbuffer = NULL, *mok;
723 UINTN MokSize = 0, MokNewSize;
724 MokListNode *MokNew;
725
726 mok = LibGetVariableAndSize(L"MokList", &shim_lock_guid, &MokSize);
727
728 status = uefi_call_wrapper(parent->Open, 5, parent, &file, filename,
729 EFI_FILE_MODE_READ, 0);
730
731 if (status != EFI_SUCCESS)
732 return 1;
733
734 status = uefi_call_wrapper(file->GetInfo, 4, file, &file_info_guid,
735 &buffersize, buffer);
736
737 if (status == EFI_BUFFER_TOO_SMALL) {
738 buffer = AllocatePool(buffersize);
739 status = uefi_call_wrapper(file->GetInfo, 4, file,
740 &file_info_guid, &buffersize,
741 buffer);
742 }
743
744 if (!buffer)
745 return 0;
746
747 readsize = buffer->FileSize;
748
749 if (mok) {
750 MokNewSize = MokSize + readsize + sizeof(UINT32);
751 mokbuffer = AllocateZeroPool(MokNewSize);
752
753 if (!mokbuffer)
754 goto out;
755
756 CopyMem(mokbuffer, mok, MokSize);
757 ((UINT32 *)mokbuffer)[0]++;
758 MokNew = (MokListNode *)(((char *)mokbuffer) + MokSize);
759 } else {
760 MokNewSize = readsize + (2 * sizeof(UINT32));
761 mokbuffer = AllocateZeroPool(MokNewSize);
762
763 if (!mokbuffer)
764 goto out;
765 ((UINT32 *)mokbuffer)[0]=1;
766 MokNew = (MokListNode *)(((UINT32 *)mokbuffer) + 1);
767 }
768
769 MokNew->MokSize = readsize;
770
771 status = uefi_call_wrapper(file->Read, 3, file, &readsize, &MokNew->Mok);
772
773 if (status != EFI_SUCCESS)
774 goto out;
775
776 mok_enrollment_prompt(mokbuffer, MokNewSize, FALSE);
777 out:
778 if (buffer)
779 FreePool(buffer);
780
781 if (mokbuffer)
782 FreePool(mokbuffer);
783
784 return 0;
785 }
786
787 static INTN directory_callback (void *data, void *data2) {
788 EFI_FILE_INFO *buffer = NULL;
789 UINTN buffersize = 0;
790 EFI_STATUS status;
791 UINTN dircount = 0, i = 0;
792 struct menu_item *dircontent;
793 EFI_FILE *dir;
794 CHAR16 *filename = data;
795 EFI_FILE *root = data2;
796
797 status = uefi_call_wrapper(root->Open, 5, root, &dir, filename,
798 EFI_FILE_MODE_READ, 0);
799
800 if (status != EFI_SUCCESS)
801 return 1;
802
803 while (1) {
804 status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize,
805 buffer);
806
807 if (status == EFI_BUFFER_TOO_SMALL) {
808 buffer = AllocatePool(buffersize);
809 status = uefi_call_wrapper(dir->Read, 3, dir,
810 &buffersize, buffer);
811 }
812
813 if (status != EFI_SUCCESS)
814 return 1;
815
816 if (!buffersize)
817 break;
818
819 if ((StrCmp(buffer->FileName, L".") == 0) ||
820 (StrCmp(buffer->FileName, L"..") == 0))
821 continue;
822
823 dircount++;
824
825 FreePool(buffer);
826 buffersize = 0;
827 }
828
829 dircount++;
830
831 dircontent = AllocatePool(sizeof(struct menu_item) * dircount);
832
833 dircontent[0].text = StrDuplicate(L"..");
834 dircontent[0].callback = NULL;
835 dircontent[0].colour = EFI_YELLOW;
836 i++;
837
838 uefi_call_wrapper(dir->SetPosition, 2, dir, 0);
839
840 while (1) {
841 status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize,
842 buffer);
843
844 if (status == EFI_BUFFER_TOO_SMALL) {
845 buffer = AllocatePool(buffersize);
846 status = uefi_call_wrapper(dir->Read, 3, dir,
847 &buffersize, buffer);
848 }
849
850 if (status != EFI_SUCCESS)
851 return 1;
852
853 if (!buffersize)
854 break;
855
856 if ((StrCmp(buffer->FileName, L".") == 0) ||
857 (StrCmp(buffer->FileName, L"..") == 0))
858 continue;
859
860 if (buffer->Attribute & EFI_FILE_DIRECTORY) {
861 dircontent[i].text = StrDuplicate(buffer->FileName);
862 dircontent[i].callback = directory_callback;
863 dircontent[i].data = dircontent[i].text;
864 dircontent[i].data2 = dir;
865 dircontent[i].colour = EFI_YELLOW;
866 } else {
867 dircontent[i].text = StrDuplicate(buffer->FileName);
868 dircontent[i].callback = file_callback;
869 dircontent[i].data = dircontent[i].text;
870 dircontent[i].data2 = dir;
871 dircontent[i].colour = EFI_WHITE;
872 }
873
874 i++;
875 FreePool(buffer);
876 buffersize = 0;
877 buffer = NULL;
878 }
879
880 run_menu(dircontent, dircount, 0);
881
882 return 0;
883 }
884
885 static INTN filesystem_callback (void *data, void *data2) {
886 EFI_FILE_INFO *buffer = NULL;
887 UINTN buffersize = 0;
888 EFI_STATUS status;
889 UINTN dircount = 0, i = 0;
890 struct menu_item *dircontent;
891 EFI_FILE *root = data;
892
893 uefi_call_wrapper(root->SetPosition, 2, root, 0);
894
895 while (1) {
896 status = uefi_call_wrapper(root->Read, 3, root, &buffersize,
897 buffer);
898
899 if (status == EFI_BUFFER_TOO_SMALL) {
900 buffer = AllocatePool(buffersize);
901 status = uefi_call_wrapper(root->Read, 3, root,
902 &buffersize, buffer);
903 }
904
905 if (status != EFI_SUCCESS)
906 return 1;
907
908 if (!buffersize)
909 break;
910
911 if ((StrCmp(buffer->FileName, L".") == 0) ||
912 (StrCmp(buffer->FileName, L"..") == 0))
913 continue;
914
915 dircount++;
916
917 FreePool(buffer);
918 buffersize = 0;
919 }
920
921 dircount++;
922
923 dircontent = AllocatePool(sizeof(struct menu_item) * dircount);
924
925 dircontent[0].text = StrDuplicate(L"Return to filesystem list");
926 dircontent[0].callback = NULL;
927 dircontent[0].colour = EFI_YELLOW;
928 i++;
929
930 uefi_call_wrapper(root->SetPosition, 2, root, 0);
931
932 while (1) {
933 status = uefi_call_wrapper(root->Read, 3, root, &buffersize,
934 buffer);
935
936 if (status == EFI_BUFFER_TOO_SMALL) {
937 buffer = AllocatePool(buffersize);
938 status = uefi_call_wrapper(root->Read, 3, root,
939 &buffersize, buffer);
940 }
941
942 if (status != EFI_SUCCESS)
943 return 1;
944
945 if (!buffersize)
946 break;
947
948 if ((StrCmp(buffer->FileName, L".") == 0) ||
949 (StrCmp(buffer->FileName, L"..") == 0))
950 continue;
951
952 if (buffer->Attribute & EFI_FILE_DIRECTORY) {
953 dircontent[i].text = StrDuplicate(buffer->FileName);
954 dircontent[i].callback = directory_callback;
955 dircontent[i].data = dircontent[i].text;
956 dircontent[i].data2 = root;
957 dircontent[i].colour = EFI_YELLOW;
958 } else {
959 dircontent[i].text = StrDuplicate(buffer->FileName);
960 dircontent[i].callback = file_callback;
961 dircontent[i].data = dircontent[i].text;
962 dircontent[i].data2 = root;
963 dircontent[i].colour = EFI_WHITE;
964 }
965
966 i++;
967 FreePool(buffer);
968 buffer = NULL;
969 buffersize = 0;
970 }
971
972 run_menu(dircontent, dircount, 0);
973
974 return 0;
975 }
976
977 static INTN find_fs (void *data, void *data2) {
978 EFI_GUID fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL;
979 UINTN count, i;
980 EFI_HANDLE **filesystem_handles;
981 struct menu_item *filesystems;
982
983 uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &fs_guid,
984 NULL, &count, &filesystem_handles);
985
986 if (!count || !filesystem_handles) {
987 Print(L"No filesystems?\n");
988 return 1;
989 }
990
991 count++;
992
993 filesystems = AllocatePool(sizeof(struct menu_item) * count);
994
995 filesystems[0].text = StrDuplicate(L"Exit");
996 filesystems[0].callback = NULL;
997 filesystems[0].colour = EFI_YELLOW;
998
999 for (i=1; i<count; i++) {
1000 EFI_HANDLE *fs = filesystem_handles[i-1];
1001 EFI_FILE_IO_INTERFACE *fs_interface;
1002 EFI_DEVICE_PATH *path;
1003 EFI_FILE *root;
1004 EFI_STATUS status;
1005 CHAR16 *VolumeLabel = NULL;
1006 EFI_FILE_SYSTEM_INFO *buffer = NULL;
1007 UINTN buffersize = 0;
1008 EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
1009
1010 status = uefi_call_wrapper(BS->HandleProtocol, 3, fs, &fs_guid,
1011 &fs_interface);
1012
1013 if (status != EFI_SUCCESS || !fs_interface)
1014 continue;
1015
1016 path = DevicePathFromHandle(fs);
1017
1018 status = uefi_call_wrapper(fs_interface->OpenVolume, 2,
1019 fs_interface, &root);
1020
1021 if (status != EFI_SUCCESS || !root)
1022 continue;
1023
1024 status = uefi_call_wrapper(root->GetInfo, 4, root,
1025 &file_info_guid, &buffersize,
1026 buffer);
1027
1028 if (status == EFI_BUFFER_TOO_SMALL) {
1029 buffer = AllocatePool(buffersize);
1030 status = uefi_call_wrapper(root->GetInfo, 4, root,
1031 &file_info_guid,
1032 &buffersize, buffer);
1033 }
1034
1035 if (status == EFI_SUCCESS)
1036 VolumeLabel = buffer->VolumeLabel;
1037
1038 if (path)
1039 filesystems[i].text = DevicePathToStr(path);
1040 else
1041 filesystems[i].text = StrDuplicate(L"Unknown device\n");
1042 if (VolumeLabel)
1043 StrCat(filesystems[i].text, VolumeLabel);
1044
1045 if (buffersize)
1046 FreePool(buffer);
1047
1048 filesystems[i].data = root;
1049 filesystems[i].data2 = NULL;
1050 filesystems[i].callback = filesystem_callback;
1051 filesystems[i].colour = EFI_YELLOW;
1052 }
1053
1054 uefi_call_wrapper(BS->FreePool, 1, filesystem_handles);
1055
1056 run_menu(filesystems, count, 0);
1057
1058 return 0;
1059 }
1060
1061 static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
1062 UINTN MokNewSize)
1063 {
1064 struct menu_item *menu_item;
1065 UINT32 MokNum;
1066 UINTN menucount = 0;
1067
1068 if (MokNew)
1069 menu_item = AllocateZeroPool(sizeof(struct menu_item) * 3);
1070 else
1071 menu_item = AllocateZeroPool(sizeof(struct menu_item) * 2);
1072
1073 if (!menu_item)
1074 return EFI_OUT_OF_RESOURCES;
1075
1076 menu_item[0].text = StrDuplicate(L"Continue boot");
1077 menu_item[0].colour = EFI_WHITE;
1078 menu_item[0].callback = NULL;
1079
1080 menucount++;
1081
1082 if (MokNew) {
1083 CopyMem(&MokNum, MokNew, sizeof(UINT32));
1084 if (MokNum == 0) {
1085 menu_item[1].text = StrDuplicate(L"Delete MOK");
1086 menu_item[1].colour = EFI_WHITE;
1087 menu_item[1].data = MokNew;
1088 menu_item[1].callback = mok_deletion_prompt;
1089 } else {
1090 menu_item[1].text = StrDuplicate(L"Enroll MOK");
1091 menu_item[1].colour = EFI_WHITE;
1092 menu_item[1].data = MokNew;
1093 menu_item[1].data2 = (void *)MokNewSize;
1094 menu_item[1].callback = mok_enrollment_prompt_callback;
1095 }
1096 menucount++;
1097 }
1098
1099 menu_item[menucount].text = StrDuplicate(L"Enroll key from disk");
1100 menu_item[menucount].colour = EFI_WHITE;
1101 menu_item[menucount].callback = find_fs;
1102
1103 menucount++;
1104
1105 run_menu(menu_item, menucount, 10);
1106
1107 return 0;
1108 }
1109
1110 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1111 {
1112 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1113 UINTN MokNewSize = 0;
1114 void *MokNew = NULL;
1115
1116 MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize);
1117
1118 enter_mok_menu(image_handle, MokNew, MokNewSize);
1119
1120 if (MokNew) {
1121 if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
1122 Print(L"Failed to delete MokNew\n");
1123 }
1124 FreePool (MokNew);
1125 }
1126 LibDeleteVariable(L"MokAuth", &shim_lock_guid);
1127
1128 return EFI_SUCCESS;
1129 }
1130
1131 EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
1132 {
1133 EFI_STATUS efi_status;
1134
1135 InitializeLib(image_handle, systab);
1136
1137 efi_status = check_mok_request(image_handle);
1138
1139 return efi_status;
1140 }