]> git.proxmox.com Git - efi-boot-shim.git/blob - MokManager.c
New upstream version 15+1533136590.3beb971
[efi-boot-shim.git] / MokManager.c
1 #include <efi.h>
2 #include <efilib.h>
3 #include <stdarg.h>
4 #include <Library/BaseCryptLib.h>
5 #include <openssl/x509.h>
6 #include <openssl/x509v3.h>
7 #include <openssl/asn1.h>
8 #include <openssl/bn.h>
9
10 #include "shim.h"
11
12 #define PASSWORD_MAX 256
13 #define PASSWORD_MIN 1
14 #define SB_PASSWORD_LEN 16
15
16 #define NAME_LINE_MAX 70
17
18 #ifndef SHIM_VENDOR
19 #define SHIM_VENDOR L"Shim"
20 #endif
21
22 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
23 #define HASH_STRING L"Select a file to trust:\n\n"
24
25 typedef struct {
26 UINT32 MokSize;
27 UINT8 *Mok;
28 EFI_GUID Type;
29 } __attribute__ ((packed)) MokListNode;
30
31 typedef struct {
32 UINT32 MokSBState;
33 UINT32 PWLen;
34 CHAR16 Password[SB_PASSWORD_LEN];
35 } __attribute__ ((packed)) MokSBvar;
36
37 typedef struct {
38 UINT32 MokDBState;
39 UINT32 PWLen;
40 CHAR16 Password[SB_PASSWORD_LEN];
41 } __attribute__ ((packed)) MokDBvar;
42
43 typedef struct {
44 INT32 Timeout;
45 } __attribute__ ((packed)) MokTimeoutvar;
46
47 static EFI_STATUS get_sha1sum(void *Data, int DataSize, UINT8 * hash)
48 {
49 EFI_STATUS efi_status;
50 unsigned int ctxsize;
51 void *ctx = NULL;
52
53 ctxsize = Sha1GetContextSize();
54 ctx = AllocatePool(ctxsize);
55
56 if (!ctx) {
57 console_notify(L"Unable to allocate memory for hash context");
58 return EFI_OUT_OF_RESOURCES;
59 }
60
61 if (!Sha1Init(ctx)) {
62 console_notify(L"Unable to initialise hash");
63 efi_status = EFI_OUT_OF_RESOURCES;
64 goto done;
65 }
66
67 if (!(Sha1Update(ctx, Data, DataSize))) {
68 console_notify(L"Unable to generate hash");
69 efi_status = EFI_OUT_OF_RESOURCES;
70 goto done;
71 }
72
73 if (!(Sha1Final(ctx, hash))) {
74 console_notify(L"Unable to finalise hash");
75 efi_status = EFI_OUT_OF_RESOURCES;
76 goto done;
77 }
78
79 efi_status = EFI_SUCCESS;
80 done:
81 return efi_status;
82 }
83
84 static BOOLEAN is_sha2_hash(EFI_GUID Type)
85 {
86 if (CompareGuid(&Type, &EFI_CERT_SHA224_GUID) == 0)
87 return TRUE;
88 else if (CompareGuid(&Type, &EFI_CERT_SHA256_GUID) == 0)
89 return TRUE;
90 else if (CompareGuid(&Type, &EFI_CERT_SHA384_GUID) == 0)
91 return TRUE;
92 else if (CompareGuid(&Type, &EFI_CERT_SHA512_GUID) == 0)
93 return TRUE;
94
95 return FALSE;
96 }
97
98 static UINT32 sha_size(EFI_GUID Type)
99 {
100 if (CompareGuid(&Type, &EFI_CERT_SHA1_GUID) == 0)
101 return SHA1_DIGEST_SIZE;
102 else if (CompareGuid(&Type, &EFI_CERT_SHA224_GUID) == 0)
103 return SHA224_DIGEST_LENGTH;
104 else if (CompareGuid(&Type, &EFI_CERT_SHA256_GUID) == 0)
105 return SHA256_DIGEST_SIZE;
106 else if (CompareGuid(&Type, &EFI_CERT_SHA384_GUID) == 0)
107 return SHA384_DIGEST_LENGTH;
108 else if (CompareGuid(&Type, &EFI_CERT_SHA512_GUID) == 0)
109 return SHA512_DIGEST_LENGTH;
110
111 return 0;
112 }
113
114 static BOOLEAN is_valid_siglist(EFI_GUID Type, UINT32 SigSize)
115 {
116 UINT32 hash_sig_size;
117
118 if (CompareGuid (&Type, &X509_GUID) == 0 && SigSize != 0)
119 return TRUE;
120
121 if (!is_sha2_hash(Type))
122 return FALSE;
123
124 hash_sig_size = sha_size(Type) + sizeof(EFI_GUID);
125 if (SigSize != hash_sig_size)
126 return FALSE;
127
128 return TRUE;
129 }
130
131 static UINT32 count_keys(void *Data, UINTN DataSize)
132 {
133 EFI_SIGNATURE_LIST *CertList = Data;
134 UINTN dbsize = DataSize;
135 UINT32 MokNum = 0;
136 void *end = Data + DataSize;
137
138 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
139 /* Use ptr arithmetics to ensure bounded access. Do not allow 0
140 * SignatureListSize that will cause endless loop. */
141 if ((void *)(CertList + 1) > end
142 || CertList->SignatureListSize == 0) {
143 console_notify
144 (L"Invalid MOK detected! Ignoring MOK List.");
145 return 0;
146 }
147
148 if (CertList->SignatureListSize == 0 ||
149 CertList->SignatureListSize <= CertList->SignatureSize) {
150 console_errorbox(L"Corrupted signature list");
151 return 0;
152 }
153
154 if (!is_valid_siglist
155 (CertList->SignatureType, CertList->SignatureSize)) {
156 console_errorbox(L"Invalid signature list found");
157 return 0;
158 }
159
160 MokNum++;
161 dbsize -= CertList->SignatureListSize;
162 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
163 CertList->SignatureListSize);
164 }
165
166 return MokNum;
167 }
168
169 static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize)
170 {
171 MokListNode *list;
172 EFI_SIGNATURE_LIST *CertList = Data;
173 EFI_SIGNATURE_DATA *Cert;
174 UINTN dbsize = DataSize;
175 UINTN count = 0;
176 void *end = Data + DataSize;
177
178 list = AllocatePool(sizeof(MokListNode) * num);
179 if (!list) {
180 console_notify(L"Unable to allocate MOK list");
181 return NULL;
182 }
183
184 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
185 /* CertList out of bounds? */
186 if ((void *)(CertList + 1) > end
187 || CertList->SignatureListSize == 0) {
188 FreePool(list);
189 return NULL;
190 }
191
192 /* Omit the signature check here since we already did it
193 in count_keys() */
194
195 Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
196 sizeof(EFI_SIGNATURE_LIST) +
197 CertList->SignatureHeaderSize);
198 /* Cert out of bounds? */
199 if ((void *)(Cert + 1) > end
200 || CertList->SignatureSize <= sizeof(EFI_GUID)) {
201 FreePool(list);
202 return NULL;
203 }
204
205 list[count].Type = CertList->SignatureType;
206 if (CompareGuid (&CertList->SignatureType, &X509_GUID) == 0) {
207 list[count].MokSize = CertList->SignatureSize -
208 sizeof(EFI_GUID);
209 list[count].Mok = (void *)Cert->SignatureData;
210 } else {
211 list[count].MokSize = CertList->SignatureListSize -
212 sizeof(EFI_SIGNATURE_LIST);
213 list[count].Mok = (void *)Cert;
214 }
215
216 /* MOK out of bounds? */
217 if (list[count].MokSize > (unsigned long)end -
218 (unsigned long)list[count].Mok) {
219 FreePool(list);
220 return NULL;
221 }
222
223 count++;
224 dbsize -= CertList->SignatureListSize;
225 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
226 CertList->SignatureListSize);
227 }
228
229 return list;
230 }
231
232 typedef struct {
233 int nid;
234 CHAR16 *name;
235 } NidName;
236
237 static NidName nidname[] = {
238 {NID_commonName, L"CN"},
239 {NID_organizationName, L"O"},
240 {NID_countryName, L"C"},
241 {NID_stateOrProvinceName, L"ST"},
242 {NID_localityName, L"L"},
243 {-1, NULL}
244 };
245
246 static CHAR16 *get_x509_name(X509_NAME * X509Name)
247 {
248 CHAR16 name[NAME_LINE_MAX + 1];
249 CHAR16 part[NAME_LINE_MAX + 1];
250 char str[NAME_LINE_MAX];
251 int i, len, rest, first;
252
253 name[0] = '\0';
254 rest = NAME_LINE_MAX;
255 first = 1;
256 for (i = 0; nidname[i].name != NULL; i++) {
257 int add;
258 len = X509_NAME_get_text_by_NID(X509Name, nidname[i].nid,
259 str, NAME_LINE_MAX);
260 if (len <= 0)
261 continue;
262
263 if (first)
264 add = len + (int)StrLen(nidname[i].name) + 1;
265 else
266 add = len + (int)StrLen(nidname[i].name) + 3;
267
268 if (add > rest)
269 continue;
270
271 if (first) {
272 SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L"%s=%a",
273 nidname[i].name, str);
274 } else {
275 SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L", %s=%a",
276 nidname[i].name, str);
277 }
278 StrCat(name, part);
279 rest -= add;
280 first = 0;
281 }
282
283 if (rest >= 0 && rest < NAME_LINE_MAX)
284 return PoolPrint(L"%s", name);
285
286 return NULL;
287 }
288
289 static CHAR16 *get_x509_time(ASN1_TIME * time)
290 {
291 BIO *bio = BIO_new(BIO_s_mem());
292 char str[30];
293 int len;
294
295 ASN1_TIME_print(bio, time);
296 len = BIO_read(bio, str, 29);
297 if (len < 0)
298 len = 0;
299 str[len] = '\0';
300 BIO_free(bio);
301
302 return PoolPrint(L"%a", str);
303 }
304
305 static void show_x509_info(X509 * X509Cert, UINT8 * hash)
306 {
307 ASN1_INTEGER *serial;
308 BIGNUM *bnser;
309 unsigned char hexbuf[30];
310 X509_NAME *X509Name;
311 ASN1_TIME *time;
312 CHAR16 *issuer = NULL;
313 CHAR16 *subject = NULL;
314 CHAR16 *from = NULL;
315 CHAR16 *until = NULL;
316 EXTENDED_KEY_USAGE *extusage;
317 POOL_PRINT hash_string1;
318 POOL_PRINT hash_string2;
319 POOL_PRINT serial_string;
320 int fields = 0;
321 CHAR16 **text;
322 int i = 0;
323
324 ZeroMem(&hash_string1, sizeof(hash_string1));
325 ZeroMem(&hash_string2, sizeof(hash_string2));
326 ZeroMem(&serial_string, sizeof(serial_string));
327
328 serial = X509_get_serialNumber(X509Cert);
329 if (serial) {
330 int i, n;
331 bnser = ASN1_INTEGER_to_BN(serial, NULL);
332 n = BN_bn2bin(bnser, hexbuf);
333 for (i = 0; i < n; i++) {
334 CatPrint(&serial_string, L"%02x:", hexbuf[i]);
335 }
336 }
337
338 if (serial_string.str)
339 fields++;
340
341 X509Name = X509_get_issuer_name(X509Cert);
342 if (X509Name) {
343 issuer = get_x509_name(X509Name);
344 if (issuer)
345 fields++;
346 }
347
348 X509Name = X509_get_subject_name(X509Cert);
349 if (X509Name) {
350 subject = get_x509_name(X509Name);
351 if (subject)
352 fields++;
353 }
354
355 time = X509_getm_notBefore(X509Cert);
356 if (time) {
357 from = get_x509_time(time);
358 if (from)
359 fields++;
360 }
361
362 time = X509_getm_notAfter(X509Cert);
363 if (time) {
364 until = get_x509_time(time);
365 if (until)
366 fields++;
367 }
368
369 for (i = 0; i < 10; i++)
370 CatPrint(&hash_string1, L"%02x ", hash[i]);
371 for (i = 10; i < 20; i++)
372 CatPrint(&hash_string2, L"%02x ", hash[i]);
373
374 if (hash_string1.str)
375 fields++;
376
377 if (hash_string2.str)
378 fields++;
379
380 if (!fields)
381 return;
382
383 i = 0;
384
385 extusage = X509_get_ext_d2i(X509Cert, NID_ext_key_usage, NULL, NULL);
386 text = AllocateZeroPool(sizeof(CHAR16 *) *
387 (fields * 3 +
388 sk_ASN1_OBJECT_num(extusage) + 3));
389 if (extusage) {
390 int j = 0;
391
392 text[i++] = StrDuplicate(L"[Extended Key Usage]");
393
394 for (j = 0; j < sk_ASN1_OBJECT_num(extusage); j++) {
395 POOL_PRINT extkeyusage;
396 ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(extusage, j);
397 int buflen = 80;
398 char buf[buflen];
399
400 ZeroMem(&extkeyusage, sizeof(extkeyusage));
401
402 OBJ_obj2txt(buf, buflen, obj, 0);
403 CatPrint(&extkeyusage, L"OID: %a", buf);
404 text[i++] = StrDuplicate(extkeyusage.str);
405 FreePool(extkeyusage.str);
406 }
407 text[i++] = StrDuplicate(L"");
408 EXTENDED_KEY_USAGE_free(extusage);
409 }
410
411 if (serial_string.str) {
412 text[i++] = StrDuplicate(L"[Serial Number]");
413 text[i++] = serial_string.str;
414 text[i++] = StrDuplicate(L"");
415 }
416 if (issuer) {
417 text[i++] = StrDuplicate(L"[Issuer]");
418 text[i++] = issuer;
419 text[i++] = StrDuplicate(L"");
420 }
421 if (subject) {
422 text[i++] = StrDuplicate(L"[Subject]");
423 text[i++] = subject;
424 text[i++] = StrDuplicate(L"");
425 }
426 if (from) {
427 text[i++] = StrDuplicate(L"[Valid Not Before]");
428 text[i++] = from;
429 text[i++] = StrDuplicate(L"");
430 }
431 if (until) {
432 text[i++] = StrDuplicate(L"[Valid Not After]");
433 text[i++] = until;
434 text[i++] = StrDuplicate(L"");
435 }
436 if (hash_string1.str) {
437 text[i++] = StrDuplicate(L"[Fingerprint]");
438 text[i++] = hash_string1.str;
439 }
440 if (hash_string2.str) {
441 text[i++] = hash_string2.str;
442 text[i++] = StrDuplicate(L"");
443 }
444 text[i] = NULL;
445
446 console_print_box(text, -1);
447
448 for (i = 0; text[i] != NULL; i++)
449 FreePool(text[i]);
450
451 FreePool(text);
452 }
453
454 static void show_sha_digest(EFI_GUID Type, UINT8 * hash)
455 {
456 CHAR16 *text[5];
457 POOL_PRINT hash_string1;
458 POOL_PRINT hash_string2;
459 int i;
460 int length;
461
462 if (CompareGuid(&Type, &EFI_CERT_SHA1_GUID) == 0) {
463 length = SHA1_DIGEST_SIZE;
464 text[0] = L"SHA1 hash";
465 } else if (CompareGuid(&Type, &EFI_CERT_SHA224_GUID) == 0) {
466 length = SHA224_DIGEST_LENGTH;
467 text[0] = L"SHA224 hash";
468 } else if (CompareGuid(&Type, &EFI_CERT_SHA256_GUID) == 0) {
469 length = SHA256_DIGEST_SIZE;
470 text[0] = L"SHA256 hash";
471 } else if (CompareGuid(&Type, &EFI_CERT_SHA384_GUID) == 0) {
472 length = SHA384_DIGEST_LENGTH;
473 text[0] = L"SHA384 hash";
474 } else if (CompareGuid(&Type, &EFI_CERT_SHA512_GUID) == 0) {
475 length = SHA512_DIGEST_LENGTH;
476 text[0] = L"SHA512 hash";
477 } else {
478 return;
479 }
480
481 ZeroMem(&hash_string1, sizeof(hash_string1));
482 ZeroMem(&hash_string2, sizeof(hash_string2));
483
484 text[1] = L"";
485
486 for (i = 0; i < length / 2; i++)
487 CatPrint(&hash_string1, L"%02x ", hash[i]);
488 for (i = length / 2; i < length; i++)
489 CatPrint(&hash_string2, L"%02x ", hash[i]);
490
491 text[2] = hash_string1.str;
492 text[3] = hash_string2.str;
493 text[4] = NULL;
494
495 console_print_box(text, -1);
496
497 if (hash_string1.str)
498 FreePool(hash_string1.str);
499
500 if (hash_string2.str)
501 FreePool(hash_string2.str);
502 }
503
504 static void show_efi_hash(EFI_GUID Type, void *Mok, UINTN MokSize)
505 {
506 UINTN sig_size;
507 UINTN hash_num;
508 UINT8 *hash;
509 CHAR16 **menu_strings;
510 CHAR16 *selection[] = { L"[Hash List]", NULL };
511 UINTN key_num = 0;
512 UINTN i;
513
514 sig_size = sha_size(Type) + sizeof(EFI_GUID);
515 if ((MokSize % sig_size) != 0) {
516 console_errorbox(L"Corrupted Hash List");
517 return;
518 }
519 hash_num = MokSize / sig_size;
520
521 if (hash_num == 1) {
522 hash = (UINT8 *) Mok + sizeof(EFI_GUID);
523 show_sha_digest(Type, hash);
524 return;
525 }
526
527 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (hash_num + 2));
528 if (!menu_strings) {
529 console_errorbox(L"Out of Resources");
530 return;
531 }
532
533 for (i = 0; i < hash_num; i++) {
534 menu_strings[i] = PoolPrint(L"View hash %d", i);
535 }
536 menu_strings[i] = StrDuplicate(L"Back");
537 menu_strings[i + 1] = NULL;
538
539 while (key_num < hash_num) {
540 int rc;
541
542 key_num = rc = console_select(selection, menu_strings, key_num);
543 if (rc < 0 || key_num >= hash_num)
544 break;
545
546 hash = (UINT8 *) Mok + sig_size * key_num + sizeof(EFI_GUID);
547 show_sha_digest(Type, hash);
548 }
549
550 for (i = 0; menu_strings[i] != NULL; i++)
551 FreePool(menu_strings[i]);
552
553 FreePool(menu_strings);
554 }
555
556 static void show_mok_info(EFI_GUID Type, void *Mok, UINTN MokSize)
557 {
558 EFI_STATUS efi_status;
559
560 if (!Mok || MokSize == 0)
561 return;
562
563 if (CompareGuid (&Type, &X509_GUID) == 0) {
564 UINT8 hash[SHA1_DIGEST_SIZE];
565 X509 *X509Cert;
566
567 efi_status = get_sha1sum(Mok, MokSize, hash);
568 if (EFI_ERROR(efi_status)) {
569 console_notify(L"Failed to compute MOK fingerprint");
570 return;
571 }
572
573 if (X509ConstructCertificate(Mok, MokSize,
574 (UINT8 **) & X509Cert)
575 && X509Cert != NULL) {
576 show_x509_info(X509Cert, hash);
577 X509_free(X509Cert);
578 } else {
579 console_notify(L"Not a valid X509 certificate");
580 return;
581 }
582 } else if (is_sha2_hash(Type)) {
583 show_efi_hash(Type, Mok, MokSize);
584 }
585 }
586
587 static EFI_STATUS list_keys(void *KeyList, UINTN KeyListSize, CHAR16 * title)
588 {
589 UINTN MokNum = 0;
590 MokListNode *keys = NULL;
591 UINT32 key_num = 0;
592 CHAR16 **menu_strings;
593 CHAR16 *selection[] = { title, NULL };
594 unsigned int i;
595
596 if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
597 sizeof(EFI_SIGNATURE_DATA))) {
598 console_notify(L"No MOK keys found");
599 return EFI_NOT_FOUND;
600 }
601
602 MokNum = count_keys(KeyList, KeyListSize);
603 if (MokNum == 0) {
604 console_errorbox(L"Invalid key list");
605 return EFI_ABORTED;
606 }
607 keys = build_mok_list(MokNum, KeyList, KeyListSize);
608 if (!keys) {
609 console_errorbox(L"Failed to construct key list");
610 return EFI_ABORTED;
611 }
612
613 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (MokNum + 2));
614 if (!menu_strings)
615 return EFI_OUT_OF_RESOURCES;
616
617 for (i = 0; i < MokNum; i++) {
618 menu_strings[i] = PoolPrint(L"View key %d", i);
619 }
620 menu_strings[i] = StrDuplicate(L"Continue");
621
622 menu_strings[i + 1] = NULL;
623
624 while (key_num < MokNum) {
625 int rc;
626 rc = key_num = console_select(selection, menu_strings, key_num);
627
628 if (rc < 0 || key_num >= MokNum)
629 break;
630
631 show_mok_info(keys[key_num].Type, keys[key_num].Mok,
632 keys[key_num].MokSize);
633 }
634
635 for (i = 0; menu_strings[i] != NULL; i++)
636 FreePool(menu_strings[i]);
637 FreePool(menu_strings);
638 FreePool(keys);
639
640 return EFI_SUCCESS;
641 }
642
643 static EFI_STATUS get_line(UINT32 * length, CHAR16 * line, UINT32 line_max,
644 UINT8 show)
645 {
646 EFI_INPUT_KEY key;
647 EFI_STATUS efi_status;
648 unsigned int count = 0;
649
650 do {
651 efi_status = console_get_keystroke(&key);
652 if (EFI_ERROR(efi_status)) {
653 console_error(L"Failed to read the keystroke",
654 efi_status);
655 *length = 0;
656 return efi_status;
657 }
658
659 if ((count >= line_max &&
660 key.UnicodeChar != CHAR_BACKSPACE) ||
661 key.UnicodeChar == CHAR_NULL ||
662 key.UnicodeChar == CHAR_TAB ||
663 key.UnicodeChar == CHAR_LINEFEED ||
664 key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
665 continue;
666 }
667
668 if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
669 continue;
670 } else if (key.UnicodeChar == CHAR_BACKSPACE) {
671 if (show) {
672 console_print(L"\b");
673 }
674 line[--count] = '\0';
675 continue;
676 }
677
678 if (show) {
679 console_print(L"%c", key.UnicodeChar);
680 }
681
682 line[count++] = key.UnicodeChar;
683 } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
684 console_print(L"\n");
685
686 *length = count;
687
688 return EFI_SUCCESS;
689 }
690
691 static EFI_STATUS compute_pw_hash(void *Data, UINTN DataSize, UINT8 * password,
692 UINT32 pw_length, UINT8 * hash)
693 {
694 EFI_STATUS efi_status;
695 unsigned int ctxsize;
696 void *ctx = NULL;
697
698 ctxsize = Sha256GetContextSize();
699 ctx = AllocatePool(ctxsize);
700 if (!ctx) {
701 console_notify(L"Unable to allocate memory for hash context");
702 return EFI_OUT_OF_RESOURCES;
703 }
704
705 if (!Sha256Init(ctx)) {
706 console_notify(L"Unable to initialise hash");
707 efi_status = EFI_OUT_OF_RESOURCES;
708 goto done;
709 }
710
711 if (Data && DataSize) {
712 if (!(Sha256Update(ctx, Data, DataSize))) {
713 console_notify(L"Unable to generate hash");
714 efi_status = EFI_OUT_OF_RESOURCES;
715 goto done;
716 }
717 }
718
719 if (!(Sha256Update(ctx, password, pw_length))) {
720 console_notify(L"Unable to generate hash");
721 efi_status = EFI_OUT_OF_RESOURCES;
722 goto done;
723 }
724
725 if (!(Sha256Final(ctx, hash))) {
726 console_notify(L"Unable to finalise hash");
727 efi_status = EFI_OUT_OF_RESOURCES;
728 goto done;
729 }
730
731 efi_status = EFI_SUCCESS;
732 done:
733 return efi_status;
734 }
735
736 static void console_save_and_set_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
737 {
738 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
739
740 if (!SavedMode) {
741 console_print(L"Invalid parameter: SavedMode\n");
742 return;
743 }
744
745 CopyMem(SavedMode, co->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
746 co->EnableCursor(co, FALSE);
747 co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
748 }
749
750 static void console_restore_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
751 {
752 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
753
754 co->EnableCursor(co, SavedMode->CursorVisible);
755 co->SetCursorPosition(co, SavedMode->CursorColumn,
756 SavedMode->CursorRow);
757 co->SetAttribute(co, SavedMode->Attribute);
758 }
759
760 static INTN reset_system()
761 {
762 gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
763 console_notify(L"Failed to reboot\n");
764 return -1;
765 }
766
767 static UINT32 get_password(CHAR16 * prompt, CHAR16 * password, UINT32 max)
768 {
769 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
770 CHAR16 *str;
771 CHAR16 *message[2];
772 UINTN length;
773 UINT32 pw_length;
774
775 if (!prompt)
776 prompt = L"Password:";
777
778 console_save_and_set_mode(&SavedMode);
779
780 str = PoolPrint(L"%s ", prompt);
781 if (!str) {
782 console_errorbox(L"Failed to allocate prompt");
783 return 0;
784 }
785
786 message[0] = str;
787 message[1] = NULL;
788 length = StrLen(message[0]);
789 console_print_box_at(message, -1, -length - 4, -5, length + 4, 3, 0, 1);
790 get_line(&pw_length, password, max, 0);
791
792 console_restore_mode(&SavedMode);
793
794 FreePool(str);
795
796 return pw_length;
797 }
798
799 static EFI_STATUS match_password(PASSWORD_CRYPT * pw_crypt,
800 void *Data, UINTN DataSize,
801 UINT8 * auth, CHAR16 * prompt)
802 {
803 EFI_STATUS efi_status;
804 UINT8 hash[128];
805 UINT8 *auth_hash;
806 UINT32 auth_size;
807 CHAR16 password[PASSWORD_MAX];
808 UINT32 pw_length;
809 UINT8 fail_count = 0;
810 unsigned int i;
811
812 if (pw_crypt) {
813 auth_hash = pw_crypt->hash;
814 auth_size = get_hash_size(pw_crypt->method);
815 if (auth_size == 0)
816 return EFI_INVALID_PARAMETER;
817 } else if (auth) {
818 auth_hash = auth;
819 auth_size = SHA256_DIGEST_SIZE;
820 } else {
821 return EFI_INVALID_PARAMETER;
822 }
823
824 while (fail_count < 3) {
825 pw_length = get_password(prompt, password, PASSWORD_MAX);
826
827 if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) {
828 console_errorbox(L"Invalid password length");
829 fail_count++;
830 continue;
831 }
832
833 /*
834 * Compute password hash
835 */
836 if (pw_crypt) {
837 char pw_ascii[PASSWORD_MAX + 1];
838 for (i = 0; i < pw_length; i++)
839 pw_ascii[i] = (char)password[i];
840 pw_ascii[pw_length] = '\0';
841
842 efi_status = password_crypt(pw_ascii, pw_length,
843 pw_crypt, hash);
844 } else {
845 /*
846 * For backward compatibility
847 */
848 efi_status = compute_pw_hash(Data, DataSize,
849 (UINT8 *) password,
850 pw_length * sizeof(CHAR16),
851 hash);
852 }
853 if (EFI_ERROR(efi_status)) {
854 console_errorbox(L"Unable to generate password hash");
855 fail_count++;
856 continue;
857 }
858
859 if (CompareMem(auth_hash, hash, auth_size) != 0) {
860 console_errorbox(L"Password doesn't match");
861 fail_count++;
862 continue;
863 }
864
865 break;
866 }
867
868 if (fail_count >= 3)
869 return EFI_ACCESS_DENIED;
870
871 return EFI_SUCCESS;
872 }
873
874 static EFI_STATUS write_db(CHAR16 * db_name, void *MokNew, UINTN MokNewSize)
875 {
876 EFI_STATUS efi_status;
877 UINT32 attributes;
878 void *old_data = NULL;
879 void *new_data = NULL;
880 UINTN old_size;
881 UINTN new_size;
882
883 /* Do not use EFI_VARIABLE_APPEND_WRITE due to faulty firmwares.
884 * ref: https://github.com/rhboot/shim/issues/55
885 * https://github.com/rhboot/shim/issues/105 */
886
887 efi_status = get_variable_attr(db_name, (UINT8 **)&old_data, &old_size,
888 SHIM_LOCK_GUID, &attributes);
889 if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
890 return efi_status;
891 }
892
893 /* Check if the old db is compromised or not */
894 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
895 FreePool(old_data);
896 old_data = NULL;
897 old_size = 0;
898 }
899
900 new_size = old_size + MokNewSize;
901 new_data = AllocatePool(new_size);
902 if (new_data == NULL) {
903 efi_status = EFI_OUT_OF_RESOURCES;
904 goto out;
905 }
906
907 CopyMem(new_data, old_data, old_size);
908 CopyMem(new_data + old_size, MokNew, MokNewSize);
909
910 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
911 EFI_VARIABLE_NON_VOLATILE |
912 EFI_VARIABLE_BOOTSERVICE_ACCESS,
913 new_size, new_data);
914 out:
915 if (old_size > 0) {
916 FreePool(old_data);
917 }
918
919 if (new_data != NULL) {
920 FreePool(new_data);
921 }
922
923 return efi_status;
924 }
925
926 static EFI_STATUS store_keys(void *MokNew, UINTN MokNewSize, int authenticate,
927 BOOLEAN MokX)
928 {
929 EFI_STATUS efi_status;
930 CHAR16 *db_name;
931 CHAR16 *auth_name;
932 UINT8 auth[PASSWORD_CRYPT_SIZE];
933 UINTN auth_size = PASSWORD_CRYPT_SIZE;
934 UINT32 attributes;
935
936 if (MokX) {
937 db_name = L"MokListX";
938 auth_name = L"MokXAuth";
939 } else {
940 db_name = L"MokList";
941 auth_name = L"MokAuth";
942 }
943
944 if (authenticate) {
945 efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID,
946 &attributes, &auth_size, auth);
947 if (EFI_ERROR(efi_status) ||
948 (auth_size != SHA256_DIGEST_SIZE &&
949 auth_size != PASSWORD_CRYPT_SIZE)) {
950 if (MokX)
951 console_error(L"Failed to get MokXAuth",
952 efi_status);
953 else
954 console_error(L"Failed to get MokAuth",
955 efi_status);
956 return efi_status;
957 }
958
959 if (auth_size == PASSWORD_CRYPT_SIZE) {
960 efi_status = match_password((PASSWORD_CRYPT *) auth,
961 NULL, 0, NULL, NULL);
962 } else {
963 efi_status = match_password(NULL, MokNew, MokNewSize,
964 auth, NULL);
965 }
966 if (EFI_ERROR(efi_status))
967 return EFI_ACCESS_DENIED;
968 }
969
970 if (!MokNewSize) {
971 /* Delete MOK */
972 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
973 EFI_VARIABLE_NON_VOLATILE |
974 EFI_VARIABLE_BOOTSERVICE_ACCESS,
975 0, NULL);
976 } else {
977 /* Write new MOK */
978 efi_status = write_db(db_name, MokNew, MokNewSize);
979 }
980
981 if (EFI_ERROR(efi_status)) {
982 console_error(L"Failed to set variable", efi_status);
983 return efi_status;
984 }
985
986 return EFI_SUCCESS;
987 }
988
989 static EFI_STATUS mok_enrollment_prompt(void *MokNew, UINTN MokNewSize,
990 int auth, BOOLEAN MokX)
991 {
992 EFI_STATUS efi_status;
993 CHAR16 *enroll_p[] = { L"Enroll the key(s)?", NULL };
994 CHAR16 *title;
995
996 if (MokX)
997 title = L"[Enroll MOKX]";
998 else
999 title = L"[Enroll MOK]";
1000
1001 efi_status = list_keys(MokNew, MokNewSize, title);
1002 if (EFI_ERROR(efi_status))
1003 return efi_status;
1004
1005 if (console_yes_no(enroll_p) == 0)
1006 return EFI_ABORTED;
1007
1008 efi_status = store_keys(MokNew, MokNewSize, auth, MokX);
1009 if (EFI_ERROR(efi_status)) {
1010 console_notify(L"Failed to enroll keys\n");
1011 return efi_status;
1012 }
1013
1014 if (auth) {
1015 if (MokX) {
1016 LibDeleteVariable(L"MokXNew", &SHIM_LOCK_GUID);
1017 LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
1018 } else {
1019 LibDeleteVariable(L"MokNew", &SHIM_LOCK_GUID);
1020 LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
1021 }
1022 }
1023
1024 return EFI_SUCCESS;
1025 }
1026
1027 static EFI_STATUS mok_reset_prompt(BOOLEAN MokX)
1028 {
1029 EFI_STATUS efi_status;
1030 CHAR16 *prompt[] = { NULL, NULL };
1031
1032 ST->ConOut->ClearScreen(ST->ConOut);
1033
1034 if (MokX)
1035 prompt[0] = L"Erase all stored keys in MokListX?";
1036 else
1037 prompt[0] = L"Erase all stored keys in MokList?";
1038
1039 if (console_yes_no(prompt) == 0)
1040 return EFI_ABORTED;
1041
1042 efi_status = store_keys(NULL, 0, TRUE, MokX);
1043 if (EFI_ERROR(efi_status)) {
1044 console_notify(L"Failed to erase keys\n");
1045 return efi_status;
1046 }
1047
1048 if (MokX) {
1049 LibDeleteVariable(L"MokXNew", &SHIM_LOCK_GUID);
1050 LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
1051 } else {
1052 LibDeleteVariable(L"MokNew", &SHIM_LOCK_GUID);
1053 LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
1054 }
1055
1056 return EFI_SUCCESS;
1057 }
1058
1059 static EFI_STATUS write_back_mok_list(MokListNode * list, INTN key_num,
1060 BOOLEAN MokX)
1061 {
1062 EFI_STATUS efi_status;
1063 EFI_SIGNATURE_LIST *CertList;
1064 EFI_SIGNATURE_DATA *CertData;
1065 void *Data = NULL, *ptr;
1066 INTN DataSize = 0;
1067 int i;
1068 CHAR16 *db_name;
1069
1070 if (MokX)
1071 db_name = L"MokListX";
1072 else
1073 db_name = L"MokList";
1074
1075 for (i = 0; i < key_num; i++) {
1076 if (list[i].Mok == NULL)
1077 continue;
1078
1079 DataSize += sizeof(EFI_SIGNATURE_LIST);
1080 if (CompareGuid(&(list[i].Type), &X509_GUID) == 0)
1081 DataSize += sizeof(EFI_GUID);
1082 DataSize += list[i].MokSize;
1083 }
1084
1085 Data = AllocatePool(DataSize);
1086 if (Data == NULL && DataSize != 0)
1087 return EFI_OUT_OF_RESOURCES;
1088
1089 ptr = Data;
1090
1091 for (i = 0; i < key_num; i++) {
1092 if (list[i].Mok == NULL)
1093 continue;
1094
1095 CertList = (EFI_SIGNATURE_LIST *) ptr;
1096 CertData = (EFI_SIGNATURE_DATA *) (((uint8_t *) ptr) +
1097 sizeof(EFI_SIGNATURE_LIST));
1098
1099 CertList->SignatureType = list[i].Type;
1100 CertList->SignatureHeaderSize = 0;
1101
1102 if (CompareGuid(&(list[i].Type), &X509_GUID) == 0) {
1103 CertList->SignatureListSize = list[i].MokSize +
1104 sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
1105 CertList->SignatureSize =
1106 list[i].MokSize + sizeof(EFI_GUID);
1107
1108 CertData->SignatureOwner = SHIM_LOCK_GUID;
1109 CopyMem(CertData->SignatureData, list[i].Mok,
1110 list[i].MokSize);
1111 } else {
1112 CertList->SignatureListSize = list[i].MokSize +
1113 sizeof(EFI_SIGNATURE_LIST);
1114 CertList->SignatureSize =
1115 sha_size(list[i].Type) + sizeof(EFI_GUID);
1116
1117 CopyMem(CertData, list[i].Mok, list[i].MokSize);
1118 }
1119 ptr = (uint8_t *) ptr + CertList->SignatureListSize;
1120 }
1121
1122 efi_status = gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1123 EFI_VARIABLE_NON_VOLATILE |
1124 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1125 DataSize, Data);
1126 if (Data)
1127 FreePool(Data);
1128
1129 if (EFI_ERROR(efi_status)) {
1130 console_error(L"Failed to set variable", efi_status);
1131 return efi_status;
1132 }
1133
1134 return EFI_SUCCESS;
1135 }
1136
1137 static void delete_cert(void *key, UINT32 key_size,
1138 MokListNode * mok, INTN mok_num)
1139 {
1140 int i;
1141
1142 for (i = 0; i < mok_num; i++) {
1143 if (CompareGuid(&(mok[i].Type), &X509_GUID) != 0)
1144 continue;
1145
1146 if (mok[i].MokSize == key_size &&
1147 CompareMem(key, mok[i].Mok, key_size) == 0) {
1148 /* Remove the key */
1149 mok[i].Mok = NULL;
1150 mok[i].MokSize = 0;
1151 }
1152 }
1153 }
1154
1155 static int match_hash(UINT8 * hash, UINT32 hash_size, int start,
1156 void *hash_list, UINT32 list_num)
1157 {
1158 UINT8 *ptr;
1159 UINTN i;
1160
1161 ptr = hash_list + sizeof(EFI_GUID);
1162 for (i = start; i < list_num; i++) {
1163 if (CompareMem(hash, ptr, hash_size) == 0)
1164 return i;
1165 ptr += hash_size + sizeof(EFI_GUID);
1166 }
1167
1168 return -1;
1169 }
1170
1171 static void mem_move(void *dest, void *src, UINTN size)
1172 {
1173 UINT8 *d, *s;
1174 UINTN i;
1175
1176 d = (UINT8 *) dest;
1177 s = (UINT8 *) src;
1178 for (i = 0; i < size; i++)
1179 d[i] = s[i];
1180 }
1181
1182 static void delete_hash_in_list(EFI_GUID Type, UINT8 * hash, UINT32 hash_size,
1183 MokListNode * mok, INTN mok_num)
1184 {
1185 UINT32 sig_size;
1186 UINT32 list_num;
1187 int i, del_ind;
1188 void *start, *end;
1189 UINT32 remain;
1190
1191 sig_size = hash_size + sizeof(EFI_GUID);
1192
1193 for (i = 0; i < mok_num; i++) {
1194 if ((CompareGuid(&(mok[i].Type), &Type) != 0) ||
1195 (mok[i].MokSize < sig_size))
1196 continue;
1197
1198 list_num = mok[i].MokSize / sig_size;
1199
1200 del_ind = match_hash(hash, hash_size, 0, mok[i].Mok, list_num);
1201 while (del_ind >= 0) {
1202 /* Remove the hash */
1203 if (sig_size == mok[i].MokSize) {
1204 mok[i].Mok = NULL;
1205 mok[i].MokSize = 0;
1206 break;
1207 }
1208
1209 start = mok[i].Mok + del_ind * sig_size;
1210 end = start + sig_size;
1211 remain = mok[i].MokSize - (del_ind + 1) * sig_size;
1212
1213 mem_move(start, end, remain);
1214 mok[i].MokSize -= sig_size;
1215 list_num--;
1216
1217 del_ind = match_hash(hash, hash_size, del_ind,
1218 mok[i].Mok, list_num);
1219 }
1220 }
1221 }
1222
1223 static void delete_hash_list(EFI_GUID Type, void *hash_list, UINT32 list_size,
1224 MokListNode * mok, INTN mok_num)
1225 {
1226 UINT32 hash_size;
1227 UINT32 hash_num;
1228 UINT32 sig_size;
1229 UINT8 *hash;
1230 UINT32 i;
1231
1232 hash_size = sha_size(Type);
1233 sig_size = hash_size + sizeof(EFI_GUID);
1234 if (list_size < sig_size)
1235 return;
1236
1237 hash_num = list_size / sig_size;
1238
1239 hash = hash_list + sizeof(EFI_GUID);
1240
1241 for (i = 0; i < hash_num; i++) {
1242 delete_hash_in_list(Type, hash, hash_size, mok, mok_num);
1243 hash += sig_size;
1244 }
1245 }
1246
1247 static EFI_STATUS delete_keys(void *MokDel, UINTN MokDelSize, BOOLEAN MokX)
1248 {
1249 EFI_STATUS efi_status;
1250 CHAR16 *db_name;
1251 CHAR16 *auth_name;
1252 CHAR16 *err_strs[] = { NULL, NULL, NULL };
1253 UINT8 auth[PASSWORD_CRYPT_SIZE];
1254 UINTN auth_size = PASSWORD_CRYPT_SIZE;
1255 UINT32 attributes;
1256 UINT8 *MokListData = NULL;
1257 UINTN MokListDataSize = 0;
1258 MokListNode *mok = NULL, *del_key = NULL;
1259 INTN mok_num, del_num;
1260 int i;
1261
1262 if (MokX) {
1263 db_name = L"MokListX";
1264 auth_name = L"MokXDelAuth";
1265 } else {
1266 db_name = L"MokList";
1267 auth_name = L"MokDelAuth";
1268 }
1269
1270 efi_status = gRT->GetVariable(auth_name, &SHIM_LOCK_GUID, &attributes,
1271 &auth_size, auth);
1272 if (EFI_ERROR(efi_status) ||
1273 (auth_size != SHA256_DIGEST_SIZE
1274 && auth_size != PASSWORD_CRYPT_SIZE)) {
1275 if (MokX)
1276 console_error(L"Failed to get MokXDelAuth", efi_status);
1277 else
1278 console_error(L"Failed to get MokDelAuth", efi_status);
1279 return efi_status;
1280 }
1281
1282 if (auth_size == PASSWORD_CRYPT_SIZE) {
1283 efi_status = match_password((PASSWORD_CRYPT *) auth, NULL, 0,
1284 NULL, NULL);
1285 } else {
1286 efi_status =
1287 match_password(NULL, MokDel, MokDelSize, auth, NULL);
1288 }
1289 if (EFI_ERROR(efi_status))
1290 return EFI_ACCESS_DENIED;
1291
1292 efi_status = get_variable_attr(db_name, &MokListData, &MokListDataSize,
1293 SHIM_LOCK_GUID, &attributes);
1294 if (EFI_ERROR(efi_status)) {
1295 if (MokX)
1296 console_errorbox(L"Failed to retrieve MokListX");
1297 else
1298 console_errorbox(L"Failed to retrieve MokList");
1299 return EFI_ABORTED;
1300 } else if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
1301 if (MokX) {
1302 err_strs[0] = L"MokListX is compromised!";
1303 err_strs[1] = L"Erase all keys in MokListX!";
1304 } else {
1305 err_strs[0] = L"MokList is compromised!";
1306 err_strs[1] = L"Erase all keys in MokList!";
1307 }
1308 console_alertbox(err_strs);
1309 gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1310 EFI_VARIABLE_NON_VOLATILE |
1311 EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
1312 efi_status = EFI_ACCESS_DENIED;
1313 goto error;
1314 }
1315
1316 /* Nothing to do */
1317 if (!MokListData || MokListDataSize == 0)
1318 return EFI_SUCCESS;
1319
1320 /* Construct lists */
1321 mok_num = count_keys(MokListData, MokListDataSize);
1322 if (mok_num == 0) {
1323 if (MokX) {
1324 err_strs[0] = L"Failed to construct the key list of MokListX";
1325 err_strs[1] = L"Reset MokListX!";
1326 } else {
1327 err_strs[0] = L"Failed to construct the key list of MokList";
1328 err_strs[1] = L"Reset MokList!";
1329 }
1330 console_alertbox(err_strs);
1331 gRT->SetVariable(db_name, &SHIM_LOCK_GUID,
1332 EFI_VARIABLE_NON_VOLATILE |
1333 EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
1334 efi_status = EFI_ABORTED;
1335 goto error;
1336 }
1337 mok = build_mok_list(mok_num, MokListData, MokListDataSize);
1338 if (!mok) {
1339 console_errorbox(L"Failed to construct key list");
1340 efi_status = EFI_ABORTED;
1341 goto error;
1342 }
1343 del_num = count_keys(MokDel, MokDelSize);
1344 if (del_num == 0) {
1345 console_errorbox(L"Invalid key delete list");
1346 efi_status = EFI_ABORTED;
1347 goto error;
1348 }
1349 del_key = build_mok_list(del_num, MokDel, MokDelSize);
1350 if (!del_key) {
1351 console_errorbox(L"Failed to construct key list");
1352 efi_status = EFI_ABORTED;
1353 goto error;
1354 }
1355
1356 /* Search and destroy */
1357 for (i = 0; i < del_num; i++) {
1358 if (CompareGuid(&(del_key[i].Type), &X509_GUID) == 0) {
1359 delete_cert(del_key[i].Mok, del_key[i].MokSize,
1360 mok, mok_num);
1361 } else if (is_sha2_hash(del_key[i].Type)) {
1362 delete_hash_list(del_key[i].Type, del_key[i].Mok,
1363 del_key[i].MokSize, mok, mok_num);
1364 }
1365 }
1366
1367 efi_status = write_back_mok_list(mok, mok_num, MokX);
1368
1369 error:
1370 if (MokListData)
1371 FreePool(MokListData);
1372 if (mok)
1373 FreePool(mok);
1374 if (del_key)
1375 FreePool(del_key);
1376
1377 return efi_status;
1378 }
1379
1380 static EFI_STATUS mok_deletion_prompt(void *MokDel, UINTN MokDelSize,
1381 BOOLEAN MokX)
1382 {
1383 EFI_STATUS efi_status;
1384 CHAR16 *delete_p[] = { L"Delete the key(s)?", NULL };
1385 CHAR16 *title;
1386
1387 if (MokX)
1388 title = L"[Delete MOKX]";
1389 else
1390 title = L"[Delete MOK]";
1391
1392 efi_status = list_keys(MokDel, MokDelSize, title);
1393 if (EFI_ERROR(efi_status))
1394 return efi_status;
1395
1396 if (console_yes_no(delete_p) == 0)
1397 return EFI_ABORTED;
1398
1399 efi_status = delete_keys(MokDel, MokDelSize, MokX);
1400 if (EFI_ERROR(efi_status)) {
1401 console_notify(L"Failed to delete keys");
1402 return efi_status;
1403 }
1404
1405 if (MokX) {
1406 LibDeleteVariable(L"MokXDel", &SHIM_LOCK_GUID);
1407 LibDeleteVariable(L"MokXDelAuth", &SHIM_LOCK_GUID);
1408 } else {
1409 LibDeleteVariable(L"MokDel", &SHIM_LOCK_GUID);
1410 LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
1411 }
1412
1413 if (MokDel)
1414 FreePool(MokDel);
1415
1416 return EFI_SUCCESS;
1417 }
1418
1419 static CHAR16 get_password_charater(CHAR16 * prompt)
1420 {
1421 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1422 EFI_STATUS efi_status;
1423 CHAR16 *message[2];
1424 CHAR16 character;
1425 UINTN length;
1426 UINT32 pw_length;
1427
1428 if (!prompt)
1429 prompt = L"Password charater: ";
1430
1431 console_save_and_set_mode(&SavedMode);
1432
1433 message[0] = prompt;
1434 message[1] = NULL;
1435 length = StrLen(message[0]);
1436 console_print_box_at(message, -1, -length - 4, -5, length + 4, 3, 0, 1);
1437 efi_status = get_line(&pw_length, &character, 1, 0);
1438 if (EFI_ERROR(efi_status))
1439 character = 0;
1440
1441 console_restore_mode(&SavedMode);
1442
1443 return character;
1444 }
1445
1446 static EFI_STATUS mok_sb_prompt(void *MokSB, UINTN MokSBSize)
1447 {
1448 EFI_STATUS efi_status;
1449 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1450 MokSBvar *var = MokSB;
1451 CHAR16 *message[4];
1452 CHAR16 pass1, pass2, pass3;
1453 CHAR16 *str;
1454 UINT8 fail_count = 0;
1455 UINT8 sbval = 1;
1456 UINT8 pos1, pos2, pos3;
1457 int ret;
1458 CHAR16 *disable_sb[] = { L"Disable Secure Boot", NULL };
1459 CHAR16 *enable_sb[] = { L"Enable Secure Boot", NULL };
1460
1461 if (MokSBSize != sizeof(MokSBvar)) {
1462 console_notify(L"Invalid MokSB variable contents");
1463 return EFI_INVALID_PARAMETER;
1464 }
1465
1466 ST->ConOut->ClearScreen(ST->ConOut);
1467
1468 message[0] = L"Change Secure Boot state";
1469 message[1] = NULL;
1470
1471 console_save_and_set_mode(&SavedMode);
1472 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1473 console_restore_mode(&SavedMode);
1474
1475 while (fail_count < 3) {
1476 RandomBytes(&pos1, sizeof(pos1));
1477 pos1 = (pos1 % var->PWLen);
1478
1479 do {
1480 RandomBytes(&pos2, sizeof(pos2));
1481 pos2 = (pos2 % var->PWLen);
1482 } while (pos2 == pos1);
1483
1484 do {
1485 RandomBytes(&pos3, sizeof(pos3));
1486 pos3 = (pos3 % var->PWLen);
1487 } while (pos3 == pos2 || pos3 == pos1);
1488
1489 str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1490 if (!str) {
1491 console_errorbox(L"Failed to allocate buffer");
1492 return EFI_OUT_OF_RESOURCES;
1493 }
1494 pass1 = get_password_charater(str);
1495 FreePool(str);
1496
1497 str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1498 if (!str) {
1499 console_errorbox(L"Failed to allocate buffer");
1500 return EFI_OUT_OF_RESOURCES;
1501 }
1502 pass2 = get_password_charater(str);
1503 FreePool(str);
1504
1505 str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1506 if (!str) {
1507 console_errorbox(L"Failed to allocate buffer");
1508 return EFI_OUT_OF_RESOURCES;
1509 }
1510 pass3 = get_password_charater(str);
1511 FreePool(str);
1512
1513 if (pass1 != var->Password[pos1] ||
1514 pass2 != var->Password[pos2] ||
1515 pass3 != var->Password[pos3]) {
1516 console_print(L"Invalid character\n");
1517 fail_count++;
1518 } else {
1519 break;
1520 }
1521 }
1522
1523 if (fail_count >= 3) {
1524 console_notify(L"Password limit reached");
1525 return EFI_ACCESS_DENIED;
1526 }
1527
1528 if (var->MokSBState == 0)
1529 ret = console_yes_no(disable_sb);
1530 else
1531 ret = console_yes_no(enable_sb);
1532
1533 if (ret == 0) {
1534 LibDeleteVariable(L"MokSB", &SHIM_LOCK_GUID);
1535 return EFI_ABORTED;
1536 }
1537
1538 if (var->MokSBState == 0) {
1539 efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
1540 EFI_VARIABLE_NON_VOLATILE |
1541 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1542 1, &sbval);
1543 if (EFI_ERROR(efi_status)) {
1544 console_notify(L"Failed to set Secure Boot state");
1545 return efi_status;
1546 }
1547 } else {
1548 efi_status = gRT->SetVariable(L"MokSBState", &SHIM_LOCK_GUID,
1549 EFI_VARIABLE_NON_VOLATILE |
1550 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1551 0, NULL);
1552 if (EFI_ERROR(efi_status)) {
1553 console_notify(L"Failed to delete Secure Boot state");
1554 return efi_status;
1555 }
1556 }
1557
1558 return EFI_SUCCESS;
1559 }
1560
1561 static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize)
1562 {
1563 EFI_STATUS efi_status;
1564 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1565 MokDBvar *var = MokDB;
1566 CHAR16 *message[4];
1567 CHAR16 pass1, pass2, pass3;
1568 CHAR16 *str;
1569 UINT8 fail_count = 0;
1570 UINT8 dbval = 1;
1571 UINT8 pos1, pos2, pos3;
1572 int ret;
1573 CHAR16 *ignore_db[] = { L"Ignore DB certs/hashes", NULL };
1574 CHAR16 *use_db[] = { L"Use DB certs/hashes", NULL };
1575
1576 if (MokDBSize != sizeof(MokDBvar)) {
1577 console_notify(L"Invalid MokDB variable contents");
1578 return EFI_INVALID_PARAMETER;
1579 }
1580
1581 ST->ConOut->ClearScreen(ST->ConOut);
1582
1583 message[0] = L"Change DB state";
1584 message[1] = NULL;
1585
1586 console_save_and_set_mode(&SavedMode);
1587 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1588 console_restore_mode(&SavedMode);
1589
1590 while (fail_count < 3) {
1591 RandomBytes(&pos1, sizeof(pos1));
1592 pos1 = (pos1 % var->PWLen);
1593
1594 do {
1595 RandomBytes(&pos2, sizeof(pos2));
1596 pos2 = (pos2 % var->PWLen);
1597 } while (pos2 == pos1);
1598
1599 do {
1600 RandomBytes(&pos3, sizeof(pos3));
1601 pos3 = (pos3 % var->PWLen);
1602 } while (pos3 == pos2 || pos3 == pos1);
1603
1604 str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1605 if (!str) {
1606 console_errorbox(L"Failed to allocate buffer");
1607 return EFI_OUT_OF_RESOURCES;
1608 }
1609 pass1 = get_password_charater(str);
1610 FreePool(str);
1611
1612 str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1613 if (!str) {
1614 console_errorbox(L"Failed to allocate buffer");
1615 return EFI_OUT_OF_RESOURCES;
1616 }
1617 pass2 = get_password_charater(str);
1618 FreePool(str);
1619
1620 str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1621 if (!str) {
1622 console_errorbox(L"Failed to allocate buffer");
1623 return EFI_OUT_OF_RESOURCES;
1624 }
1625 pass3 = get_password_charater(str);
1626 FreePool(str);
1627
1628 if (pass1 != var->Password[pos1] ||
1629 pass2 != var->Password[pos2] ||
1630 pass3 != var->Password[pos3]) {
1631 console_print(L"Invalid character\n");
1632 fail_count++;
1633 } else {
1634 break;
1635 }
1636 }
1637
1638 if (fail_count >= 3) {
1639 console_notify(L"Password limit reached");
1640 return EFI_ACCESS_DENIED;
1641 }
1642
1643 if (var->MokDBState == 0)
1644 ret = console_yes_no(ignore_db);
1645 else
1646 ret = console_yes_no(use_db);
1647
1648 if (ret == 0) {
1649 LibDeleteVariable(L"MokDB", &SHIM_LOCK_GUID);
1650 return EFI_ABORTED;
1651 }
1652
1653 if (var->MokDBState == 0) {
1654 efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
1655 EFI_VARIABLE_NON_VOLATILE |
1656 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1657 1, &dbval);
1658 if (EFI_ERROR(efi_status)) {
1659 console_notify(L"Failed to set DB state");
1660 return efi_status;
1661 }
1662 } else {
1663 efi_status = gRT->SetVariable(L"MokDBState", &SHIM_LOCK_GUID,
1664 EFI_VARIABLE_NON_VOLATILE |
1665 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1666 0, NULL);
1667 if (EFI_ERROR(efi_status)) {
1668 console_notify(L"Failed to delete DB state");
1669 return efi_status;
1670 }
1671 }
1672
1673 return EFI_SUCCESS;
1674 }
1675
1676 static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize)
1677 {
1678 EFI_STATUS efi_status;
1679 UINT8 hash[PASSWORD_CRYPT_SIZE];
1680 UINT8 clear = 0;
1681 CHAR16 *clear_p[] = { L"Clear MOK password?", NULL };
1682 CHAR16 *set_p[] = { L"Set MOK password?", NULL };
1683
1684 if (MokPWSize != SHA256_DIGEST_SIZE && MokPWSize != PASSWORD_CRYPT_SIZE) {
1685 console_notify(L"Invalid MokPW variable contents");
1686 return EFI_INVALID_PARAMETER;
1687 }
1688
1689 ST->ConOut->ClearScreen(ST->ConOut);
1690
1691 SetMem(hash, PASSWORD_CRYPT_SIZE, 0);
1692
1693 if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1694 if (CompareMem(MokPW, hash, PASSWORD_CRYPT_SIZE) == 0)
1695 clear = 1;
1696 } else {
1697 if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0)
1698 clear = 1;
1699 }
1700
1701 if (clear) {
1702 if (console_yes_no(clear_p) == 0)
1703 return EFI_ABORTED;
1704
1705 gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
1706 EFI_VARIABLE_NON_VOLATILE |
1707 EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
1708 goto mokpw_done;
1709 }
1710
1711 if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1712 efi_status = match_password((PASSWORD_CRYPT *) MokPW, NULL, 0,
1713 NULL, L"Confirm MOK passphrase: ");
1714 } else {
1715 efi_status = match_password(NULL, NULL, 0, MokPW,
1716 L"Confirm MOK passphrase: ");
1717 }
1718
1719 if (EFI_ERROR(efi_status)) {
1720 console_notify(L"Password limit reached");
1721 return efi_status;
1722 }
1723
1724 if (console_yes_no(set_p) == 0)
1725 return EFI_ABORTED;
1726
1727 efi_status = gRT->SetVariable(L"MokPWStore", &SHIM_LOCK_GUID,
1728 EFI_VARIABLE_NON_VOLATILE |
1729 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1730 MokPWSize, MokPW);
1731 if (EFI_ERROR(efi_status)) {
1732 console_notify(L"Failed to set MOK password");
1733 return efi_status;
1734 }
1735
1736 mokpw_done:
1737 LibDeleteVariable(L"MokPW", &SHIM_LOCK_GUID);
1738
1739 return EFI_SUCCESS;
1740 }
1741
1742 static BOOLEAN verify_certificate(UINT8 * cert, UINTN size)
1743 {
1744 X509 *X509Cert;
1745 UINTN length;
1746 if (!cert || size < 4)
1747 return FALSE;
1748
1749 /*
1750 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
1751 * the number of length bytes, and the number of value bytes.
1752 * The size of a x509 certificate is usually between 127 bytes
1753 * and 64KB. For convenience, assume the number of value bytes
1754 * is 2, i.e. the second byte is 0x82.
1755 */
1756 if (cert[0] != 0x30 || cert[1] != 0x82) {
1757 console_notify(L"Not a DER encoding X509 certificate");
1758 return FALSE;
1759 }
1760
1761 length = (cert[2] << 8 | cert[3]);
1762 if (length != (size - 4)) {
1763 console_notify(L"Invalid X509 certificate: Inconsistent size");
1764 return FALSE;
1765 }
1766
1767 if (!(X509ConstructCertificate(cert, size, (UINT8 **) & X509Cert)) ||
1768 X509Cert == NULL) {
1769 console_notify(L"Invalid X509 certificate");
1770 return FALSE;
1771 }
1772
1773 X509_free(X509Cert);
1774 return TRUE;
1775 }
1776
1777 static EFI_STATUS enroll_file(void *data, UINTN datasize, BOOLEAN hash)
1778 {
1779 EFI_STATUS efi_status = EFI_SUCCESS;
1780 EFI_SIGNATURE_LIST *CertList;
1781 EFI_SIGNATURE_DATA *CertData;
1782 UINTN mokbuffersize;
1783 void *mokbuffer = NULL;
1784
1785 if (hash) {
1786 UINT8 sha256[SHA256_DIGEST_SIZE];
1787 UINT8 sha1[SHA1_DIGEST_SIZE];
1788 SHIM_LOCK *shim_lock;
1789 PE_COFF_LOADER_IMAGE_CONTEXT context;
1790
1791 efi_status = LibLocateProtocol(&SHIM_LOCK_GUID,
1792 (VOID **) &shim_lock);
1793 if (EFI_ERROR(efi_status))
1794 goto out;
1795
1796 mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) +
1797 SHA256_DIGEST_SIZE;
1798
1799 mokbuffer = AllocatePool(mokbuffersize);
1800 if (!mokbuffer)
1801 goto out;
1802
1803 efi_status = shim_lock->Context(data, datasize, &context);
1804 if (EFI_ERROR(efi_status))
1805 goto out;
1806
1807 efi_status = shim_lock->Hash(data, datasize, &context, sha256,
1808 sha1);
1809 if (EFI_ERROR(efi_status))
1810 goto out;
1811
1812 CertList = mokbuffer;
1813 CertList->SignatureType = EFI_CERT_SHA256_GUID;
1814 CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE;
1815 CertData = (EFI_SIGNATURE_DATA *) (((UINT8 *) mokbuffer) +
1816 sizeof(EFI_SIGNATURE_LIST));
1817 CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
1818 } else {
1819 mokbuffersize = datasize + sizeof(EFI_SIGNATURE_LIST) +
1820 sizeof(EFI_GUID);
1821 mokbuffer = AllocatePool(mokbuffersize);
1822
1823 if (!mokbuffer)
1824 goto out;
1825
1826 CertList = mokbuffer;
1827 CertList->SignatureType = X509_GUID;
1828 CertList->SignatureSize = 16 + datasize;
1829
1830 memcpy(mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16, data,
1831 datasize);
1832
1833 CertData = (EFI_SIGNATURE_DATA *) (((UINT8 *) mokbuffer) +
1834 sizeof(EFI_SIGNATURE_LIST));
1835 }
1836
1837 CertList->SignatureListSize = mokbuffersize;
1838 CertList->SignatureHeaderSize = 0;
1839 CertData->SignatureOwner = SHIM_LOCK_GUID;
1840
1841 if (!hash) {
1842 if (!verify_certificate(CertData->SignatureData, datasize))
1843 goto out;
1844 }
1845
1846 efi_status = mok_enrollment_prompt(mokbuffer, mokbuffersize,
1847 FALSE, FALSE);
1848 out:
1849 if (mokbuffer)
1850 FreePool(mokbuffer);
1851
1852 return efi_status;
1853 }
1854
1855 static EFI_STATUS mok_hash_enroll(void)
1856 {
1857 EFI_STATUS efi_status;
1858 CHAR16 *file_name = NULL;
1859 EFI_HANDLE im = NULL;
1860 EFI_FILE *file = NULL;
1861 UINTN filesize;
1862 void *data;
1863 CHAR16 *selections[] = {
1864 L"Select Binary",
1865 L"",
1866 L"The Selected Binary will have its hash Enrolled",
1867 L"This means it will subsequently Boot with no prompting",
1868 L"Remember to make sure it is a genuine binary before enrolling its hash",
1869 NULL
1870 };
1871
1872 simple_file_selector(&im, selections, L"\\", L"", &file_name);
1873
1874 if (!file_name)
1875 return EFI_INVALID_PARAMETER;
1876
1877 efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1878 if (EFI_ERROR(efi_status)) {
1879 console_error(L"Unable to open file", efi_status);
1880 return efi_status;
1881 }
1882
1883 simple_file_read_all(file, &filesize, &data);
1884 file->Close(file);
1885 if (!filesize) {
1886 console_error(L"Unable to read file", efi_status);
1887 return EFI_BAD_BUFFER_SIZE;
1888 }
1889
1890 efi_status = enroll_file(data, filesize, TRUE);
1891 if (EFI_ERROR(efi_status))
1892 console_error(
1893 L"Hash failed (did you select a valid EFI binary?)",
1894 efi_status);
1895
1896 FreePool(data);
1897
1898 return efi_status;
1899 }
1900
1901 static CHAR16 *der_suffix[] = {
1902 L".cer",
1903 L".der",
1904 L".crt",
1905 NULL
1906 };
1907
1908 static BOOLEAN check_der_suffix(CHAR16 * file_name)
1909 {
1910 CHAR16 suffix[5];
1911 int i;
1912
1913 if (!file_name || StrLen(file_name) <= 4)
1914 return FALSE;
1915
1916 suffix[0] = '\0';
1917 StrnCat(suffix, file_name + StrLen(file_name) - 4, 4);
1918
1919 StrLwr(suffix);
1920 for (i = 0; der_suffix[i] != NULL; i++) {
1921 if (StrCmp(suffix, der_suffix[i]) == 0) {
1922 return TRUE;
1923 }
1924 }
1925
1926 return FALSE;
1927 }
1928
1929 static EFI_STATUS mok_key_enroll(void)
1930 {
1931 EFI_STATUS efi_status;
1932 CHAR16 *file_name = NULL;
1933 EFI_HANDLE im = NULL;
1934 EFI_FILE *file = NULL;
1935 UINTN filesize;
1936 void *data;
1937 CHAR16 *selections[] = {
1938 L"Select Key",
1939 L"",
1940 L"The selected key will be enrolled into the MOK database",
1941 L"This means any binaries signed with it will be run without prompting",
1942 L"Remember to make sure it is a genuine key before Enrolling it",
1943 NULL
1944 };
1945 CHAR16 *alert[] = {
1946 L"Unsupported Format",
1947 L"",
1948 L"Only DER encoded certificate (*.cer/der/crt) is supported",
1949 NULL
1950 };
1951
1952 simple_file_selector(&im, selections, L"\\", L"", &file_name);
1953
1954 if (!file_name)
1955 return EFI_INVALID_PARAMETER;
1956
1957 if (!check_der_suffix(file_name)) {
1958 console_alertbox(alert);
1959 return EFI_UNSUPPORTED;
1960 }
1961
1962 efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1963 if (EFI_ERROR(efi_status)) {
1964 console_error(L"Unable to open file", efi_status);
1965 return efi_status;
1966 }
1967
1968 simple_file_read_all(file, &filesize, &data);
1969 file->Close(file);
1970 if (!filesize) {
1971 console_error(L"Unable to read file", efi_status);
1972 return EFI_BAD_BUFFER_SIZE;
1973 }
1974
1975 efi_status = enroll_file(data, filesize, FALSE);
1976 FreePool(data);
1977
1978 return efi_status;
1979 }
1980
1981 static BOOLEAN verify_pw(BOOLEAN * protected)
1982 {
1983 EFI_STATUS efi_status;
1984 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1985 UINT8 pwhash[PASSWORD_CRYPT_SIZE];
1986 UINTN size = PASSWORD_CRYPT_SIZE;
1987 UINT32 attributes;
1988 CHAR16 *message[2];
1989
1990 *protected = FALSE;
1991
1992 efi_status = gRT->GetVariable(L"MokPWStore", &SHIM_LOCK_GUID, &attributes,
1993 &size, pwhash);
1994 /*
1995 * If anything can attack the password it could just set it to a
1996 * known value, so there's no safety advantage in failing to validate
1997 * purely because of a failure to read the variable
1998 */
1999 if (EFI_ERROR(efi_status) ||
2000 (size != SHA256_DIGEST_SIZE && size != PASSWORD_CRYPT_SIZE))
2001 return TRUE;
2002
2003 if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
2004 return TRUE;
2005
2006 ST->ConOut->ClearScreen(ST->ConOut);
2007
2008 /* Draw the background */
2009 console_save_and_set_mode(&SavedMode);
2010 message[0] = PoolPrint(L"%s UEFI key management", SHIM_VENDOR);
2011 message[1] = NULL;
2012 console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
2013 FreePool(message[0]);
2014 console_restore_mode(&SavedMode);
2015
2016 if (size == PASSWORD_CRYPT_SIZE) {
2017 efi_status = match_password((PASSWORD_CRYPT *) pwhash, NULL, 0,
2018 NULL, L"Enter MOK password:");
2019 } else {
2020 efi_status = match_password(NULL, NULL, 0, pwhash,
2021 L"Enter MOK password:");
2022 }
2023 if (EFI_ERROR(efi_status)) {
2024 console_notify(L"Password limit reached");
2025 return FALSE;
2026 }
2027
2028 *protected = TRUE;
2029
2030 return TRUE;
2031 }
2032
2033 static int draw_countdown()
2034 {
2035 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
2036 SIMPLE_INPUT_INTERFACE *ci = ST->ConIn;
2037 SIMPLE_TEXT_OUTPUT_MODE SavedMode;
2038 EFI_INPUT_KEY key;
2039 EFI_STATUS efi_status;
2040 UINTN cols, rows;
2041 CHAR16 *title[2];
2042 CHAR16 *message = L"Press any key to perform MOK management";
2043 void *MokTimeout = NULL;
2044 MokTimeoutvar *var;
2045 UINTN MokTimeoutSize = 0;
2046 int timeout, wait = 10000000;
2047
2048 efi_status = get_variable(L"MokTimeout", (UINT8 **) &MokTimeout,
2049 &MokTimeoutSize, SHIM_LOCK_GUID);
2050 if (EFI_ERROR(efi_status)) {
2051 timeout = 10;
2052 } else {
2053 var = MokTimeout;
2054 timeout = (int)var->Timeout;
2055 FreePool(MokTimeout);
2056 LibDeleteVariable(L"MokTimeout", &SHIM_LOCK_GUID);
2057 }
2058
2059 if (timeout < 0)
2060 return timeout;
2061
2062 console_save_and_set_mode(&SavedMode);
2063
2064 title[0] = PoolPrint(L"%s UEFI key management", SHIM_VENDOR);
2065 title[1] = NULL;
2066
2067 console_print_box_at(title, -1, 0, 0, -1, -1, 1, 1);
2068
2069 co->QueryMode(co, co->Mode->Mode, &cols, &rows);
2070
2071 console_print_at((cols - StrLen(message)) / 2, rows / 2, message);
2072 while (1) {
2073 if (timeout > 1)
2074 console_print_at(2, rows - 3,
2075 L"Booting in %d seconds ",
2076 timeout);
2077 else if (timeout)
2078 console_print_at(2, rows - 3,
2079 L"Booting in %d second ",
2080 timeout);
2081
2082 efi_status = WaitForSingleEvent(ci->WaitForKey, wait);
2083 if (efi_status != EFI_TIMEOUT) {
2084 /* Clear the key in the queue */
2085 ci->ReadKeyStroke(ci, &key);
2086 break;
2087 }
2088
2089 timeout--;
2090 if (!timeout)
2091 break;
2092 }
2093
2094 FreePool(title[0]);
2095
2096 console_restore_mode(&SavedMode);
2097
2098 return timeout;
2099 }
2100
2101 typedef enum {
2102 MOK_BOOT,
2103 MOK_RESET_MOK,
2104 MOK_RESET_MOKX,
2105 MOK_ENROLL_MOK,
2106 MOK_ENROLL_MOKX,
2107 MOK_DELETE_MOK,
2108 MOK_DELETE_MOKX,
2109 MOK_CHANGE_SB,
2110 MOK_SET_PW,
2111 MOK_CHANGE_DB,
2112 MOK_KEY_ENROLL,
2113 MOK_HASH_ENROLL
2114 } mok_menu_item;
2115
2116 static void free_menu(mok_menu_item * menu_item, CHAR16 ** menu_strings)
2117 {
2118 if (menu_strings)
2119 FreePool(menu_strings);
2120
2121 if (menu_item)
2122 FreePool(menu_item);
2123 }
2124
2125 static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
2126 void *MokNew, UINTN MokNewSize,
2127 void *MokDel, UINTN MokDelSize,
2128 void *MokSB, UINTN MokSBSize,
2129 void *MokPW, UINTN MokPWSize,
2130 void *MokDB, UINTN MokDBSize,
2131 void *MokXNew, UINTN MokXNewSize,
2132 void *MokXDel, UINTN MokXDelSize)
2133 {
2134 CHAR16 **menu_strings = NULL;
2135 mok_menu_item *menu_item = NULL;
2136 int choice = 0;
2137 int mok_changed = 0;
2138 EFI_STATUS efi_status;
2139 UINT8 auth[PASSWORD_CRYPT_SIZE];
2140 UINTN auth_size = PASSWORD_CRYPT_SIZE;
2141 UINT32 attributes;
2142 BOOLEAN protected;
2143 CHAR16 *mok_mgmt_p[] = { L"Perform MOK management", NULL };
2144 EFI_STATUS ret = EFI_SUCCESS;
2145
2146 if (verify_pw(&protected) == FALSE)
2147 return EFI_ACCESS_DENIED;
2148
2149 if (protected == FALSE && draw_countdown() == 0)
2150 goto out;
2151
2152 while (choice >= 0) {
2153 UINTN menucount = 3, i = 0;
2154 UINT32 MokAuth = 0;
2155 UINT32 MokDelAuth = 0;
2156 UINT32 MokXAuth = 0;
2157 UINT32 MokXDelAuth = 0;
2158
2159 efi_status = gRT->GetVariable(L"MokAuth", &SHIM_LOCK_GUID,
2160 &attributes, &auth_size, auth);
2161 if (!EFI_ERROR(efi_status) &&
2162 (auth_size == SHA256_DIGEST_SIZE ||
2163 auth_size == PASSWORD_CRYPT_SIZE))
2164 MokAuth = 1;
2165
2166 efi_status = gRT->GetVariable(L"MokDelAuth", &SHIM_LOCK_GUID,
2167 &attributes, &auth_size, auth);
2168 if (!EFI_ERROR(efi_status) &&
2169 (auth_size == SHA256_DIGEST_SIZE ||
2170 auth_size == PASSWORD_CRYPT_SIZE))
2171 MokDelAuth = 1;
2172
2173 efi_status = gRT->GetVariable(L"MokXAuth", &SHIM_LOCK_GUID,
2174 &attributes, &auth_size, auth);
2175 if (!EFI_ERROR(efi_status) &&
2176 (auth_size == SHA256_DIGEST_SIZE ||
2177 auth_size == PASSWORD_CRYPT_SIZE))
2178 MokXAuth = 1;
2179
2180 efi_status = gRT->GetVariable(L"MokXDelAuth", &SHIM_LOCK_GUID,
2181 &attributes, &auth_size, auth);
2182 if (!EFI_ERROR(efi_status) &&
2183 (auth_size == SHA256_DIGEST_SIZE ||
2184 auth_size == PASSWORD_CRYPT_SIZE))
2185 MokXDelAuth = 1;
2186
2187 if (MokNew || MokAuth)
2188 menucount++;
2189
2190 if (MokDel || MokDelAuth)
2191 menucount++;
2192
2193 if (MokXNew || MokXAuth)
2194 menucount++;
2195
2196 if (MokXDel || MokXDelAuth)
2197 menucount++;
2198
2199 if (MokSB)
2200 menucount++;
2201
2202 if (MokPW)
2203 menucount++;
2204
2205 if (MokDB)
2206 menucount++;
2207
2208 menu_strings = AllocateZeroPool(sizeof(CHAR16 *) *
2209 (menucount + 1));
2210 if (!menu_strings)
2211 return EFI_OUT_OF_RESOURCES;
2212
2213 menu_item = AllocateZeroPool(sizeof(mok_menu_item) * menucount);
2214 if (!menu_item) {
2215 FreePool(menu_strings);
2216 return EFI_OUT_OF_RESOURCES;
2217 }
2218
2219 if (mok_changed)
2220 menu_strings[i] = L"Reboot";
2221 else
2222 menu_strings[i] = L"Continue boot";
2223 menu_item[i] = MOK_BOOT;
2224
2225 i++;
2226
2227 if (MokNew || MokAuth) {
2228 if (!MokNew) {
2229 menu_strings[i] = L"Reset MOK";
2230 menu_item[i] = MOK_RESET_MOK;
2231 } else {
2232 menu_strings[i] = L"Enroll MOK";
2233 menu_item[i] = MOK_ENROLL_MOK;
2234 }
2235 i++;
2236 }
2237
2238 if (MokDel || MokDelAuth) {
2239 menu_strings[i] = L"Delete MOK";
2240 menu_item[i] = MOK_DELETE_MOK;
2241 i++;
2242 }
2243
2244 if (MokXNew || MokXAuth) {
2245 if (!MokXNew) {
2246 menu_strings[i] = L"Reset MOKX";
2247 menu_item[i] = MOK_RESET_MOKX;
2248 } else {
2249 menu_strings[i] = L"Enroll MOKX";
2250 menu_item[i] = MOK_ENROLL_MOKX;
2251 }
2252 i++;
2253 }
2254
2255 if (MokXDel || MokXDelAuth) {
2256 menu_strings[i] = L"Delete MOKX";
2257 menu_item[i] = MOK_DELETE_MOKX;
2258 i++;
2259 }
2260
2261 if (MokSB) {
2262 menu_strings[i] = L"Change Secure Boot state";
2263 menu_item[i] = MOK_CHANGE_SB;
2264 i++;
2265 }
2266
2267 if (MokPW) {
2268 menu_strings[i] = L"Set MOK password";
2269 menu_item[i] = MOK_SET_PW;
2270 i++;
2271 }
2272
2273 if (MokDB) {
2274 menu_strings[i] = L"Change DB state";
2275 menu_item[i] = MOK_CHANGE_DB;
2276 i++;
2277 }
2278
2279 menu_strings[i] = L"Enroll key from disk";
2280 menu_item[i] = MOK_KEY_ENROLL;
2281 i++;
2282
2283 menu_strings[i] = L"Enroll hash from disk";
2284 menu_item[i] = MOK_HASH_ENROLL;
2285 i++;
2286
2287 menu_strings[i] = NULL;
2288
2289 choice = console_select(mok_mgmt_p, menu_strings, 0);
2290 if (choice < 0)
2291 goto out;
2292
2293 switch (menu_item[choice]) {
2294 case MOK_BOOT:
2295 goto out;
2296 case MOK_RESET_MOK:
2297 efi_status = mok_reset_prompt(FALSE);
2298 break;
2299 case MOK_ENROLL_MOK:
2300 if (!MokNew) {
2301 console_print(L"MokManager: internal error: %s",
2302 L"MokNew was !NULL but is now NULL\n");
2303 ret = EFI_ABORTED;
2304 goto out;
2305 }
2306 efi_status = mok_enrollment_prompt(MokNew, MokNewSize,
2307 TRUE, FALSE);
2308 if (!EFI_ERROR(efi_status))
2309 MokNew = NULL;
2310 break;
2311 case MOK_DELETE_MOK:
2312 if (!MokDel) {
2313 console_print(L"MokManager: internal error: %s",
2314 L"MokDel was !NULL but is now NULL\n");
2315 ret = EFI_ABORTED;
2316 goto out;
2317 }
2318 efi_status = mok_deletion_prompt(MokDel, MokDelSize,
2319 FALSE);
2320 if (!EFI_ERROR(efi_status))
2321 MokDel = NULL;
2322 break;
2323 case MOK_RESET_MOKX:
2324 efi_status = mok_reset_prompt(TRUE);
2325 break;
2326 case MOK_ENROLL_MOKX:
2327 if (!MokXNew) {
2328 console_print(L"MokManager: internal error: %s",
2329 L"MokXNew was !NULL but is now NULL\n");
2330 ret = EFI_ABORTED;
2331 goto out;
2332 }
2333 efi_status = mok_enrollment_prompt(MokXNew, MokXNewSize,
2334 TRUE, TRUE);
2335 if (!EFI_ERROR(efi_status))
2336 MokXNew = NULL;
2337 break;
2338 case MOK_DELETE_MOKX:
2339 if (!MokXDel) {
2340 console_print(L"MokManager: internal error: %s",
2341 L"MokXDel was !NULL but is now NULL\n");
2342 ret = EFI_ABORTED;
2343 goto out;
2344 }
2345 efi_status = mok_deletion_prompt(MokXDel, MokXDelSize,
2346 TRUE);
2347 if (!EFI_ERROR(efi_status))
2348 MokXDel = NULL;
2349 break;
2350 case MOK_CHANGE_SB:
2351 if (!MokSB) {
2352 console_print(L"MokManager: internal error: %s",
2353 L"MokSB was !NULL but is now NULL\n");
2354 ret = EFI_ABORTED;
2355 goto out;
2356 }
2357 efi_status = mok_sb_prompt(MokSB, MokSBSize);
2358 if (!EFI_ERROR(efi_status))
2359 MokSB = NULL;
2360 break;
2361 case MOK_SET_PW:
2362 if (!MokPW) {
2363 console_print(L"MokManager: internal error: %s",
2364 L"MokPW was !NULL but is now NULL\n");
2365 ret = EFI_ABORTED;
2366 goto out;
2367 }
2368 efi_status = mok_pw_prompt(MokPW, MokPWSize);
2369 if (!EFI_ERROR(efi_status))
2370 MokPW = NULL;
2371 break;
2372 case MOK_CHANGE_DB:
2373 if (!MokDB) {
2374 console_print(L"MokManager: internal error: %s",
2375 L"MokDB was !NULL but is now NULL\n");
2376 ret = EFI_ABORTED;
2377 goto out;
2378 }
2379 efi_status = mok_db_prompt(MokDB, MokDBSize);
2380 if (!EFI_ERROR(efi_status))
2381 MokDB = NULL;
2382 break;
2383 case MOK_KEY_ENROLL:
2384 efi_status = mok_key_enroll();
2385 break;
2386 case MOK_HASH_ENROLL:
2387 efi_status = mok_hash_enroll();
2388 break;
2389 }
2390
2391 if (!EFI_ERROR(efi_status))
2392 mok_changed = 1;
2393
2394 free_menu(menu_item, menu_strings);
2395 menu_item = NULL;
2396 menu_strings = NULL;
2397 }
2398
2399 out:
2400 free_menu(menu_item, menu_strings);
2401
2402 if (mok_changed)
2403 return reset_system();
2404
2405 console_reset();
2406
2407 return ret;
2408 }
2409
2410 static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
2411 {
2412 UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
2413 UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0;
2414 void *MokNew = NULL;
2415 void *MokDel = NULL;
2416 void *MokSB = NULL;
2417 void *MokPW = NULL;
2418 void *MokDB = NULL;
2419 void *MokXNew = NULL;
2420 void *MokXDel = NULL;
2421 EFI_STATUS efi_status;
2422
2423 efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize,
2424 SHIM_LOCK_GUID);
2425 if (!EFI_ERROR(efi_status)) {
2426 efi_status = LibDeleteVariable(L"MokNew", &SHIM_LOCK_GUID);
2427 if (EFI_ERROR(efi_status))
2428 console_notify(L"Failed to delete MokNew");
2429 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2430 console_error(L"Could not retrieve MokNew", efi_status);
2431 }
2432
2433 efi_status = get_variable(L"MokDel", (UINT8 **) & MokDel, &MokDelSize,
2434 SHIM_LOCK_GUID);
2435 if (!EFI_ERROR(efi_status)) {
2436 efi_status = LibDeleteVariable(L"MokDel", &SHIM_LOCK_GUID);
2437 if (EFI_ERROR(efi_status))
2438 console_notify(L"Failed to delete MokDel");
2439 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2440 console_error(L"Could not retrieve MokDel", efi_status);
2441 }
2442
2443 efi_status = get_variable(L"MokSB", (UINT8 **) & MokSB, &MokSBSize,
2444 SHIM_LOCK_GUID);
2445 if (!EFI_ERROR(efi_status)) {
2446 efi_status = LibDeleteVariable(L"MokSB", &SHIM_LOCK_GUID);
2447 if (EFI_ERROR(efi_status))
2448 console_notify(L"Failed to delete MokSB");
2449 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2450 console_error(L"Could not retrieve MokSB", efi_status);
2451 }
2452
2453 efi_status = get_variable(L"MokPW", (UINT8 **) & MokPW, &MokPWSize,
2454 SHIM_LOCK_GUID);
2455 if (!EFI_ERROR(efi_status)) {
2456 efi_status = LibDeleteVariable(L"MokPW", &SHIM_LOCK_GUID);
2457 if (EFI_ERROR(efi_status))
2458 console_notify(L"Failed to delete MokPW");
2459 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2460 console_error(L"Could not retrieve MokPW", efi_status);
2461 }
2462
2463 efi_status = get_variable(L"MokDB", (UINT8 **) & MokDB, &MokDBSize,
2464 SHIM_LOCK_GUID);
2465 if (!EFI_ERROR(efi_status)) {
2466 efi_status = LibDeleteVariable(L"MokDB", &SHIM_LOCK_GUID);
2467 if (EFI_ERROR(efi_status))
2468 console_notify(L"Failed to delete MokDB");
2469 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2470 console_error(L"Could not retrieve MokDB", efi_status);
2471 }
2472
2473 efi_status = get_variable(L"MokXNew", (UINT8 **) & MokXNew,
2474 &MokXNewSize, SHIM_LOCK_GUID);
2475 if (!EFI_ERROR(efi_status)) {
2476 efi_status = LibDeleteVariable(L"MokXNew", &SHIM_LOCK_GUID);
2477 if (EFI_ERROR(efi_status))
2478 console_notify(L"Failed to delete MokXNew");
2479 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2480 console_error(L"Could not retrieve MokXNew", efi_status);
2481 }
2482
2483 efi_status = get_variable(L"MokXDel", (UINT8 **) & MokXDel,
2484 &MokXDelSize, SHIM_LOCK_GUID);
2485 if (!EFI_ERROR(efi_status)) {
2486 efi_status = LibDeleteVariable(L"MokXDel", &SHIM_LOCK_GUID);
2487 if (EFI_ERROR(efi_status))
2488 console_notify(L"Failed to delete MokXDel");
2489 } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) {
2490 console_error(L"Could not retrieve MokXDel", efi_status);
2491 }
2492
2493 enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
2494 MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize,
2495 MokXNew, MokXNewSize, MokXDel, MokXDelSize);
2496
2497 if (MokNew)
2498 FreePool(MokNew);
2499
2500 if (MokDel)
2501 FreePool(MokDel);
2502
2503 if (MokSB)
2504 FreePool(MokSB);
2505
2506 if (MokPW)
2507 FreePool(MokPW);
2508
2509 if (MokDB)
2510 FreePool(MokDB);
2511
2512 if (MokXNew)
2513 FreePool(MokXNew);
2514
2515 if (MokXDel)
2516 FreePool(MokXDel);
2517
2518 LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID);
2519 LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID);
2520 LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID);
2521 LibDeleteVariable(L"MokXDelAuth", &SHIM_LOCK_GUID);
2522
2523 return EFI_SUCCESS;
2524 }
2525
2526 static EFI_STATUS setup_rand(void)
2527 {
2528 EFI_TIME time;
2529 EFI_STATUS efi_status;
2530 UINT64 seed;
2531 BOOLEAN status;
2532
2533 efi_status = gRT->GetTime(&time, NULL);
2534 if (EFI_ERROR(efi_status))
2535 return efi_status;
2536
2537 seed = ((UINT64) time.Year << 48) | ((UINT64) time.Month << 40) |
2538 ((UINT64) time.Day << 32) | ((UINT64) time.Hour << 24) |
2539 ((UINT64) time.Minute << 16) | ((UINT64) time.Second << 8) |
2540 ((UINT64) time.Daylight);
2541
2542 status = RandomSeed((UINT8 *) & seed, sizeof(seed));
2543 if (!status)
2544 return EFI_ABORTED;
2545
2546 return EFI_SUCCESS;
2547 }
2548
2549 EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * systab)
2550 {
2551 EFI_STATUS efi_status;
2552
2553 InitializeLib(image_handle, systab);
2554
2555 setup_rand();
2556
2557 efi_status = check_mok_request(image_handle);
2558
2559 console_fini();
2560 return efi_status;
2561 }