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