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