]>
Commit | Line | Data |
---|---|---|
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 |
31 | typedef struct { |
32 | UINT32 MokSize; | |
33 | UINT8 *Mok; | |
990dcdb6 | 34 | EFI_GUID Type; |
ae46cf9d | 35 | } __attribute__ ((packed)) MokListNode; |
481c1e1e | 36 | |
c1faa462 MG |
37 | typedef struct { |
38 | UINT32 MokSBState; | |
eb4c59b0 | 39 | UINT32 PWLen; |
afb61e79 | 40 | CHAR16 Password[SB_PASSWORD_LEN]; |
c1faa462 MG |
41 | } __attribute__ ((packed)) MokSBvar; |
42 | ||
ef0383d0 JB |
43 | typedef struct { |
44 | UINT32 MokDBState; | |
45 | UINT32 PWLen; | |
46 | CHAR16 Password[SB_PASSWORD_LEN]; | |
47 | } __attribute__ ((packed)) MokDBvar; | |
48 | ||
74718677 MTL |
49 | typedef struct { |
50 | INT32 Timeout; | |
51 | } __attribute__ ((packed)) MokTimeoutvar; | |
52 | ||
01b5d9c6 | 53 | static 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 | 86 | done: |
bfeaae23 | 87 | return efi_status; |
481c1e1e GCPL |
88 | } |
89 | ||
01b5d9c6 | 90 | static 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 | 104 | static 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 | 120 | static 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 |
137 | static 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 |
175 | static 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 |
238 | typedef struct { |
239 | int nid; | |
240 | CHAR16 *name; | |
241 | } NidName; | |
242 | ||
243 | static 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 | 252 | static 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 | 295 | static 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 | 311 | static 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 | 460 | static 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 | 510 | static 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 | 562 | static 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 | 593 | static 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 |
649 | static 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 |
697 | static 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 | 738 | done: |
bfeaae23 | 739 | return efi_status; |
7dc45398 GCPL |
740 | } |
741 | ||
01b5d9c6 | 742 | static 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 | 749 | static 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 |
781 | static 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 | 856 | static 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 |
896 | out: |
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 |
908 | static 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 |
971 | static 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 | 1009 | static 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 |
1043 | static 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 |
1133 | static 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 |
1153 | static 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 | 1169 | static 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 |
1180 | static 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 |
1223 | static 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 | 1247 | static 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 | 1380 | error: |
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 |
1391 | static 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 | 1430 | static 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 |
1457 | static 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 |
1572 | static 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 |
1687 | static 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 | 1747 | mokpw_done: |
b953468e | 1748 | LibDeleteVariable(L"MokPW", &SHIM_LOCK_GUID); |
077c2525 | 1749 | |
5202f80c | 1750 | return EFI_SUCCESS; |
e4889c52 MG |
1751 | } |
1752 | ||
01b5d9c6 | 1753 | static 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 | 1788 | static 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 | 1859 | out: |
e4889c52 MG |
1860 | if (mokbuffer) |
1861 | FreePool(mokbuffer); | |
1862 | ||
bfeaae23 | 1863 | return efi_status; |
e4889c52 MG |
1864 | } |
1865 | ||
5202f80c | 1866 | static 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 |
1912 | static CHAR16 *der_suffix[] = { |
1913 | L".cer", | |
1914 | L".der", | |
1915 | L".crt", | |
1916 | NULL | |
1917 | }; | |
1918 | ||
01b5d9c6 | 1919 | static 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 | 1940 | static 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 | 1992 | static 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 |
2044 | static 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 | 2073 | typedef 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 | 2088 | static 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 |
2097 | static 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 | 2371 | out: |
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 | ||
2382 | static 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 | 2498 | static 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 | 2521 | EFI_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 | } |