]> git.proxmox.com Git - efi-boot-shim.git/blob - MokManager.c
Add another missing screen clearing
[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 #include "signature.h"
7 #include "PeImage.h"
8
9 #define PASSWORD_MAX 16
10 #define PASSWORD_MIN 8
11 #define SB_PASSWORD_LEN 8
12
13 #ifndef SHIM_VENDOR
14 #define SHIM_VENDOR L"Shim"
15 #endif
16
17 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
18
19 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
20 #define HASH_STRING L"Select a file to trust:\n\n"
21
22 struct menu_item {
23 CHAR16 *text;
24 INTN (* callback)(void *data, void *data2, void *data3);
25 void *data;
26 void *data2;
27 void *data3;
28 UINTN colour;
29 };
30
31 typedef struct {
32 UINT32 MokSize;
33 UINT8 *Mok;
34 } __attribute__ ((packed)) MokListNode;
35
36 typedef struct {
37 UINT32 MokSBState;
38 UINT32 PWLen;
39 CHAR16 Password[PASSWORD_MAX];
40 } __attribute__ ((packed)) MokSBvar;
41
42 static EFI_INPUT_KEY get_keystroke (void)
43 {
44 EFI_INPUT_KEY key;
45 UINTN EventIndex;
46
47 uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey,
48 &EventIndex);
49 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key);
50
51 return key;
52 }
53
54 static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash)
55 {
56 EFI_STATUS status;
57 unsigned int ctxsize;
58 void *ctx = NULL;
59
60 ctxsize = Sha1GetContextSize();
61 ctx = AllocatePool(ctxsize);
62
63 if (!ctx) {
64 Print(L"Unable to allocate memory for hash context\n");
65 return EFI_OUT_OF_RESOURCES;
66 }
67
68 if (!Sha1Init(ctx)) {
69 Print(L"Unable to initialise hash\n");
70 status = EFI_OUT_OF_RESOURCES;
71 goto done;
72 }
73
74 if (!(Sha1Update(ctx, Data, DataSize))) {
75 Print(L"Unable to generate hash\n");
76 status = EFI_OUT_OF_RESOURCES;
77 goto done;
78 }
79
80 if (!(Sha1Final(ctx, hash))) {
81 Print(L"Unable to finalise hash\n");
82 status = EFI_OUT_OF_RESOURCES;
83 goto done;
84 }
85
86 status = EFI_SUCCESS;
87 done:
88 return status;
89 }
90
91 static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
92 MokListNode *list;
93 EFI_SIGNATURE_LIST *CertList = Data;
94 EFI_SIGNATURE_DATA *Cert;
95 EFI_GUID CertType = EfiCertX509Guid;
96 EFI_GUID HashType = EfiHashSha256Guid;
97 UINTN dbsize = DataSize;
98 UINTN count = 0;
99
100 list = AllocatePool(sizeof(MokListNode) * num);
101
102 if (!list) {
103 Print(L"Unable to allocate MOK list\n");
104 return NULL;
105 }
106
107 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
108 if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
109 (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
110 dbsize -= CertList->SignatureListSize;
111 CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
112 CertList->SignatureListSize);
113 continue;
114 }
115
116 if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) &&
117 (CertList->SignatureSize != 48)) {
118 dbsize -= CertList->SignatureListSize;
119 CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
120 CertList->SignatureListSize);
121 continue;
122 }
123
124 Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
125 sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
126
127 list[count].MokSize = CertList->SignatureSize;
128 list[count].Mok = (void *)Cert->SignatureData;
129
130 count++;
131 dbsize -= CertList->SignatureListSize;
132 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
133 CertList->SignatureListSize);
134 }
135
136 return list;
137 }
138
139 static void print_x509_name (X509_NAME *X509Name, CHAR16 *name)
140 {
141 char *str;
142
143 str = X509_NAME_oneline(X509Name, NULL, 0);
144 if (str) {
145 Print(L" %s:\n %a\n", name, str);
146 OPENSSL_free(str);
147 }
148 }
149
150 static const char *mon[12]= {
151 "Jan","Feb","Mar","Apr","May","Jun",
152 "Jul","Aug","Sep","Oct","Nov","Dec"
153 };
154
155 static void print_x509_GENERALIZEDTIME_time (ASN1_TIME *time, CHAR16 *time_string)
156 {
157 char *v;
158 int gmt = 0;
159 int i;
160 int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0;
161 char *f = NULL;
162 int f_len = 0;
163
164 i=time->length;
165 v=(char *)time->data;
166
167 if (i < 12)
168 goto error;
169
170 if (v[i-1] == 'Z')
171 gmt=1;
172
173 for (i=0; i<12; i++) {
174 if ((v[i] > '9') || (v[i] < '0'))
175 goto error;
176 }
177
178 y = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0');
179 M = (v[4]-'0')*10+(v[5]-'0');
180
181 if ((M > 12) || (M < 1))
182 goto error;
183
184 d = (v[6]-'0')*10+(v[7]-'0');
185 h = (v[8]-'0')*10+(v[9]-'0');
186 m = (v[10]-'0')*10+(v[11]-'0');
187
188 if (time->length >= 14 &&
189 (v[12] >= '0') && (v[12] <= '9') &&
190 (v[13] >= '0') && (v[13] <= '9')) {
191 s = (v[12]-'0')*10+(v[13]-'0');
192 /* Check for fractions of seconds. */
193 if (time->length >= 15 && v[14] == '.') {
194 int l = time->length;
195 f = &v[14]; /* The decimal point. */
196 f_len = 1;
197 while (14 + f_len < l && f[f_len] >= '0' &&
198 f[f_len] <= '9')
199 ++f_len;
200 }
201 }
202
203 SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d%.*a %d%a",
204 mon[M-1], d, h, m, s, f_len, f, y, (gmt)?" GMT":"");
205 error:
206 return;
207 }
208
209 static void print_x509_UTCTIME_time (ASN1_TIME *time, CHAR16 *time_string)
210 {
211 char *v;
212 int gmt=0;
213 int i;
214 int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0;
215
216 i=time->length;
217 v=(char *)time->data;
218
219 if (i < 10)
220 goto error;
221
222 if (v[i-1] == 'Z')
223 gmt=1;
224
225 for (i=0; i<10; i++)
226 if ((v[i] > '9') || (v[i] < '0'))
227 goto error;
228
229 y = (v[0]-'0')*10+(v[1]-'0');
230
231 if (y < 50)
232 y+=100;
233
234 M = (v[2]-'0')*10+(v[3]-'0');
235
236 if ((M > 12) || (M < 1))
237 goto error;
238
239 d = (v[4]-'0')*10+(v[5]-'0');
240 h = (v[6]-'0')*10+(v[7]-'0');
241 m = (v[8]-'0')*10+(v[9]-'0');
242
243 if (time->length >=12 &&
244 (v[10] >= '0') && (v[10] <= '9') &&
245 (v[11] >= '0') && (v[11] <= '9'))
246 s = (v[10]-'0')*10+(v[11]-'0');
247
248 SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d %d%a",
249 mon[M-1], d, h, m, s, y+1900, (gmt)?" GMT":"");
250 error:
251 return;
252 }
253
254 static void print_x509_time (ASN1_TIME *time, CHAR16 *name)
255 {
256 CHAR16 time_string[30];
257
258 if (time->type == V_ASN1_UTCTIME) {
259 print_x509_UTCTIME_time(time, time_string);
260 } else if (time->type == V_ASN1_GENERALIZEDTIME) {
261 print_x509_GENERALIZEDTIME_time(time, time_string);
262 } else {
263 time_string[0] = '\0';
264 }
265
266 Print(L" %s:\n %s\n", name, time_string);
267 }
268
269 static void show_x509_info (X509 *X509Cert)
270 {
271 ASN1_INTEGER *serial;
272 BIGNUM *bnser;
273 unsigned char hexbuf[30];
274 X509_NAME *X509Name;
275 ASN1_TIME *time;
276
277 serial = X509_get_serialNumber(X509Cert);
278 if (serial) {
279 int i, n;
280 bnser = ASN1_INTEGER_to_BN(serial, NULL);
281 n = BN_bn2bin(bnser, hexbuf);
282 Print(L" Serial Number:\n ");
283 for (i = 0; i < n-1; i++) {
284 Print(L"%02x:", hexbuf[i]);
285 }
286 Print(L"%02x\n", hexbuf[n-1]);
287 }
288
289 X509Name = X509_get_issuer_name(X509Cert);
290 if (X509Name) {
291 print_x509_name(X509Name, L"Issuer");
292 }
293
294 X509Name = X509_get_subject_name(X509Cert);
295 if (X509Name) {
296 print_x509_name(X509Name, L"Subject");
297 }
298
299 time = X509_get_notBefore(X509Cert);
300 if (time) {
301 print_x509_time(time, L"Validity from");
302 }
303
304 time = X509_get_notAfter(X509Cert);
305 if (time) {
306 print_x509_time(time, L"Validity till");
307 }
308 }
309
310 static void show_mok_info (void *Mok, UINTN MokSize)
311 {
312 EFI_STATUS efi_status;
313 UINT8 hash[SHA1_DIGEST_SIZE];
314 unsigned int i;
315 X509 *X509Cert;
316
317 if (!Mok || MokSize == 0)
318 return;
319
320 if (MokSize != 48) {
321 if (X509ConstructCertificate(Mok, MokSize,
322 (UINT8 **) &X509Cert) && X509Cert != NULL) {
323 show_x509_info(X509Cert);
324 X509_free(X509Cert);
325 } else {
326 Print(L" Not a valid X509 certificate: %x\n\n",
327 ((UINT32 *)Mok)[0]);
328 return;
329 }
330
331 efi_status = get_sha1sum(Mok, MokSize, hash);
332
333 if (efi_status != EFI_SUCCESS) {
334 Print(L"Failed to compute MOK fingerprint\n");
335 return;
336 }
337
338 Print(L" Fingerprint (SHA1):\n ");
339 for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
340 Print(L" %02x", hash[i]);
341 if (i % 10 == 9)
342 Print(L"\n ");
343 }
344 } else {
345 Print(L"SHA256 hash:\n ");
346 for (i = 0; i < SHA256_DIGEST_SIZE; i++) {
347 Print(L" %02x", ((UINT8 *)Mok)[i]);
348 if (i % 10 == 9)
349 Print(L"\n ");
350 }
351 Print(L"\n");
352 }
353
354 Print(L"\n");
355 }
356
357 static INTN get_number ()
358 {
359 EFI_INPUT_KEY input_key;
360 CHAR16 input[10];
361 int count = 0;
362
363 do {
364 input_key = get_keystroke();
365
366 if ((input_key.UnicodeChar < '0' ||
367 input_key.UnicodeChar > '9' ||
368 count >= 10) &&
369 input_key.UnicodeChar != CHAR_BACKSPACE) {
370 continue;
371 }
372
373 if (count == 0 && input_key.UnicodeChar == CHAR_BACKSPACE)
374 continue;
375
376 Print(L"%c", input_key.UnicodeChar);
377
378 if (input_key.UnicodeChar == CHAR_BACKSPACE) {
379 input[--count] = '\0';
380 continue;
381 }
382
383 input[count++] = input_key.UnicodeChar;
384 } while (input_key.UnicodeChar != CHAR_CARRIAGE_RETURN);
385
386 if (count == 0)
387 return -1;
388
389 input[count] = '\0';
390
391 return (INTN)Atoi(input);
392 }
393
394 static UINT8 list_keys (void *MokNew, UINTN MokNewSize)
395 {
396 UINT32 MokNum = 0;
397 MokListNode *keys = NULL;
398 INTN key_num = 0;
399 UINT8 initial = 1;
400 EFI_SIGNATURE_LIST *CertList = MokNew;
401 EFI_GUID CertType = EfiCertX509Guid;
402 EFI_GUID HashType = EfiHashSha256Guid;
403 UINTN dbsize = MokNewSize;
404
405 if (MokNewSize < (sizeof(EFI_SIGNATURE_LIST) +
406 sizeof(EFI_SIGNATURE_DATA))) {
407 Print(L"No keys\n");
408 Pause();
409 return 0;
410 }
411
412 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
413 if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
414 (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
415 Print(L"Doesn't look like a key or hash\n");
416 dbsize -= CertList->SignatureListSize;
417 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
418 CertList->SignatureListSize);
419 continue;
420 }
421
422 if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
423 (CertList->SignatureSize != 48)) {
424 Print(L"Doesn't look like a valid hash\n");
425 dbsize -= CertList->SignatureListSize;
426 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
427 CertList->SignatureListSize);
428 continue;
429 }
430
431 MokNum++;
432 dbsize -= CertList->SignatureListSize;
433 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
434 CertList->SignatureListSize);
435 }
436
437 keys = build_mok_list(MokNum, MokNew, MokNewSize);
438
439 if (!keys) {
440 Print(L"Failed to construct key list in MokNew\n");
441 return 0;
442 }
443
444 do {
445 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
446 Print(L"Input the key number to show the details of the key or\n"
447 L"type \'0\' to continue\n\n");
448 Print(L"%d key(s) in the new key list\n\n", MokNum);
449
450 if (key_num > MokNum) {
451 Print(L"[Key %d]\n", key_num);
452 Print(L"No such key\n\n");
453 } else if (initial != 1 && key_num > 0){
454 Print(L"[Key %d]\n", key_num);
455 show_mok_info(keys[key_num-1].Mok, keys[key_num-1].MokSize);
456 }
457
458 Print(L"Key Number: ");
459
460 key_num = get_number();
461
462 Print(L"\n\n");
463
464 if (key_num == -1)
465 continue;
466
467 initial = 0;
468 } while (key_num != 0);
469
470 FreePool(keys);
471
472 return 1;
473 }
474
475 static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show)
476 {
477 EFI_INPUT_KEY key;
478 int count = 0;
479
480 do {
481 key = get_keystroke();
482
483 if ((count >= line_max &&
484 key.UnicodeChar != CHAR_BACKSPACE) ||
485 key.UnicodeChar == CHAR_NULL ||
486 key.UnicodeChar == CHAR_TAB ||
487 key.UnicodeChar == CHAR_LINEFEED ||
488 key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
489 continue;
490 }
491
492 if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
493 continue;
494 } else if (key.UnicodeChar == CHAR_BACKSPACE) {
495 if (show) {
496 Print(L"\b");
497 }
498 line[--count] = '\0';
499 continue;
500 }
501
502 if (show) {
503 Print(L"%c", key.UnicodeChar);
504 }
505
506 line[count++] = key.UnicodeChar;
507 } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
508 Print(L"\n");
509
510 *length = count;
511
512 return 1;
513 }
514
515 static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *password,
516 UINT32 pw_length, UINT8 *hash)
517 {
518 EFI_STATUS status;
519 unsigned int ctxsize;
520 void *ctx = NULL;
521
522 ctxsize = Sha256GetContextSize();
523 ctx = AllocatePool(ctxsize);
524
525 if (!ctx) {
526 Print(L"Unable to allocate memory for hash context\n");
527 return EFI_OUT_OF_RESOURCES;
528 }
529
530 if (!Sha256Init(ctx)) {
531 Print(L"Unable to initialise hash\n");
532 status = EFI_OUT_OF_RESOURCES;
533 goto done;
534 }
535
536 if (MokNew && MokNewSize) {
537 if (!(Sha256Update(ctx, MokNew, MokNewSize))) {
538 Print(L"Unable to generate hash\n");
539 status = EFI_OUT_OF_RESOURCES;
540 goto done;
541 }
542 }
543
544 if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) {
545 Print(L"Unable to generate hash\n");
546 status = EFI_OUT_OF_RESOURCES;
547 goto done;
548 }
549
550 if (!(Sha256Final(ctx, hash))) {
551 Print(L"Unable to finalise hash\n");
552 status = EFI_OUT_OF_RESOURCES;
553 goto done;
554 }
555
556 status = EFI_SUCCESS;
557 done:
558 return status;
559 }
560
561 static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
562 {
563 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
564 EFI_STATUS efi_status;
565 UINT8 hash[SHA256_DIGEST_SIZE];
566 UINT8 auth[SHA256_DIGEST_SIZE];
567 UINTN auth_size;
568 UINT32 attributes;
569 CHAR16 password[PASSWORD_MAX];
570 UINT32 pw_length;
571 UINT8 fail_count = 0;
572
573 if (authenticate) {
574 auth_size = SHA256_DIGEST_SIZE;
575 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
576 &shim_lock_guid,
577 &attributes, &auth_size, auth);
578
579
580 if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
581 Print(L"Failed to get MokAuth %d\n", efi_status);
582 return efi_status;
583 }
584
585 while (fail_count < 3) {
586 Print(L"Password(%d-%d characters): ",
587 PASSWORD_MIN, PASSWORD_MAX);
588 get_line(&pw_length, password, PASSWORD_MAX, 0);
589
590 if (pw_length < 8) {
591 Print(L"At least %d characters for the password\n",
592 PASSWORD_MIN);
593 }
594
595 efi_status = compute_pw_hash(MokNew, MokNewSize, password,
596 pw_length, hash);
597
598 if (efi_status != EFI_SUCCESS) {
599 return efi_status;
600 }
601
602 if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) {
603 Print(L"Password doesn't match\n");
604 fail_count++;
605 } else {
606 break;
607 }
608 }
609
610 if (fail_count >= 3)
611 return EFI_ACCESS_DENIED;
612 }
613
614 if (!MokNewSize) {
615 /* Delete MOK */
616 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
617 &shim_lock_guid,
618 EFI_VARIABLE_NON_VOLATILE
619 | EFI_VARIABLE_BOOTSERVICE_ACCESS,
620 0, NULL);
621 } else {
622 /* Write new MOK */
623 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
624 &shim_lock_guid,
625 EFI_VARIABLE_NON_VOLATILE
626 | EFI_VARIABLE_BOOTSERVICE_ACCESS
627 | EFI_VARIABLE_APPEND_WRITE,
628 MokNewSize, MokNew);
629 }
630
631 if (efi_status != EFI_SUCCESS) {
632 Print(L"Failed to set variable %d\n", efi_status);
633 return efi_status;
634 }
635
636 return EFI_SUCCESS;
637 }
638
639 static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
640 CHAR16 line[1];
641 UINT32 length;
642 EFI_STATUS efi_status;
643
644 do {
645 if (!list_keys(MokNew, MokNewSize)) {
646 return 0;
647 }
648
649 Print(L"Enroll the key(s)? (y/n): ");
650
651 get_line (&length, line, 1, 1);
652
653 if (line[0] == 'Y' || line[0] == 'y') {
654 efi_status = store_keys(MokNew, MokNewSize, auth);
655
656 if (efi_status != EFI_SUCCESS) {
657 Print(L"Failed to enroll keys\n");
658 return -1;
659 }
660 return 0;
661 }
662 } while (line[0] != 'N' && line[0] != 'n');
663 return -1;
664 }
665
666 static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2,
667 void *data3)
668 {
669 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
670 return mok_enrollment_prompt(MokNew, (UINTN)data2, TRUE);
671 }
672
673 static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
674 CHAR16 line[1];
675 UINT32 length;
676 EFI_STATUS efi_status;
677
678 Print(L"Erase all stored keys? (y/N): ");
679
680 get_line (&length, line, 1, 1);
681
682 if (line[0] == 'Y' || line[0] == 'y') {
683 efi_status = store_keys(NULL, 0, TRUE);
684
685 if (efi_status != EFI_SUCCESS) {
686 Print(L"Failed to erase keys\n");
687 return -1;
688 }
689 }
690
691 return 0;
692 }
693
694 static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) {
695 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
696 EFI_STATUS efi_status;
697 UINTN MokSBSize = (UINTN)data2;
698 MokSBvar *var = MokSB;
699 CHAR16 password[1];
700 UINT8 correct = 0, fail_count = 0;
701 UINT8 hash[SHA256_DIGEST_SIZE];
702 UINT32 length;
703 CHAR16 line[1];
704 UINT8 sbval = 1;
705 UINT8 pos;
706
707 LibDeleteVariable(L"MokSB", &shim_lock_guid);
708
709 if (MokSBSize != sizeof(MokSBvar)) {
710 Print(L"Invalid MokSB variable contents\n");
711 return -1;
712 }
713
714 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
715
716 while (correct < 3) {
717 RandomBytes (&pos, sizeof(pos));
718
719 pos = pos % var->PWLen;
720
721 Print(L"Enter password character %d: ", pos + 1);
722 get_line(&length, password, 1, 0);
723
724 if (password[0] != var->Password[pos]) {
725 Print(L"Invalid character\n");
726 fail_count++;
727 } else {
728 correct++;
729 }
730
731 if (fail_count >= 3)
732 break;
733 }
734
735 if (fail_count >= 3) {
736 Print(L"Password limit reached\n");
737 return -1;
738 }
739
740 if (var->MokSBState == 0) {
741 Print(L"Disable Secure Boot? (y/n): ");
742 } else {
743 Print(L"Enable Secure Boot? (y/n): ");
744 }
745
746 do {
747 get_line (&length, line, 1, 1);
748
749 if (line[0] == 'Y' || line[0] == 'y') {
750 if (var->MokSBState == 0) {
751 efi_status = uefi_call_wrapper(RT->SetVariable,
752 5, L"MokSBState",
753 &shim_lock_guid,
754 EFI_VARIABLE_NON_VOLATILE |
755 EFI_VARIABLE_BOOTSERVICE_ACCESS,
756 1, &sbval);
757 if (efi_status != EFI_SUCCESS) {
758 Print(L"Failed to set Secure Boot state\n");
759 return -1;
760 }
761 } else {
762 LibDeleteVariable(L"MokSBState",
763 &shim_lock_guid);
764 }
765
766 Print(L"Press a key to reboot system\n");
767 Pause();
768 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
769 EFI_SUCCESS, 0, NULL);
770 Print(L"Failed to reboot\n");
771 return -1;
772 }
773 } while (line[0] != 'N' && line[0] != 'n');
774
775 return -1;
776 }
777
778
779 static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
780 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
781 EFI_STATUS efi_status;
782 UINTN MokPWSize = (UINTN)data2;
783 UINT8 fail_count = 0;
784 UINT8 hash[SHA256_DIGEST_SIZE];
785 CHAR16 password[PASSWORD_MAX];
786 UINT32 length;
787 CHAR16 line[1];
788
789 if (MokPWSize != SHA256_DIGEST_SIZE) {
790 Print(L"Invalid MokPW variable contents\n");
791 return -1;
792 }
793
794 LibDeleteVariable(L"MokPW", &shim_lock_guid);
795
796 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
797
798 while (fail_count < 3) {
799 Print(L"Confirm MOK passphrase: ");
800 get_line(&length, password, PASSWORD_MAX, 0);
801
802 if ((length < PASSWORD_MIN) || (length > PASSWORD_MAX)) {
803 Print(L"Invalid password length\n");
804 fail_count++;
805 continue;
806 }
807
808 efi_status = compute_pw_hash(NULL, 0, password, length, hash);
809
810 if (efi_status != EFI_SUCCESS) {
811 Print(L"Unable to generate password hash\n");
812 fail_count++;
813 continue;
814 }
815
816 if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) != 0) {
817 Print(L"Password doesn't match\n");
818 fail_count++;
819 continue;
820 }
821
822 break;
823 }
824
825 if (fail_count >= 3) {
826 Print(L"Password limit reached\n");
827 return -1;
828 }
829
830 Print(L"Set MOK password? (y/n): ");
831
832 do {
833 get_line (&length, line, 1, 1);
834
835 if (line[0] == 'Y' || line[0] == 'y') {
836 efi_status = uefi_call_wrapper(RT->SetVariable, 5,
837 L"MokPWStore",
838 &shim_lock_guid,
839 EFI_VARIABLE_NON_VOLATILE |
840 EFI_VARIABLE_BOOTSERVICE_ACCESS,
841 MokPWSize, MokPW);
842 if (efi_status != EFI_SUCCESS) {
843 Print(L"Failed to set MOK password\n");
844 return -1;
845 }
846
847 Print(L"Press a key to reboot system\n");
848 Pause();
849 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
850 EFI_SUCCESS, 0, NULL);
851 Print(L"Failed to reboot\n");
852 return -1;
853 }
854 } while (line[0] != 'N' && line[0] != 'n');
855
856 return 0;
857 }
858
859 static UINTN draw_menu (CHAR16 *header, UINTN lines, struct menu_item *items,
860 UINTN count) {
861 UINTN i;
862
863 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
864
865 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
866 EFI_WHITE | EFI_BACKGROUND_BLACK);
867
868 Print(L"%s UEFI key management\n\n", SHIM_VENDOR);
869
870 if (header)
871 Print(L"%s", header);
872
873 for (i = 0; i < count; i++) {
874 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
875 items[i].colour | EFI_BACKGROUND_BLACK);
876 Print(L" %s\n", items[i].text);
877 }
878
879 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0);
880 uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
881
882 return 2 + lines;
883 }
884
885 static void free_menu (struct menu_item *items, UINTN count) {
886 UINTN i;
887
888 for (i=0; i<count; i++) {
889 if (items[i].text)
890 FreePool(items[i].text);
891 }
892
893 FreePool(items);
894 }
895
896 static void update_time (UINTN position, UINTN timeout)
897 {
898 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0,
899 position);
900
901 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
902 EFI_BLACK | EFI_BACKGROUND_BLACK);
903
904 Print(L" ", timeout);
905
906 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0,
907 position);
908
909 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
910 EFI_WHITE | EFI_BACKGROUND_BLACK);
911
912 if (timeout > 1)
913 Print(L"Booting in %d seconds\n", timeout);
914 else if (timeout)
915 Print(L"Booting in %d second\n", timeout);
916 }
917
918 static void run_menu (CHAR16 *header, UINTN lines, struct menu_item *items,
919 UINTN count, UINTN timeout) {
920 UINTN index, pos = 0, wait = 0, offset;
921 EFI_INPUT_KEY key;
922 EFI_STATUS status;
923 INTN ret;
924
925 if (timeout)
926 wait = 10000000;
927
928 offset = draw_menu (header, lines, items, count);
929
930 while (1) {
931 update_time(count + offset + 1, timeout);
932
933 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut,
934 0, pos + offset);
935 status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait);
936
937 if (status == EFI_TIMEOUT) {
938 timeout--;
939 if (!timeout) {
940 free_menu(items, count);
941 return;
942 }
943 continue;
944 }
945
946 wait = 0;
947 timeout = 0;
948
949 uefi_call_wrapper(BS->WaitForEvent, 3, 1,
950 &ST->ConIn->WaitForKey, &index);
951 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
952 &key);
953
954 switch(key.ScanCode) {
955 case SCAN_UP:
956 if (pos == 0)
957 continue;
958 pos--;
959 continue;
960 break;
961 case SCAN_DOWN:
962 if (pos == (count - 1))
963 continue;
964 pos++;
965 continue;
966 break;
967 }
968
969 switch(key.UnicodeChar) {
970 case CHAR_LINEFEED:
971 case CHAR_CARRIAGE_RETURN:
972 if (items[pos].callback == NULL) {
973 free_menu(items, count);
974 return;
975 }
976
977 ret = items[pos].callback(items[pos].data,
978 items[pos].data2,
979 items[pos].data3);
980 if (ret < 0) {
981 Print(L"Press a key to continue\n");
982 Pause();
983 }
984 draw_menu (header, lines, items, count);
985 pos = 0;
986 break;
987 }
988 }
989 }
990
991 static UINTN verify_certificate(void *cert, UINTN size)
992 {
993 X509 *X509Cert;
994 if (!cert || size == 0)
995 return FALSE;
996
997 if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) ||
998 X509Cert == NULL) {
999 Print(L"Invalid X509 certificate\n");
1000 Pause();
1001 return FALSE;
1002 }
1003
1004 X509_free(X509Cert);
1005 return TRUE;
1006 }
1007
1008 static INTN file_callback (void *data, void *data2, void *data3) {
1009 EFI_FILE_INFO *buffer = NULL;
1010 UINTN buffersize = 0, mokbuffersize;
1011 EFI_STATUS status;
1012 EFI_FILE *file;
1013 CHAR16 *filename = data;
1014 EFI_FILE *parent = data2;
1015 BOOLEAN hash = !!data3;
1016 EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
1017 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1018 EFI_SIGNATURE_LIST *CertList;
1019 EFI_SIGNATURE_DATA *CertData;
1020 void *mokbuffer = NULL;
1021
1022 status = uefi_call_wrapper(parent->Open, 5, parent, &file, filename,
1023 EFI_FILE_MODE_READ, 0);
1024
1025 if (status != EFI_SUCCESS)
1026 return 1;
1027
1028 status = uefi_call_wrapper(file->GetInfo, 4, file, &file_info_guid,
1029 &buffersize, buffer);
1030
1031 if (status == EFI_BUFFER_TOO_SMALL) {
1032 buffer = AllocatePool(buffersize);
1033 status = uefi_call_wrapper(file->GetInfo, 4, file,
1034 &file_info_guid, &buffersize,
1035 buffer);
1036 }
1037
1038 if (!buffer)
1039 return 0;
1040
1041 buffersize = buffer->FileSize;
1042
1043 if (hash) {
1044 void *binary;
1045 UINT8 sha256[SHA256_DIGEST_SIZE];
1046 UINT8 sha1[SHA1_DIGEST_SIZE];
1047 SHIM_LOCK *shim_lock;
1048 EFI_GUID shim_guid = SHIM_LOCK_GUID;
1049 PE_COFF_LOADER_IMAGE_CONTEXT context;
1050
1051 status = LibLocateProtocol(&shim_guid, (VOID **)&shim_lock);
1052
1053 if (status != EFI_SUCCESS)
1054 goto out;
1055
1056 mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) +
1057 SHA256_DIGEST_SIZE;
1058
1059 mokbuffer = AllocatePool(mokbuffersize);
1060
1061 if (!mokbuffer)
1062 goto out;
1063
1064 binary = AllocatePool(buffersize);
1065
1066 status = uefi_call_wrapper(file->Read, 3, file, &buffersize,
1067 binary);
1068
1069 if (status != EFI_SUCCESS)
1070 goto out;
1071
1072 status = shim_lock->Context(binary, buffersize, &context);
1073
1074 if (status != EFI_SUCCESS)
1075 goto out;
1076
1077 status = shim_lock->Hash(binary, buffersize, &context, sha256,
1078 sha1);
1079
1080 if (status != EFI_SUCCESS)
1081 goto out;
1082
1083 CertList = mokbuffer;
1084 CertList->SignatureType = EfiHashSha256Guid;
1085 CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE;
1086 CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
1087 sizeof(EFI_SIGNATURE_LIST));
1088 CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
1089 } else {
1090 mokbuffersize = buffersize + sizeof(EFI_SIGNATURE_LIST) +
1091 sizeof(EFI_GUID);
1092 mokbuffer = AllocatePool(mokbuffersize);
1093
1094 if (!mokbuffer)
1095 goto out;
1096
1097 CertList = mokbuffer;
1098 CertList->SignatureType = EfiCertX509Guid;
1099 CertList->SignatureSize = 16 + buffersize;
1100 status = uefi_call_wrapper(file->Read, 3, file, &buffersize,
1101 mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16);
1102
1103 if (status != EFI_SUCCESS)
1104 goto out;
1105 CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
1106 sizeof(EFI_SIGNATURE_LIST));
1107 }
1108
1109 CertList->SignatureListSize = mokbuffersize;
1110 CertList->SignatureHeaderSize = 0;
1111 CertData->SignatureOwner = shim_lock_guid;
1112
1113 if (!hash) {
1114 if (!verify_certificate(CertData->SignatureData, buffersize))
1115 goto out;
1116 }
1117
1118 mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE);
1119 out:
1120 if (buffer)
1121 FreePool(buffer);
1122
1123 if (mokbuffer)
1124 FreePool(mokbuffer);
1125
1126 return 0;
1127 }
1128
1129 static INTN directory_callback (void *data, void *data2, void *data3) {
1130 EFI_FILE_INFO *buffer = NULL;
1131 UINTN buffersize = 0;
1132 EFI_STATUS status;
1133 UINTN dircount = 0, i = 0;
1134 struct menu_item *dircontent;
1135 EFI_FILE *dir;
1136 CHAR16 *filename = data;
1137 EFI_FILE *root = data2;
1138 BOOLEAN hash = !!data3;
1139
1140 status = uefi_call_wrapper(root->Open, 5, root, &dir, filename,
1141 EFI_FILE_MODE_READ, 0);
1142
1143 if (status != EFI_SUCCESS)
1144 return 1;
1145
1146 while (1) {
1147 status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize,
1148 buffer);
1149
1150 if (status == EFI_BUFFER_TOO_SMALL) {
1151 buffer = AllocatePool(buffersize);
1152 status = uefi_call_wrapper(dir->Read, 3, dir,
1153 &buffersize, buffer);
1154 }
1155
1156 if (status != EFI_SUCCESS)
1157 return 1;
1158
1159 if (!buffersize)
1160 break;
1161
1162 if ((StrCmp(buffer->FileName, L".") == 0) ||
1163 (StrCmp(buffer->FileName, L"..") == 0))
1164 continue;
1165
1166 dircount++;
1167
1168 FreePool(buffer);
1169 buffersize = 0;
1170 }
1171
1172 dircount++;
1173
1174 dircontent = AllocatePool(sizeof(struct menu_item) * dircount);
1175
1176 dircontent[0].text = StrDuplicate(L"..");
1177 dircontent[0].callback = NULL;
1178 dircontent[0].colour = EFI_YELLOW;
1179 i++;
1180
1181 uefi_call_wrapper(dir->SetPosition, 2, dir, 0);
1182
1183 while (1) {
1184 status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize,
1185 buffer);
1186
1187 if (status == EFI_BUFFER_TOO_SMALL) {
1188 buffer = AllocatePool(buffersize);
1189 status = uefi_call_wrapper(dir->Read, 3, dir,
1190 &buffersize, buffer);
1191 }
1192
1193 if (status != EFI_SUCCESS)
1194 return 1;
1195
1196 if (!buffersize)
1197 break;
1198
1199 if ((StrCmp(buffer->FileName, L".") == 0) ||
1200 (StrCmp(buffer->FileName, L"..") == 0))
1201 continue;
1202
1203 if (buffer->Attribute & EFI_FILE_DIRECTORY) {
1204 dircontent[i].text = StrDuplicate(buffer->FileName);
1205 dircontent[i].callback = directory_callback;
1206 dircontent[i].data = dircontent[i].text;
1207 dircontent[i].data2 = dir;
1208 dircontent[i].data3 = data3;
1209 dircontent[i].colour = EFI_YELLOW;
1210 } else {
1211 dircontent[i].text = StrDuplicate(buffer->FileName);
1212 dircontent[i].callback = file_callback;
1213 dircontent[i].data = dircontent[i].text;
1214 dircontent[i].data2 = dir;
1215 dircontent[i].data3 = data3;
1216 dircontent[i].colour = EFI_WHITE;
1217 }
1218
1219 i++;
1220 FreePool(buffer);
1221 buffersize = 0;
1222 buffer = NULL;
1223 }
1224
1225 if (hash)
1226 run_menu(HASH_STRING, 2, dircontent, dircount, 0);
1227 else
1228 run_menu(CERT_STRING, 2, dircontent, dircount, 0);
1229
1230 return 0;
1231 }
1232
1233 static INTN filesystem_callback (void *data, void *data2, void *data3) {
1234 EFI_FILE_INFO *buffer = NULL;
1235 UINTN buffersize = 0;
1236 EFI_STATUS status;
1237 UINTN dircount = 0, i = 0;
1238 struct menu_item *dircontent;
1239 EFI_FILE *root = data;
1240 BOOLEAN hash = !!data3;
1241
1242 uefi_call_wrapper(root->SetPosition, 2, root, 0);
1243
1244 while (1) {
1245 status = uefi_call_wrapper(root->Read, 3, root, &buffersize,
1246 buffer);
1247
1248 if (status == EFI_BUFFER_TOO_SMALL) {
1249 buffer = AllocatePool(buffersize);
1250 status = uefi_call_wrapper(root->Read, 3, root,
1251 &buffersize, buffer);
1252 }
1253
1254 if (status != EFI_SUCCESS)
1255 return 1;
1256
1257 if (!buffersize)
1258 break;
1259
1260 if ((StrCmp(buffer->FileName, L".") == 0) ||
1261 (StrCmp(buffer->FileName, L"..") == 0))
1262 continue;
1263
1264 dircount++;
1265
1266 FreePool(buffer);
1267 buffersize = 0;
1268 }
1269
1270 dircount++;
1271
1272 dircontent = AllocatePool(sizeof(struct menu_item) * dircount);
1273
1274 dircontent[0].text = StrDuplicate(L"Return to filesystem list");
1275 dircontent[0].callback = NULL;
1276 dircontent[0].colour = EFI_YELLOW;
1277 i++;
1278
1279 uefi_call_wrapper(root->SetPosition, 2, root, 0);
1280
1281 while (1) {
1282 status = uefi_call_wrapper(root->Read, 3, root, &buffersize,
1283 buffer);
1284
1285 if (status == EFI_BUFFER_TOO_SMALL) {
1286 buffer = AllocatePool(buffersize);
1287 status = uefi_call_wrapper(root->Read, 3, root,
1288 &buffersize, buffer);
1289 }
1290
1291 if (status != EFI_SUCCESS)
1292 return 1;
1293
1294 if (!buffersize)
1295 break;
1296
1297 if ((StrCmp(buffer->FileName, L".") == 0) ||
1298 (StrCmp(buffer->FileName, L"..") == 0))
1299 continue;
1300
1301 if (buffer->Attribute & EFI_FILE_DIRECTORY) {
1302 dircontent[i].text = StrDuplicate(buffer->FileName);
1303 dircontent[i].callback = directory_callback;
1304 dircontent[i].data = dircontent[i].text;
1305 dircontent[i].data2 = root;
1306 dircontent[i].data3 = data3;
1307 dircontent[i].colour = EFI_YELLOW;
1308 } else {
1309 dircontent[i].text = StrDuplicate(buffer->FileName);
1310 dircontent[i].callback = file_callback;
1311 dircontent[i].data = dircontent[i].text;
1312 dircontent[i].data2 = root;
1313 dircontent[i].data3 = data3;
1314 dircontent[i].colour = EFI_WHITE;
1315 }
1316
1317 i++;
1318 FreePool(buffer);
1319 buffer = NULL;
1320 buffersize = 0;
1321 }
1322
1323 if (hash)
1324 run_menu(HASH_STRING, 2, dircontent, dircount, 0);
1325 else
1326 run_menu(CERT_STRING, 2, dircontent, dircount, 0);
1327
1328 return 0;
1329 }
1330
1331 static INTN find_fs (void *data, void *data2, void *data3) {
1332 EFI_GUID fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL;
1333 UINTN count, i;
1334 UINTN OldSize, NewSize;
1335 EFI_HANDLE **filesystem_handles;
1336 struct menu_item *filesystems;
1337 BOOLEAN hash = !!data3;
1338
1339 uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &fs_guid,
1340 NULL, &count, &filesystem_handles);
1341
1342 if (!count || !filesystem_handles) {
1343 Print(L"No filesystems?\n");
1344 return 1;
1345 }
1346
1347 count++;
1348
1349 filesystems = AllocatePool(sizeof(struct menu_item) * count);
1350
1351 filesystems[0].text = StrDuplicate(L"Exit");
1352 filesystems[0].callback = NULL;
1353 filesystems[0].colour = EFI_YELLOW;
1354
1355 for (i=1; i<count; i++) {
1356 EFI_HANDLE *fs = filesystem_handles[i-1];
1357 EFI_FILE_IO_INTERFACE *fs_interface;
1358 EFI_DEVICE_PATH *path;
1359 EFI_FILE *root;
1360 EFI_STATUS status;
1361 CHAR16 *VolumeLabel = NULL;
1362 EFI_FILE_SYSTEM_INFO *buffer = NULL;
1363 UINTN buffersize = 0;
1364 EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
1365
1366 status = uefi_call_wrapper(BS->HandleProtocol, 3, fs, &fs_guid,
1367 &fs_interface);
1368
1369 if (status != EFI_SUCCESS || !fs_interface)
1370 continue;
1371
1372 path = DevicePathFromHandle(fs);
1373
1374 status = uefi_call_wrapper(fs_interface->OpenVolume, 2,
1375 fs_interface, &root);
1376
1377 if (status != EFI_SUCCESS || !root)
1378 continue;
1379
1380 status = uefi_call_wrapper(root->GetInfo, 4, root,
1381 &file_info_guid, &buffersize,
1382 buffer);
1383
1384 if (status == EFI_BUFFER_TOO_SMALL) {
1385 buffer = AllocatePool(buffersize);
1386 status = uefi_call_wrapper(root->GetInfo, 4, root,
1387 &file_info_guid,
1388 &buffersize, buffer);
1389 }
1390
1391 if (status == EFI_SUCCESS)
1392 VolumeLabel = buffer->VolumeLabel;
1393
1394 if (path)
1395 filesystems[i].text = DevicePathToStr(path);
1396 else
1397 filesystems[i].text = StrDuplicate(L"Unknown device\n");
1398 if (VolumeLabel) {
1399 OldSize = (StrLen(filesystems[i].text) + 1) * sizeof(CHAR16);
1400 NewSize = OldSize + StrLen(VolumeLabel) * sizeof(CHAR16);
1401 filesystems[i].text = ReallocatePool(filesystems[i].text,
1402 OldSize, NewSize);
1403 StrCat(filesystems[i].text, VolumeLabel);
1404 }
1405
1406 if (buffersize)
1407 FreePool(buffer);
1408
1409 filesystems[i].data = root;
1410 filesystems[i].data2 = NULL;
1411 filesystems[i].data3 = data3;
1412 filesystems[i].callback = filesystem_callback;
1413 filesystems[i].colour = EFI_YELLOW;
1414 }
1415
1416 uefi_call_wrapper(BS->FreePool, 1, filesystem_handles);
1417
1418 if (hash)
1419 run_menu(HASH_STRING, 2, filesystems, count, 0);
1420 else
1421 run_menu(CERT_STRING, 2, filesystems, count, 0);
1422
1423 return 0;
1424 }
1425
1426 static BOOLEAN verify_pw(void)
1427 {
1428 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1429 EFI_STATUS efi_status;
1430 CHAR16 password[PASSWORD_MAX];
1431 UINT8 fail_count = 0;
1432 UINT8 hash[SHA256_DIGEST_SIZE];
1433 UINT8 pwhash[SHA256_DIGEST_SIZE];
1434 UINTN size = SHA256_DIGEST_SIZE;
1435 UINT32 length;
1436 UINT32 attributes;
1437
1438 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore",
1439 &shim_lock_guid, &attributes, &size,
1440 pwhash);
1441
1442 /*
1443 * If anything can attack the password it could just set it to a
1444 * known value, so there's no safety advantage in failing to validate
1445 * purely because of a failure to read the variable
1446 */
1447 if (efi_status != EFI_SUCCESS)
1448 return TRUE;
1449
1450 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
1451 return TRUE;
1452
1453 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1454
1455 while (fail_count < 3) {
1456 Print(L"Enter MOK password: ");
1457 get_line(&length, password, PASSWORD_MAX, 0);
1458
1459 if (length < PASSWORD_MIN || length > PASSWORD_MAX) {
1460 Print(L"Invalid password length\n");
1461 fail_count++;
1462 continue;
1463 }
1464
1465 efi_status = compute_pw_hash(NULL, 0, password, length, hash);
1466
1467 if (efi_status != EFI_SUCCESS) {
1468 Print(L"Unable to generate password hash\n");
1469 fail_count++;
1470 continue;
1471 }
1472
1473 if (CompareMem(pwhash, hash, SHA256_DIGEST_SIZE) != 0) {
1474 Print(L"Password doesn't match\n");
1475 fail_count++;
1476 continue;
1477 }
1478
1479 return TRUE;
1480 }
1481
1482 Print(L"Password limit reached\n");
1483 return FALSE;
1484 }
1485
1486 static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
1487 UINTN MokNewSize, void *MokSB,
1488 UINTN MokSBSize, void *MokPW, UINTN MokPWSize)
1489 {
1490 struct menu_item *menu_item;
1491 UINT32 MokAuth = 0;
1492 UINTN menucount = 3, i = 0;
1493 EFI_STATUS efi_status;
1494 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1495 UINT8 auth[SHA256_DIGEST_SIZE];
1496 UINTN auth_size = SHA256_DIGEST_SIZE;
1497 UINT32 attributes;
1498
1499 if (verify_pw() == FALSE)
1500 return EFI_ACCESS_DENIED;
1501
1502 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
1503 &shim_lock_guid,
1504 &attributes, &auth_size, auth);
1505
1506 if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE))
1507 MokAuth = 1;
1508
1509 if (MokNew || MokAuth)
1510 menucount++;
1511
1512 if (MokSB)
1513 menucount++;
1514
1515 if (MokPW)
1516 menucount++;
1517
1518 menu_item = AllocateZeroPool(sizeof(struct menu_item) * menucount);
1519
1520 if (!menu_item)
1521 return EFI_OUT_OF_RESOURCES;
1522
1523 menu_item[i].text = StrDuplicate(L"Continue boot");
1524 menu_item[i].colour = EFI_WHITE;
1525 menu_item[i].callback = NULL;
1526
1527 i++;
1528
1529 if (MokNew || MokAuth) {
1530 if (!MokNew) {
1531 menu_item[i].text = StrDuplicate(L"Delete MOK");
1532 menu_item[i].colour = EFI_WHITE;
1533 menu_item[i].callback = mok_deletion_prompt;
1534 } else {
1535 menu_item[i].text = StrDuplicate(L"Enroll MOK");
1536 menu_item[i].colour = EFI_WHITE;
1537 menu_item[i].data = MokNew;
1538 menu_item[i].data2 = (void *)MokNewSize;
1539 menu_item[i].callback = mok_enrollment_prompt_callback;
1540 }
1541 i++;
1542 }
1543
1544 if (MokSB) {
1545 menu_item[i].text = StrDuplicate(L"Change Secure Boot state");
1546 menu_item[i].colour = EFI_WHITE;
1547 menu_item[i].callback = mok_sb_prompt;
1548 menu_item[i].data = MokSB;
1549 menu_item[i].data2 = (void *)MokSBSize;
1550 i++;
1551 }
1552
1553 if (MokPW) {
1554 menu_item[i].text = StrDuplicate(L"Set MOK password");
1555 menu_item[i].colour = EFI_WHITE;
1556 menu_item[i].callback = mok_pw_prompt;
1557 menu_item[i].data = MokPW;
1558 menu_item[i].data2 = (void *)MokPWSize;
1559 i++;
1560 }
1561
1562 menu_item[i].text = StrDuplicate(L"Enroll key from disk");
1563 menu_item[i].colour = EFI_WHITE;
1564 menu_item[i].callback = find_fs;
1565 menu_item[i].data3 = (void *)FALSE;
1566
1567 i++;
1568
1569 menu_item[i].text = StrDuplicate(L"Enroll hash from disk");
1570 menu_item[i].colour = EFI_WHITE;
1571 menu_item[i].callback = find_fs;
1572 menu_item[i].data3 = (void *)TRUE;
1573
1574 i++;
1575
1576 run_menu(NULL, 0, menu_item, menucount, 10);
1577
1578 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1579
1580 return 0;
1581 }
1582
1583 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1584 {
1585 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1586 UINTN MokNewSize = 0, MokSBSize = 0, MokPWSize = 0;
1587 void *MokNew = NULL;
1588 void *MokSB = NULL;
1589 void *MokPW = NULL;
1590
1591 MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize);
1592
1593 MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize);
1594
1595 MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize);
1596
1597 enter_mok_menu(image_handle, MokNew, MokNewSize, MokSB, MokSBSize,
1598 MokPW, MokPWSize);
1599
1600 if (MokNew) {
1601 if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
1602 Print(L"Failed to delete MokNew\n");
1603 }
1604 FreePool (MokNew);
1605 }
1606
1607 if (MokSB) {
1608 if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) {
1609 Print(L"Failed to delete MokSB\n");
1610 }
1611 FreePool (MokNew);
1612 }
1613
1614 if (MokPW) {
1615 if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) {
1616 Print(L"Failed to delete MokPW\n");
1617 }
1618 FreePool (MokNew);
1619 }
1620
1621 LibDeleteVariable(L"MokAuth", &shim_lock_guid);
1622
1623 return EFI_SUCCESS;
1624 }
1625
1626 static EFI_STATUS setup_rand (void)
1627 {
1628 EFI_TIME time;
1629 EFI_STATUS efi_status;
1630 UINT64 seed;
1631 BOOLEAN status;
1632
1633 efi_status = uefi_call_wrapper(RT->GetTime, 2, &time, NULL);
1634
1635 if (efi_status != EFI_SUCCESS)
1636 return efi_status;
1637
1638 seed = ((UINT64)time.Year << 48) | ((UINT64)time.Month << 40) |
1639 ((UINT64)time.Day << 32) | ((UINT64)time.Hour << 24) |
1640 ((UINT64)time.Minute << 16) | ((UINT64)time.Second << 8) |
1641 ((UINT64)time.Daylight);
1642
1643 status = RandomSeed((UINT8 *)&seed, sizeof(seed));
1644
1645 if (!status)
1646 return EFI_ABORTED;
1647
1648 return EFI_SUCCESS;
1649 }
1650
1651 EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
1652 {
1653 EFI_STATUS efi_status;
1654
1655 InitializeLib(image_handle, systab);
1656
1657 setup_rand();
1658
1659 efi_status = check_mok_request(image_handle);
1660
1661 return efi_status;
1662 }