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