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