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