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