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