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