]> git.proxmox.com Git - efi-boot-shim.git/blame - MokManager.c
Fix menu items
[efi-boot-shim.git] / MokManager.c
CommitLineData
481c1e1e
GCPL
1#include <efi.h>
2#include <efilib.h>
3#include <Library/BaseCryptLib.h>
4#include <openssl/x509.h>
5#include "shim.h"
6
a737c142
GCPL
7#define PASSWORD_MAX 16
8#define PASSWORD_MIN 8
c83f3216 9
e4889c52
MG
10struct menu_item {
11 CHAR16 *text;
12 UINTN (* callback)(void *data, void *data2);
13 void *data;
14 void *data2;
15 UINTN colour;
16};
17
481c1e1e
GCPL
18typedef struct {
19 UINT32 MokSize;
20 UINT8 *Mok;
21} MokListNode;
22
481c1e1e
GCPL
23static EFI_INPUT_KEY get_keystroke (void)
24{
25 EFI_INPUT_KEY key;
26 UINTN EventIndex;
27
28 uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey,
29 &EventIndex);
30 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key);
31
32 return key;
33}
34
3b8cc123 35static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash)
481c1e1e
GCPL
36{
37 EFI_STATUS status;
38 unsigned int ctxsize;
39 void *ctx = NULL;
40
3b8cc123 41 ctxsize = Sha1GetContextSize();
481c1e1e
GCPL
42 ctx = AllocatePool(ctxsize);
43
44 if (!ctx) {
45 Print(L"Unable to allocate memory for hash context\n");
46 return EFI_OUT_OF_RESOURCES;
47 }
48
3b8cc123 49 if (!Sha1Init(ctx)) {
481c1e1e
GCPL
50 Print(L"Unable to initialise hash\n");
51 status = EFI_OUT_OF_RESOURCES;
52 goto done;
53 }
54
3b8cc123 55 if (!(Sha1Update(ctx, Data, DataSize))) {
481c1e1e
GCPL
56 Print(L"Unable to generate hash\n");
57 status = EFI_OUT_OF_RESOURCES;
58 goto done;
59 }
60
3b8cc123 61 if (!(Sha1Final(ctx, hash))) {
481c1e1e
GCPL
62 Print(L"Unable to finalise hash\n");
63 status = EFI_OUT_OF_RESOURCES;
64 goto done;
65 }
66
67 status = EFI_SUCCESS;
68done:
69 return status;
70}
71
72static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
73 MokListNode *list;
1d7c0f86
GCPL
74 INT64 remain = DataSize;
75 int i;
481c1e1e
GCPL
76 void *ptr;
77
ce238449
GCPL
78 if (DataSize < sizeof(UINT32))
79 return NULL;
80
481c1e1e
GCPL
81 list = AllocatePool(sizeof(MokListNode) * num);
82
83 if (!list) {
84 Print(L"Unable to allocate MOK list\n");
85 return NULL;
86 }
87
88 ptr = Data;
89 for (i = 0; i < num; i++) {
1d7c0f86
GCPL
90 CopyMem(&list[i].MokSize, ptr, sizeof(UINT32));
91 remain -= sizeof(UINT32) + list[i].MokSize;
92
481c1e1e 93 if (remain < 0) {
1d7c0f86 94 Print(L"the list was corrupted\n");
481c1e1e
GCPL
95 FreePool(list);
96 return NULL;
97 }
98
481c1e1e
GCPL
99 ptr += sizeof(UINT32);
100 list[i].Mok = ptr;
101 ptr += list[i].MokSize;
481c1e1e
GCPL
102 }
103
104 return list;
105}
106
ff8d867c 107static void print_x509_name (X509_NAME *X509Name, CHAR16 *name)
481c1e1e
GCPL
108{
109 char *str;
110
111 str = X509_NAME_oneline(X509Name, NULL, 0);
112 if (str) {
ff8d867c 113 Print(L" %s:\n %a\n", name, str);
481c1e1e
GCPL
114 OPENSSL_free(str);
115 }
116}
117
118static const char *mon[12]= {
119"Jan","Feb","Mar","Apr","May","Jun",
120"Jul","Aug","Sep","Oct","Nov","Dec"
121};
122
ff8d867c
GCPL
123static void print_x509_GENERALIZEDTIME_time (ASN1_TIME *time, CHAR16 *time_string)
124{
481c1e1e
GCPL
125 char *v;
126 int gmt = 0;
127 int i;
128 int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0;
129 char *f = NULL;
130 int f_len = 0;
131
132 i=time->length;
133 v=(char *)time->data;
134
135 if (i < 12)
136 goto error;
137
138 if (v[i-1] == 'Z')
139 gmt=1;
140
141 for (i=0; i<12; i++) {
142 if ((v[i] > '9') || (v[i] < '0'))
143 goto error;
144 }
145
146 y = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0');
147 M = (v[4]-'0')*10+(v[5]-'0');
148
149 if ((M > 12) || (M < 1))
150 goto error;
151
152 d = (v[6]-'0')*10+(v[7]-'0');
153 h = (v[8]-'0')*10+(v[9]-'0');
154 m = (v[10]-'0')*10+(v[11]-'0');
155
156 if (time->length >= 14 &&
157 (v[12] >= '0') && (v[12] <= '9') &&
158 (v[13] >= '0') && (v[13] <= '9')) {
159 s = (v[12]-'0')*10+(v[13]-'0');
160 /* Check for fractions of seconds. */
161 if (time->length >= 15 && v[14] == '.') {
162 int l = time->length;
163 f = &v[14]; /* The decimal point. */
164 f_len = 1;
ff8d867c
GCPL
165 while (14 + f_len < l && f[f_len] >= '0' &&
166 f[f_len] <= '9')
481c1e1e
GCPL
167 ++f_len;
168 }
169 }
170
ff8d867c
GCPL
171 SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d%.*a %d%a",
172 mon[M-1], d, h, m, s, f_len, f, y, (gmt)?" GMT":"");
481c1e1e
GCPL
173error:
174 return;
175}
176
ff8d867c 177static void print_x509_UTCTIME_time (ASN1_TIME *time, CHAR16 *time_string)
481c1e1e
GCPL
178{
179 char *v;
180 int gmt=0;
181 int i;
182 int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0;
183
184 i=time->length;
185 v=(char *)time->data;
186
187 if (i < 10)
188 goto error;
189
190 if (v[i-1] == 'Z')
191 gmt=1;
192
193 for (i=0; i<10; i++)
194 if ((v[i] > '9') || (v[i] < '0'))
195 goto error;
196
197 y = (v[0]-'0')*10+(v[1]-'0');
198
199 if (y < 50)
200 y+=100;
201
202 M = (v[2]-'0')*10+(v[3]-'0');
203
204 if ((M > 12) || (M < 1))
205 goto error;
206
207 d = (v[4]-'0')*10+(v[5]-'0');
208 h = (v[6]-'0')*10+(v[7]-'0');
209 m = (v[8]-'0')*10+(v[9]-'0');
210
211 if (time->length >=12 &&
212 (v[10] >= '0') && (v[10] <= '9') &&
213 (v[11] >= '0') && (v[11] <= '9'))
214 s = (v[10]-'0')*10+(v[11]-'0');
215
ff8d867c
GCPL
216 SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d %d%a",
217 mon[M-1], d, h, m, s, y+1900, (gmt)?" GMT":"");
481c1e1e
GCPL
218error:
219 return;
220}
221
ff8d867c 222static void print_x509_time (ASN1_TIME *time, CHAR16 *name)
481c1e1e 223{
ff8d867c
GCPL
224 CHAR16 time_string[30];
225
caf006b4 226 if (time->type == V_ASN1_UTCTIME) {
ff8d867c 227 print_x509_UTCTIME_time(time, time_string);
caf006b4 228 } else if (time->type == V_ASN1_GENERALIZEDTIME) {
ff8d867c 229 print_x509_GENERALIZEDTIME_time(time, time_string);
caf006b4
GCPL
230 } else {
231 time_string[0] = '\0';
232 }
ff8d867c
GCPL
233
234 Print(L" %s:\n %s\n", name, time_string);
481c1e1e
GCPL
235}
236
237static void show_x509_info (X509 *X509Cert)
238{
ff8d867c
GCPL
239 ASN1_INTEGER *serial;
240 BIGNUM *bnser;
241 unsigned char hexbuf[30];
481c1e1e
GCPL
242 X509_NAME *X509Name;
243 ASN1_TIME *time;
244
ff8d867c
GCPL
245 serial = X509_get_serialNumber(X509Cert);
246 if (serial) {
247 int i, n;
248 bnser = ASN1_INTEGER_to_BN(serial, NULL);
249 n = BN_bn2bin(bnser, hexbuf);
250 Print(L" Serial Number:\n ");
251 for (i = 0; i < n-1; i++) {
252 Print(L"%02x:", hexbuf[i]);
253 }
254 Print(L"%02x\n", hexbuf[n-1]);
255 }
256
481c1e1e
GCPL
257 X509Name = X509_get_issuer_name(X509Cert);
258 if (X509Name) {
ff8d867c 259 print_x509_name(X509Name, L"Issuer");
481c1e1e
GCPL
260 }
261
262 X509Name = X509_get_subject_name(X509Cert);
263 if (X509Name) {
ff8d867c 264 print_x509_name(X509Name, L"Subject");
481c1e1e
GCPL
265 }
266
267 time = X509_get_notBefore(X509Cert);
268 if (time) {
ff8d867c 269 print_x509_time(time, L"Validity from");
481c1e1e
GCPL
270 }
271
272 time = X509_get_notAfter(X509Cert);
273 if (time) {
ff8d867c 274 print_x509_time(time, L"Validity till");
481c1e1e
GCPL
275 }
276}
277
278static void show_mok_info (void *Mok, UINTN MokSize)
279{
280 EFI_STATUS efi_status;
3b8cc123 281 UINT8 hash[SHA1_DIGEST_SIZE];
481c1e1e
GCPL
282 unsigned int i;
283 X509 *X509Cert;
284
285 if (!Mok || MokSize == 0)
286 return;
287
ff8d867c
GCPL
288 if (X509ConstructCertificate(Mok, MokSize, (UINT8 **) &X509Cert) &&
289 X509Cert != NULL) {
290 show_x509_info(X509Cert);
291 X509_free(X509Cert);
292 } else {
e4889c52
MG
293 Print(L" Not a valid X509 certificate: %x\n\n",
294 ((UINT32 *)Mok)[0]);
ff8d867c
GCPL
295 return;
296 }
297
3b8cc123 298 efi_status = get_sha1sum(Mok, MokSize, hash);
481c1e1e
GCPL
299
300 if (efi_status != EFI_SUCCESS) {
301 Print(L"Failed to compute MOK fingerprint\n");
302 return;
303 }
304
3b8cc123
GCPL
305 Print(L" Fingerprint (SHA1):\n ");
306 for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
481c1e1e 307 Print(L" %02x", hash[i]);
3b8cc123 308 if (i % 10 == 9)
ff8d867c 309 Print(L"\n ");
481c1e1e 310 }
ff8d867c 311 Print(L"\n");
481c1e1e
GCPL
312}
313
12e2d625
GCPL
314static INTN get_number ()
315{
316 EFI_INPUT_KEY input_key;
317 CHAR16 input[10];
318 int count = 0;
319
320 do {
321 input_key = get_keystroke();
322
323 if ((input_key.UnicodeChar < '0' ||
324 input_key.UnicodeChar > '9' ||
325 count >= 10) &&
326 input_key.UnicodeChar != CHAR_BACKSPACE) {
327 continue;
328 }
329
330 if (count == 0 && input_key.UnicodeChar == CHAR_BACKSPACE)
331 continue;
332
333 Print(L"%c", input_key.UnicodeChar);
334
335 if (input_key.UnicodeChar == CHAR_BACKSPACE) {
336 input[--count] = '\0';
337 continue;
338 }
339
340 input[count++] = input_key.UnicodeChar;
341 } while (input_key.UnicodeChar != CHAR_CARRIAGE_RETURN);
342
343 if (count == 0)
344 return -1;
345
346 input[count] = '\0';
347
348 return (INTN)Atoi(input);
349}
350
1d7c0f86 351static UINT8 list_keys (void *MokNew, UINTN MokNewSize)
481c1e1e 352{
481c1e1e 353 UINT32 MokNum;
1d7c0f86 354 MokListNode *keys = NULL;
12e2d625
GCPL
355 INTN key_num = 0;
356 UINT8 initial = 1;
481c1e1e 357
1d7c0f86 358 CopyMem(&MokNum, MokNew, sizeof(UINT32));
481c1e1e 359 if (MokNum == 0) {
1d7c0f86 360 Print(L"No key exists\n");
b3868602 361 return 0;
481c1e1e 362 }
481c1e1e 363
1d7c0f86
GCPL
364 keys = build_mok_list(MokNum,
365 (void *)MokNew + sizeof(UINT32),
366 MokNewSize - sizeof(UINT32));
367
368 if (!keys) {
369 Print(L"Failed to construct key list in MokNew\n");
b3868602 370 return 0;
481c1e1e
GCPL
371 }
372
12e2d625
GCPL
373 do {
374 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
375 Print(L"Input the key number to show the details of the key or\n"
376 L"type \'0\' to continue\n\n");
377 Print(L"%d key(s) in the new key list\n\n", MokNum);
378
379 if (key_num > MokNum) {
419c5e35 380 Print(L"[Key %d]\n", key_num);
12e2d625 381 Print(L"No such key\n\n");
0e81abac 382 } else if (initial != 1 && key_num > 0){
12e2d625
GCPL
383 Print(L"[Key %d]\n", key_num);
384 show_mok_info(keys[key_num-1].Mok, keys[key_num-1].MokSize);
385 }
386
387 Print(L"Key Number: ");
388
389 key_num = get_number();
390
391 Print(L"\n\n");
392
393 if (key_num == -1)
394 continue;
395
396 initial = 0;
397 } while (key_num != 0);
481c1e1e 398
b3868602 399 FreePool(keys);
1d7c0f86 400
b3868602 401 return 1;
481c1e1e
GCPL
402}
403
8bddd681 404static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show)
481c1e1e
GCPL
405{
406 EFI_INPUT_KEY key;
8bddd681
GCPL
407 int count = 0;
408
409 do {
410 key = get_keystroke();
411
412 if ((count >= line_max &&
413 key.UnicodeChar != CHAR_BACKSPACE) ||
414 key.UnicodeChar == CHAR_NULL ||
415 key.UnicodeChar == CHAR_TAB ||
416 key.UnicodeChar == CHAR_LINEFEED ||
417 key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
418 continue;
419 }
420
421 if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
422 continue;
423 } else if (key.UnicodeChar == CHAR_BACKSPACE) {
424 if (show) {
425 Print(L"\b");
426 }
427 line[--count] = '\0';
428 continue;
429 }
430
431 if (show) {
432 Print(L"%c", key.UnicodeChar);
433 }
434
435 line[count++] = key.UnicodeChar;
436 } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
437 Print(L"\n");
438
439 *length = count;
440
441 return 1;
442}
443
7dc45398
GCPL
444static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *password,
445 UINT32 pw_length, UINT8 *hash)
446{
447 EFI_STATUS status;
448 unsigned int ctxsize;
449 void *ctx = NULL;
450
451 ctxsize = Sha256GetContextSize();
452 ctx = AllocatePool(ctxsize);
453
454 if (!ctx) {
455 Print(L"Unable to allocate memory for hash context\n");
456 return EFI_OUT_OF_RESOURCES;
457 }
458
459 if (!Sha256Init(ctx)) {
460 Print(L"Unable to initialise hash\n");
461 status = EFI_OUT_OF_RESOURCES;
462 goto done;
463 }
464
465 if (!(Sha256Update(ctx, MokNew, MokNewSize))) {
466 Print(L"Unable to generate hash\n");
467 status = EFI_OUT_OF_RESOURCES;
468 goto done;
469 }
470
471 if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) {
472 Print(L"Unable to generate hash\n");
473 status = EFI_OUT_OF_RESOURCES;
474 goto done;
475 }
476
477 if (!(Sha256Final(ctx, hash))) {
478 Print(L"Unable to finalise hash\n");
479 status = EFI_OUT_OF_RESOURCES;
480 goto done;
481 }
482
483 status = EFI_SUCCESS;
484done:
485 return status;
486}
487
f42825e6 488static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize)
481c1e1e
GCPL
489{
490 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
491 EFI_STATUS efi_status;
7dc45398
GCPL
492 UINT8 hash[SHA256_DIGEST_SIZE];
493 UINT8 auth[SHA256_DIGEST_SIZE];
494 UINTN auth_size;
495 UINT32 attributes;
a737c142 496 CHAR16 password[PASSWORD_MAX];
7dc45398
GCPL
497 UINT32 pw_length;
498 UINT8 fail_count = 0;
499
500 auth_size = SHA256_DIGEST_SIZE;
501 efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
502 &shim_lock_guid,
503 &attributes, &auth_size, auth);
504
505
506 if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
507 Print(L"Failed to get MokAuth %d\n", efi_status);
508 return efi_status;
509 }
510
511 while (fail_count < 3) {
a737c142
GCPL
512 Print(L"Password(%d-%d characters): ",
513 PASSWORD_MIN, PASSWORD_MAX);
8bddd681 514 get_line(&pw_length, password, PASSWORD_MAX, 0);
7dc45398
GCPL
515
516 if (pw_length < 8) {
a737c142
GCPL
517 Print(L"At least %d characters for the password\n",
518 PASSWORD_MIN);
7dc45398
GCPL
519 }
520
521 efi_status = compute_pw_hash(MokNew, MokNewSize, password,
522 pw_length, hash);
523
524 if (efi_status != EFI_SUCCESS) {
525 return efi_status;
526 }
527
7ad1f3b8 528 if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) {
a737c142 529 Print(L"Password doesn't match\n");
7dc45398
GCPL
530 fail_count++;
531 } else {
532 break;
533 }
534 }
535
536 if (fail_count >= 3)
537 return EFI_ACCESS_DENIED;
481c1e1e
GCPL
538
539 /* Write new MOK */
481c1e1e
GCPL
540 efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
541 &shim_lock_guid,
542 EFI_VARIABLE_NON_VOLATILE
543 | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1d7c0f86 544 MokNewSize, MokNew);
481c1e1e
GCPL
545 if (efi_status != EFI_SUCCESS) {
546 Print(L"Failed to set variable %d\n", efi_status);
f42825e6 547 return efi_status;
481c1e1e
GCPL
548 }
549
f42825e6 550 return EFI_SUCCESS;
481c1e1e
GCPL
551}
552
e4889c52
MG
553static UINTN mok_enrollment_prompt (void *MokNew, void *data2) {
554 CHAR16 line[1];
555 UINT32 length;
556 UINTN MokNewSize = (UINTN)data2;
481c1e1e 557 EFI_STATUS efi_status;
481c1e1e 558
e4889c52
MG
559 do {
560 if (!list_keys(MokNew, MokNewSize)) {
561 return 0;
562 }
481c1e1e 563
e4889c52 564 Print(L"Enroll the key(s)? (y/n): ");
481c1e1e 565
e4889c52 566 get_line (&length, line, 1, 1);
481c1e1e 567
e4889c52
MG
568 if (line[0] == 'Y' || line[0] == 'y') {
569 efi_status = store_keys(MokNew, MokNewSize);
481c1e1e 570
e4889c52
MG
571 if (efi_status != EFI_SUCCESS) {
572 Print(L"Failed to enroll keys\n");
573 return -1;
574 }
575 return 0;
576 }
577 } while (line[0] != 'N' && line[0] != 'n');
578 return -1;
579}
580
581static UINTN mok_deletion_prompt (void *MokNew, void *data2) {
582 CHAR16 line[1];
583 UINT32 length;
584 EFI_STATUS efi_status;
585
586 Print(L"Erase all stored keys? (y/N): ");
587
588 get_line (&length, line, 1, 1);
589
590 if (line[0] == 'Y' || line[0] == 'y') {
f42825e6 591 efi_status = store_keys(MokNew, sizeof(UINT32));
481c1e1e 592
f42825e6
GCPL
593 if (efi_status != EFI_SUCCESS) {
594 Print(L"Failed to erase keys\n");
e4889c52 595 return -1;
f42825e6 596 }
e4889c52 597 }
f42825e6 598
e4889c52
MG
599 return 0;
600}
481c1e1e 601
e4889c52
MG
602void draw_menu (struct menu_item *items, UINTN count) {
603 UINTN i;
f42825e6 604
e4889c52
MG
605 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
606
607 for (i = 0; i < count; i++) {
608 uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
609 items[i].colour | EFI_BACKGROUND_BLACK);
610 Print(L" %s\n", items[i].text);
611 }
612
613 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0);
614 uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
615}
616
617void run_menu (struct menu_item *items, UINTN count) {
618 UINTN index, pos = 0;
619 EFI_INPUT_KEY key;
620
621 draw_menu (items, count);
622
623 while (1) {
624 uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut,
625 0, pos);
626 uefi_call_wrapper(BS->WaitForEvent, 3, 1,
627 &ST->ConIn->WaitForKey, &index);
628 uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn,
629 &key);
630
631 switch(key.ScanCode) {
632 case SCAN_UP:
633 if (pos == 0)
634 continue;
635 pos--;
636 continue;
637 break;
638 case SCAN_DOWN:
639 if (pos == (count - 1))
640 continue;
641 pos++;
642 continue;
643 break;
f42825e6 644 }
e4889c52
MG
645
646 switch(key.UnicodeChar) {
647 case CHAR_LINEFEED:
648 case CHAR_CARRIAGE_RETURN:
649 if (items[pos].callback == NULL)
650 return;
651
652 items[pos].callback(items[pos].data, items[pos].data2);
653 draw_menu (items, count);
654 pos = 0;
655 break;
656 }
657 }
658}
659
660UINTN file_callback (void *data, void *data2) {
661 EFI_FILE_INFO *buffer = NULL;
662 UINTN buffersize = 0, readsize;
663 EFI_STATUS status;
664 EFI_FILE *file;
665 CHAR16 *filename = data;
666 EFI_FILE *parent = data2;
667 EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
668 void *mokbuffer = NULL;
669 void *filebuffer;
670
671 status = uefi_call_wrapper(parent->Open, 5, parent, &file, filename,
672 EFI_FILE_MODE_READ, 0);
673
674 if (status != EFI_SUCCESS)
675 return 1;
676
677 status = uefi_call_wrapper(file->GetInfo, 4, file, &file_info_guid,
678 &buffersize, buffer);
679
680 if (status == EFI_BUFFER_TOO_SMALL) {
681 buffer = AllocatePool(buffersize);
682 status = uefi_call_wrapper(file->GetInfo, 4, file,
683 &file_info_guid, &buffersize,
684 buffer);
f42825e6 685 }
e4889c52
MG
686
687 if (!buffer)
688 return 0;
689
690 readsize = buffer->FileSize;
691
692 mokbuffer = AllocateZeroPool(readsize + (2 * sizeof(UINT32)));
693 if (!mokbuffer)
694 goto out;
695
696 ((UINT32 *)mokbuffer)[0] = 1;
697 ((UINT32 *)mokbuffer)[1] = readsize;
698 filebuffer = (UINT32 *)mokbuffer + 2;
699
700 status = uefi_call_wrapper(file->Read, 3, file, &readsize, filebuffer);
701
702 if (status != EFI_SUCCESS)
703 goto out;
704
705 mok_enrollment_prompt(mokbuffer,
706 (void *)buffer->FileSize + (2 * sizeof(UINT32)));
707out:
708 if (buffer)
709 FreePool(buffer);
710
711 if (mokbuffer)
712 FreePool(mokbuffer);
713
714 return 0;
715}
716
717UINTN directory_callback (void *data, void *data2) {
718 EFI_FILE_INFO *buffer = NULL;
719 UINTN buffersize = 0;
720 EFI_STATUS status;
721 UINTN dircount = 0, i = 0;
722 struct menu_item *dircontent;
723 EFI_FILE *dir;
724 CHAR16 *filename = data;
725 EFI_FILE *root = data2;
726
727 status = uefi_call_wrapper(root->Open, 5, root, &dir, filename,
728 EFI_FILE_MODE_READ, 0);
729
730 if (status != EFI_SUCCESS)
731 return 1;
732
733 while (1) {
734 status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize,
735 buffer);
736
737 if (status == EFI_BUFFER_TOO_SMALL) {
738 buffer = AllocatePool(buffersize);
739 status = uefi_call_wrapper(dir->Read, 3, dir,
740 &buffersize, buffer);
741 }
742
743 if (status != EFI_SUCCESS)
744 return 1;
745
746 if (!buffersize)
747 break;
748
749 if ((StrCmp(buffer->FileName, L".") == 0) ||
750 (StrCmp(buffer->FileName, L"..") == 0))
751 continue;
752
753 dircount++;
754
755 FreePool(buffer);
756 buffersize = 0;
757 }
758
759 dircount++;
760
761 dircontent = AllocatePool(sizeof(struct menu_item) * dircount);
762
763 dircontent[0].text = StrDuplicate(L"..");
764 dircontent[0].callback = NULL;
765 dircontent[0].colour = EFI_YELLOW;
766 i++;
767
768 uefi_call_wrapper(dir->SetPosition, 2, dir, 0);
769
770 while (1) {
771 status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize,
772 buffer);
773
774 if (status == EFI_BUFFER_TOO_SMALL) {
775 buffer = AllocatePool(buffersize);
776 status = uefi_call_wrapper(dir->Read, 3, dir,
777 &buffersize, buffer);
778 }
779
780 if (status != EFI_SUCCESS)
781 return 1;
782
783 if (!buffersize)
784 break;
785
786 if ((StrCmp(buffer->FileName, L".") == 0) ||
787 (StrCmp(buffer->FileName, L"..") == 0))
788 continue;
789
790 if (buffer->Attribute & EFI_FILE_DIRECTORY) {
791 dircontent[i].text = StrDuplicate(buffer->FileName);
792 dircontent[i].callback = directory_callback;
793 dircontent[i].data = dircontent[i].text;
794 dircontent[i].data2 = dir;
795 dircontent[i].colour = EFI_YELLOW;
796 } else {
797 dircontent[i].text = StrDuplicate(buffer->FileName);
798 dircontent[i].callback = file_callback;
799 dircontent[i].data = dircontent[i].text;
800 dircontent[i].data2 = dir;
801 dircontent[i].colour = EFI_WHITE;
802 }
803
804 i++;
805 FreePool(buffer);
806 buffersize = 0;
807 buffer = NULL;
808 }
809
810 run_menu(dircontent, dircount);
811
812 return 0;
813}
814
815UINTN filesystem_callback (void *data, void *data2) {
816 EFI_FILE_INFO *buffer = NULL;
817 UINTN buffersize = 0;
818 EFI_STATUS status;
819 UINTN dircount = 0, i = 0;
820 struct menu_item *dircontent;
821 EFI_FILE *root = data;
822 EFI_FILE *parent = data2;
823
824 uefi_call_wrapper(root->SetPosition, 2, root, 0);
825
826 while (1) {
827 status = uefi_call_wrapper(root->Read, 3, root, &buffersize,
828 buffer);
829
830 if (status == EFI_BUFFER_TOO_SMALL) {
831 buffer = AllocatePool(buffersize);
832 status = uefi_call_wrapper(root->Read, 3, root,
833 &buffersize, buffer);
834 }
835
836 if (status != EFI_SUCCESS)
837 return 1;
838
839 if (!buffersize)
840 break;
841
842 if ((StrCmp(buffer->FileName, L".") == 0) ||
843 (StrCmp(buffer->FileName, L"..") == 0))
844 continue;
845
846 dircount++;
847
848 FreePool(buffer);
849 buffersize = 0;
850 }
851
852 if (parent)
853 dircount++;
854
855 dircontent = AllocatePool(sizeof(struct menu_item) * dircount);
856
857 dircontent[0].text = StrDuplicate(L"Return to filesystem list");
858 dircontent[0].callback = NULL;
859 dircontent[0].colour = EFI_YELLOW;
860 i++;
861
862 uefi_call_wrapper(root->SetPosition, 2, root, 0);
863
864 while (1) {
865 status = uefi_call_wrapper(root->Read, 3, root, &buffersize,
866 buffer);
867
868 if (status == EFI_BUFFER_TOO_SMALL) {
869 buffer = AllocatePool(buffersize);
870 status = uefi_call_wrapper(root->Read, 3, root,
871 &buffersize, buffer);
872 }
873
874 if (status != EFI_SUCCESS)
875 return 1;
876
877 if (!buffersize)
878 break;
879
880 if ((StrCmp(buffer->FileName, L".") == 0) ||
881 (StrCmp(buffer->FileName, L"..") == 0))
882 continue;
883
884 if (buffer->Attribute & EFI_FILE_DIRECTORY) {
885 dircontent[i].text = StrDuplicate(buffer->FileName);
886 dircontent[i].callback = directory_callback;
887 dircontent[i].data = dircontent[i].text;
888 dircontent[i].data2 = root;
889 dircontent[i].colour = EFI_YELLOW;
890 } else {
891 dircontent[i].text = StrDuplicate(buffer->FileName);
892 dircontent[i].callback = file_callback;
893 dircontent[i].data = dircontent[i].text;
894 dircontent[i].data2 = root;
895 dircontent[i].colour = EFI_WHITE;
896 }
897
898 i++;
899 FreePool(buffer);
900 buffer = NULL;
901 buffersize = 0;
902 }
903
904 run_menu(dircontent, dircount);
905
906 return 0;
907}
908
909UINTN find_fs (void *data, void *data2) {
910 EFI_GUID fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL;
911 UINTN count, i;
912 EFI_HANDLE **filesystem_handles;
913 struct menu_item *filesystems;
914
915 uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &fs_guid,
916 NULL, &count, &filesystem_handles);
917
918 if (!count || !filesystem_handles) {
919 Print(L"No filesystems?\n");
920 return 1;
921 }
922
923 count++;
924
925 filesystems = AllocatePool(sizeof(struct menu_item) * count);
926
927 filesystems[0].text = StrDuplicate(L"Exit");
928 filesystems[0].callback = NULL;
929 filesystems[0].colour = EFI_YELLOW;
930
931 for (i=1; i<count; i++) {
932 EFI_HANDLE *fs = filesystem_handles[i-1];
933 EFI_FILE_IO_INTERFACE *fs_interface;
934 EFI_DEVICE_PATH *path;
935 EFI_FILE *root;
936 EFI_STATUS status;
937 CHAR16 *VolumeLabel = NULL;
938 EFI_FILE_SYSTEM_INFO *buffer = NULL;
939 UINTN buffersize = 0;
940 EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
941
942 status = uefi_call_wrapper(BS->HandleProtocol, 3, fs, &fs_guid,
943 &fs_interface);
944
945 if (status != EFI_SUCCESS || !fs_interface)
946 continue;
947
948 path = DevicePathFromHandle(fs);
949
950 status = uefi_call_wrapper(fs_interface->OpenVolume, 2,
951 fs_interface, &root);
952
953 if (status != EFI_SUCCESS || !root)
954 continue;
955
956 status = uefi_call_wrapper(root->GetInfo, 4, root,
957 &file_info_guid, &buffersize,
958 buffer);
959
960 if (status == EFI_BUFFER_TOO_SMALL) {
961 buffer = AllocatePool(buffersize);
962 status = uefi_call_wrapper(root->GetInfo, 4, root,
963 &file_info_guid,
964 &buffersize, buffer);
965 }
966
967 if (status == EFI_SUCCESS)
968 VolumeLabel = buffer->VolumeLabel;
969
970 if (path)
971 filesystems[i].text = DevicePathToStr(path);
972 else
973 filesystems[i].text = StrDuplicate(L"Unknown device\n");
974 if (VolumeLabel)
975 StrCat(filesystems[i].text, VolumeLabel);
976
977 if (buffersize)
978 FreePool(buffer);
979
980 filesystems[i].data = root;
981 filesystems[i].data2 = NULL;
982 filesystems[i].callback = filesystem_callback;
983 filesystems[i].colour = EFI_YELLOW;
984 }
985
986 uefi_call_wrapper(BS->FreePool, 1, filesystem_handles);
987
988 run_menu(filesystems, count);
989
990 return 0;
991}
992
d2188bbf 993static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew)
e4889c52 994{
d2188bbf 995 struct menu_item *menu_item;
e4889c52 996 UINT32 MokNum;
d2188bbf
MG
997 UINTN menucount = 0;
998
999 if (MokNew)
1000 menu_item = AllocatePool(sizeof(struct menu_item) * 3);
1001 else
1002 menu_item = AllocatePool(sizeof(struct menu_item) * 2);
1003
1004 if (!menu_item)
1005 return EFI_OUT_OF_RESOURCES;
e4889c52
MG
1006
1007 menu_item[0].text = StrDuplicate(L"Continue boot");
1008 menu_item[0].colour = EFI_WHITE;
1009 menu_item[0].callback = NULL;
1010
d2188bbf
MG
1011 menucount++;
1012
1013 if (MokNew) {
1014 CopyMem(&MokNum, MokNew, sizeof(UINT32));
1015 if (MokNum == 0) {
1016 menu_item[1].text = StrDuplicate(L"Delete MOK");
1017 menu_item[1].colour = EFI_WHITE;
1018 menu_item[1].data = MokNew;
1019 menu_item[1].callback = mok_deletion_prompt;
1020 } else {
1021 menu_item[1].text = StrDuplicate(L"Enroll MOK\n");
1022 menu_item[1].colour = EFI_WHITE;
1023 menu_item[1].data = MokNew;
1024 menu_item[1].callback = mok_enrollment_prompt;
1025 }
1026 menucount++;
e4889c52
MG
1027 }
1028
d2188bbf
MG
1029 menu_item[menucount].text = StrDuplicate(L"Enroll key from disk");
1030 menu_item[menucount].colour = EFI_WHITE;
1031 menu_item[menucount].callback = find_fs;
e4889c52 1032
d2188bbf 1033 run_menu(menu_item, menucount);
e4889c52
MG
1034
1035 return 0;
1036}
1037
1038static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1039{
1040 EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1041 UINTN MokNewSize = 0;
1042 void *MokNew = NULL;
1043
1044 MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize);
1045
e4889c52
MG
1046 enter_mok_menu(image_handle, MokNew);
1047
1d7c0f86 1048 if (MokNew) {
000e2351 1049 if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
481c1e1e
GCPL
1050 Print(L"Failed to delete MokNew\n");
1051 }
1d7c0f86 1052 FreePool (MokNew);
481c1e1e 1053 }
000e2351 1054 LibDeleteVariable(L"MokAuth", &shim_lock_guid);
481c1e1e 1055
481c1e1e
GCPL
1056 return EFI_SUCCESS;
1057}
1058
1059EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
1060{
1061 EFI_STATUS efi_status;
1062
1063 InitializeLib(image_handle, systab);
1064
1065 efi_status = check_mok_request(image_handle);
1066
1067 return efi_status;
1068}