]>
Commit | Line | Data |
---|---|---|
333bd977 GCPL |
1 | #include <efi.h> |
2 | #include <efilib.h> | |
3 | #include <Library/BaseCryptLib.h> | |
4 | #include <openssl/x509.h> | |
5 | #include "shim.h" | |
0a6565c5 MG |
6 | #include "signature.h" |
7 | #include "PeImage.h" | |
333bd977 | 8 | |
aa8e9067 GCPL |
9 | #define PASSWORD_MAX 16 |
10 | #define PASSWORD_MIN 8 | |
9272bc5b | 11 | #define SB_PASSWORD_LEN 8 |
ff857b4b | 12 | |
e204505d MG |
13 | #ifndef SHIM_VENDOR |
14 | #define SHIM_VENDOR L"Shim" | |
15 | #endif | |
16 | ||
0a6565c5 MG |
17 | #define EFI_VARIABLE_APPEND_WRITE 0x00000040 |
18 | ||
1bc1cd96 MG |
19 | #define CERT_STRING L"Select an X509 certificate to enroll:\n\n" |
20 | #define HASH_STRING L"Select a file to trust:\n\n" | |
21 | ||
d991c4a1 MG |
22 | struct menu_item { |
23 | CHAR16 *text; | |
0a6565c5 | 24 | INTN (* callback)(void *data, void *data2, void *data3); |
d991c4a1 MG |
25 | void *data; |
26 | void *data2; | |
0a6565c5 | 27 | void *data3; |
d991c4a1 MG |
28 | UINTN colour; |
29 | }; | |
30 | ||
333bd977 GCPL |
31 | typedef struct { |
32 | UINT32 MokSize; | |
33 | UINT8 *Mok; | |
92a136d8 | 34 | EFI_GUID Type; |
cb22de62 | 35 | } __attribute__ ((packed)) MokListNode; |
333bd977 | 36 | |
9272bc5b MG |
37 | typedef struct { |
38 | UINT32 MokSBState; | |
79a5aa03 MG |
39 | UINT32 PWLen; |
40 | CHAR16 Password[PASSWORD_MAX]; | |
9272bc5b MG |
41 | } __attribute__ ((packed)) MokSBvar; |
42 | ||
92a136d8 GCPL |
43 | static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, |
44 | UINTN *size, void **buffer) | |
45 | { | |
46 | EFI_STATUS efi_status; | |
47 | char allocate = !(*size); | |
48 | ||
49 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, | |
50 | attributes, size, buffer); | |
51 | ||
52 | if (efi_status != EFI_BUFFER_TOO_SMALL || !allocate) { | |
53 | return efi_status; | |
54 | } | |
55 | ||
56 | *buffer = AllocatePool(*size); | |
57 | ||
58 | if (!*buffer) { | |
59 | Print(L"Unable to allocate variable buffer\n"); | |
60 | return EFI_OUT_OF_RESOURCES; | |
61 | } | |
62 | ||
63 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, | |
64 | attributes, size, *buffer); | |
65 | ||
66 | return efi_status; | |
67 | } | |
68 | ||
333bd977 GCPL |
69 | static EFI_INPUT_KEY get_keystroke (void) |
70 | { | |
71 | EFI_INPUT_KEY key; | |
72 | UINTN EventIndex; | |
73 | ||
74 | uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, | |
75 | &EventIndex); | |
76 | uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key); | |
77 | ||
78 | return key; | |
79 | } | |
80 | ||
5e43e91f | 81 | static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash) |
333bd977 GCPL |
82 | { |
83 | EFI_STATUS status; | |
84 | unsigned int ctxsize; | |
85 | void *ctx = NULL; | |
86 | ||
5e43e91f | 87 | ctxsize = Sha1GetContextSize(); |
333bd977 GCPL |
88 | ctx = AllocatePool(ctxsize); |
89 | ||
90 | if (!ctx) { | |
91 | Print(L"Unable to allocate memory for hash context\n"); | |
92 | return EFI_OUT_OF_RESOURCES; | |
93 | } | |
94 | ||
5e43e91f | 95 | if (!Sha1Init(ctx)) { |
333bd977 GCPL |
96 | Print(L"Unable to initialise hash\n"); |
97 | status = EFI_OUT_OF_RESOURCES; | |
98 | goto done; | |
99 | } | |
100 | ||
5e43e91f | 101 | if (!(Sha1Update(ctx, Data, DataSize))) { |
333bd977 GCPL |
102 | Print(L"Unable to generate hash\n"); |
103 | status = EFI_OUT_OF_RESOURCES; | |
104 | goto done; | |
105 | } | |
106 | ||
5e43e91f | 107 | if (!(Sha1Final(ctx, hash))) { |
333bd977 GCPL |
108 | Print(L"Unable to finalise hash\n"); |
109 | status = EFI_OUT_OF_RESOURCES; | |
110 | goto done; | |
111 | } | |
112 | ||
113 | status = EFI_SUCCESS; | |
114 | done: | |
115 | return status; | |
116 | } | |
117 | ||
92a136d8 GCPL |
118 | static UINT32 count_keys(void *Data, UINTN DataSize) |
119 | { | |
120 | EFI_SIGNATURE_LIST *CertList = Data; | |
121 | EFI_GUID CertType = EfiCertX509Guid; | |
122 | EFI_GUID HashType = EfiHashSha256Guid; | |
123 | UINTN dbsize = DataSize; | |
124 | UINT32 MokNum = 0; | |
125 | ||
126 | while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { | |
127 | if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) && | |
128 | (CompareGuid (&CertList->SignatureType, &HashType) != 0)) { | |
129 | Print(L"Doesn't look like a key or hash\n"); | |
130 | dbsize -= CertList->SignatureListSize; | |
131 | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + | |
132 | CertList->SignatureListSize); | |
133 | continue; | |
134 | } | |
135 | ||
136 | if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) && | |
137 | (CertList->SignatureSize != 48)) { | |
138 | Print(L"Doesn't look like a valid hash\n"); | |
139 | dbsize -= CertList->SignatureListSize; | |
140 | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + | |
141 | CertList->SignatureListSize); | |
142 | continue; | |
143 | } | |
144 | ||
145 | MokNum++; | |
146 | dbsize -= CertList->SignatureListSize; | |
147 | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + | |
148 | CertList->SignatureListSize); | |
149 | } | |
150 | ||
151 | return MokNum; | |
152 | } | |
153 | ||
333bd977 GCPL |
154 | static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) { |
155 | MokListNode *list; | |
0a6565c5 MG |
156 | EFI_SIGNATURE_LIST *CertList = Data; |
157 | EFI_SIGNATURE_DATA *Cert; | |
158 | EFI_GUID CertType = EfiCertX509Guid; | |
159 | EFI_GUID HashType = EfiHashSha256Guid; | |
160 | UINTN dbsize = DataSize; | |
161 | UINTN count = 0; | |
6919a3f7 | 162 | |
333bd977 GCPL |
163 | list = AllocatePool(sizeof(MokListNode) * num); |
164 | ||
165 | if (!list) { | |
166 | Print(L"Unable to allocate MOK list\n"); | |
167 | return NULL; | |
168 | } | |
169 | ||
0a6565c5 MG |
170 | while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { |
171 | if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) && | |
172 | (CompareGuid (&CertList->SignatureType, &HashType) != 0)) { | |
173 | dbsize -= CertList->SignatureListSize; | |
174 | CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList + | |
3a593361 | 175 | CertList->SignatureListSize); |
0a6565c5 MG |
176 | continue; |
177 | } | |
c326e2df | 178 | |
0a6565c5 MG |
179 | if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) && |
180 | (CertList->SignatureSize != 48)) { | |
181 | dbsize -= CertList->SignatureListSize; | |
182 | CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList + | |
3a593361 | 183 | CertList->SignatureListSize); |
0a6565c5 | 184 | continue; |
333bd977 GCPL |
185 | } |
186 | ||
0a6565c5 MG |
187 | Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) + |
188 | sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); | |
189 | ||
a05c7c57 | 190 | list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID); |
0a6565c5 | 191 | list[count].Mok = (void *)Cert->SignatureData; |
92a136d8 | 192 | list[count].Type = CertList->SignatureType; |
0a6565c5 MG |
193 | |
194 | count++; | |
195 | dbsize -= CertList->SignatureListSize; | |
196 | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + | |
3a593361 | 197 | CertList->SignatureListSize); |
333bd977 GCPL |
198 | } |
199 | ||
200 | return list; | |
201 | } | |
202 | ||
ea8ee444 | 203 | static void print_x509_name (X509_NAME *X509Name, CHAR16 *name) |
333bd977 GCPL |
204 | { |
205 | char *str; | |
206 | ||
207 | str = X509_NAME_oneline(X509Name, NULL, 0); | |
208 | if (str) { | |
ea8ee444 | 209 | Print(L" %s:\n %a\n", name, str); |
333bd977 GCPL |
210 | OPENSSL_free(str); |
211 | } | |
212 | } | |
213 | ||
214 | static const char *mon[12]= { | |
215 | "Jan","Feb","Mar","Apr","May","Jun", | |
216 | "Jul","Aug","Sep","Oct","Nov","Dec" | |
217 | }; | |
218 | ||
ea8ee444 GCPL |
219 | static void print_x509_GENERALIZEDTIME_time (ASN1_TIME *time, CHAR16 *time_string) |
220 | { | |
333bd977 GCPL |
221 | char *v; |
222 | int gmt = 0; | |
223 | int i; | |
224 | int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0; | |
225 | char *f = NULL; | |
226 | int f_len = 0; | |
227 | ||
228 | i=time->length; | |
229 | v=(char *)time->data; | |
230 | ||
231 | if (i < 12) | |
232 | goto error; | |
233 | ||
234 | if (v[i-1] == 'Z') | |
235 | gmt=1; | |
236 | ||
237 | for (i=0; i<12; i++) { | |
238 | if ((v[i] > '9') || (v[i] < '0')) | |
239 | goto error; | |
240 | } | |
241 | ||
242 | y = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0'); | |
243 | M = (v[4]-'0')*10+(v[5]-'0'); | |
244 | ||
245 | if ((M > 12) || (M < 1)) | |
246 | goto error; | |
247 | ||
248 | d = (v[6]-'0')*10+(v[7]-'0'); | |
249 | h = (v[8]-'0')*10+(v[9]-'0'); | |
250 | m = (v[10]-'0')*10+(v[11]-'0'); | |
251 | ||
252 | if (time->length >= 14 && | |
253 | (v[12] >= '0') && (v[12] <= '9') && | |
254 | (v[13] >= '0') && (v[13] <= '9')) { | |
255 | s = (v[12]-'0')*10+(v[13]-'0'); | |
256 | /* Check for fractions of seconds. */ | |
257 | if (time->length >= 15 && v[14] == '.') { | |
258 | int l = time->length; | |
259 | f = &v[14]; /* The decimal point. */ | |
260 | f_len = 1; | |
ea8ee444 GCPL |
261 | while (14 + f_len < l && f[f_len] >= '0' && |
262 | f[f_len] <= '9') | |
333bd977 GCPL |
263 | ++f_len; |
264 | } | |
265 | } | |
266 | ||
ea8ee444 GCPL |
267 | SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d%.*a %d%a", |
268 | mon[M-1], d, h, m, s, f_len, f, y, (gmt)?" GMT":""); | |
333bd977 GCPL |
269 | error: |
270 | return; | |
271 | } | |
272 | ||
ea8ee444 | 273 | static void print_x509_UTCTIME_time (ASN1_TIME *time, CHAR16 *time_string) |
333bd977 GCPL |
274 | { |
275 | char *v; | |
276 | int gmt=0; | |
277 | int i; | |
278 | int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0; | |
279 | ||
280 | i=time->length; | |
281 | v=(char *)time->data; | |
282 | ||
283 | if (i < 10) | |
284 | goto error; | |
285 | ||
286 | if (v[i-1] == 'Z') | |
287 | gmt=1; | |
288 | ||
289 | for (i=0; i<10; i++) | |
290 | if ((v[i] > '9') || (v[i] < '0')) | |
291 | goto error; | |
292 | ||
293 | y = (v[0]-'0')*10+(v[1]-'0'); | |
294 | ||
295 | if (y < 50) | |
296 | y+=100; | |
297 | ||
298 | M = (v[2]-'0')*10+(v[3]-'0'); | |
299 | ||
300 | if ((M > 12) || (M < 1)) | |
301 | goto error; | |
302 | ||
303 | d = (v[4]-'0')*10+(v[5]-'0'); | |
304 | h = (v[6]-'0')*10+(v[7]-'0'); | |
305 | m = (v[8]-'0')*10+(v[9]-'0'); | |
306 | ||
307 | if (time->length >=12 && | |
308 | (v[10] >= '0') && (v[10] <= '9') && | |
309 | (v[11] >= '0') && (v[11] <= '9')) | |
310 | s = (v[10]-'0')*10+(v[11]-'0'); | |
311 | ||
ea8ee444 GCPL |
312 | SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d %d%a", |
313 | mon[M-1], d, h, m, s, y+1900, (gmt)?" GMT":""); | |
333bd977 GCPL |
314 | error: |
315 | return; | |
316 | } | |
317 | ||
ea8ee444 | 318 | static void print_x509_time (ASN1_TIME *time, CHAR16 *name) |
333bd977 | 319 | { |
ea8ee444 GCPL |
320 | CHAR16 time_string[30]; |
321 | ||
f78ff3bf | 322 | if (time->type == V_ASN1_UTCTIME) { |
ea8ee444 | 323 | print_x509_UTCTIME_time(time, time_string); |
f78ff3bf | 324 | } else if (time->type == V_ASN1_GENERALIZEDTIME) { |
ea8ee444 | 325 | print_x509_GENERALIZEDTIME_time(time, time_string); |
f78ff3bf GCPL |
326 | } else { |
327 | time_string[0] = '\0'; | |
328 | } | |
ea8ee444 GCPL |
329 | |
330 | Print(L" %s:\n %s\n", name, time_string); | |
333bd977 GCPL |
331 | } |
332 | ||
333 | static void show_x509_info (X509 *X509Cert) | |
334 | { | |
ea8ee444 GCPL |
335 | ASN1_INTEGER *serial; |
336 | BIGNUM *bnser; | |
337 | unsigned char hexbuf[30]; | |
333bd977 GCPL |
338 | X509_NAME *X509Name; |
339 | ASN1_TIME *time; | |
340 | ||
ea8ee444 GCPL |
341 | serial = X509_get_serialNumber(X509Cert); |
342 | if (serial) { | |
343 | int i, n; | |
344 | bnser = ASN1_INTEGER_to_BN(serial, NULL); | |
345 | n = BN_bn2bin(bnser, hexbuf); | |
346 | Print(L" Serial Number:\n "); | |
347 | for (i = 0; i < n-1; i++) { | |
348 | Print(L"%02x:", hexbuf[i]); | |
349 | } | |
350 | Print(L"%02x\n", hexbuf[n-1]); | |
351 | } | |
352 | ||
333bd977 GCPL |
353 | X509Name = X509_get_issuer_name(X509Cert); |
354 | if (X509Name) { | |
ea8ee444 | 355 | print_x509_name(X509Name, L"Issuer"); |
333bd977 GCPL |
356 | } |
357 | ||
358 | X509Name = X509_get_subject_name(X509Cert); | |
359 | if (X509Name) { | |
ea8ee444 | 360 | print_x509_name(X509Name, L"Subject"); |
333bd977 GCPL |
361 | } |
362 | ||
363 | time = X509_get_notBefore(X509Cert); | |
364 | if (time) { | |
ea8ee444 | 365 | print_x509_time(time, L"Validity from"); |
333bd977 GCPL |
366 | } |
367 | ||
368 | time = X509_get_notAfter(X509Cert); | |
369 | if (time) { | |
ea8ee444 | 370 | print_x509_time(time, L"Validity till"); |
333bd977 GCPL |
371 | } |
372 | } | |
373 | ||
374 | static void show_mok_info (void *Mok, UINTN MokSize) | |
375 | { | |
376 | EFI_STATUS efi_status; | |
5e43e91f | 377 | UINT8 hash[SHA1_DIGEST_SIZE]; |
333bd977 GCPL |
378 | unsigned int i; |
379 | X509 *X509Cert; | |
380 | ||
381 | if (!Mok || MokSize == 0) | |
382 | return; | |
383 | ||
a05c7c57 | 384 | if (MokSize != SHA256_DIGEST_SIZE) { |
16c512f9 MG |
385 | if (X509ConstructCertificate(Mok, MokSize, |
386 | (UINT8 **) &X509Cert) && X509Cert != NULL) { | |
0a6565c5 MG |
387 | show_x509_info(X509Cert); |
388 | X509_free(X509Cert); | |
389 | } else { | |
390 | Print(L" Not a valid X509 certificate: %x\n\n", | |
391 | ((UINT32 *)Mok)[0]); | |
392 | return; | |
393 | } | |
16c512f9 MG |
394 | |
395 | efi_status = get_sha1sum(Mok, MokSize, hash); | |
396 | ||
397 | if (efi_status != EFI_SUCCESS) { | |
398 | Print(L"Failed to compute MOK fingerprint\n"); | |
399 | return; | |
400 | } | |
401 | ||
402 | Print(L" Fingerprint (SHA1):\n "); | |
403 | for (i = 0; i < SHA1_DIGEST_SIZE; i++) { | |
404 | Print(L" %02x", hash[i]); | |
405 | if (i % 10 == 9) | |
406 | Print(L"\n "); | |
407 | } | |
ea8ee444 | 408 | } else { |
0a6565c5 MG |
409 | Print(L"SHA256 hash:\n "); |
410 | for (i = 0; i < SHA256_DIGEST_SIZE; i++) { | |
411 | Print(L" %02x", ((UINT8 *)Mok)[i]); | |
412 | if (i % 10 == 9) | |
413 | Print(L"\n "); | |
414 | } | |
415 | Print(L"\n"); | |
ea8ee444 | 416 | } |
333bd977 | 417 | |
ea8ee444 | 418 | Print(L"\n"); |
333bd977 GCPL |
419 | } |
420 | ||
f775849e GCPL |
421 | static INTN get_number () |
422 | { | |
423 | EFI_INPUT_KEY input_key; | |
424 | CHAR16 input[10]; | |
425 | int count = 0; | |
426 | ||
427 | do { | |
428 | input_key = get_keystroke(); | |
429 | ||
430 | if ((input_key.UnicodeChar < '0' || | |
431 | input_key.UnicodeChar > '9' || | |
432 | count >= 10) && | |
433 | input_key.UnicodeChar != CHAR_BACKSPACE) { | |
434 | continue; | |
435 | } | |
436 | ||
437 | if (count == 0 && input_key.UnicodeChar == CHAR_BACKSPACE) | |
438 | continue; | |
439 | ||
440 | Print(L"%c", input_key.UnicodeChar); | |
441 | ||
442 | if (input_key.UnicodeChar == CHAR_BACKSPACE) { | |
443 | input[--count] = '\0'; | |
444 | continue; | |
445 | } | |
446 | ||
447 | input[count++] = input_key.UnicodeChar; | |
448 | } while (input_key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
449 | ||
450 | if (count == 0) | |
451 | return -1; | |
452 | ||
453 | input[count] = '\0'; | |
454 | ||
455 | return (INTN)Atoi(input); | |
456 | } | |
457 | ||
92a136d8 | 458 | static UINT8 list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title) |
333bd977 | 459 | { |
0a6565c5 | 460 | UINT32 MokNum = 0; |
c326e2df | 461 | MokListNode *keys = NULL; |
f775849e GCPL |
462 | INTN key_num = 0; |
463 | UINT8 initial = 1; | |
0a6565c5 | 464 | |
92a136d8 GCPL |
465 | if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) + |
466 | sizeof(EFI_SIGNATURE_DATA))) { | |
0a6565c5 MG |
467 | Print(L"No keys\n"); |
468 | Pause(); | |
6306b495 | 469 | return 0; |
333bd977 | 470 | } |
333bd977 | 471 | |
92a136d8 GCPL |
472 | MokNum = count_keys(KeyList, KeyListSize); |
473 | keys = build_mok_list(MokNum, KeyList, KeyListSize); | |
c326e2df GCPL |
474 | |
475 | if (!keys) { | |
92a136d8 | 476 | Print(L"Failed to construct key list\n"); |
6306b495 | 477 | return 0; |
333bd977 GCPL |
478 | } |
479 | ||
f775849e GCPL |
480 | do { |
481 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); | |
92a136d8 GCPL |
482 | if (title) |
483 | Print(L"%s\n", title); | |
f775849e GCPL |
484 | Print(L"Input the key number to show the details of the key or\n" |
485 | L"type \'0\' to continue\n\n"); | |
92a136d8 | 486 | Print(L"%d key(s) in the key list\n\n", MokNum); |
f775849e GCPL |
487 | |
488 | if (key_num > MokNum) { | |
67f1e0b2 | 489 | Print(L"[Key %d]\n", key_num); |
f775849e | 490 | Print(L"No such key\n\n"); |
577029ad | 491 | } else if (initial != 1 && key_num > 0){ |
f775849e GCPL |
492 | Print(L"[Key %d]\n", key_num); |
493 | show_mok_info(keys[key_num-1].Mok, keys[key_num-1].MokSize); | |
494 | } | |
495 | ||
496 | Print(L"Key Number: "); | |
497 | ||
498 | key_num = get_number(); | |
499 | ||
500 | Print(L"\n\n"); | |
501 | ||
502 | if (key_num == -1) | |
503 | continue; | |
504 | ||
505 | initial = 0; | |
506 | } while (key_num != 0); | |
333bd977 | 507 | |
6306b495 | 508 | FreePool(keys); |
c326e2df | 509 | |
6306b495 | 510 | return 1; |
333bd977 GCPL |
511 | } |
512 | ||
3ece2b33 | 513 | static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show) |
333bd977 GCPL |
514 | { |
515 | EFI_INPUT_KEY key; | |
3ece2b33 GCPL |
516 | int count = 0; |
517 | ||
518 | do { | |
519 | key = get_keystroke(); | |
520 | ||
521 | if ((count >= line_max && | |
522 | key.UnicodeChar != CHAR_BACKSPACE) || | |
523 | key.UnicodeChar == CHAR_NULL || | |
524 | key.UnicodeChar == CHAR_TAB || | |
525 | key.UnicodeChar == CHAR_LINEFEED || | |
526 | key.UnicodeChar == CHAR_CARRIAGE_RETURN) { | |
527 | continue; | |
528 | } | |
529 | ||
530 | if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) { | |
531 | continue; | |
532 | } else if (key.UnicodeChar == CHAR_BACKSPACE) { | |
533 | if (show) { | |
534 | Print(L"\b"); | |
535 | } | |
536 | line[--count] = '\0'; | |
537 | continue; | |
538 | } | |
539 | ||
540 | if (show) { | |
541 | Print(L"%c", key.UnicodeChar); | |
542 | } | |
543 | ||
544 | line[count++] = key.UnicodeChar; | |
545 | } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN); | |
546 | Print(L"\n"); | |
547 | ||
548 | *length = count; | |
549 | ||
550 | return 1; | |
551 | } | |
552 | ||
215e462b GCPL |
553 | static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *password, |
554 | UINT32 pw_length, UINT8 *hash) | |
555 | { | |
556 | EFI_STATUS status; | |
557 | unsigned int ctxsize; | |
558 | void *ctx = NULL; | |
559 | ||
560 | ctxsize = Sha256GetContextSize(); | |
561 | ctx = AllocatePool(ctxsize); | |
562 | ||
563 | if (!ctx) { | |
564 | Print(L"Unable to allocate memory for hash context\n"); | |
565 | return EFI_OUT_OF_RESOURCES; | |
566 | } | |
567 | ||
568 | if (!Sha256Init(ctx)) { | |
569 | Print(L"Unable to initialise hash\n"); | |
570 | status = EFI_OUT_OF_RESOURCES; | |
571 | goto done; | |
572 | } | |
573 | ||
0a6565c5 MG |
574 | if (MokNew && MokNewSize) { |
575 | if (!(Sha256Update(ctx, MokNew, MokNewSize))) { | |
576 | Print(L"Unable to generate hash\n"); | |
577 | status = EFI_OUT_OF_RESOURCES; | |
578 | goto done; | |
579 | } | |
215e462b GCPL |
580 | } |
581 | ||
582 | if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) { | |
583 | Print(L"Unable to generate hash\n"); | |
584 | status = EFI_OUT_OF_RESOURCES; | |
585 | goto done; | |
586 | } | |
587 | ||
588 | if (!(Sha256Final(ctx, hash))) { | |
589 | Print(L"Unable to finalise hash\n"); | |
590 | status = EFI_OUT_OF_RESOURCES; | |
591 | goto done; | |
592 | } | |
593 | ||
594 | status = EFI_SUCCESS; | |
595 | done: | |
596 | return status; | |
597 | } | |
598 | ||
262d6714 GCPL |
599 | static EFI_STATUS match_password (void *Data, UINTN DataSize, |
600 | UINT8 auth[SHA256_DIGEST_SIZE], | |
601 | CHAR16 *prompt) | |
602 | { | |
603 | EFI_STATUS efi_status; | |
604 | UINT8 hash[SHA256_DIGEST_SIZE]; | |
605 | CHAR16 password[PASSWORD_MAX]; | |
606 | UINT32 pw_length; | |
607 | UINT8 fail_count = 0; | |
608 | ||
609 | while (fail_count < 3) { | |
610 | if (prompt) { | |
611 | Print(L"%s", prompt); | |
612 | } else { | |
613 | Print(L"Password: "); | |
614 | } | |
615 | get_line(&pw_length, password, PASSWORD_MAX, 0); | |
616 | ||
617 | if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) { | |
618 | Print(L"Invalid password length\n"); | |
619 | fail_count++; | |
620 | continue; | |
621 | } | |
622 | ||
623 | efi_status = compute_pw_hash(Data, DataSize, password, | |
624 | pw_length, hash); | |
625 | ||
626 | if (efi_status != EFI_SUCCESS) { | |
627 | Print(L"Unable to generate password hash\n"); | |
628 | fail_count++; | |
629 | continue; | |
630 | } | |
631 | ||
632 | if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) { | |
633 | Print(L"Password doesn't match\n"); | |
634 | fail_count++; | |
635 | continue; | |
636 | } | |
637 | ||
638 | break; | |
639 | } | |
640 | ||
641 | if (fail_count >= 3) | |
642 | return EFI_ACCESS_DENIED; | |
643 | ||
644 | return EFI_SUCCESS; | |
645 | } | |
646 | ||
1e9de96f | 647 | static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate) |
333bd977 GCPL |
648 | { |
649 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
650 | EFI_STATUS efi_status; | |
215e462b GCPL |
651 | UINT8 auth[SHA256_DIGEST_SIZE]; |
652 | UINTN auth_size; | |
653 | UINT32 attributes; | |
215e462b | 654 | |
1e9de96f MG |
655 | if (authenticate) { |
656 | auth_size = SHA256_DIGEST_SIZE; | |
657 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth", | |
658 | &shim_lock_guid, | |
659 | &attributes, &auth_size, auth); | |
215e462b GCPL |
660 | |
661 | ||
1e9de96f MG |
662 | if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) { |
663 | Print(L"Failed to get MokAuth %d\n", efi_status); | |
664 | return efi_status; | |
665 | } | |
215e462b | 666 | |
262d6714 GCPL |
667 | efi_status = match_password(MokNew, MokNewSize, auth, NULL); |
668 | if (efi_status != EFI_SUCCESS) | |
1e9de96f MG |
669 | return EFI_ACCESS_DENIED; |
670 | } | |
333bd977 | 671 | |
0a6565c5 MG |
672 | if (!MokNewSize) { |
673 | /* Delete MOK */ | |
674 | efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList", | |
675 | &shim_lock_guid, | |
676 | EFI_VARIABLE_NON_VOLATILE | |
868d5b90 | 677 | | EFI_VARIABLE_BOOTSERVICE_ACCESS, |
0a6565c5 MG |
678 | 0, NULL); |
679 | } else { | |
680 | /* Write new MOK */ | |
681 | efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList", | |
682 | &shim_lock_guid, | |
683 | EFI_VARIABLE_NON_VOLATILE | |
684 | | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
685 | | EFI_VARIABLE_APPEND_WRITE, | |
686 | MokNewSize, MokNew); | |
687 | } | |
688 | ||
333bd977 GCPL |
689 | if (efi_status != EFI_SUCCESS) { |
690 | Print(L"Failed to set variable %d\n", efi_status); | |
5d328c6c | 691 | return efi_status; |
333bd977 GCPL |
692 | } |
693 | ||
5d328c6c | 694 | return EFI_SUCCESS; |
333bd977 GCPL |
695 | } |
696 | ||
1e9de96f | 697 | static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) { |
a64ab2ec | 698 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; |
d991c4a1 MG |
699 | CHAR16 line[1]; |
700 | UINT32 length; | |
333bd977 | 701 | EFI_STATUS efi_status; |
333bd977 | 702 | |
d991c4a1 | 703 | do { |
92a136d8 | 704 | if (!list_keys(MokNew, MokNewSize, L"[Enroll MOK]")) { |
d991c4a1 MG |
705 | return 0; |
706 | } | |
333bd977 | 707 | |
d991c4a1 | 708 | Print(L"Enroll the key(s)? (y/n): "); |
333bd977 | 709 | |
d991c4a1 | 710 | get_line (&length, line, 1, 1); |
333bd977 | 711 | |
d991c4a1 | 712 | if (line[0] == 'Y' || line[0] == 'y') { |
1e9de96f | 713 | efi_status = store_keys(MokNew, MokNewSize, auth); |
333bd977 | 714 | |
d991c4a1 MG |
715 | if (efi_status != EFI_SUCCESS) { |
716 | Print(L"Failed to enroll keys\n"); | |
717 | return -1; | |
718 | } | |
a64ab2ec GCPL |
719 | |
720 | if (auth) { | |
721 | LibDeleteVariable(L"MokNew", &shim_lock_guid); | |
722 | LibDeleteVariable(L"MokAuth", &shim_lock_guid); | |
723 | ||
724 | Print(L"\nPress a key to reboot system\n"); | |
725 | Pause(); | |
726 | uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, | |
727 | EFI_SUCCESS, 0, NULL); | |
728 | Print(L"Failed to reboot\n"); | |
729 | return -1; | |
730 | } | |
731 | ||
d991c4a1 MG |
732 | return 0; |
733 | } | |
734 | } while (line[0] != 'N' && line[0] != 'n'); | |
735 | return -1; | |
736 | } | |
737 | ||
0a6565c5 | 738 | static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2, |
6e05b32d MG |
739 | void *data3) |
740 | { | |
741 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); | |
1e9de96f MG |
742 | return mok_enrollment_prompt(MokNew, (UINTN)data2, TRUE); |
743 | } | |
744 | ||
92a136d8 GCPL |
745 | static INTN mok_reset_prompt (void *MokNew, void *data2, void *data3) |
746 | { | |
a64ab2ec | 747 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; |
d991c4a1 MG |
748 | CHAR16 line[1]; |
749 | UINT32 length; | |
750 | EFI_STATUS efi_status; | |
751 | ||
4895ca39 | 752 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); |
d991c4a1 MG |
753 | Print(L"Erase all stored keys? (y/N): "); |
754 | ||
755 | get_line (&length, line, 1, 1); | |
756 | ||
757 | if (line[0] == 'Y' || line[0] == 'y') { | |
0a6565c5 | 758 | efi_status = store_keys(NULL, 0, TRUE); |
333bd977 | 759 | |
5d328c6c GCPL |
760 | if (efi_status != EFI_SUCCESS) { |
761 | Print(L"Failed to erase keys\n"); | |
d991c4a1 | 762 | return -1; |
5d328c6c | 763 | } |
a64ab2ec GCPL |
764 | |
765 | LibDeleteVariable(L"MokNew", &shim_lock_guid); | |
766 | LibDeleteVariable(L"MokAuth", &shim_lock_guid); | |
767 | ||
768 | Print(L"\nPress a key to reboot system\n"); | |
769 | Pause(); | |
770 | uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, | |
771 | EFI_SUCCESS, 0, NULL); | |
772 | Print(L"Failed to reboot\n"); | |
773 | return -1; | |
d991c4a1 | 774 | } |
5d328c6c | 775 | |
d991c4a1 MG |
776 | return 0; |
777 | } | |
333bd977 | 778 | |
92a136d8 GCPL |
779 | static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num) |
780 | { | |
781 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
782 | EFI_STATUS efi_status; | |
783 | EFI_SIGNATURE_LIST *CertList; | |
784 | EFI_SIGNATURE_DATA *CertData; | |
785 | void *Data = NULL, *ptr; | |
786 | INTN DataSize = 0; | |
787 | int i; | |
788 | ||
789 | for (i = 0; i < key_num; i++) { | |
790 | if (list[i].Mok == NULL) | |
791 | continue; | |
792 | ||
793 | DataSize += sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID); | |
794 | DataSize += list[i].MokSize; | |
795 | } | |
796 | ||
797 | Data = AllocatePool(DataSize); | |
798 | if (Data == NULL && DataSize != 0) | |
799 | return EFI_OUT_OF_RESOURCES; | |
800 | ||
801 | ptr = Data; | |
802 | ||
803 | for (i = 0; i < key_num; i++) { | |
804 | if (list[i].Mok == NULL) | |
805 | continue; | |
806 | ||
807 | CertList = (EFI_SIGNATURE_LIST *)ptr; | |
808 | CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) + | |
809 | sizeof(EFI_SIGNATURE_LIST)); | |
810 | ||
811 | CertList->SignatureType = list[i].Type; | |
812 | CertList->SignatureListSize = list[i].MokSize + | |
813 | sizeof(EFI_SIGNATURE_LIST) + | |
814 | sizeof(EFI_SIGNATURE_DATA) - 1; | |
815 | CertList->SignatureHeaderSize = 0; | |
816 | CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID); | |
817 | ||
818 | CertData->SignatureOwner = shim_lock_guid; | |
819 | CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize); | |
820 | ||
821 | ptr = (uint8_t *)ptr + sizeof(EFI_SIGNATURE_LIST) + | |
822 | sizeof(EFI_GUID) + list[i].MokSize; | |
823 | } | |
824 | ||
825 | efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList", | |
826 | &shim_lock_guid, | |
827 | EFI_VARIABLE_NON_VOLATILE | |
828 | | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
829 | DataSize, Data); | |
830 | if (Data) | |
831 | FreePool(Data); | |
832 | ||
833 | if (efi_status != EFI_SUCCESS) { | |
834 | Print(L"Failed to set variable %d\n", efi_status); | |
835 | return efi_status; | |
836 | } | |
837 | ||
838 | return EFI_SUCCESS; | |
839 | } | |
840 | ||
841 | static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize) | |
842 | { | |
843 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
844 | EFI_STATUS efi_status; | |
845 | UINT8 auth[SHA256_DIGEST_SIZE]; | |
846 | UINTN auth_size = SHA256_DIGEST_SIZE; | |
847 | UINT32 attributes; | |
848 | void *MokListData = NULL; | |
849 | UINTN MokListDataSize = 0; | |
850 | MokListNode *mok, *del_key; | |
851 | INTN mok_num, del_num; | |
852 | int i, j; | |
853 | ||
854 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth", | |
855 | &shim_lock_guid, | |
856 | &attributes, &auth_size, auth); | |
857 | ||
858 | if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) { | |
859 | Print(L"Failed to get MokDelAuth %d\n", efi_status); | |
860 | return efi_status; | |
861 | } | |
862 | ||
863 | efi_status = match_password(MokDel, MokDelSize, auth, NULL); | |
864 | if (efi_status != EFI_SUCCESS) | |
865 | return EFI_ACCESS_DENIED; | |
866 | ||
867 | efi_status = get_variable(L"MokList", shim_lock_guid, &attributes, | |
868 | &MokListDataSize, &MokListData); | |
869 | ||
870 | if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) { | |
871 | Print(L"MokList is compromised!\nErase all keys in MokList!\n"); | |
872 | if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) { | |
873 | Print(L"Failed to erase MokList\n"); | |
874 | } | |
875 | return EFI_ACCESS_DENIED; | |
876 | } | |
877 | ||
878 | /* Nothing to do */ | |
879 | if (!MokListData || MokListDataSize == 0) | |
880 | return EFI_SUCCESS; | |
881 | ||
882 | /* Construct lists */ | |
883 | mok_num = count_keys(MokListData, MokListDataSize); | |
884 | mok = build_mok_list(mok_num, MokListData, MokListDataSize); | |
885 | del_num = count_keys(MokDel, MokDelSize); | |
886 | del_key = build_mok_list(del_num, MokDel, MokDelSize); | |
887 | ||
888 | /* Search and destroy */ | |
889 | for (i = 0; i < del_num; i++) { | |
890 | UINT32 key_size = del_key[i].MokSize; | |
891 | void *key = del_key[i].Mok; | |
892 | for (j = 0; j < mok_num; j++) { | |
893 | if (mok[j].MokSize == key_size && | |
894 | CompareMem(key, mok[j].Mok, key_size) == 0) { | |
895 | /* Remove the key */ | |
896 | mok[j].Mok = NULL; | |
897 | mok[j].MokSize = 0; | |
898 | } | |
899 | } | |
900 | } | |
901 | ||
902 | efi_status = write_back_mok_list(mok, mok_num); | |
903 | ||
904 | if (MokListData) | |
905 | FreePool(MokListData); | |
906 | if (mok) | |
907 | FreePool(mok); | |
908 | if (del_key) | |
909 | FreePool(del_key); | |
910 | ||
911 | return efi_status; | |
912 | } | |
913 | ||
914 | static INTN mok_deletion_prompt (void *MokDel, void *data2, void *data3) | |
915 | { | |
916 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
917 | UINTN MokDelSize = (UINTN)data2; | |
918 | CHAR16 line[1]; | |
919 | UINT32 length; | |
920 | EFI_STATUS efi_status; | |
921 | ||
922 | do { | |
923 | if (!list_keys(MokDel, MokDelSize, L"[Delete MOK]")) { | |
924 | return 0; | |
925 | } | |
926 | ||
927 | Print(L"Delete the key(s)? (y/n): "); | |
928 | ||
929 | get_line (&length, line, 1, 1); | |
930 | ||
931 | if (line[0] == 'Y' || line[0] == 'y') { | |
932 | efi_status = delete_keys(MokDel, MokDelSize); | |
933 | ||
934 | if (efi_status != EFI_SUCCESS) { | |
935 | Print(L"Failed to delete keys\n"); | |
936 | return -1; | |
937 | } | |
938 | ||
939 | LibDeleteVariable(L"MokDel", &shim_lock_guid); | |
940 | LibDeleteVariable(L"MokDelAuth", &shim_lock_guid); | |
941 | ||
942 | Print(L"\nPress a key to reboot system\n"); | |
943 | Pause(); | |
944 | uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, | |
945 | EFI_SUCCESS, 0, NULL); | |
946 | Print(L"Failed to reboot\n"); | |
947 | return -1; | |
948 | } | |
949 | } while (line[0] != 'N' && line[0] != 'n'); | |
950 | return -1; | |
951 | } | |
952 | ||
9272bc5b MG |
953 | static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) { |
954 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
955 | EFI_STATUS efi_status; | |
956 | UINTN MokSBSize = (UINTN)data2; | |
957 | MokSBvar *var = MokSB; | |
8a169068 MG |
958 | CHAR16 pass1, pass2, pass3; |
959 | UINT8 fail_count = 0; | |
9272bc5b MG |
960 | UINT32 length; |
961 | CHAR16 line[1]; | |
962 | UINT8 sbval = 1; | |
8a169068 | 963 | UINT8 pos1, pos2, pos3; |
9272bc5b | 964 | |
9272bc5b MG |
965 | if (MokSBSize != sizeof(MokSBvar)) { |
966 | Print(L"Invalid MokSB variable contents\n"); | |
967 | return -1; | |
968 | } | |
969 | ||
34f0c4ab MG |
970 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); |
971 | ||
8a169068 MG |
972 | while (fail_count < 3) { |
973 | RandomBytes (&pos1, sizeof(pos1)); | |
974 | pos1 = (pos1 % var->PWLen); | |
975 | ||
976 | do { | |
977 | RandomBytes (&pos2, sizeof(pos2)); | |
978 | pos2 = (pos2 % var->PWLen); | |
979 | } while (pos2 == pos1); | |
980 | ||
981 | do { | |
982 | RandomBytes (&pos3, sizeof(pos3)); | |
983 | pos3 = (pos3 % var->PWLen) ; | |
984 | } while (pos3 == pos2 || pos3 == pos1); | |
985 | ||
986 | Print(L"Enter password character %d: ", pos1 + 1); | |
987 | get_line(&length, &pass1, 1, 0); | |
9272bc5b | 988 | |
8a169068 MG |
989 | Print(L"Enter password character %d: ", pos2 + 1); |
990 | get_line(&length, &pass2, 1, 0); | |
9272bc5b | 991 | |
8a169068 MG |
992 | Print(L"Enter password character %d: ", pos3 + 1); |
993 | get_line(&length, &pass3, 1, 0); | |
9272bc5b | 994 | |
8a169068 MG |
995 | if (pass1 != var->Password[pos1] || |
996 | pass2 != var->Password[pos2] || | |
997 | pass3 != var->Password[pos3]) { | |
79a5aa03 | 998 | Print(L"Invalid character\n"); |
9272bc5b | 999 | fail_count++; |
79a5aa03 | 1000 | } else { |
79a5aa03 | 1001 | break; |
8a169068 | 1002 | } |
9272bc5b MG |
1003 | } |
1004 | ||
1005 | if (fail_count >= 3) { | |
1006 | Print(L"Password limit reached\n"); | |
1007 | return -1; | |
1008 | } | |
1009 | ||
1010 | if (var->MokSBState == 0) { | |
1011 | Print(L"Disable Secure Boot? (y/n): "); | |
1012 | } else { | |
1013 | Print(L"Enable Secure Boot? (y/n): "); | |
1014 | } | |
1015 | ||
1016 | do { | |
1017 | get_line (&length, line, 1, 1); | |
1018 | ||
1019 | if (line[0] == 'Y' || line[0] == 'y') { | |
1020 | if (var->MokSBState == 0) { | |
1021 | efi_status = uefi_call_wrapper(RT->SetVariable, | |
1022 | 5, L"MokSBState", | |
1023 | &shim_lock_guid, | |
1024 | EFI_VARIABLE_NON_VOLATILE | | |
1025 | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
1026 | 1, &sbval); | |
1027 | if (efi_status != EFI_SUCCESS) { | |
1028 | Print(L"Failed to set Secure Boot state\n"); | |
1029 | return -1; | |
1030 | } | |
1031 | } else { | |
1032 | LibDeleteVariable(L"MokSBState", | |
1033 | &shim_lock_guid); | |
1034 | } | |
1035 | ||
d77f421b MG |
1036 | LibDeleteVariable(L"MokSB", &shim_lock_guid); |
1037 | ||
9272bc5b MG |
1038 | Print(L"Press a key to reboot system\n"); |
1039 | Pause(); | |
1040 | uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, | |
1041 | EFI_SUCCESS, 0, NULL); | |
1042 | Print(L"Failed to reboot\n"); | |
1043 | return -1; | |
1044 | } | |
1045 | } while (line[0] != 'N' && line[0] != 'n'); | |
1046 | ||
1047 | return -1; | |
1048 | } | |
1049 | ||
801d1b93 MG |
1050 | |
1051 | static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) { | |
1052 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
1053 | EFI_STATUS efi_status; | |
1054 | UINTN MokPWSize = (UINTN)data2; | |
801d1b93 | 1055 | UINT8 hash[SHA256_DIGEST_SIZE]; |
801d1b93 MG |
1056 | UINT32 length; |
1057 | CHAR16 line[1]; | |
1058 | ||
1059 | if (MokPWSize != SHA256_DIGEST_SIZE) { | |
1060 | Print(L"Invalid MokPW variable contents\n"); | |
1061 | return -1; | |
1062 | } | |
1063 | ||
34f0c4ab MG |
1064 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); |
1065 | ||
d77f421b MG |
1066 | SetMem(hash, SHA256_DIGEST_SIZE, 0); |
1067 | ||
1068 | if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0) { | |
1069 | Print(L"Clear MOK password? (y/n): "); | |
1070 | ||
1071 | do { | |
1072 | get_line (&length, line, 1, 1); | |
1073 | ||
1074 | if (line[0] == 'Y' || line[0] == 'y') { | |
1075 | LibDeleteVariable(L"MokPWStore", &shim_lock_guid); | |
1076 | LibDeleteVariable(L"MokPW", &shim_lock_guid); | |
1077 | } | |
1078 | } while (line[0] != 'N' && line[0] != 'n'); | |
1079 | ||
1080 | return 0; | |
1081 | } | |
1082 | ||
262d6714 GCPL |
1083 | efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: "); |
1084 | if (efi_status != EFI_SUCCESS) { | |
801d1b93 MG |
1085 | Print(L"Password limit reached\n"); |
1086 | return -1; | |
1087 | } | |
1088 | ||
1089 | Print(L"Set MOK password? (y/n): "); | |
1090 | ||
1091 | do { | |
1092 | get_line (&length, line, 1, 1); | |
1093 | ||
1094 | if (line[0] == 'Y' || line[0] == 'y') { | |
1095 | efi_status = uefi_call_wrapper(RT->SetVariable, 5, | |
1096 | L"MokPWStore", | |
1097 | &shim_lock_guid, | |
1098 | EFI_VARIABLE_NON_VOLATILE | | |
1099 | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
1100 | MokPWSize, MokPW); | |
1101 | if (efi_status != EFI_SUCCESS) { | |
1102 | Print(L"Failed to set MOK password\n"); | |
1103 | return -1; | |
1104 | } | |
1105 | ||
d77f421b MG |
1106 | LibDeleteVariable(L"MokPW", &shim_lock_guid); |
1107 | ||
801d1b93 MG |
1108 | Print(L"Press a key to reboot system\n"); |
1109 | Pause(); | |
1110 | uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, | |
1111 | EFI_SUCCESS, 0, NULL); | |
1112 | Print(L"Failed to reboot\n"); | |
1113 | return -1; | |
1114 | } | |
1115 | } while (line[0] != 'N' && line[0] != 'n'); | |
1116 | ||
1117 | return 0; | |
1118 | } | |
1119 | ||
1bc1cd96 MG |
1120 | static UINTN draw_menu (CHAR16 *header, UINTN lines, struct menu_item *items, |
1121 | UINTN count) { | |
d991c4a1 | 1122 | UINTN i; |
5d328c6c | 1123 | |
d991c4a1 MG |
1124 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); |
1125 | ||
e204505d MG |
1126 | uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, |
1127 | EFI_WHITE | EFI_BACKGROUND_BLACK); | |
1128 | ||
1129 | Print(L"%s UEFI key management\n\n", SHIM_VENDOR); | |
1130 | ||
1bc1cd96 MG |
1131 | if (header) |
1132 | Print(L"%s", header); | |
1133 | ||
d991c4a1 MG |
1134 | for (i = 0; i < count; i++) { |
1135 | uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, | |
1136 | items[i].colour | EFI_BACKGROUND_BLACK); | |
1137 | Print(L" %s\n", items[i].text); | |
1138 | } | |
1139 | ||
1140 | uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0); | |
1141 | uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE); | |
e204505d | 1142 | |
1bc1cd96 | 1143 | return 2 + lines; |
d991c4a1 MG |
1144 | } |
1145 | ||
c9d2ff8c MG |
1146 | static void free_menu (struct menu_item *items, UINTN count) { |
1147 | UINTN i; | |
1148 | ||
1149 | for (i=0; i<count; i++) { | |
1150 | if (items[i].text) | |
1151 | FreePool(items[i].text); | |
1152 | } | |
1153 | ||
1154 | FreePool(items); | |
1155 | } | |
1156 | ||
37635f54 MG |
1157 | static void update_time (UINTN position, UINTN timeout) |
1158 | { | |
1159 | uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, | |
1160 | position); | |
1161 | ||
1162 | uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, | |
1163 | EFI_BLACK | EFI_BACKGROUND_BLACK); | |
1164 | ||
1165 | Print(L" ", timeout); | |
1166 | ||
1167 | uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, | |
1168 | position); | |
1169 | ||
1170 | uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, | |
1171 | EFI_WHITE | EFI_BACKGROUND_BLACK); | |
1172 | ||
1173 | if (timeout > 1) | |
1174 | Print(L"Booting in %d seconds\n", timeout); | |
1175 | else if (timeout) | |
1176 | Print(L"Booting in %d second\n", timeout); | |
1177 | } | |
1178 | ||
1bc1cd96 MG |
1179 | static void run_menu (CHAR16 *header, UINTN lines, struct menu_item *items, |
1180 | UINTN count, UINTN timeout) { | |
e204505d | 1181 | UINTN index, pos = 0, wait = 0, offset; |
d991c4a1 | 1182 | EFI_INPUT_KEY key; |
202b5c3e | 1183 | EFI_STATUS status; |
d08ea536 | 1184 | INTN ret; |
d991c4a1 | 1185 | |
202b5c3e MG |
1186 | if (timeout) |
1187 | wait = 10000000; | |
d991c4a1 | 1188 | |
37635f54 | 1189 | offset = draw_menu (header, lines, items, count); |
202b5c3e | 1190 | |
37635f54 MG |
1191 | while (1) { |
1192 | update_time(count + offset + 1, timeout); | |
202b5c3e | 1193 | |
d991c4a1 | 1194 | uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, |
e204505d | 1195 | 0, pos + offset); |
202b5c3e MG |
1196 | status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait); |
1197 | ||
1198 | if (status == EFI_TIMEOUT) { | |
1199 | timeout--; | |
1200 | if (!timeout) { | |
1201 | free_menu(items, count); | |
1202 | return; | |
1203 | } | |
1204 | continue; | |
1205 | } | |
1206 | ||
1207 | wait = 0; | |
1208 | timeout = 0; | |
1209 | ||
d991c4a1 MG |
1210 | uefi_call_wrapper(BS->WaitForEvent, 3, 1, |
1211 | &ST->ConIn->WaitForKey, &index); | |
1212 | uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, | |
1213 | &key); | |
1214 | ||
1215 | switch(key.ScanCode) { | |
1216 | case SCAN_UP: | |
1217 | if (pos == 0) | |
1218 | continue; | |
1219 | pos--; | |
1220 | continue; | |
1221 | break; | |
1222 | case SCAN_DOWN: | |
1223 | if (pos == (count - 1)) | |
1224 | continue; | |
1225 | pos++; | |
1226 | continue; | |
1227 | break; | |
5d328c6c | 1228 | } |
d991c4a1 MG |
1229 | |
1230 | switch(key.UnicodeChar) { | |
1231 | case CHAR_LINEFEED: | |
1232 | case CHAR_CARRIAGE_RETURN: | |
c9d2ff8c MG |
1233 | if (items[pos].callback == NULL) { |
1234 | free_menu(items, count); | |
d991c4a1 | 1235 | return; |
c9d2ff8c | 1236 | } |
d991c4a1 | 1237 | |
d08ea536 MG |
1238 | ret = items[pos].callback(items[pos].data, |
1239 | items[pos].data2, | |
1240 | items[pos].data3); | |
1241 | if (ret < 0) { | |
1242 | Print(L"Press a key to continue\n"); | |
1243 | Pause(); | |
4a88de58 GCPL |
1244 | /* Clear the key in the queue */ |
1245 | uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, | |
1246 | ST->ConIn, &key); | |
d08ea536 | 1247 | } |
1bc1cd96 | 1248 | draw_menu (header, lines, items, count); |
d991c4a1 MG |
1249 | pos = 0; |
1250 | break; | |
1251 | } | |
1252 | } | |
1253 | } | |
1254 | ||
0a6565c5 MG |
1255 | static UINTN verify_certificate(void *cert, UINTN size) |
1256 | { | |
1257 | X509 *X509Cert; | |
1258 | if (!cert || size == 0) | |
1259 | return FALSE; | |
1260 | ||
1261 | if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) || | |
1262 | X509Cert == NULL) { | |
1263 | Print(L"Invalid X509 certificate\n"); | |
1264 | Pause(); | |
1265 | return FALSE; | |
1266 | } | |
1267 | ||
1268 | X509_free(X509Cert); | |
1269 | return TRUE; | |
1270 | } | |
1271 | ||
1272 | static INTN file_callback (void *data, void *data2, void *data3) { | |
d991c4a1 | 1273 | EFI_FILE_INFO *buffer = NULL; |
0a6565c5 | 1274 | UINTN buffersize = 0, mokbuffersize; |
d991c4a1 MG |
1275 | EFI_STATUS status; |
1276 | EFI_FILE *file; | |
1277 | CHAR16 *filename = data; | |
1278 | EFI_FILE *parent = data2; | |
0a6565c5 | 1279 | BOOLEAN hash = !!data3; |
d991c4a1 | 1280 | EFI_GUID file_info_guid = EFI_FILE_INFO_ID; |
0a6565c5 MG |
1281 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; |
1282 | EFI_SIGNATURE_LIST *CertList; | |
1283 | EFI_SIGNATURE_DATA *CertData; | |
1284 | void *mokbuffer = NULL; | |
d991c4a1 MG |
1285 | |
1286 | status = uefi_call_wrapper(parent->Open, 5, parent, &file, filename, | |
1287 | EFI_FILE_MODE_READ, 0); | |
1288 | ||
1289 | if (status != EFI_SUCCESS) | |
1290 | return 1; | |
1291 | ||
1292 | status = uefi_call_wrapper(file->GetInfo, 4, file, &file_info_guid, | |
1293 | &buffersize, buffer); | |
1294 | ||
1295 | if (status == EFI_BUFFER_TOO_SMALL) { | |
1296 | buffer = AllocatePool(buffersize); | |
1297 | status = uefi_call_wrapper(file->GetInfo, 4, file, | |
1298 | &file_info_guid, &buffersize, | |
1299 | buffer); | |
5d328c6c | 1300 | } |
d991c4a1 MG |
1301 | |
1302 | if (!buffer) | |
1303 | return 0; | |
1304 | ||
0a6565c5 | 1305 | buffersize = buffer->FileSize; |
d991c4a1 | 1306 | |
0a6565c5 MG |
1307 | if (hash) { |
1308 | void *binary; | |
1309 | UINT8 sha256[SHA256_DIGEST_SIZE]; | |
1310 | UINT8 sha1[SHA1_DIGEST_SIZE]; | |
1311 | SHIM_LOCK *shim_lock; | |
1312 | EFI_GUID shim_guid = SHIM_LOCK_GUID; | |
1313 | PE_COFF_LOADER_IMAGE_CONTEXT context; | |
1314 | ||
1315 | status = LibLocateProtocol(&shim_guid, (VOID **)&shim_lock); | |
1316 | ||
1317 | if (status != EFI_SUCCESS) | |
1318 | goto out; | |
1319 | ||
1320 | mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) + | |
1321 | SHA256_DIGEST_SIZE; | |
1322 | ||
1323 | mokbuffer = AllocatePool(mokbuffersize); | |
d1c2586c MG |
1324 | |
1325 | if (!mokbuffer) | |
1326 | goto out; | |
1327 | ||
0a6565c5 MG |
1328 | binary = AllocatePool(buffersize); |
1329 | ||
1330 | status = uefi_call_wrapper(file->Read, 3, file, &buffersize, | |
1331 | binary); | |
1332 | ||
1333 | if (status != EFI_SUCCESS) | |
1334 | goto out; | |
1335 | ||
1336 | status = shim_lock->Context(binary, buffersize, &context); | |
1337 | ||
1338 | if (status != EFI_SUCCESS) | |
1339 | goto out; | |
1340 | ||
1341 | status = shim_lock->Hash(binary, buffersize, &context, sha256, | |
1342 | sha1); | |
1343 | ||
1344 | if (status != EFI_SUCCESS) | |
1345 | goto out; | |
1346 | ||
1347 | CertList = mokbuffer; | |
1348 | CertList->SignatureType = EfiHashSha256Guid; | |
1349 | CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE; | |
1350 | CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) + | |
1351 | sizeof(EFI_SIGNATURE_LIST)); | |
1352 | CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE); | |
d1c2586c | 1353 | } else { |
0a6565c5 MG |
1354 | mokbuffersize = buffersize + sizeof(EFI_SIGNATURE_LIST) + |
1355 | sizeof(EFI_GUID); | |
1356 | mokbuffer = AllocatePool(mokbuffersize); | |
d1c2586c MG |
1357 | |
1358 | if (!mokbuffer) | |
1359 | goto out; | |
d991c4a1 | 1360 | |
0a6565c5 MG |
1361 | CertList = mokbuffer; |
1362 | CertList->SignatureType = EfiCertX509Guid; | |
1363 | CertList->SignatureSize = 16 + buffersize; | |
1364 | status = uefi_call_wrapper(file->Read, 3, file, &buffersize, | |
1365 | mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16); | |
1366 | ||
1367 | if (status != EFI_SUCCESS) | |
1368 | goto out; | |
1369 | CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) + | |
1370 | sizeof(EFI_SIGNATURE_LIST)); | |
1371 | } | |
d991c4a1 | 1372 | |
0a6565c5 MG |
1373 | CertList->SignatureListSize = mokbuffersize; |
1374 | CertList->SignatureHeaderSize = 0; | |
1375 | CertData->SignatureOwner = shim_lock_guid; | |
d991c4a1 | 1376 | |
0a6565c5 MG |
1377 | if (!hash) { |
1378 | if (!verify_certificate(CertData->SignatureData, buffersize)) | |
1379 | goto out; | |
1380 | } | |
d991c4a1 | 1381 | |
0a6565c5 | 1382 | mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE); |
d991c4a1 MG |
1383 | out: |
1384 | if (buffer) | |
1385 | FreePool(buffer); | |
1386 | ||
1387 | if (mokbuffer) | |
1388 | FreePool(mokbuffer); | |
1389 | ||
1390 | return 0; | |
1391 | } | |
1392 | ||
0a6565c5 | 1393 | static INTN directory_callback (void *data, void *data2, void *data3) { |
d991c4a1 MG |
1394 | EFI_FILE_INFO *buffer = NULL; |
1395 | UINTN buffersize = 0; | |
1396 | EFI_STATUS status; | |
1397 | UINTN dircount = 0, i = 0; | |
1398 | struct menu_item *dircontent; | |
1399 | EFI_FILE *dir; | |
1400 | CHAR16 *filename = data; | |
1401 | EFI_FILE *root = data2; | |
1bc1cd96 | 1402 | BOOLEAN hash = !!data3; |
d991c4a1 MG |
1403 | |
1404 | status = uefi_call_wrapper(root->Open, 5, root, &dir, filename, | |
1405 | EFI_FILE_MODE_READ, 0); | |
1406 | ||
1407 | if (status != EFI_SUCCESS) | |
1408 | return 1; | |
1409 | ||
1410 | while (1) { | |
1411 | status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize, | |
1412 | buffer); | |
1413 | ||
1414 | if (status == EFI_BUFFER_TOO_SMALL) { | |
1415 | buffer = AllocatePool(buffersize); | |
1416 | status = uefi_call_wrapper(dir->Read, 3, dir, | |
1417 | &buffersize, buffer); | |
1418 | } | |
1419 | ||
1420 | if (status != EFI_SUCCESS) | |
1421 | return 1; | |
1422 | ||
1423 | if (!buffersize) | |
1424 | break; | |
1425 | ||
1426 | if ((StrCmp(buffer->FileName, L".") == 0) || | |
1427 | (StrCmp(buffer->FileName, L"..") == 0)) | |
1428 | continue; | |
1429 | ||
1430 | dircount++; | |
1431 | ||
1432 | FreePool(buffer); | |
1433 | buffersize = 0; | |
1434 | } | |
1435 | ||
1436 | dircount++; | |
1437 | ||
1438 | dircontent = AllocatePool(sizeof(struct menu_item) * dircount); | |
1439 | ||
1440 | dircontent[0].text = StrDuplicate(L".."); | |
1441 | dircontent[0].callback = NULL; | |
1442 | dircontent[0].colour = EFI_YELLOW; | |
1443 | i++; | |
1444 | ||
1445 | uefi_call_wrapper(dir->SetPosition, 2, dir, 0); | |
1446 | ||
1447 | while (1) { | |
1448 | status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize, | |
1449 | buffer); | |
1450 | ||
1451 | if (status == EFI_BUFFER_TOO_SMALL) { | |
1452 | buffer = AllocatePool(buffersize); | |
1453 | status = uefi_call_wrapper(dir->Read, 3, dir, | |
1454 | &buffersize, buffer); | |
1455 | } | |
1456 | ||
1457 | if (status != EFI_SUCCESS) | |
1458 | return 1; | |
1459 | ||
1460 | if (!buffersize) | |
1461 | break; | |
1462 | ||
1463 | if ((StrCmp(buffer->FileName, L".") == 0) || | |
1464 | (StrCmp(buffer->FileName, L"..") == 0)) | |
1465 | continue; | |
1466 | ||
1467 | if (buffer->Attribute & EFI_FILE_DIRECTORY) { | |
1468 | dircontent[i].text = StrDuplicate(buffer->FileName); | |
1469 | dircontent[i].callback = directory_callback; | |
1470 | dircontent[i].data = dircontent[i].text; | |
1471 | dircontent[i].data2 = dir; | |
0a6565c5 | 1472 | dircontent[i].data3 = data3; |
d991c4a1 MG |
1473 | dircontent[i].colour = EFI_YELLOW; |
1474 | } else { | |
1475 | dircontent[i].text = StrDuplicate(buffer->FileName); | |
1476 | dircontent[i].callback = file_callback; | |
1477 | dircontent[i].data = dircontent[i].text; | |
1478 | dircontent[i].data2 = dir; | |
0a6565c5 | 1479 | dircontent[i].data3 = data3; |
d991c4a1 MG |
1480 | dircontent[i].colour = EFI_WHITE; |
1481 | } | |
1482 | ||
1483 | i++; | |
1484 | FreePool(buffer); | |
1485 | buffersize = 0; | |
1486 | buffer = NULL; | |
1487 | } | |
1488 | ||
1bc1cd96 MG |
1489 | if (hash) |
1490 | run_menu(HASH_STRING, 2, dircontent, dircount, 0); | |
1491 | else | |
1492 | run_menu(CERT_STRING, 2, dircontent, dircount, 0); | |
d991c4a1 MG |
1493 | |
1494 | return 0; | |
1495 | } | |
1496 | ||
0a6565c5 | 1497 | static INTN filesystem_callback (void *data, void *data2, void *data3) { |
d991c4a1 MG |
1498 | EFI_FILE_INFO *buffer = NULL; |
1499 | UINTN buffersize = 0; | |
1500 | EFI_STATUS status; | |
1501 | UINTN dircount = 0, i = 0; | |
1502 | struct menu_item *dircontent; | |
1503 | EFI_FILE *root = data; | |
1bc1cd96 | 1504 | BOOLEAN hash = !!data3; |
d991c4a1 MG |
1505 | |
1506 | uefi_call_wrapper(root->SetPosition, 2, root, 0); | |
1507 | ||
1508 | while (1) { | |
1509 | status = uefi_call_wrapper(root->Read, 3, root, &buffersize, | |
1510 | buffer); | |
1511 | ||
1512 | if (status == EFI_BUFFER_TOO_SMALL) { | |
1513 | buffer = AllocatePool(buffersize); | |
1514 | status = uefi_call_wrapper(root->Read, 3, root, | |
1515 | &buffersize, buffer); | |
1516 | } | |
1517 | ||
1518 | if (status != EFI_SUCCESS) | |
1519 | return 1; | |
1520 | ||
1521 | if (!buffersize) | |
1522 | break; | |
1523 | ||
1524 | if ((StrCmp(buffer->FileName, L".") == 0) || | |
1525 | (StrCmp(buffer->FileName, L"..") == 0)) | |
1526 | continue; | |
1527 | ||
1528 | dircount++; | |
1529 | ||
1530 | FreePool(buffer); | |
1531 | buffersize = 0; | |
1532 | } | |
1533 | ||
c9696a1c | 1534 | dircount++; |
d991c4a1 MG |
1535 | |
1536 | dircontent = AllocatePool(sizeof(struct menu_item) * dircount); | |
1537 | ||
1538 | dircontent[0].text = StrDuplicate(L"Return to filesystem list"); | |
1539 | dircontent[0].callback = NULL; | |
1540 | dircontent[0].colour = EFI_YELLOW; | |
1541 | i++; | |
1542 | ||
1543 | uefi_call_wrapper(root->SetPosition, 2, root, 0); | |
1544 | ||
1545 | while (1) { | |
1546 | status = uefi_call_wrapper(root->Read, 3, root, &buffersize, | |
1547 | buffer); | |
1548 | ||
1549 | if (status == EFI_BUFFER_TOO_SMALL) { | |
1550 | buffer = AllocatePool(buffersize); | |
1551 | status = uefi_call_wrapper(root->Read, 3, root, | |
1552 | &buffersize, buffer); | |
1553 | } | |
1554 | ||
1555 | if (status != EFI_SUCCESS) | |
1556 | return 1; | |
1557 | ||
1558 | if (!buffersize) | |
1559 | break; | |
1560 | ||
1561 | if ((StrCmp(buffer->FileName, L".") == 0) || | |
1562 | (StrCmp(buffer->FileName, L"..") == 0)) | |
1563 | continue; | |
1564 | ||
1565 | if (buffer->Attribute & EFI_FILE_DIRECTORY) { | |
1566 | dircontent[i].text = StrDuplicate(buffer->FileName); | |
1567 | dircontent[i].callback = directory_callback; | |
1568 | dircontent[i].data = dircontent[i].text; | |
1569 | dircontent[i].data2 = root; | |
0a6565c5 | 1570 | dircontent[i].data3 = data3; |
d991c4a1 MG |
1571 | dircontent[i].colour = EFI_YELLOW; |
1572 | } else { | |
1573 | dircontent[i].text = StrDuplicate(buffer->FileName); | |
1574 | dircontent[i].callback = file_callback; | |
1575 | dircontent[i].data = dircontent[i].text; | |
1576 | dircontent[i].data2 = root; | |
0a6565c5 | 1577 | dircontent[i].data3 = data3; |
d991c4a1 MG |
1578 | dircontent[i].colour = EFI_WHITE; |
1579 | } | |
1580 | ||
1581 | i++; | |
1582 | FreePool(buffer); | |
1583 | buffer = NULL; | |
1584 | buffersize = 0; | |
1585 | } | |
1586 | ||
1bc1cd96 MG |
1587 | if (hash) |
1588 | run_menu(HASH_STRING, 2, dircontent, dircount, 0); | |
1589 | else | |
1590 | run_menu(CERT_STRING, 2, dircontent, dircount, 0); | |
d991c4a1 MG |
1591 | |
1592 | return 0; | |
1593 | } | |
1594 | ||
0a6565c5 | 1595 | static INTN find_fs (void *data, void *data2, void *data3) { |
d991c4a1 MG |
1596 | EFI_GUID fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL; |
1597 | UINTN count, i; | |
e65370d7 | 1598 | UINTN OldSize, NewSize; |
ed711b02 | 1599 | EFI_HANDLE *filesystem_handles = NULL; |
d991c4a1 | 1600 | struct menu_item *filesystems; |
1bc1cd96 | 1601 | BOOLEAN hash = !!data3; |
d991c4a1 MG |
1602 | |
1603 | uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &fs_guid, | |
1604 | NULL, &count, &filesystem_handles); | |
1605 | ||
1606 | if (!count || !filesystem_handles) { | |
1607 | Print(L"No filesystems?\n"); | |
1608 | return 1; | |
1609 | } | |
1610 | ||
1611 | count++; | |
1612 | ||
1613 | filesystems = AllocatePool(sizeof(struct menu_item) * count); | |
1614 | ||
1615 | filesystems[0].text = StrDuplicate(L"Exit"); | |
1616 | filesystems[0].callback = NULL; | |
1617 | filesystems[0].colour = EFI_YELLOW; | |
1618 | ||
1619 | for (i=1; i<count; i++) { | |
ed711b02 | 1620 | EFI_HANDLE fs = filesystem_handles[i-1]; |
d991c4a1 MG |
1621 | EFI_FILE_IO_INTERFACE *fs_interface; |
1622 | EFI_DEVICE_PATH *path; | |
1623 | EFI_FILE *root; | |
1624 | EFI_STATUS status; | |
1625 | CHAR16 *VolumeLabel = NULL; | |
1626 | EFI_FILE_SYSTEM_INFO *buffer = NULL; | |
1627 | UINTN buffersize = 0; | |
1628 | EFI_GUID file_info_guid = EFI_FILE_INFO_ID; | |
1629 | ||
1630 | status = uefi_call_wrapper(BS->HandleProtocol, 3, fs, &fs_guid, | |
ed711b02 | 1631 | (void **)&fs_interface); |
d991c4a1 MG |
1632 | |
1633 | if (status != EFI_SUCCESS || !fs_interface) | |
1634 | continue; | |
1635 | ||
1636 | path = DevicePathFromHandle(fs); | |
1637 | ||
1638 | status = uefi_call_wrapper(fs_interface->OpenVolume, 2, | |
1639 | fs_interface, &root); | |
1640 | ||
1641 | if (status != EFI_SUCCESS || !root) | |
1642 | continue; | |
1643 | ||
1644 | status = uefi_call_wrapper(root->GetInfo, 4, root, | |
1645 | &file_info_guid, &buffersize, | |
1646 | buffer); | |
1647 | ||
1648 | if (status == EFI_BUFFER_TOO_SMALL) { | |
1649 | buffer = AllocatePool(buffersize); | |
1650 | status = uefi_call_wrapper(root->GetInfo, 4, root, | |
1651 | &file_info_guid, | |
1652 | &buffersize, buffer); | |
1653 | } | |
1654 | ||
1655 | if (status == EFI_SUCCESS) | |
1656 | VolumeLabel = buffer->VolumeLabel; | |
1657 | ||
1658 | if (path) | |
1659 | filesystems[i].text = DevicePathToStr(path); | |
1660 | else | |
1661 | filesystems[i].text = StrDuplicate(L"Unknown device\n"); | |
e65370d7 GCPL |
1662 | if (VolumeLabel) { |
1663 | OldSize = (StrLen(filesystems[i].text) + 1) * sizeof(CHAR16); | |
1664 | NewSize = OldSize + StrLen(VolumeLabel) * sizeof(CHAR16); | |
1665 | filesystems[i].text = ReallocatePool(filesystems[i].text, | |
1666 | OldSize, NewSize); | |
d991c4a1 | 1667 | StrCat(filesystems[i].text, VolumeLabel); |
e65370d7 | 1668 | } |
d991c4a1 MG |
1669 | |
1670 | if (buffersize) | |
1671 | FreePool(buffer); | |
1672 | ||
1673 | filesystems[i].data = root; | |
1674 | filesystems[i].data2 = NULL; | |
0a6565c5 | 1675 | filesystems[i].data3 = data3; |
d991c4a1 MG |
1676 | filesystems[i].callback = filesystem_callback; |
1677 | filesystems[i].colour = EFI_YELLOW; | |
1678 | } | |
1679 | ||
1680 | uefi_call_wrapper(BS->FreePool, 1, filesystem_handles); | |
1681 | ||
1bc1cd96 MG |
1682 | if (hash) |
1683 | run_menu(HASH_STRING, 2, filesystems, count, 0); | |
1684 | else | |
1685 | run_menu(CERT_STRING, 2, filesystems, count, 0); | |
d991c4a1 MG |
1686 | |
1687 | return 0; | |
1688 | } | |
1689 | ||
801d1b93 MG |
1690 | static BOOLEAN verify_pw(void) |
1691 | { | |
1692 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
1693 | EFI_STATUS efi_status; | |
801d1b93 MG |
1694 | UINT8 pwhash[SHA256_DIGEST_SIZE]; |
1695 | UINTN size = SHA256_DIGEST_SIZE; | |
801d1b93 MG |
1696 | UINT32 attributes; |
1697 | ||
1698 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore", | |
1699 | &shim_lock_guid, &attributes, &size, | |
1700 | pwhash); | |
1701 | ||
1702 | /* | |
1703 | * If anything can attack the password it could just set it to a | |
1704 | * known value, so there's no safety advantage in failing to validate | |
1705 | * purely because of a failure to read the variable | |
1706 | */ | |
1707 | if (efi_status != EFI_SUCCESS) | |
1708 | return TRUE; | |
1709 | ||
1710 | if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) | |
1711 | return TRUE; | |
1712 | ||
34f0c4ab MG |
1713 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); |
1714 | ||
262d6714 GCPL |
1715 | efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: "); |
1716 | if (efi_status != EFI_SUCCESS) { | |
1717 | Print(L"Password limit reached\n"); | |
1718 | return FALSE; | |
801d1b93 MG |
1719 | } |
1720 | ||
262d6714 | 1721 | return TRUE; |
801d1b93 MG |
1722 | } |
1723 | ||
92a136d8 GCPL |
1724 | static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, |
1725 | void *MokNew, UINTN MokNewSize, | |
1726 | void *MokDel, UINTN MokDelSize, | |
1727 | void *MokSB, UINTN MokSBSize, | |
1728 | void *MokPW, UINTN MokPWSize) | |
d991c4a1 | 1729 | { |
24eace99 | 1730 | struct menu_item *menu_item; |
0a6565c5 | 1731 | UINT32 MokAuth = 0; |
92a136d8 | 1732 | UINT32 MokDelAuth = 0; |
9272bc5b | 1733 | UINTN menucount = 3, i = 0; |
0a6565c5 MG |
1734 | EFI_STATUS efi_status; |
1735 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
1736 | UINT8 auth[SHA256_DIGEST_SIZE]; | |
1737 | UINTN auth_size = SHA256_DIGEST_SIZE; | |
1738 | UINT32 attributes; | |
24eace99 | 1739 | |
801d1b93 MG |
1740 | if (verify_pw() == FALSE) |
1741 | return EFI_ACCESS_DENIED; | |
1742 | ||
0a6565c5 MG |
1743 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth", |
1744 | &shim_lock_guid, | |
1745 | &attributes, &auth_size, auth); | |
1746 | ||
1747 | if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE)) | |
1748 | MokAuth = 1; | |
1749 | ||
92a136d8 GCPL |
1750 | efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth", |
1751 | &shim_lock_guid, | |
1752 | &attributes, &auth_size, auth); | |
1753 | ||
1754 | if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE)) | |
1755 | MokDelAuth = 1; | |
1756 | ||
0a6565c5 | 1757 | if (MokNew || MokAuth) |
9272bc5b MG |
1758 | menucount++; |
1759 | ||
92a136d8 GCPL |
1760 | if (MokDel || MokDelAuth) |
1761 | menucount++; | |
1762 | ||
9272bc5b MG |
1763 | if (MokSB) |
1764 | menucount++; | |
1765 | ||
801d1b93 MG |
1766 | if (MokPW) |
1767 | menucount++; | |
1768 | ||
9272bc5b | 1769 | menu_item = AllocateZeroPool(sizeof(struct menu_item) * menucount); |
24eace99 MG |
1770 | |
1771 | if (!menu_item) | |
1772 | return EFI_OUT_OF_RESOURCES; | |
d991c4a1 | 1773 | |
9272bc5b MG |
1774 | menu_item[i].text = StrDuplicate(L"Continue boot"); |
1775 | menu_item[i].colour = EFI_WHITE; | |
1776 | menu_item[i].callback = NULL; | |
d991c4a1 | 1777 | |
9272bc5b | 1778 | i++; |
24eace99 | 1779 | |
0a6565c5 MG |
1780 | if (MokNew || MokAuth) { |
1781 | if (!MokNew) { | |
92a136d8 | 1782 | menu_item[i].text = StrDuplicate(L"Reset MOK"); |
9272bc5b | 1783 | menu_item[i].colour = EFI_WHITE; |
92a136d8 | 1784 | menu_item[i].callback = mok_reset_prompt; |
24eace99 | 1785 | } else { |
9272bc5b MG |
1786 | menu_item[i].text = StrDuplicate(L"Enroll MOK"); |
1787 | menu_item[i].colour = EFI_WHITE; | |
1788 | menu_item[i].data = MokNew; | |
1789 | menu_item[i].data2 = (void *)MokNewSize; | |
1790 | menu_item[i].callback = mok_enrollment_prompt_callback; | |
24eace99 | 1791 | } |
9272bc5b MG |
1792 | i++; |
1793 | } | |
1794 | ||
92a136d8 GCPL |
1795 | if (MokDel || MokDelAuth) { |
1796 | menu_item[i].text = StrDuplicate(L"Delete MOK"); | |
1797 | menu_item[i].colour = EFI_WHITE; | |
1798 | menu_item[i].data = MokDel; | |
1799 | menu_item[i].data2 = (void *)MokDelSize; | |
1800 | menu_item[i].callback = mok_deletion_prompt; | |
1801 | i++; | |
1802 | } | |
1803 | ||
9272bc5b MG |
1804 | if (MokSB) { |
1805 | menu_item[i].text = StrDuplicate(L"Change Secure Boot state"); | |
1806 | menu_item[i].colour = EFI_WHITE; | |
1807 | menu_item[i].callback = mok_sb_prompt; | |
1808 | menu_item[i].data = MokSB; | |
1809 | menu_item[i].data2 = (void *)MokSBSize; | |
1810 | i++; | |
d991c4a1 MG |
1811 | } |
1812 | ||
801d1b93 MG |
1813 | if (MokPW) { |
1814 | menu_item[i].text = StrDuplicate(L"Set MOK password"); | |
1815 | menu_item[i].colour = EFI_WHITE; | |
1816 | menu_item[i].callback = mok_pw_prompt; | |
1817 | menu_item[i].data = MokPW; | |
1818 | menu_item[i].data2 = (void *)MokPWSize; | |
1819 | i++; | |
1820 | } | |
1821 | ||
9272bc5b MG |
1822 | menu_item[i].text = StrDuplicate(L"Enroll key from disk"); |
1823 | menu_item[i].colour = EFI_WHITE; | |
1824 | menu_item[i].callback = find_fs; | |
1825 | menu_item[i].data3 = (void *)FALSE; | |
0a6565c5 | 1826 | |
9272bc5b | 1827 | i++; |
0a6565c5 | 1828 | |
9272bc5b MG |
1829 | menu_item[i].text = StrDuplicate(L"Enroll hash from disk"); |
1830 | menu_item[i].colour = EFI_WHITE; | |
1831 | menu_item[i].callback = find_fs; | |
1832 | menu_item[i].data3 = (void *)TRUE; | |
d991c4a1 | 1833 | |
9272bc5b | 1834 | i++; |
a68a0c7b | 1835 | |
1bc1cd96 | 1836 | run_menu(NULL, 0, menu_item, menucount, 10); |
d991c4a1 | 1837 | |
5f292f8f MG |
1838 | uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); |
1839 | ||
d991c4a1 MG |
1840 | return 0; |
1841 | } | |
1842 | ||
1843 | static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) | |
1844 | { | |
1845 | EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; | |
92a136d8 | 1846 | UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0; |
d991c4a1 | 1847 | void *MokNew = NULL; |
92a136d8 | 1848 | void *MokDel = NULL; |
9272bc5b | 1849 | void *MokSB = NULL; |
801d1b93 | 1850 | void *MokPW = NULL; |
d991c4a1 MG |
1851 | |
1852 | MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize); | |
1853 | ||
92a136d8 GCPL |
1854 | MokDel = LibGetVariableAndSize(L"MokDel", &shim_lock_guid, &MokDelSize); |
1855 | ||
801d1b93 MG |
1856 | MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize); |
1857 | ||
1858 | MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize); | |
9272bc5b | 1859 | |
92a136d8 GCPL |
1860 | enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize, |
1861 | MokSB, MokSBSize, MokPW, MokPWSize); | |
d991c4a1 | 1862 | |
c326e2df | 1863 | if (MokNew) { |
f3104a73 | 1864 | if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) { |
333bd977 GCPL |
1865 | Print(L"Failed to delete MokNew\n"); |
1866 | } | |
c326e2df | 1867 | FreePool (MokNew); |
333bd977 | 1868 | } |
9272bc5b | 1869 | |
92a136d8 GCPL |
1870 | if (MokDel) { |
1871 | if (LibDeleteVariable(L"MokDel", &shim_lock_guid) != EFI_SUCCESS) { | |
1872 | Print(L"Failed to delete MokDel\n"); | |
1873 | } | |
1874 | FreePool (MokDel); | |
1875 | } | |
1876 | ||
9272bc5b MG |
1877 | if (MokSB) { |
1878 | if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) { | |
1879 | Print(L"Failed to delete MokSB\n"); | |
1880 | } | |
1881 | FreePool (MokNew); | |
1882 | } | |
801d1b93 MG |
1883 | |
1884 | if (MokPW) { | |
1885 | if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) { | |
1886 | Print(L"Failed to delete MokPW\n"); | |
1887 | } | |
1888 | FreePool (MokNew); | |
1889 | } | |
1890 | ||
f3104a73 | 1891 | LibDeleteVariable(L"MokAuth", &shim_lock_guid); |
92a136d8 | 1892 | LibDeleteVariable(L"MokDelAuth", &shim_lock_guid); |
333bd977 | 1893 | |
333bd977 GCPL |
1894 | return EFI_SUCCESS; |
1895 | } | |
1896 | ||
79a5aa03 MG |
1897 | static EFI_STATUS setup_rand (void) |
1898 | { | |
1899 | EFI_TIME time; | |
1900 | EFI_STATUS efi_status; | |
1901 | UINT64 seed; | |
1902 | BOOLEAN status; | |
1903 | ||
1904 | efi_status = uefi_call_wrapper(RT->GetTime, 2, &time, NULL); | |
1905 | ||
1906 | if (efi_status != EFI_SUCCESS) | |
1907 | return efi_status; | |
1908 | ||
1909 | seed = ((UINT64)time.Year << 48) | ((UINT64)time.Month << 40) | | |
1910 | ((UINT64)time.Day << 32) | ((UINT64)time.Hour << 24) | | |
1911 | ((UINT64)time.Minute << 16) | ((UINT64)time.Second << 8) | | |
1912 | ((UINT64)time.Daylight); | |
1913 | ||
1914 | status = RandomSeed((UINT8 *)&seed, sizeof(seed)); | |
1915 | ||
1916 | if (!status) | |
1917 | return EFI_ABORTED; | |
1918 | ||
1919 | return EFI_SUCCESS; | |
1920 | } | |
1921 | ||
333bd977 GCPL |
1922 | EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab) |
1923 | { | |
1924 | EFI_STATUS efi_status; | |
1925 | ||
1926 | InitializeLib(image_handle, systab); | |
1927 | ||
79a5aa03 MG |
1928 | setup_rand(); |
1929 | ||
333bd977 GCPL |
1930 | efi_status = check_mok_request(image_handle); |
1931 | ||
1932 | return efi_status; | |
1933 | } |