1
2 #include <efi.h>
3 #include <efilib.h>
4
5 #include "shelliface.h"
6 #include "sb.h"
7
8 /* XXX probably shouldn't ship defaulting to this */
9 EFI_GUID rh_guid = {0x0abba7dc, 0xe516, 0x4167, {0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}};
10
11 /* XXX this needs to be moved into gnu-efi */
12 EFI_GUID gEfiShellInterfaceGuid = EFI_SHELL_INTERFACE_GUID;
13
14 /* XXX this needs to be moved into gnu-efi */
15 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
16 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
17 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
18
19 /* XXX this needs to be moved into gnu-efi */
20 #define EFI_SHELL_DEVICE_PATH_MAP \
21 {0x47c7b225, 0xc42a, 0x11d2, {0x8e,0x57,0x0,0xa0,0xc9,0x69,0x72,0x3b}}
22 EFI_GUID gEfiShellDevPathMap = EFI_SHELL_DEVICE_PATH_MAP;
23
24 static void
25 __attribute__((unused))
dumphex(UINT8 * data,UINTN data_size)26 dumphex(UINT8 *data, UINTN data_size)
27 {
28 int i, j;
29 for (i = 0, j = 0; i < data_size; i++, j++) {
30 Print(L"%02x ", data[i]);
31 if (j == 15) {
32 j = -1;
33 Print(L"\n");
34 }
35 }
36 if (j != -1)
37 Print(L"\n");
38 }
39
40 static void
41 __attribute__((unused))
dumphex_str(CHAR16 * data,UINTN data_size)42 dumphex_str(CHAR16 *data, UINTN data_size)
43 {
44 int i, j;
45 for (i = 0, j = 0; i < data_size; i+=2, j++) {
46 Print(L"%c%c ", data[i], data[i+1]);
47 if (j == 15) {
48 j = -1;
49 Print(L"\n");
50 }
51 }
52 if (j != -1)
53 Print(L"\n");
54 }
55
56 static EFI_STATUS
get_args(EFI_HANDLE image,UINTN * argc,CHAR16 *** argv)57 get_args(EFI_HANDLE image, UINTN *argc, CHAR16 ***argv)
58 {
59 EFI_STATUS rc;
60 EFI_SHELL_INTERFACE *shell;
61
62 rc = uefi_call_wrapper(BS->OpenProtocol, 6,
63 image,
64 &gEfiShellInterfaceGuid,
65 (VOID **)&shell, image, NULL,
66 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
67
68 if (EFI_ERROR(rc))
69 return rc;
70
71 *argc = shell->Argc;
72 *argv = shell->Argv;
73 uefi_call_wrapper(BS->CloseProtocol, 4, image,
74 &gEfiShellInterfaceGuid,
75 image, NULL);
76 return EFI_SUCCESS;
77 }
78
79 static int
pk_is_populated(void)80 pk_is_populated(void)
81 {
82 char *data = NULL;
83 UINTN data_size = 0;
84
85 data = LibGetVariableAndSize(EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
86 &data_size);
87 FreePool(data);
88 if (!data || data_size == 0)
89 return 0;
90 return 1;
91 }
92
93 static int
kek_is_populated(void)94 kek_is_populated(void)
95 {
96 char *data = NULL;
97 UINTN data_size = 0;
98
99 data = LibGetVariableAndSize(EFI_KEY_EXCHANGE_KEY_NAME,
100 &EfiGlobalVariable, &data_size);
101 FreePool(data);
102 if (!data || data_size == 0)
103 return 0;
104 return 1;
105 }
106
107 static int
db_is_populated(void)108 db_is_populated(void)
109 {
110 char *data = NULL;
111 UINTN data_size = 0;
112
113 data = LibGetVariableAndSize(EFI_IMAGE_SECURITY_DATABASE,
114 &gEfiImageSecurityDatabaseGuid, &data_size);
115 FreePool(data);
116 if (!data || data_size == 0)
117 return 0;
118 return 1;
119 }
120
121 #if 0 /* doesn't appear necessary */
122 static int
123 dbx_is_populated(void)
124 {
125 char *data = NULL;
126 UINTN data_size = 0;
127
128 data = LibGetVariableAndSize(EFI_IMAGE_SECURITY_DATABASE1,
129 &gEfiImageSecurityDatabaseGuid, &data_size);
130 FreePool(data);
131 if (!data || data_size == 0)
132 return 0;
133 return 1;
134 }
135 #endif
136
137 static EFI_STATUS
make_variable(UINT8 * hash,UINTN hash_size,EFI_GUID owner,EFI_GUID signature_type,VOID ** data,UINTN * data_size)138 make_variable(UINT8 *hash, UINTN hash_size,
139 EFI_GUID owner, EFI_GUID signature_type,
140 VOID **data, UINTN *data_size)
141 {
142 if (!data || !data_size)
143 return EFI_INVALID_PARAMETER;
144
145 struct {
146 EFI_SIGNATURE_LIST sl;
147 EFI_SIGNATURE_DATA sd;
148 UINT8 cert[hash_size];
149 } __attribute__((aligned (1))) __attribute__((packed)) *var;
150
151 var = AllocatePool(sizeof(*var));
152 if (!var)
153 return EFI_OUT_OF_RESOURCES;
154
155 var->sl.SignatureType = signature_type;
156 var->sl.SignatureListSize = sizeof(*var);
157 var->sl.SignatureHeaderSize = 0;
158 var->sl.SignatureSize = sizeof(EFI_SIGNATURE_DATA) + hash_size;
159
160 var->sd.SignatureOwner = owner;
161 CopyMem(var->cert, hash, hash_size);
162
163 *data = var;
164 *data_size = sizeof(*var);
165
166 return EFI_SUCCESS;
167 }
168
169 static void
usage(void)170 usage(void)
171 {
172 Print(L"Usage: setupbs COMMAND \n");
173 Print(L" COMMAND := { set KEY SET_OPTIONS |\n"
174 L" append KEY SET_OPTIONS |\n"
175 L" clear KEY CLEAR_OPTIONS |\n"
176 L" help }\n");
177 Print(L" KEY := { pk | kek | db | dbx }\n");
178 Print(L" SET_OPTIONS := [ --force ] { HASH | FILE }\n");
179 Print(L" HASH := --hash SIG_TYPE <hash>\n");
180 Print(L" FILE := --file SIG_TYPE <filename>\n");
181 Print(L" SIG_TYPE := sha1 sha256 rsa2048 x509\n");
182 Print(L" CLEAR_OPTIONS := [ --force ]\n");
183 }
184
185 static int
has_force(UINTN argc,CHAR16 ** argv)186 has_force(UINTN argc, CHAR16 **argv)
187 {
188 int i;
189 for (i = 0; i < argc; i++) {
190 if (!StrCmp(argv[i], L"--force"))
191 return 1;
192 }
193 return 0;
194 }
195
196 static inline int
hex_to_ord(CHAR16 x)197 hex_to_ord(CHAR16 x)
198 {
199 char y = x & 0xff;
200 int c = y >= 'a' ? 'a'-0xa
201 : y >= 'A' ? 'A'-0xa
202 : '0';
203 y -= c;
204
205 if (y < 0 && y > 0xf)
206 return -1;
207 return y;
208 }
209
210 static struct {
211 CHAR16 *name;
212 EFI_GUID guid;
213 UINTN size;
214 } hashes[] = {
215 { L"SHA1", EFI_CERT_SHA1_GUID, 20 },
216 { L"SHA256", EFI_CERT_SHA256_GUID, 32 },
217 { L"RSA2048", EFI_CERT_RSA2048_GUID, 256 },
218 { L"X509", EFI_CERT_X509_GUID, -1 },
219 { NULL, }
220 };
221
222 static EFI_STATUS
get_hash(UINTN argc,CHAR16 ** argv,EFI_GUID * sig_type_guid,UINT8 ** hashp,UINTN * hash_sizep)223 get_hash(UINTN argc, CHAR16 **argv, EFI_GUID *sig_type_guid,
224 UINT8 **hashp, UINTN *hash_sizep)
225 {
226 int i;
227
228 UINT8 *hash = NULL;
229 UINTN hash_size = 0;
230
231 EFI_GUID hash_guid;
232 UINTN expected_hash_size = 0;
233
234 if (!hashp || !hash_sizep)
235 return EFI_INVALID_PARAMETER;
236
237 for (i = 1; i < argc; i++) {
238 if (!StrCmp(argv[i], L"--hash")) {
239 if (argc <= i+2) {
240 Print(L"argc is %d and we need %d\n",
241 argc, i+2);
242 return EFI_INVALID_PARAMETER;
243 }
244
245 StrUpr(argv[i+1]);
246 int j;
247 for (j = 0; hashes[j].name != NULL; j++) {
248 if (!StrCmp(hashes[j].name, argv[i+1])) {
249 hash_guid = hashes[j].guid;
250 expected_hash_size = hashes[j].size;
251 break;
252 }
253 }
254
255 if (!expected_hash_size) {
256 Print(L"Unknown hash %s\n", argv[i+1]);
257 return EFI_UNSUPPORTED;
258 }
259
260 CHAR16 *text = argv[i+2];
261 int text_len = StrLen(text);
262
263 hash_size = text_len / 2;
264 if (hash_size != expected_hash_size) {
265 Print(L"Hash size was expected to be %d, but was actually %d\n", expected_hash_size, hash_size);
266 return EFI_INVALID_PARAMETER;
267 }
268
269
270 hash = AllocatePool(hash_size);
271 int k;
272 for (j = 0, k = 0; j < hash_size; j++, k+=2) {
273 int x = hex_to_ord(text[k]);
274 int y = hex_to_ord(text[k+1]);
275
276 if (x < 0 || y < 0) {
277 Print(L"Coding error: {%d,%d} should both be positive\n", x, y);
278 FreePool(hash);
279 return EFI_INVALID_PARAMETER;
280 }
281 hash[j] = (x << 4) | y;
282 }
283
284 *sig_type_guid = hash_guid;
285 *hashp = hash;
286 *hash_sizep = hash_size;
287 return EFI_SUCCESS;
288 }
289 }
290 return EFI_NOT_FOUND;
291 }
292
293 static EFI_STATUS
get_file(UINTN argc,CHAR16 ** argv,EFI_GUID * sig_type_guid,UINT8 ** hashp,UINTN * hash_sizep)294 get_file(UINTN argc, CHAR16 **argv, EFI_GUID *sig_type_guid,
295 UINT8 **hashp, UINTN *hash_sizep)
296 {
297 return EFI_UNSUPPORTED;
298 }
299
300 static EFI_STATUS
set_pk(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)301 set_pk(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
302 {
303 EFI_STATUS rc;
304 UINT8 *hash = NULL;
305 UINTN hash_size = 0;
306 EFI_GUID sig_type_guid;
307
308 rc = get_hash(argc, argv, &sig_type_guid, &hash, &hash_size);
309 if (rc == EFI_NOT_FOUND) {
310 rc = get_file(argc, argv, &sig_type_guid, &hash, &hash_size);
311 if (rc == EFI_NOT_FOUND)
312 return EFI_INVALID_PARAMETER;
313 }
314 if (EFI_ERROR(rc))
315 return rc;
316
317 if (!CompareMem(&sig_type_guid, &gEfiCertRsa2048Guid,
318 sizeof(sig_type_guid))) {
319 Print(L"PK must be an RSA2048 Modulus.\n");
320 return EFI_INVALID_PARAMETER;
321 }
322
323 UINTN flags = EFI_VARIABLE_NON_VOLATILE |
324 EFI_VARIABLE_RUNTIME_ACCESS |
325 EFI_VARIABLE_BOOTSERVICE_ACCESS;
326
327 #if 0 /* this is what you'd expect */
328 VOID *data = NULL;
329 UINTN data_size = 0;
330
331 rc = make_variable(hash, hash_size, rh_guid,
332 sig_type_guid, &data, &data_size);
333
334 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
335 EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
336 flags, data_size, data);
337 FreePool(data);
338 #else /* this is what you get */
339 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
340 EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
341 flags, hash_size, hash);
342 #endif
343
344 FreePool(hash);
345
346 return rc;
347 }
348
349 static EFI_STATUS
set_db_helper(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv,EFI_GUID * vendor_guid,CHAR16 * dbname,int append)350 set_db_helper(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image,
351 UINTN argc, CHAR16 **argv,
352 EFI_GUID *vendor_guid, CHAR16 *dbname,
353 int append)
354 {
355 EFI_STATUS rc;
356 UINT8 *hash = NULL;
357 UINTN hash_size = 0;
358 EFI_GUID sig_type_guid;
359
360 rc = get_hash(argc, argv, &sig_type_guid, &hash, &hash_size);
361 if (rc == EFI_NOT_FOUND) {
362 rc = get_file(argc, argv, &sig_type_guid, &hash, &hash_size);
363 if (rc == EFI_NOT_FOUND)
364 return EFI_INVALID_PARAMETER;
365 }
366 if (EFI_ERROR(rc))
367 return rc;
368
369 VOID *data = NULL;
370 UINTN data_size = 0;
371
372 rc = make_variable(hash, hash_size, rh_guid,
373 sig_type_guid, &data, &data_size);
374
375 UINTN flags = EFI_VARIABLE_NON_VOLATILE |
376 EFI_VARIABLE_RUNTIME_ACCESS |
377 EFI_VARIABLE_BOOTSERVICE_ACCESS;
378 if (append)
379 flags |= EFI_VARIABLE_APPEND_WRITE;
380
381 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
382 dbname, vendor_guid, flags, data_size, data);
383 FreePool(data);
384 FreePool(hash);
385
386 return rc;
387 }
388
389 static EFI_STATUS
set_db(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)390 set_db(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
391 {
392 return set_db_helper(systab, image, argc, argv,
393 &gEfiImageSecurityDatabaseGuid,
394 EFI_IMAGE_SECURITY_DATABASE, 0);
395 }
396
397 static EFI_STATUS
set_dbx(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)398 set_dbx(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
399 {
400 return set_db_helper(systab, image, argc, argv,
401 &gEfiImageSecurityDatabaseGuid,
402 EFI_IMAGE_SECURITY_DATABASE1, 0);
403 }
404
405 static EFI_STATUS
set_kek(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)406 set_kek(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
407 {
408 return set_db_helper(systab, image, argc, argv,
409 &EfiGlobalVariable,
410 EFI_KEY_EXCHANGE_KEY_NAME, 0);
411 }
412
413 static EFI_STATUS
append_db(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)414 append_db(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
415 {
416
417 return set_db_helper(systab, image, argc, argv,
418 &gEfiImageSecurityDatabaseGuid,
419 EFI_IMAGE_SECURITY_DATABASE, 1);
420 }
421
422 static EFI_STATUS
append_dbx(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)423 append_dbx(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
424 {
425 return set_db_helper(systab, image, argc, argv,
426 &gEfiImageSecurityDatabaseGuid,
427 EFI_IMAGE_SECURITY_DATABASE1, 1);
428 }
429
430 static EFI_STATUS
append_kek(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)431 append_kek(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
432 {
433 return set_db_helper(systab, image, argc, argv,
434 &EfiGlobalVariable,
435 EFI_KEY_EXCHANGE_KEY_NAME, 1);
436 }
437
438 static EFI_STATUS
append_pk(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)439 append_pk(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
440 {
441 Print(L"PK Can only be one entry.\n");
442 return EFI_UNSUPPORTED;
443 }
444
445 static EFI_STATUS
clear_pk(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)446 clear_pk(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
447 {
448 EFI_STATUS rc;
449 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
450 EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
451 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
452 EFI_VARIABLE_BOOTSERVICE_ACCESS,
453 0, NULL);
454 if (rc == EFI_NOT_FOUND)
455 rc = EFI_SUCCESS;
456 return rc;
457 }
458
459 static EFI_STATUS
clear_db(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)460 clear_db(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
461 {
462 EFI_STATUS rc;
463
464 if (pk_is_populated() && !kek_is_populated() && !has_force(argc,argv)) {
465 Print(L"Cowardly refusing to clear db with PK set "
466 L"and no KEK\n");
467 return EFI_UNSUPPORTED;
468 }
469 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
470 EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid,
471 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
472 EFI_VARIABLE_BOOTSERVICE_ACCESS,
473 0, NULL);
474 if (rc == EFI_NOT_FOUND)
475 rc = EFI_SUCCESS;
476 return rc;
477 }
478
479 static EFI_STATUS
clear_dbx(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)480 clear_dbx(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
481 {
482 EFI_STATUS rc;
483 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
484 EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid,
485 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
486 EFI_VARIABLE_BOOTSERVICE_ACCESS,
487 0, NULL);
488 if (rc == EFI_NOT_FOUND)
489 rc = EFI_SUCCESS;
490 return rc;
491 }
492
493 static EFI_STATUS
clear_kek(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)494 clear_kek(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
495 {
496 EFI_STATUS rc;
497 if (pk_is_populated() && !db_is_populated() && !has_force(argc,argv)) {
498 Print(L"Cowardly refusing to clear KEK with PK set "
499 L"and no DB entries\n");
500 return EFI_UNSUPPORTED;
501 }
502 rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
503 EFI_KEY_EXCHANGE_KEY_NAME, &EfiGlobalVariable,
504 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
505 EFI_VARIABLE_BOOTSERVICE_ACCESS,
506 0, NULL);
507 if (rc == EFI_NOT_FOUND)
508 rc = EFI_SUCCESS;
509 return rc;
510 }
511
512 struct {
513 CHAR16 *name;
514 CHAR16 *db;
515 EFI_STATUS (*handler)(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv);
516 } actions[] = {
517 { L"set", L"pk", set_pk},
518 { L"set", L"kek", set_kek},
519 { L"set", L"db", set_db},
520 { L"set", L"dbx", set_dbx},
521 { L"append", L"PK", append_pk},
522 { L"append", L"kek", append_kek},
523 { L"append", L"db", append_db},
524 { L"append", L"dbx", append_dbx},
525 { L"clear", L"pk", clear_pk},
526 { L"clear", L"kek", clear_kek},
527 { L"clear", L"db", clear_db},
528 { L"clear", L"dbx", clear_dbx},
529 { NULL, NULL, NULL},
530 };
531
532 typedef EFI_STATUS (*handler)(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv);
533
534 EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)535 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
536 {
537 UINTN argc;
538 CHAR16 **argv;
539 EFI_STATUS rc = EFI_SUCCESS;
540
541 InitializeLib(image, systab);
542
543 rc = get_args(image, &argc, &argv);
544 if (EFI_ERROR(rc)) {
545 Print(L"Error: %d\n", rc);
546 return rc;
547 }
548
549 if (argc == 1) {
550 Print(L"Too few arguments.\n");
551 show_usage:
552 usage();
553 return EFI_INVALID_PARAMETER;
554 }
555
556 if (argc == 2) {
557 if (!StrCmp(argv[1], L"help") ||
558 !StrCmp(argv[1], L"/help") ||
559 !StrCmp(argv[1], L"--help") ||
560 !StrCmp(argv[1], L"-?")) {
561 usage();
562 return EFI_SUCCESS;
563 }
564 goto show_usage;
565 }
566
567 int i = 1;
568
569 rc = EFI_INVALID_PARAMETER;
570 int j;
571
572 for(j = 0; actions[j].name != NULL; j++ ) {
573 if (!StrCmp(actions[j].name, argv[i]) &&
574 !StrCmp(actions[j].db, argv[i+1])) {
575 rc = actions[j].handler(systab, image, argc-i, argv+i);
576 break;
577 }
578 }
579 if (rc == EFI_UNSUPPORTED || rc == EFI_INVALID_PARAMETER)
580 goto show_usage;
581
582 if (EFI_ERROR(rc))
583 Print(L"Error: %d\n", rc);
584 return rc;
585 }
586