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