1 // SPDX-License-Identifier: GPL-2.0+
3 * Menu-driven UEFI Secure Boot Key Maintenance
5 * Copyright (c) 2022 Masahisa Kojima, Linaro Limited
14 #include <efi_loader.h>
15 #include <efi_config.h>
16 #include <efi_variable.h>
17 #include <crypto/pkcs7_parser.h>
19 struct eficonfig_sig_data {
20 struct efi_signature_list *esl;
21 struct efi_signature_data *esd;
22 struct list_head list;
26 enum efi_sbkey_signature_type {
33 struct eficonfig_sigtype_to_str {
36 enum efi_sbkey_signature_type type;
39 static const struct eficonfig_sigtype_to_str sigtype_to_str[] = {
40 {EFI_CERT_X509_GUID, "X509", SIG_TYPE_X509},
41 {EFI_CERT_SHA256_GUID, "SHA256", SIG_TYPE_HASH},
42 {EFI_CERT_X509_SHA256_GUID, "X509_SHA256 CRL", SIG_TYPE_CRL},
43 {EFI_CERT_X509_SHA384_GUID, "X509_SHA384 CRL", SIG_TYPE_CRL},
44 {EFI_CERT_X509_SHA512_GUID, "X509_SHA512 CRL", SIG_TYPE_CRL},
45 /* U-Boot does not support the following signature types */
46 /* {EFI_CERT_RSA2048_GUID, "RSA2048", SIG_TYPE_RSA2048}, */
47 /* {EFI_CERT_RSA2048_SHA256_GUID, "RSA2048_SHA256", SIG_TYPE_RSA2048}, */
48 /* {EFI_CERT_SHA1_GUID, "SHA1", SIG_TYPE_HASH}, */
49 /* {EFI_CERT_RSA2048_SHA_GUID, "RSA2048_SHA", SIG_TYPE_RSA2048 }, */
50 /* {EFI_CERT_SHA224_GUID, "SHA224", SIG_TYPE_HASH}, */
51 /* {EFI_CERT_SHA384_GUID, "SHA384", SIG_TYPE_HASH}, */
52 /* {EFI_CERT_SHA512_GUID, "SHA512", SIG_TYPE_HASH}, */
56 * file_have_auth_header() - check file has EFI_VARIABLE_AUTHENTICATION_2 header
57 * @buf: pointer to file
59 * Return: true if file has auth header, false otherwise
61 static bool file_have_auth_header(void *buf, efi_uintn_t size)
63 struct efi_variable_authentication_2 *auth = buf;
65 if (auth->auth_info.hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
68 if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
75 * file_is_null_key() - check the file is an authenticated and signed null key
77 * @auth: pointer to the file
79 * @null_key: pointer to store the result
82 static efi_status_t file_is_null_key(struct efi_variable_authentication_2 *auth,
83 efi_uintn_t size, bool *null_key)
85 efi_uintn_t auth_size =
86 sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength;
89 return EFI_INVALID_PARAMETER;
91 *null_key = (size == auth_size);
97 * eficonfig_process_enroll_key() - enroll key into signature database
99 * @data: pointer to the data for each entry
100 * Return: status code
102 static efi_status_t eficonfig_process_enroll_key(void *data)
108 bool null_key = false;
109 struct efi_file_handle *f = NULL;
110 struct efi_device_path *full_dp = NULL;
111 struct eficonfig_select_file_info file_info;
113 file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
114 if (!file_info.current_path) {
115 ret = EFI_OUT_OF_RESOURCES;
119 ret = eficonfig_process_select_file(&file_info);
120 if (ret != EFI_SUCCESS)
123 full_dp = eficonfig_create_device_path(file_info.dp_volume, file_info.current_path);
125 ret = EFI_OUT_OF_RESOURCES;
128 f = efi_file_from_path(full_dp);
135 ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, NULL));
136 if (ret != EFI_BUFFER_TOO_SMALL)
141 ret = EFI_OUT_OF_RESOURCES;
144 ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, buf));
145 if (ret != EFI_SUCCESS)
148 size = ((struct efi_file_info *)buf)->file_size;
152 eficonfig_print_msg("ERROR! File is empty.");
153 ret = EFI_INVALID_PARAMETER;
159 ret = EFI_OUT_OF_RESOURCES;
163 ret = EFI_CALL(f->read(f, &size, buf));
164 if (ret != EFI_SUCCESS) {
165 eficonfig_print_msg("ERROR! Failed to read file.");
168 if (!file_have_auth_header(buf, size)) {
169 eficonfig_print_msg("ERROR! Invalid file format. Only .auth variables is allowed.");
170 ret = EFI_INVALID_PARAMETER;
174 ret = file_is_null_key((struct efi_variable_authentication_2 *)buf,
176 if (ret != EFI_SUCCESS) {
177 eficonfig_print_msg("ERROR! Invalid file format.");
181 attr = EFI_VARIABLE_NON_VOLATILE |
182 EFI_VARIABLE_BOOTSERVICE_ACCESS |
183 EFI_VARIABLE_RUNTIME_ACCESS |
184 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
187 * PK can enroll only one certificate.
188 * The signed null key is used to clear KEK, db and dbx.
189 * EFI_VARIABLE_APPEND_WRITE attribute must not be set in these cases.
191 if (u16_strcmp(data, u"PK") && !null_key) {
192 efi_uintn_t db_size = 0;
194 /* check the variable exists. If exists, add APPEND_WRITE attribute */
195 ret = efi_get_variable_int(data, efi_auth_var_get_guid(data), NULL,
196 &db_size, NULL, NULL);
197 if (ret == EFI_BUFFER_TOO_SMALL)
198 attr |= EFI_VARIABLE_APPEND_WRITE;
201 ret = efi_set_variable_int((u16 *)data, efi_auth_var_get_guid((u16 *)data),
202 attr, size, buf, false);
203 if (ret != EFI_SUCCESS)
204 eficonfig_print_msg("ERROR! Failed to update signature database");
207 free(file_info.current_path);
209 efi_free_pool(full_dp);
211 EFI_CALL(f->close(f));
213 /* return to the parent menu */
214 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
220 * eficonfig_process_show_siglist() - show signature list content
222 * @data: pointer to the data for each entry
223 * Return: status code
225 static efi_status_t eficonfig_process_show_siglist(void *data)
228 struct eficonfig_sig_data *sg = data;
230 puts(ANSI_CURSOR_HIDE);
231 puts(ANSI_CLEAR_CONSOLE);
232 printf(ANSI_CURSOR_POSITION, 1, 1);
234 printf("\n ** Show Signature Database (%ls) **\n\n"
237 sg->varname, sg->esd->signature_owner.b);
239 for (i = 0; i < ARRAY_SIZE(sigtype_to_str); i++) {
240 if (!guidcmp(&sg->esl->signature_type, &sigtype_to_str[i].sig_type)) {
241 printf(" Signature Type:\n"
242 " %s\n", sigtype_to_str[i].str);
244 switch (sigtype_to_str[i].type) {
247 struct x509_certificate *cert_tmp;
249 cert_tmp = x509_cert_parse(sg->esd->signature_data,
250 sg->esl->signature_size);
255 cert_tmp->subject, cert_tmp->issuer);
260 u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t) -
261 sizeof(struct efi_time);
262 struct efi_time *time =
263 (struct efi_time *)((u8 *)sg->esd->signature_data +
266 printf(" ToBeSignedHash:\n");
267 print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1,
268 sg->esd->signature_data, hash_size, false);
269 printf(" TimeOfRevocation:\n"
270 " %d-%d-%d %02d:%02d:%02d\n",
271 time->year, time->month, time->day,
272 time->hour, time->minute, time->second);
277 u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t);
280 print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1,
281 sg->esd->signature_data, hash_size, false);
285 eficonfig_print_msg("ERROR! Unsupported format.");
286 return EFI_INVALID_PARAMETER;
294 printf("\n\n Press any key to continue");
301 * prepare_signature_list_menu() - create the signature list menu entry
303 * @efimenu: pointer to the efimenu structure
304 * @varname: pointer to the variable name
305 * @db: pointer to the variable raw data
306 * @db_size: variable data size
307 * @func: callback of each entry
308 * Return: status code
310 static efi_status_t prepare_signature_list_menu(struct efimenu *efi_menu, void *varname,
311 void *db, efi_uintn_t db_size,
312 eficonfig_entry_func func)
316 struct eficonfig_sig_data *sg;
317 struct efi_signature_list *esl;
318 struct efi_signature_data *esd;
319 efi_status_t ret = EFI_SUCCESS;
321 INIT_LIST_HEAD(&efi_menu->list);
328 esd = (struct efi_signature_data *)((u8 *)esl +
329 (sizeof(struct efi_signature_list) +
330 esl->signature_header_size));
331 remain = esl->signature_list_size - sizeof(struct efi_signature_list) -
332 esl->signature_header_size;
333 for (; remain > 0; remain -= esl->signature_size) {
337 if (num >= EFICONFIG_ENTRY_NUM_MAX - 1) {
338 ret = EFI_OUT_OF_RESOURCES;
342 sg = calloc(1, sizeof(struct eficonfig_sig_data));
344 ret = EFI_OUT_OF_RESOURCES;
348 snprintf(buf, sizeof(buf), "%pUL", &esd->signature_owner);
352 ret = EFI_OUT_OF_RESOURCES;
358 sg->varname = varname;
359 ret = eficonfig_append_menu_entry(efi_menu, title, func, sg);
360 if (ret != EFI_SUCCESS) {
365 esd = (struct efi_signature_data *)((u8 *)esd + esl->signature_size);
369 size -= esl->signature_list_size;
370 esl = (struct efi_signature_list *)((u8 *)esl + esl->signature_list_size);
373 ret = eficonfig_append_quit_entry(efi_menu);
379 * enumerate_and_show_signature_database() - enumerate and show the signature database
381 * @data: pointer to the data for each entry
382 * Return: status code
384 static efi_status_t enumerate_and_show_signature_database(void *varname)
390 struct efimenu *efi_menu;
391 struct list_head *pos, *n;
392 struct eficonfig_entry *entry;
394 db = efi_get_var(varname, efi_auth_var_get_guid(varname), &db_size);
396 eficonfig_print_msg("There is no entry in the signature database.");
397 return EFI_NOT_FOUND;
400 efi_menu = calloc(1, sizeof(struct efimenu));
403 return EFI_OUT_OF_RESOURCES;
406 ret = prepare_signature_list_menu(efi_menu, varname, db, db_size,
407 eficonfig_process_show_siglist);
408 if (ret != EFI_SUCCESS)
411 snprintf(buf, sizeof(buf), " ** Show Signature Database (%ls) **", (u16 *)varname);
412 ret = eficonfig_process_common(efi_menu, buf, eficonfig_menu_desc,
413 eficonfig_display_statusline,
414 eficonfig_print_entry,
415 eficonfig_choice_entry);
417 list_for_each_safe(pos, n, &efi_menu->list) {
418 entry = list_entry(pos, struct eficonfig_entry, list);
421 eficonfig_destroy(efi_menu);
428 * eficonfig_process_show_signature_database() - process show signature database
430 * @data: pointer to the data for each entry
431 * Return: status code
433 static efi_status_t eficonfig_process_show_signature_database(void *data)
438 ret = enumerate_and_show_signature_database(data);
439 if (ret != EFI_SUCCESS && ret != EFI_NOT_READY)
443 /* return to the parent menu */
444 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
449 static struct eficonfig_item key_config_menu_items[] = {
450 {"Enroll New Key", eficonfig_process_enroll_key},
451 {"Show Signature Database", eficonfig_process_show_signature_database},
452 {"Quit", eficonfig_process_quit},
456 * eficonfig_process_set_secure_boot_key() - display the key configuration menu
458 * @data: pointer to the data for each entry
459 * Return: status code
461 static efi_status_t eficonfig_process_set_secure_boot_key(void *data)
466 struct efimenu *efi_menu;
468 for (i = 0; i < ARRAY_SIZE(key_config_menu_items); i++)
469 key_config_menu_items[i].data = data;
471 snprintf(header_str, sizeof(header_str), " ** Configure %ls **", (u16 *)data);
474 efi_menu = eficonfig_create_fixed_menu(key_config_menu_items,
475 ARRAY_SIZE(key_config_menu_items));
477 ret = eficonfig_process_common(efi_menu, header_str,
479 eficonfig_display_statusline,
480 eficonfig_print_entry,
481 eficonfig_choice_entry);
482 eficonfig_destroy(efi_menu);
484 if (ret == EFI_ABORTED)
488 /* return to the parent menu */
489 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
494 static const struct eficonfig_item secure_boot_menu_items[] = {
495 {"PK", eficonfig_process_set_secure_boot_key, u"PK"},
496 {"KEK", eficonfig_process_set_secure_boot_key, u"KEK"},
497 {"db", eficonfig_process_set_secure_boot_key, u"db"},
498 {"dbx", eficonfig_process_set_secure_boot_key, u"dbx"},
499 {"Quit", eficonfig_process_quit},
503 * eficonfig_process_secure_boot_config() - display the key list menu
505 * @data: pointer to the data for each entry
506 * Return: status code
508 efi_status_t eficonfig_process_secure_boot_config(void *data)
511 struct efimenu *efi_menu;
516 snprintf(header_str, sizeof(header_str),
517 " ** UEFI Secure Boot Key Configuration (SecureBoot : %s) **",
518 (efi_secure_boot_enabled() ? "ON" : "OFF"));
520 efi_menu = eficonfig_create_fixed_menu(secure_boot_menu_items,
521 ARRAY_SIZE(secure_boot_menu_items));
523 ret = EFI_OUT_OF_RESOURCES;
527 ret = eficonfig_process_common(efi_menu, header_str,
529 eficonfig_display_statusline,
530 eficonfig_print_entry,
531 eficonfig_choice_entry);
533 eficonfig_destroy(efi_menu);
535 if (ret == EFI_ABORTED)
539 /* return to the parent menu */
540 ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;