]> git.proxmox.com Git - efi-boot-shim.git/blob - MokManager.c
Make verbose stuff use console_notify
[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 "console_control.h"
6 #include "shim.h"
7 #include "PeImage.h"
8 #include "PasswordCrypt.h"
9
10 #include "guid.h"
11 #include "console.h"
12 #include "variables.h"
13 #include "simple_file.h"
14 #include "efiauthenticated.h"
15
16 #define PASSWORD_MAX 256
17 #define PASSWORD_MIN 1
18 #define SB_PASSWORD_LEN 16
19
20 #define NAME_LINE_MAX 70
21
22 #ifndef SHIM_VENDOR
23 #define SHIM_VENDOR L"Shim"
24 #endif
25
26 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
27
28 EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
29
30 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
31 #define HASH_STRING L"Select a file to trust:\n\n"
32
33 struct menu_item {
34 CHAR16 *text;
35 INTN (* callback)(void *data, void *data2, void *data3);
36 void *data;
37 void *data2;
38 void *data3;
39 UINTN colour;
40 };
41
42 typedef struct {
43 UINT32 MokSize;
44 UINT8 *Mok;
45 EFI_GUID Type;
46 } __attribute__ ((packed)) MokListNode;
47
48 typedef struct {
49 UINT32 MokSBState;
50 UINT32 PWLen;
51 CHAR16 Password[SB_PASSWORD_LEN];
52 } __attribute__ ((packed)) MokSBvar;
53
54 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 console_notify(L"Unable to allocate memory for hash context");
65 return EFI_OUT_OF_RESOURCES;
66 }
67
68 if (!Sha1Init(ctx)) {
69 console_notify(L"Unable to initialise hash");
70 status = EFI_OUT_OF_RESOURCES;
71 goto done;
72 }
73
74 if (!(Sha1Update(ctx, Data, DataSize))) {
75 console_notify(L"Unable to generate hash");
76 status = EFI_OUT_OF_RESOURCES;
77 goto done;
78 }
79
80 if (!(Sha1Final(ctx, hash))) {
81 console_notify(L"Unable to finalise hash");
82 status = EFI_OUT_OF_RESOURCES;
83 goto done;
84 }
85
86 status = EFI_SUCCESS;
87 done:
88 return status;
89 }
90
91 static UINT32 count_keys(void *Data, UINTN DataSize)
92 {
93 EFI_SIGNATURE_LIST *CertList = Data;
94 EFI_GUID CertType = X509_GUID;
95 EFI_GUID HashType = EFI_CERT_SHA256_GUID;
96 UINTN dbsize = DataSize;
97 UINT32 MokNum = 0;
98
99 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
100 if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
101 (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
102 console_notify(L"Doesn't look like a key or hash");
103 dbsize -= CertList->SignatureListSize;
104 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
105 CertList->SignatureListSize);
106 continue;
107 }
108
109 if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
110 (CertList->SignatureSize != 48)) {
111 console_notify(L"Doesn't look like a valid hash");
112 dbsize -= CertList->SignatureListSize;
113 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
114 CertList->SignatureListSize);
115 continue;
116 }
117
118 MokNum++;
119 dbsize -= CertList->SignatureListSize;
120 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
121 CertList->SignatureListSize);
122 }
123
124 return MokNum;
125 }
126
127 static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
128 MokListNode *list;
129 EFI_SIGNATURE_LIST *CertList = Data;
130 EFI_SIGNATURE_DATA *Cert;
131 EFI_GUID CertType = X509_GUID;
132 EFI_GUID HashType = EFI_CERT_SHA256_GUID;
133 UINTN dbsize = DataSize;
134 UINTN count = 0;
135
136 list = AllocatePool(sizeof(MokListNode) * num);
137
138 if (!list) {
139 console_notify(L"Unable to allocate MOK list");
140 return NULL;
141 }
142
143 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
144 if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
145 (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
146 dbsize -= CertList->SignatureListSize;
147 CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
148 CertList->SignatureListSize);
149 continue;
150 }
151
152 if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) &&
153 (CertList->SignatureSize != 48)) {
154 dbsize -= CertList->SignatureListSize;
155 CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
156 CertList->SignatureListSize);
157 continue;
158 }
159
160 Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
161 sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
162
163 list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID);
164 list[count].Mok = (void *)Cert->SignatureData;
165 list[count].Type = CertList->SignatureType;
166
167 count++;
168 dbsize -= CertList->SignatureListSize;
169 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
170 CertList->SignatureListSize);
171 }
172
173 return list;
174 }
175
176 typedef struct {
177 int nid;
178 CHAR16 *name;
179 } NidName;
180
181 static NidName nidname[] = {
182 {NID_commonName, L"CN"},
183 {NID_organizationName, L"O"},
184 {NID_countryName, L"C"},
185 {NID_stateOrProvinceName, L"ST"},
186 {NID_localityName, L"L"},
187 {-1, NULL}
188 };
189
190 static CHAR16* get_x509_name (X509_NAME *X509Name)
191 {
192 CHAR16 name[NAME_LINE_MAX+1];
193 CHAR16 part[NAME_LINE_MAX+1];
194 char str[NAME_LINE_MAX];
195 int i, len, rest, first;
196
197 name[0] = '\0';
198 rest = NAME_LINE_MAX;
199 first = 1;
200 for (i = 0; nidname[i].name != NULL; i++) {
201 int add;
202 len = X509_NAME_get_text_by_NID (X509Name, nidname[i].nid,
203 str, NAME_LINE_MAX);
204 if (len <= 0)
205 continue;
206
207 if (first)
208 add = len + (int)StrLen(nidname[i].name) + 1;
209 else
210 add = len + (int)StrLen(nidname[i].name) + 3;
211
212 if (add > rest)
213 continue;
214
215 if (first) {
216 SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L"%s=%a",
217 nidname[i].name, str);
218 } else {
219 SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L", %s=%a",
220 nidname[i].name, str);
221 }
222 StrCat(name, part);
223 rest -= add;
224 first = 0;
225 }
226
227 if (rest >= 0 && rest < NAME_LINE_MAX)
228 return PoolPrint(L"%s", name);
229
230 return NULL;
231 }
232
233 static CHAR16* get_x509_time (ASN1_TIME *time)
234 {
235 BIO *bio = BIO_new (BIO_s_mem());
236 char str[30];
237 int len;
238
239 ASN1_TIME_print (bio, time);
240 len = BIO_read(bio, str, 29);
241 if (len < 0)
242 len = 0;
243 str[len] = '\0';
244 BIO_free (bio);
245
246 return PoolPrint(L"%a", str);
247 }
248
249 static void show_x509_info (X509 *X509Cert, UINT8 *hash)
250 {
251 ASN1_INTEGER *serial;
252 BIGNUM *bnser;
253 unsigned char hexbuf[30];
254 X509_NAME *X509Name;
255 ASN1_TIME *time;
256 CHAR16 *issuer = NULL;
257 CHAR16 *subject = NULL;
258 CHAR16 *from = NULL;
259 CHAR16 *until = NULL;
260 POOL_PRINT hash_string1;
261 POOL_PRINT hash_string2;
262 POOL_PRINT serial_string;
263 int fields = 0;
264 CHAR16 **text;
265 int i = 0;
266
267 ZeroMem(&hash_string1, sizeof(hash_string1));
268 ZeroMem(&hash_string2, sizeof(hash_string2));
269 ZeroMem(&serial_string, sizeof(serial_string));
270
271 serial = X509_get_serialNumber(X509Cert);
272 if (serial) {
273 int i, n;
274 bnser = ASN1_INTEGER_to_BN(serial, NULL);
275 n = BN_bn2bin(bnser, hexbuf);
276 for (i = 0; i < n; i++) {
277 CatPrint(&serial_string, L"%02x:", hexbuf[i]);
278 }
279 }
280
281 if (serial_string.str)
282 fields++;
283
284 X509Name = X509_get_issuer_name(X509Cert);
285 if (X509Name) {
286 issuer = get_x509_name(X509Name);
287 if (issuer)
288 fields++;
289 }
290
291 X509Name = X509_get_subject_name(X509Cert);
292 if (X509Name) {
293 subject = get_x509_name(X509Name);
294 if (subject)
295 fields++;
296 }
297
298 time = X509_get_notBefore(X509Cert);
299 if (time) {
300 from = get_x509_time(time);
301 if (from)
302 fields++;
303 }
304
305 time = X509_get_notAfter(X509Cert);
306 if (time) {
307 until = get_x509_time(time);
308 if (until)
309 fields++;
310 }
311
312 for (i=0; i<10; i++)
313 CatPrint(&hash_string1, L"%02x ", hash[i]);
314 for (i=10; i<20; i++)
315 CatPrint(&hash_string2, L"%02x ", hash[i]);
316
317 if (hash_string1.str)
318 fields++;
319
320 if (hash_string2.str)
321 fields++;
322
323 if (!fields)
324 return;
325
326 i = 0;
327 text = AllocateZeroPool(sizeof(CHAR16 *) * (fields*3 + 1));
328 if (serial_string.str) {
329 text[i++] = StrDuplicate(L"[Serial Number]");
330 text[i++] = serial_string.str;
331 text[i++] = StrDuplicate(L"");
332 }
333 if (issuer) {
334 text[i++] = StrDuplicate(L"[Issuer]");
335 text[i++] = issuer;
336 text[i++] = StrDuplicate(L"");
337 }
338 if (subject) {
339 text[i++] = StrDuplicate(L"[Subject]");
340 text[i++] = subject;
341 text[i++] = StrDuplicate(L"");
342 }
343 if (from) {
344 text[i++] = StrDuplicate(L"[Valid Not Before]");
345 text[i++] = from;
346 text[i++] = StrDuplicate(L"");
347 }
348 if (until) {
349 text[i++] = StrDuplicate(L"[Valid Not After]");
350 text[i++] = until;
351 text[i++] = StrDuplicate(L"");
352 }
353 if (hash_string1.str) {
354 text[i++] = StrDuplicate(L"[Fingerprint]");
355 text[i++] = hash_string1.str;
356 }
357 if (hash_string2.str) {
358 text[i++] = hash_string2.str;
359 text[i++] = StrDuplicate(L"");
360 }
361 text[i] = NULL;
362
363 console_print_box(text, -1);
364
365 for (i=0; text[i] != NULL; i++)
366 FreePool(text[i]);
367
368 FreePool(text);
369 }
370
371 static void show_efi_hash (UINT8 *hash)
372 {
373 CHAR16 *text[5];
374 POOL_PRINT hash_string1;
375 POOL_PRINT hash_string2;
376 int i;
377
378 ZeroMem(&hash_string1, sizeof(hash_string1));
379 ZeroMem(&hash_string2, sizeof(hash_string2));
380
381 text[0] = L"SHA256 hash";
382 text[1] = L"";
383
384 for (i=0; i<16; i++)
385 CatPrint(&hash_string1, L"%02x ", hash[i]);
386 for (i=16; i<32; i++)
387 CatPrint(&hash_string2, L"%02x ", hash[i]);
388
389 text[2] = hash_string1.str;
390 text[3] = hash_string2.str;
391 text[4] = NULL;
392
393 console_print_box(text, -1);
394
395 if (hash_string1.str)
396 FreePool(hash_string1.str);
397
398 if (hash_string2.str)
399 FreePool(hash_string2.str);
400 }
401
402 static void show_mok_info (void *Mok, UINTN MokSize)
403 {
404 EFI_STATUS efi_status;
405 UINT8 hash[SHA1_DIGEST_SIZE];
406 X509 *X509Cert;
407
408 if (!Mok || MokSize == 0)
409 return;
410
411 if (MokSize != SHA256_DIGEST_SIZE) {
412 efi_status = get_sha1sum(Mok, MokSize, hash);
413
414 if (efi_status != EFI_SUCCESS) {
415 console_notify(L"Failed to compute MOK fingerprint");
416 return;
417 }
418
419 if (X509ConstructCertificate(Mok, MokSize,
420 (UINT8 **) &X509Cert) && X509Cert != NULL) {
421 show_x509_info(X509Cert, hash);
422 X509_free(X509Cert);
423 } else {
424 console_notify(L"Not a valid X509 certificate");
425 return;
426 }
427 } else {
428 show_efi_hash(Mok);
429 }
430 }
431
432 static EFI_STATUS list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title)
433 {
434 UINT32 MokNum = 0;
435 MokListNode *keys = NULL;
436 INTN key_num = 0;
437 CHAR16 **menu_strings;
438 int i;
439
440 if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
441 sizeof(EFI_SIGNATURE_DATA))) {
442 console_notify(L"No MOK keys found");
443 return 0;
444 }
445
446 MokNum = count_keys(KeyList, KeyListSize);
447 keys = build_mok_list(MokNum, KeyList, KeyListSize);
448
449 if (!keys) {
450 console_notify(L"Failed to construct key list");
451 return 0;
452 }
453
454 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (MokNum + 2));
455
456 if (!menu_strings)
457 return EFI_OUT_OF_RESOURCES;
458
459 for (i=0; i<MokNum; i++) {
460 menu_strings[i] = PoolPrint(L"View key %d", i);
461 }
462 menu_strings[i] = StrDuplicate(L"Continue");
463
464 menu_strings[i+1] = NULL;
465
466 while (key_num < MokNum) {
467 key_num = console_select((CHAR16 *[]){ title, NULL },
468 menu_strings, 0);
469
470 if (key_num < 0)
471 break;
472 else if (key_num < MokNum)
473 show_mok_info(keys[key_num].Mok, keys[key_num].MokSize);
474 }
475
476 for (i=0; menu_strings[i] != NULL; i++)
477 FreePool(menu_strings[i]);
478
479 FreePool(menu_strings);
480
481 FreePool(keys);
482
483 return EFI_SUCCESS;
484 }
485
486 static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show)
487 {
488 EFI_INPUT_KEY key;
489 int count = 0;
490
491 do {
492 key = console_get_keystroke();
493
494 if ((count >= line_max &&
495 key.UnicodeChar != CHAR_BACKSPACE) ||
496 key.UnicodeChar == CHAR_NULL ||
497 key.UnicodeChar == CHAR_TAB ||
498 key.UnicodeChar == CHAR_LINEFEED ||
499 key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
500 continue;
501 }
502
503 if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
504 continue;
505 } else if (key.UnicodeChar == CHAR_BACKSPACE) {
506 if (show) {
507 Print(L"\b");
508 }
509 line[--count] = '\0';
510 continue;
511 }
512
513 if (show) {
514 Print(L"%c", key.UnicodeChar);
515 }
516
517 line[count++] = key.UnicodeChar;
518 } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
519 Print(L"\n");
520
521 *length = count;
522
523 return 1;
524 }
525
526 static EFI_STATUS compute_pw_hash (void *Data, UINTN DataSize, UINT8 *password,
527 UINT32 pw_length, UINT8 *hash)
528 {
529 EFI_STATUS status;
530 unsigned int ctxsize;
531 void *ctx = NULL;
532
533 ctxsize = Sha256GetContextSize();
534 ctx = AllocatePool(ctxsize);
535
536 if (!ctx) {
537 console_notify(L"Unable to allocate memory for hash context");
538 return EFI_OUT_OF_RESOURCES;
539 }
540
541 if (!Sha256Init(ctx)) {
542 console_notify(L"Unable to initialise hash");
543 status = EFI_OUT_OF_RESOURCES;
544 goto done;
545 }
546
547 if (Data && DataSize) {
548 if (!(Sha256Update(ctx, Data, DataSize))) {
549 console_notify(L"Unable to generate hash");
550 status = EFI_OUT_OF_RESOURCES;
551 goto done;
552 }
553 }
554
555 if (!(Sha256Update(ctx, password, pw_length))) {
556 console_notify(L"Unable to generate hash");
557 status = EFI_OUT_OF_RESOURCES;
558 goto done;
559 }
560
561 if (!(Sha256Final(ctx, hash))) {
562 console_notify(L"Unable to finalise hash");
563 status = EFI_OUT_OF_RESOURCES;
564 goto done;
565 }
566
567 status = EFI_SUCCESS;
568 done:
569 return status;
570 }
571
572 static void console_save_and_set_mode (SIMPLE_TEXT_OUTPUT_MODE *SavedMode)
573 {
574 if (!SavedMode) {
575 Print(L"Invalid parameter: SavedMode\n");
576 return;
577 }
578
579 CopyMem(SavedMode, ST->ConOut->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
580 uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
581 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
582 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
583 }
584
585 static void console_restore_mode (SIMPLE_TEXT_OUTPUT_MODE *SavedMode)
586 {
587 uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut,
588 SavedMode->CursorVisible);
589 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut,
590 SavedMode->CursorColumn, SavedMode->CursorRow);
591 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
592 SavedMode->Attribute);
593 }
594
595 static UINT32 get_password (CHAR16 *prompt, CHAR16 *password, UINT32 max)
596 {
597 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
598 CHAR16 *str;
599 CHAR16 *message[2];
600 UINTN length;
601 UINT32 pw_length;
602
603 if (!prompt)
604 prompt = L"Password:";
605
606 console_save_and_set_mode(&SavedMode);
607
608 str = PoolPrint(L"%s ", prompt);
609 if (!str) {
610 console_errorbox(L"Failed to allocate prompt");
611 return 0;
612 }
613
614 message[0] = str;
615 message[1] = NULL;
616 length = StrLen(message[0]);
617 console_print_box_at(message, -1, -length-4, -5, length+4, 3, 0, 1);
618 get_line(&pw_length, password, max, 0);
619
620 console_restore_mode(&SavedMode);
621
622 FreePool(str);
623
624 return pw_length;
625 }
626
627 static EFI_STATUS match_password (PASSWORD_CRYPT *pw_crypt,
628 void *Data, UINTN DataSize,
629 UINT8 *auth, CHAR16 *prompt)
630 {
631 EFI_STATUS status;
632 UINT8 hash[128];
633 UINT8 *auth_hash;
634 UINT32 auth_size;
635 CHAR16 password[PASSWORD_MAX];
636 UINT32 pw_length;
637 UINT8 fail_count = 0;
638 int i;
639
640 if (pw_crypt) {
641 auth_hash = pw_crypt->hash;
642 auth_size = get_hash_size (pw_crypt->method);
643 if (auth_size == 0)
644 return EFI_INVALID_PARAMETER;
645 } else if (auth) {
646 auth_hash = auth;
647 auth_size = SHA256_DIGEST_SIZE;
648 } else {
649 return EFI_INVALID_PARAMETER;
650 }
651
652 while (fail_count < 3) {
653 pw_length = get_password(prompt, password, PASSWORD_MAX);
654
655 if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) {
656 console_errorbox(L"Invalid password length");
657 fail_count++;
658 continue;
659 }
660
661 /*
662 * Compute password hash
663 */
664 if (pw_crypt) {
665 char pw_ascii[PASSWORD_MAX + 1];
666 for (i = 0; i < pw_length; i++)
667 pw_ascii[i] = (char)password[i];
668 pw_ascii[pw_length] = '\0';
669
670 status = password_crypt(pw_ascii, pw_length, pw_crypt, hash);
671 } else {
672 /*
673 * For backward compatibility
674 */
675 status = compute_pw_hash(Data, DataSize, (UINT8 *)password,
676 pw_length * sizeof(CHAR16), hash);
677 }
678 if (status != EFI_SUCCESS) {
679 console_errorbox(L"Unable to generate password hash");
680 fail_count++;
681 continue;
682 }
683
684 if (CompareMem(auth_hash, hash, auth_size) != 0) {
685 console_errorbox(L"Password doesn't match");
686 fail_count++;
687 continue;
688 }
689
690 break;
691 }
692
693 if (fail_count >= 3)
694 return EFI_ACCESS_DENIED;
695
696 return EFI_SUCCESS;
697 }
698
699 static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
700 {
701 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
702 EFI_STATUS efi_status;
703 UINT8 auth[PASSWORD_CRYPT_SIZE];
704 UINTN auth_size = PASSWORD_CRYPT_SIZE;
705 UINT32 attributes;
706
707 if (authenticate) {
708 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
709 &shim_lock_guid,
710 &attributes, &auth_size, auth);
711
712 if (efi_status != EFI_SUCCESS ||
713 (auth_size != SHA256_DIGEST_SIZE &&
714 auth_size != PASSWORD_CRYPT_SIZE)) {
715 console_error(L"Failed to get MokAuth", efi_status);
716 return efi_status;
717 }
718
719 if (auth_size == PASSWORD_CRYPT_SIZE) {
720 efi_status = match_password((PASSWORD_CRYPT *)auth,
721 NULL, 0, NULL, NULL);
722 } else {
723 efi_status = match_password(NULL, MokNew, MokNewSize,
724 auth, NULL);
725 }
726 if (efi_status != EFI_SUCCESS)
727 return EFI_ACCESS_DENIED;
728 }
729
730 if (!MokNewSize) {
731 /* Delete MOK */
732 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
733 &shim_lock_guid,
734 EFI_VARIABLE_NON_VOLATILE
735 | EFI_VARIABLE_BOOTSERVICE_ACCESS,
736 0, NULL);
737 } else {
738 /* Write new MOK */
739 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
740 &shim_lock_guid,
741 EFI_VARIABLE_NON_VOLATILE
742 | EFI_VARIABLE_BOOTSERVICE_ACCESS
743 | EFI_VARIABLE_APPEND_WRITE,
744 MokNewSize, MokNew);
745 }
746
747 if (efi_status != EFI_SUCCESS) {
748 console_error(L"Failed to set variable", efi_status);
749 return efi_status;
750 }
751
752 return EFI_SUCCESS;
753 }
754
755 static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
756 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
757 EFI_STATUS efi_status;
758
759 if (list_keys(MokNew, MokNewSize, L"[Enroll MOK]") != EFI_SUCCESS)
760 return 0;
761
762 if (console_yes_no((CHAR16 *[]){L"Enroll the key(s)?", NULL}) == 0)
763 return 0;
764
765 efi_status = store_keys(MokNew, MokNewSize, auth);
766
767 if (efi_status != EFI_SUCCESS) {
768 console_notify(L"Failed to enroll keys\n");
769 return -1;
770 }
771
772 if (auth) {
773 LibDeleteVariable(L"MokNew", &shim_lock_guid);
774 LibDeleteVariable(L"MokAuth", &shim_lock_guid);
775
776 console_notify(L"The system must now be rebooted");
777 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
778 EFI_SUCCESS, 0, NULL);
779 console_notify(L"Failed to reboot");
780 return -1;
781 }
782
783 return 0;
784 }
785
786 static INTN mok_reset_prompt ()
787 {
788 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
789 EFI_STATUS efi_status;
790
791 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
792
793 if (console_yes_no((CHAR16 *[]){L"Erase all stored keys?", NULL }) == 0)
794 return 0;
795
796 efi_status = store_keys(NULL, 0, TRUE);
797
798 if (efi_status != EFI_SUCCESS) {
799 console_notify(L"Failed to erase keys\n");
800 return -1;
801 }
802
803 LibDeleteVariable(L"MokNew", &shim_lock_guid);
804 LibDeleteVariable(L"MokAuth", &shim_lock_guid);
805
806 console_notify(L"The system must now be rebooted");
807 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
808 EFI_SUCCESS, 0, NULL);
809 console_notify(L"Failed to reboot\n");
810 return -1;
811 }
812
813 static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num)
814 {
815 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
816 EFI_STATUS efi_status;
817 EFI_SIGNATURE_LIST *CertList;
818 EFI_SIGNATURE_DATA *CertData;
819 void *Data = NULL, *ptr;
820 INTN DataSize = 0;
821 int i;
822
823 for (i = 0; i < key_num; i++) {
824 if (list[i].Mok == NULL)
825 continue;
826
827 DataSize += sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
828 DataSize += list[i].MokSize;
829 }
830
831 Data = AllocatePool(DataSize);
832 if (Data == NULL && DataSize != 0)
833 return EFI_OUT_OF_RESOURCES;
834
835 ptr = Data;
836
837 for (i = 0; i < key_num; i++) {
838 if (list[i].Mok == NULL)
839 continue;
840
841 CertList = (EFI_SIGNATURE_LIST *)ptr;
842 CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) +
843 sizeof(EFI_SIGNATURE_LIST));
844
845 CertList->SignatureType = list[i].Type;
846 CertList->SignatureListSize = list[i].MokSize +
847 sizeof(EFI_SIGNATURE_LIST) +
848 sizeof(EFI_SIGNATURE_DATA) - 1;
849 CertList->SignatureHeaderSize = 0;
850 CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID);
851
852 CertData->SignatureOwner = shim_lock_guid;
853 CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize);
854
855 ptr = (uint8_t *)ptr + sizeof(EFI_SIGNATURE_LIST) +
856 sizeof(EFI_GUID) + list[i].MokSize;
857 }
858
859 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
860 &shim_lock_guid,
861 EFI_VARIABLE_NON_VOLATILE
862 | EFI_VARIABLE_BOOTSERVICE_ACCESS,
863 DataSize, Data);
864 if (Data)
865 FreePool(Data);
866
867 if (efi_status != EFI_SUCCESS) {
868 console_error(L"Failed to set variable", efi_status);
869 return efi_status;
870 }
871
872 return EFI_SUCCESS;
873 }
874
875 static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
876 {
877 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
878 EFI_STATUS efi_status;
879 UINT8 auth[PASSWORD_CRYPT_SIZE];
880 UINTN auth_size = PASSWORD_CRYPT_SIZE;
881 UINT32 attributes;
882 UINT8 *MokListData = NULL;
883 UINTN MokListDataSize = 0;
884 MokListNode *mok, *del_key;
885 INTN mok_num, del_num;
886 int i, j;
887
888 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
889 &shim_lock_guid,
890 &attributes, &auth_size, auth);
891
892 if (efi_status != EFI_SUCCESS ||
893 (auth_size != SHA256_DIGEST_SIZE && auth_size != PASSWORD_CRYPT_SIZE)) {
894 console_error(L"Failed to get MokDelAuth", efi_status);
895 return efi_status;
896 }
897
898 if (auth_size == PASSWORD_CRYPT_SIZE) {
899 efi_status = match_password((PASSWORD_CRYPT *)auth, NULL, 0,
900 NULL, NULL);
901 } else {
902 efi_status = match_password(NULL, MokDel, MokDelSize, auth, NULL);
903 }
904 if (efi_status != EFI_SUCCESS)
905 return EFI_ACCESS_DENIED;
906
907 efi_status = get_variable_attr (L"MokList", &MokListData, &MokListDataSize,
908 shim_lock_guid, &attributes);
909 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
910 console_alertbox((CHAR16 *[]){L"MokList is compromised!",
911 L"Erase all keys in MokList!",
912 NULL});
913 if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
914 console_notify(L"Failed to erase MokList");
915 }
916 return EFI_ACCESS_DENIED;
917 }
918
919 /* Nothing to do */
920 if (!MokListData || MokListDataSize == 0)
921 return EFI_SUCCESS;
922
923 /* Construct lists */
924 mok_num = count_keys(MokListData, MokListDataSize);
925 mok = build_mok_list(mok_num, MokListData, MokListDataSize);
926 del_num = count_keys(MokDel, MokDelSize);
927 del_key = build_mok_list(del_num, MokDel, MokDelSize);
928
929 /* Search and destroy */
930 for (i = 0; i < del_num; i++) {
931 UINT32 key_size = del_key[i].MokSize;
932 void *key = del_key[i].Mok;
933 for (j = 0; j < mok_num; j++) {
934 if (mok[j].MokSize == key_size &&
935 CompareMem(key, mok[j].Mok, key_size) == 0) {
936 /* Remove the key */
937 mok[j].Mok = NULL;
938 mok[j].MokSize = 0;
939 }
940 }
941 }
942
943 efi_status = write_back_mok_list(mok, mok_num);
944
945 if (MokListData)
946 FreePool(MokListData);
947 if (mok)
948 FreePool(mok);
949 if (del_key)
950 FreePool(del_key);
951
952 return efi_status;
953 }
954
955 static INTN mok_deletion_prompt (void *MokDel, UINTN MokDelSize)
956 {
957 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
958 EFI_STATUS efi_status;
959
960 if (list_keys(MokDel, MokDelSize, L"[Delete MOK]") != EFI_SUCCESS) {
961 return 0;
962 }
963
964 if (console_yes_no((CHAR16 *[]){L"Delete the key(s)?", NULL}) == 0)
965 return 0;
966
967 efi_status = delete_keys(MokDel, MokDelSize);
968
969 if (efi_status != EFI_SUCCESS) {
970 console_notify(L"Failed to delete keys");
971 return -1;
972 }
973
974 LibDeleteVariable(L"MokDel", &shim_lock_guid);
975 LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
976
977 console_notify(L"The system must now be rebooted");
978 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
979 EFI_SUCCESS, 0, NULL);
980 console_notify(L"Failed to reboot");
981 return -1;
982 }
983
984 static CHAR16 get_password_charater (CHAR16 *prompt)
985 {
986 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
987 CHAR16 *message[2];
988 CHAR16 character;
989 UINTN length;
990 UINT32 pw_length;
991
992 if (!prompt)
993 prompt = L"Password charater: ";
994
995 console_save_and_set_mode(&SavedMode);
996
997 message[0] = prompt;
998 message[1] = NULL;
999 length = StrLen(message[0]);
1000 console_print_box_at(message, -1, -length-4, -5, length+4, 3, 0, 1);
1001 get_line(&pw_length, &character, 1, 0);
1002
1003 console_restore_mode(&SavedMode);
1004
1005 return character;
1006 }
1007
1008 static INTN mok_sb_prompt (void *MokSB, UINTN MokSBSize) {
1009 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1010 EFI_STATUS efi_status;
1011 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1012 MokSBvar *var = MokSB;
1013 CHAR16 *message[4];
1014 CHAR16 pass1, pass2, pass3;
1015 CHAR16 *str;
1016 UINT8 fail_count = 0;
1017 UINT8 sbval = 1;
1018 UINT8 pos1, pos2, pos3;
1019 int ret;
1020
1021 if (MokSBSize != sizeof(MokSBvar)) {
1022 console_notify(L"Invalid MokSB variable contents");
1023 return -1;
1024 }
1025
1026 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1027
1028 message[0] = L"Change Secure Boot state";
1029 message[1] = NULL;
1030
1031 console_save_and_set_mode(&SavedMode);
1032 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1033 console_restore_mode(&SavedMode);
1034
1035 while (fail_count < 3) {
1036 RandomBytes (&pos1, sizeof(pos1));
1037 pos1 = (pos1 % var->PWLen);
1038
1039 do {
1040 RandomBytes (&pos2, sizeof(pos2));
1041 pos2 = (pos2 % var->PWLen);
1042 } while (pos2 == pos1);
1043
1044 do {
1045 RandomBytes (&pos3, sizeof(pos3));
1046 pos3 = (pos3 % var->PWLen) ;
1047 } while (pos3 == pos2 || pos3 == pos1);
1048
1049 str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1050 if (!str) {
1051 console_errorbox(L"Failed to allocate buffer");
1052 return -1;
1053 }
1054 pass1 = get_password_charater(str);
1055 FreePool(str);
1056
1057 str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1058 if (!str) {
1059 console_errorbox(L"Failed to allocate buffer");
1060 return -1;
1061 }
1062 pass2 = get_password_charater(str);
1063 FreePool(str);
1064
1065 str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1066 if (!str) {
1067 console_errorbox(L"Failed to allocate buffer");
1068 return -1;
1069 }
1070 pass3 = get_password_charater(str);
1071 FreePool(str);
1072
1073 if (pass1 != var->Password[pos1] ||
1074 pass2 != var->Password[pos2] ||
1075 pass3 != var->Password[pos3]) {
1076 Print(L"Invalid character\n");
1077 fail_count++;
1078 } else {
1079 break;
1080 }
1081 }
1082
1083 if (fail_count >= 3) {
1084 console_notify(L"Password limit reached");
1085 return -1;
1086 }
1087
1088 if (var->MokSBState == 0)
1089 ret = console_yes_no((CHAR16 *[]){L"Disable Secure Boot", NULL});
1090 else
1091 ret = console_yes_no((CHAR16 *[]){L"Enable Secure Boot", NULL});
1092
1093 if (ret == 0) {
1094 LibDeleteVariable(L"MokSB", &shim_lock_guid);
1095 return -1;
1096 }
1097
1098 if (var->MokSBState == 0) {
1099 efi_status = uefi_call_wrapper(RT->SetVariable,
1100 5, L"MokSBState",
1101 &shim_lock_guid,
1102 EFI_VARIABLE_NON_VOLATILE |
1103 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1104 1, &sbval);
1105 if (efi_status != EFI_SUCCESS) {
1106 console_notify(L"Failed to set Secure Boot state");
1107 return -1;
1108 }
1109 } else {
1110 LibDeleteVariable(L"MokSBState", &shim_lock_guid);
1111 }
1112
1113 console_notify(L"The system must now be rebooted");
1114 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
1115 EFI_SUCCESS, 0, NULL);
1116 console_notify(L"Failed to reboot");
1117 return -1;
1118 }
1119
1120 static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) {
1121 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1122 EFI_STATUS efi_status;
1123 UINT8 hash[PASSWORD_CRYPT_SIZE];
1124 UINT8 clear = 0;
1125
1126 if (MokPWSize != SHA256_DIGEST_SIZE && MokPWSize != PASSWORD_CRYPT_SIZE) {
1127 console_notify(L"Invalid MokPW variable contents");
1128 return -1;
1129 }
1130
1131 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1132
1133 SetMem(hash, PASSWORD_CRYPT_SIZE, 0);
1134
1135 if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1136 if (CompareMem(MokPW, hash, PASSWORD_CRYPT_SIZE) == 0)
1137 clear = 1;
1138 } else {
1139 if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0)
1140 clear = 1;
1141 }
1142
1143 if (clear) {
1144 if (console_yes_no((CHAR16 *[]){L"Clear MOK password?", NULL}) == 0)
1145 return 0;
1146
1147 LibDeleteVariable(L"MokPWStore", &shim_lock_guid);
1148 LibDeleteVariable(L"MokPW", &shim_lock_guid);
1149 console_notify(L"The system must now be rebooted");
1150 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0,
1151 NULL);
1152 console_notify(L"Failed to reboot");
1153 return -1;
1154 }
1155
1156 if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1157 efi_status = match_password((PASSWORD_CRYPT *)MokPW, NULL, 0,
1158 NULL, L"Confirm MOK passphrase: ");
1159 } else {
1160 efi_status = match_password(NULL, NULL, 0, MokPW,
1161 L"Confirm MOK passphrase: ");
1162 }
1163
1164 if (efi_status != EFI_SUCCESS) {
1165 console_notify(L"Password limit reached");
1166 return -1;
1167 }
1168
1169 if (console_yes_no((CHAR16 *[]){L"Set MOK password?", NULL}) == 0)
1170 return 0;
1171
1172 efi_status = uefi_call_wrapper(RT->SetVariable, 5,
1173 L"MokPWStore",
1174 &shim_lock_guid,
1175 EFI_VARIABLE_NON_VOLATILE |
1176 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1177 MokPWSize, MokPW);
1178 if (efi_status != EFI_SUCCESS) {
1179 console_notify(L"Failed to set MOK password");
1180 return -1;
1181 }
1182
1183 LibDeleteVariable(L"MokPW", &shim_lock_guid);
1184
1185 console_notify(L"The system must now be rebooted");
1186 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0,
1187 NULL);
1188 console_notify(L"Failed to reboot");
1189 return -1;
1190 }
1191
1192 static BOOLEAN verify_certificate(void *cert, UINTN size)
1193 {
1194 X509 *X509Cert;
1195 if (!cert || size == 0)
1196 return FALSE;
1197
1198 if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) ||
1199 X509Cert == NULL) {
1200 console_notify(L"Invalid X509 certificate");
1201 return FALSE;
1202 }
1203
1204 X509_free(X509Cert);
1205 return TRUE;
1206 }
1207
1208 static EFI_STATUS enroll_file (void *data, UINTN datasize, BOOLEAN hash)
1209 {
1210 EFI_STATUS status = EFI_SUCCESS;
1211 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1212 EFI_SIGNATURE_LIST *CertList;
1213 EFI_SIGNATURE_DATA *CertData;
1214 UINTN mokbuffersize;
1215 void *mokbuffer = NULL;
1216
1217 if (hash) {
1218 UINT8 sha256[SHA256_DIGEST_SIZE];
1219 UINT8 sha1[SHA1_DIGEST_SIZE];
1220 SHIM_LOCK *shim_lock;
1221 EFI_GUID shim_guid = SHIM_LOCK_GUID;
1222 PE_COFF_LOADER_IMAGE_CONTEXT context;
1223
1224 status = LibLocateProtocol(&shim_guid, (VOID **)&shim_lock);
1225
1226 if (status != EFI_SUCCESS)
1227 goto out;
1228
1229 mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) +
1230 SHA256_DIGEST_SIZE;
1231
1232 mokbuffer = AllocatePool(mokbuffersize);
1233
1234 if (!mokbuffer)
1235 goto out;
1236
1237 status = shim_lock->Context(data, datasize, &context);
1238
1239 if (status != EFI_SUCCESS)
1240 goto out;
1241
1242 status = shim_lock->Hash(data, datasize, &context, sha256,
1243 sha1);
1244
1245 if (status != EFI_SUCCESS)
1246 goto out;
1247
1248 CertList = mokbuffer;
1249 CertList->SignatureType = EFI_CERT_SHA256_GUID;
1250 CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE;
1251 CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
1252 sizeof(EFI_SIGNATURE_LIST));
1253 CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
1254 } else {
1255 mokbuffersize = datasize + sizeof(EFI_SIGNATURE_LIST) +
1256 sizeof(EFI_GUID);
1257 mokbuffer = AllocatePool(mokbuffersize);
1258
1259 if (!mokbuffer)
1260 goto out;
1261
1262 CertList = mokbuffer;
1263 CertList->SignatureType = X509_GUID;
1264 CertList->SignatureSize = 16 + datasize;
1265
1266 memcpy(mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16, data,
1267 datasize);
1268
1269 CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
1270 sizeof(EFI_SIGNATURE_LIST));
1271 }
1272
1273 CertList->SignatureListSize = mokbuffersize;
1274 CertList->SignatureHeaderSize = 0;
1275 CertData->SignatureOwner = shim_lock_guid;
1276
1277 if (!hash) {
1278 if (!verify_certificate(CertData->SignatureData, datasize))
1279 goto out;
1280 }
1281
1282 mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE);
1283 out:
1284 if (mokbuffer)
1285 FreePool(mokbuffer);
1286
1287 return status;
1288 }
1289
1290 static void mok_hash_enroll(void)
1291 {
1292 EFI_STATUS efi_status;
1293 CHAR16 *file_name = NULL;
1294 EFI_HANDLE im = NULL;
1295 EFI_FILE *file = NULL;
1296 UINTN filesize;
1297 void *data;
1298
1299 simple_file_selector(&im, (CHAR16 *[]){
1300 L"Select Binary",
1301 L"",
1302 L"The Selected Binary will have its hash Enrolled",
1303 L"This means it will Subsequently Boot with no prompting",
1304 L"Remember to make sure it is a genuine binary before Enroling its hash",
1305 NULL
1306 }, L"\\", L"", &file_name);
1307
1308 if (!file_name)
1309 return;
1310
1311 efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1312
1313 if (efi_status != EFI_SUCCESS) {
1314 console_error(L"Unable to open file", efi_status);
1315 return;
1316 }
1317
1318 simple_file_read_all(file, &filesize, &data);
1319 simple_file_close(file);
1320
1321 if (!filesize) {
1322 console_error(L"Unable to read file", efi_status);
1323 return;
1324 }
1325
1326 efi_status = enroll_file(data, filesize, TRUE);
1327
1328 if (efi_status != EFI_SUCCESS)
1329 console_error(L"Hash failed (did you select a valid EFI binary?)", efi_status);
1330
1331 FreePool(data);
1332 }
1333
1334 static CHAR16 *der_suffix[] = {
1335 L".cer",
1336 L".der",
1337 L".crt",
1338 NULL
1339 };
1340
1341 static BOOLEAN check_der_suffix (CHAR16 *file_name)
1342 {
1343 CHAR16 suffix[5];
1344 int i;
1345
1346 if (!file_name || StrLen(file_name) <= 4)
1347 return FALSE;
1348
1349 suffix[0] = '\0';
1350 StrCat(suffix, file_name + StrLen(file_name) - 4);
1351
1352 StrLwr (suffix);
1353 for (i = 0; der_suffix[i] != NULL; i++) {
1354 if (StrCmp(suffix, der_suffix[i]) == 0) {
1355 return TRUE;
1356 }
1357 }
1358
1359 return FALSE;
1360 }
1361
1362 static void mok_key_enroll(void)
1363 {
1364 EFI_STATUS efi_status;
1365 CHAR16 *file_name = NULL;
1366 EFI_HANDLE im = NULL;
1367 EFI_FILE *file = NULL;
1368 UINTN filesize;
1369 void *data;
1370
1371 simple_file_selector(&im, (CHAR16 *[]){
1372 L"Select Key",
1373 L"",
1374 L"The selected key will be enrolled into the MOK database",
1375 L"This means any binaries signed with it will be run without prompting",
1376 L"Remember to make sure it is a genuine key before Enroling it",
1377 NULL
1378 }, L"\\", L"", &file_name);
1379
1380 if (!file_name)
1381 return;
1382
1383 if (!check_der_suffix(file_name)) {
1384 console_alertbox((CHAR16 *[]){
1385 L"Unsupported Format",
1386 L"",
1387 L"Only DER encoded certificate (*.cer/der/crt) is supported",
1388 NULL});
1389 return;
1390 }
1391
1392 efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1393
1394 if (efi_status != EFI_SUCCESS) {
1395 console_error(L"Unable to open file", efi_status);
1396 return;
1397 }
1398
1399 simple_file_read_all(file, &filesize, &data);
1400 simple_file_close(file);
1401
1402 if (!filesize) {
1403 console_error(L"Unable to read file", efi_status);
1404 return;
1405 }
1406
1407 enroll_file(data, filesize, FALSE);
1408 FreePool(data);
1409 }
1410
1411 static BOOLEAN verify_pw(BOOLEAN *protected)
1412 {
1413 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1414 EFI_STATUS efi_status;
1415 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1416 UINT8 pwhash[PASSWORD_CRYPT_SIZE];
1417 UINTN size = PASSWORD_CRYPT_SIZE;
1418 UINT32 attributes;
1419 CHAR16 *message[2];
1420
1421 *protected = FALSE;
1422
1423 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore",
1424 &shim_lock_guid, &attributes, &size,
1425 pwhash);
1426
1427 /*
1428 * If anything can attack the password it could just set it to a
1429 * known value, so there's no safety advantage in failing to validate
1430 * purely because of a failure to read the variable
1431 */
1432 if (efi_status != EFI_SUCCESS ||
1433 (size != SHA256_DIGEST_SIZE && size != PASSWORD_CRYPT_SIZE))
1434 return TRUE;
1435
1436 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
1437 return TRUE;
1438
1439 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1440
1441 /* Draw the background */
1442 console_save_and_set_mode(&SavedMode);
1443 message[0] = PoolPrint (L"%s UEFI key management", SHIM_VENDOR);
1444 message[1] = NULL;
1445 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1446 FreePool(message[0]);
1447 console_restore_mode(&SavedMode);
1448
1449 if (size == PASSWORD_CRYPT_SIZE) {
1450 efi_status = match_password((PASSWORD_CRYPT *)pwhash, NULL, 0,
1451 NULL, L"Enter MOK password:");
1452 } else {
1453 efi_status = match_password(NULL, NULL, 0, pwhash,
1454 L"Enter MOK password:");
1455 }
1456 if (efi_status != EFI_SUCCESS) {
1457 console_notify(L"Password limit reached");
1458 return FALSE;
1459 }
1460
1461 *protected = TRUE;
1462
1463 return TRUE;
1464 }
1465
1466 static int draw_countdown()
1467 {
1468 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1469 EFI_INPUT_KEY key;
1470 EFI_STATUS status;
1471 UINTN cols, rows;
1472 CHAR16 *title[2];
1473 CHAR16 *message = L"Press any key to perform MOK management";
1474 int timeout = 10, wait = 10000000;
1475
1476 console_save_and_set_mode (&SavedMode);
1477
1478 title[0] = PoolPrint (L"%s UEFI key management", SHIM_VENDOR);
1479 title[1] = NULL;
1480
1481 console_print_box_at(title, -1, 0, 0, -1, -1, 1, 1);
1482
1483 uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
1484 ST->ConOut->Mode->Mode, &cols, &rows);
1485
1486 PrintAt((cols - StrLen(message))/2, rows/2, message);
1487 while (1) {
1488 if (timeout > 1)
1489 PrintAt(2, rows - 3, L"Booting in %d seconds ", timeout);
1490 else if (timeout)
1491 PrintAt(2, rows - 3, L"Booting in %d second ", timeout);
1492
1493 status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait);
1494
1495 if (status != EFI_TIMEOUT) {
1496 /* Clear the key in the queue */
1497 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
1498 ST->ConIn, &key);
1499 break;
1500 }
1501
1502 timeout--;
1503 if (!timeout)
1504 break;
1505 }
1506
1507 FreePool(title[0]);
1508
1509 console_restore_mode(&SavedMode);
1510
1511 return timeout;
1512 }
1513
1514 typedef enum {
1515 MOK_CONTINUE_BOOT,
1516 MOK_RESET_MOK,
1517 MOK_ENROLL_MOK,
1518 MOK_DELETE_MOK,
1519 MOK_CHANGE_SB,
1520 MOK_SET_PW,
1521 MOK_KEY_ENROLL,
1522 MOK_HASH_ENROLL
1523 } mok_menu_item;
1524
1525 static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
1526 void *MokNew, UINTN MokNewSize,
1527 void *MokDel, UINTN MokDelSize,
1528 void *MokSB, UINTN MokSBSize,
1529 void *MokPW, UINTN MokPWSize)
1530 {
1531 CHAR16 **menu_strings;
1532 mok_menu_item *menu_item;
1533 int choice = 0;
1534 UINT32 MokAuth = 0;
1535 UINT32 MokDelAuth = 0;
1536 UINTN menucount = 3, i = 0;
1537 EFI_STATUS efi_status;
1538 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1539 UINT8 auth[PASSWORD_CRYPT_SIZE];
1540 UINTN auth_size = PASSWORD_CRYPT_SIZE;
1541 UINT32 attributes;
1542 BOOLEAN protected;
1543 EFI_STATUS ret = EFI_SUCCESS;
1544
1545 if (verify_pw(&protected) == FALSE)
1546 return EFI_ACCESS_DENIED;
1547
1548 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
1549 &shim_lock_guid,
1550 &attributes, &auth_size, auth);
1551
1552 if ((efi_status == EFI_SUCCESS) &&
1553 (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
1554 MokAuth = 1;
1555
1556 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
1557 &shim_lock_guid,
1558 &attributes, &auth_size, auth);
1559
1560 if ((efi_status == EFI_SUCCESS) &&
1561 (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
1562 MokDelAuth = 1;
1563
1564 if (MokNew || MokAuth)
1565 menucount++;
1566
1567 if (MokDel || MokDelAuth)
1568 menucount++;
1569
1570 if (MokSB)
1571 menucount++;
1572
1573 if (MokPW)
1574 menucount++;
1575
1576 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1));
1577
1578 if (!menu_strings)
1579 return EFI_OUT_OF_RESOURCES;
1580
1581 menu_item = AllocateZeroPool(sizeof(mok_menu_item) * menucount);
1582
1583 if (!menu_item) {
1584 FreePool(menu_strings);
1585 return EFI_OUT_OF_RESOURCES;
1586 }
1587
1588 menu_strings[i] = L"Continue boot";
1589 menu_item[i] = MOK_CONTINUE_BOOT;
1590
1591 i++;
1592
1593 if (MokNew || MokAuth) {
1594 if (!MokNew) {
1595 menu_strings[i] = L"Reset MOK";
1596 menu_item[i] = MOK_RESET_MOK;
1597 } else {
1598 menu_strings[i] = L"Enroll MOK";
1599 menu_item[i] = MOK_ENROLL_MOK;
1600 }
1601 i++;
1602 }
1603
1604 if (MokDel || MokDelAuth) {
1605 menu_strings[i] = L"Delete MOK";
1606 menu_item[i] = MOK_DELETE_MOK;
1607 i++;
1608 }
1609
1610 if (MokSB) {
1611 menu_strings[i] = L"Change Secure Boot state";
1612 menu_item[i] = MOK_CHANGE_SB;
1613 i++;
1614 }
1615
1616 if (MokPW) {
1617 menu_strings[i] = L"Set MOK password";
1618 menu_item[i] = MOK_SET_PW;
1619 i++;
1620 }
1621
1622 menu_strings[i] = L"Enroll key from disk";
1623 menu_item[i] = MOK_KEY_ENROLL;
1624 i++;
1625
1626 menu_strings[i] = L"Enroll hash from disk";
1627 menu_item[i] = MOK_HASH_ENROLL;
1628 i++;
1629
1630 menu_strings[i] = NULL;
1631
1632 if (protected == FALSE && draw_countdown() == 0)
1633 goto out;
1634
1635 while (choice >= 0) {
1636 choice = console_select((CHAR16 *[]){ L"Perform MOK management", NULL },
1637 menu_strings, 0);
1638
1639 if (choice < 0)
1640 goto out;
1641
1642 switch (menu_item[choice]) {
1643 case MOK_CONTINUE_BOOT:
1644 goto out;
1645 case MOK_RESET_MOK:
1646 mok_reset_prompt();
1647 break;
1648 case MOK_ENROLL_MOK:
1649 mok_enrollment_prompt(MokNew, MokNewSize, TRUE);
1650 break;
1651 case MOK_DELETE_MOK:
1652 mok_deletion_prompt(MokDel, MokDelSize);
1653 break;
1654 case MOK_CHANGE_SB:
1655 mok_sb_prompt(MokSB, MokSBSize);
1656 break;
1657 case MOK_SET_PW:
1658 mok_pw_prompt(MokPW, MokPWSize);
1659 break;
1660 case MOK_KEY_ENROLL:
1661 mok_key_enroll();
1662 break;
1663 case MOK_HASH_ENROLL:
1664 mok_hash_enroll();
1665 break;
1666 }
1667 }
1668
1669 out:
1670 console_reset();
1671
1672 FreePool(menu_strings);
1673
1674 if (menu_item)
1675 FreePool(menu_item);
1676
1677 return ret;
1678 }
1679
1680 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1681 {
1682 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1683 UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
1684 void *MokNew = NULL;
1685 void *MokDel = NULL;
1686 void *MokSB = NULL;
1687 void *MokPW = NULL;
1688 EFI_STATUS status;
1689
1690 status = get_variable(L"MokNew", (UINT8 **)&MokNew, &MokNewSize,
1691 shim_lock_guid);
1692 if (status == EFI_SUCCESS) {
1693 if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
1694 console_notify(L"Failed to delete MokNew");
1695 }
1696 } else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1697 console_error(L"Could not retrieve MokNew", status);
1698 }
1699
1700 status = get_variable(L"MokDel", (UINT8 **)&MokDel, &MokDelSize,
1701 shim_lock_guid);
1702 if (status == EFI_SUCCESS) {
1703 if (LibDeleteVariable(L"MokDel", &shim_lock_guid) != EFI_SUCCESS) {
1704 console_notify(L"Failed to delete MokDel");
1705 }
1706 } else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1707 console_error(L"Could not retrieve MokDel", status);
1708 }
1709
1710 status = get_variable(L"MokSB", (UINT8 **)&MokSB, &MokSBSize,
1711 shim_lock_guid);
1712 if (status == EFI_SUCCESS) {
1713 if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) {
1714 console_notify(L"Failed to delete MokSB");
1715 }
1716 } else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1717 console_error(L"Could not retrieve MokSB", status);
1718 }
1719
1720 status = get_variable(L"MokPW", (UINT8 **)&MokPW, &MokPWSize,
1721 shim_lock_guid);
1722 if (status == EFI_SUCCESS) {
1723 if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) {
1724 console_notify(L"Failed to delete MokPW");
1725 }
1726 } else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1727 console_error(L"Could not retrieve MokPW", status);
1728 }
1729
1730 enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
1731 MokSB, MokSBSize, MokPW, MokPWSize);
1732
1733 if (MokNew)
1734 FreePool (MokNew);
1735
1736 if (MokDel)
1737 FreePool (MokDel);
1738
1739 if (MokSB)
1740 FreePool (MokSB);
1741
1742 if (MokPW)
1743 FreePool (MokPW);
1744
1745 LibDeleteVariable(L"MokAuth", &shim_lock_guid);
1746 LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
1747
1748 return EFI_SUCCESS;
1749 }
1750
1751 static EFI_STATUS setup_rand (void)
1752 {
1753 EFI_TIME time;
1754 EFI_STATUS efi_status;
1755 UINT64 seed;
1756 BOOLEAN status;
1757
1758 efi_status = uefi_call_wrapper(RT->GetTime, 2, &time, NULL);
1759
1760 if (efi_status != EFI_SUCCESS)
1761 return efi_status;
1762
1763 seed = ((UINT64)time.Year << 48) | ((UINT64)time.Month << 40) |
1764 ((UINT64)time.Day << 32) | ((UINT64)time.Hour << 24) |
1765 ((UINT64)time.Minute << 16) | ((UINT64)time.Second << 8) |
1766 ((UINT64)time.Daylight);
1767
1768 status = RandomSeed((UINT8 *)&seed, sizeof(seed));
1769
1770 if (!status)
1771 return EFI_ABORTED;
1772
1773 return EFI_SUCCESS;
1774 }
1775
1776 EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
1777 {
1778 EFI_STATUS efi_status;
1779
1780 InitializeLib(image_handle, systab);
1781
1782 setup_console(1);
1783
1784 setup_rand();
1785
1786 efi_status = check_mok_request(image_handle);
1787
1788 setup_console(0);
1789 return efi_status;
1790 }