Merge tag 'efi-2023-01-rc2-2' of https://source.denx.de/u-boot/custodians/u-boot-efi
Pull request for efi-2023-01-rc2-2
UEFI:
* add UEFI Secure Boot Key enrollment interface to eficonfig command
* fix buffer underflow in FatToStr() implementation
diff --git a/cmd/Makefile b/cmd/Makefile
index 2444d11..0b6a96c 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -66,6 +66,11 @@
obj-$(CONFIG_EFI) += efi.o
obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o
obj-$(CONFIG_CMD_EFICONFIG) += eficonfig.o
+ifdef CONFIG_CMD_EFICONFIG
+ifdef CONFIG_EFI_MM_COMM_TEE
+obj-$(CONFIG_EFI_SECURE_BOOT) += eficonfig_sbkey.o
+endif
+endif
obj-$(CONFIG_CMD_ELF) += elf.o
obj-$(CONFIG_CMD_EROFS) += erofs.o
obj-$(CONFIG_HUSH_PARSER) += exit.o
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index 2b14389..97d3559 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -93,20 +93,14 @@
};
/**
- * struct eficonfig_boot_order - structure to be used to update BootOrder variable
+ * struct eficonfig_boot_order_data - structure to be used to update BootOrder variable
*
- * @num: index in the menu entry
- * @description: pointer to the description string
* @boot_index: boot option index
* @active: flag to include the boot option into BootOrder variable
- * @list: list structure
*/
-struct eficonfig_boot_order {
- u32 num;
- u16 *description;
+struct eficonfig_boot_order_data {
u32 boot_index;
bool active;
- struct list_head list;
};
/**
@@ -263,7 +257,7 @@
}
/**
- * append_entry() - append menu item
+ * eficonfig_append_menu_entry() - append menu item
*
* @efi_menu: pointer to the efimenu structure
* @title: pointer to the entry title
@@ -271,8 +265,9 @@
* @data: pointer to the data to be passed to each entry callback
* Return: status code
*/
-static efi_status_t append_entry(struct efimenu *efi_menu,
- char *title, eficonfig_entry_func func, void *data)
+efi_status_t eficonfig_append_menu_entry(struct efimenu *efi_menu,
+ char *title, eficonfig_entry_func func,
+ void *data)
{
struct eficonfig_entry *entry;
@@ -295,12 +290,12 @@
}
/**
- * append_quit_entry() - append quit entry
+ * eficonfig_append_quit_entry() - append quit entry
*
* @efi_menu: pointer to the efimenu structure
* Return: status code
*/
-static efi_status_t append_quit_entry(struct efimenu *efi_menu)
+efi_status_t eficonfig_append_quit_entry(struct efimenu *efi_menu)
{
char *title;
efi_status_t ret;
@@ -309,7 +304,7 @@
if (!title)
return EFI_OUT_OF_RESOURCES;
- ret = append_entry(efi_menu, title, eficonfig_process_quit, NULL);
+ ret = eficonfig_append_menu_entry(efi_menu, title, eficonfig_process_quit, NULL);
if (ret != EFI_SUCCESS)
free(title);
@@ -341,7 +336,7 @@
if (!title)
goto out;
- ret = append_entry(efi_menu, title, iter->func, iter->data);
+ ret = eficonfig_append_menu_entry(efi_menu, title, iter->func, iter->data);
if (ret != EFI_SUCCESS) {
free(title);
goto out;
@@ -441,14 +436,15 @@
}
/**
- * create_selected_device_path() - create device path
+ * eficonfig_create_device_path() - create device path
*
- * @file_info: pointer to the selected file information
+ * @dp_volume: pointer to the volume
+ * @current_path: pointer to the file path u16 string
* Return:
* device path or NULL. Caller must free the returned value
*/
-static
-struct efi_device_path *create_selected_device_path(struct eficonfig_select_file_info *file_info)
+struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *dp_volume,
+ u16 *current_path)
{
char *p;
void *buf;
@@ -457,7 +453,7 @@
struct efi_device_path_file_path *fp;
fp_size = sizeof(struct efi_device_path) +
- ((u16_strlen(file_info->current_path) + 1) * sizeof(u16));
+ ((u16_strlen(current_path) + 1) * sizeof(u16));
buf = calloc(1, fp_size + sizeof(END));
if (!buf)
return NULL;
@@ -466,13 +462,13 @@
fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
fp->dp.length = (u16)fp_size;
- u16_strcpy(fp->str, file_info->current_path);
+ u16_strcpy(fp->str, current_path);
p = buf;
p += fp_size;
*((struct efi_device_path *)p) = END;
- dp = efi_dp_append(file_info->dp_volume, (struct efi_device_path *)buf);
+ dp = efi_dp_append(dp_volume, (struct efi_device_path *)buf);
free(buf);
return dp;
@@ -634,14 +630,15 @@
info->v = v;
info->dp = device_path;
info->file_info = file_info;
- ret = append_entry(efi_menu, devname, eficonfig_volume_selected, info);
+ ret = eficonfig_append_menu_entry(efi_menu, devname, eficonfig_volume_selected,
+ info);
if (ret != EFI_SUCCESS) {
free(info);
goto out;
}
}
- ret = append_quit_entry(efi_menu);
+ ret = eficonfig_append_quit_entry(efi_menu);
if (ret != EFI_SUCCESS)
goto out;
@@ -699,14 +696,14 @@
u32 i, entry_num = 0;
struct eficonfig_file_entry_data *info;
- efi_file_setpos_int(f, 0);
+ EFI_CALL(f->setpos(f, 0));
/* Read directory and construct menu structure */
for (i = 0; i < count; i++) {
if (entry_num >= EFICONFIG_ENTRY_NUM_MAX - 1)
break;
len = sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE;
- ret = efi_file_read_int(f, &len, buf);
+ ret = EFI_CALL(f->read(f, &len, buf));
if (ret != EFI_SUCCESS || len == 0)
break;
@@ -745,8 +742,8 @@
(int (*)(const void *, const void *))sort_file);
for (i = 0; i < entry_num; i++) {
- ret = append_entry(efi_menu, tmp_infos[i]->file_name,
- eficonfig_file_selected, tmp_infos[i]);
+ ret = eficonfig_append_menu_entry(efi_menu, tmp_infos[i]->file_name,
+ eficonfig_file_selected, tmp_infos[i]);
if (ret != EFI_SUCCESS)
goto out;
}
@@ -756,14 +753,14 @@
}
/**
- * eficonfig_select_file() - construct the file selection menu
+ * eficonfig_show_file_selection() - construct the file selection menu
*
* @file_info: pointer to the file selection structure
* @root: pointer to the file handle
* Return: status code
*/
-static efi_status_t eficonfig_select_file(struct eficonfig_select_file_info *file_info,
- struct efi_file_handle *root)
+static efi_status_t eficonfig_show_file_selection(struct eficonfig_select_file_info *file_info,
+ struct efi_file_handle *root)
{
u32 count = 0, i;
efi_uintn_t len;
@@ -785,7 +782,8 @@
}
INIT_LIST_HEAD(&efi_menu->list);
- ret = efi_file_open_int(root, &f, file_info->current_path, EFI_FILE_MODE_READ, 0);
+ ret = EFI_CALL(root->open(root, &f, file_info->current_path,
+ EFI_FILE_MODE_READ, 0));
if (ret != EFI_SUCCESS) {
eficonfig_print_msg("Reading volume failed!");
free(efi_menu);
@@ -796,7 +794,7 @@
/* Count the number of directory entries */
for (;;) {
len = sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE;
- ret = efi_file_read_int(f, &len, buf);
+ ret = EFI_CALL(f->read(f, &len, buf));
if (ret != EFI_SUCCESS || len == 0)
break;
@@ -815,13 +813,13 @@
if (ret != EFI_SUCCESS)
goto err;
- ret = append_quit_entry(efi_menu);
+ ret = eficonfig_append_quit_entry(efi_menu);
if (ret != EFI_SUCCESS)
goto err;
ret = eficonfig_process_common(efi_menu, " ** Select File **");
err:
- efi_file_close_int(f);
+ EFI_CALL(f->close(f));
eficonfig_destroy(efi_menu);
if (tmp_infos) {
@@ -939,17 +937,6 @@
}
/**
- * eficonfig_process_select_file() - callback function for "Select File" entry
- *
- * @data: pointer to the data
- * Return: status code
- */
-efi_status_t eficonfig_process_select_file(void *data)
-{
- return EFI_SUCCESS;
-}
-
-/**
* eficonfig_process_clear_file_selection() - callback function for "Clear" entry
*
* @data: pointer to the data
@@ -973,19 +960,19 @@
{"Quit", eficonfig_process_quit},
};
-
/**
- * eficonfig_display_select_file_option() - display select file option
+ * eficonfig_process_show_file_option() - display select file option
*
* @file_info: pointer to the file information structure
* Return: status code
*/
-efi_status_t eficonfig_display_select_file_option(struct eficonfig_select_file_info *file_info)
+efi_status_t eficonfig_process_show_file_option(void *data)
{
efi_status_t ret;
struct efimenu *efi_menu;
- select_file_menu_items[1].data = file_info;
+ select_file_menu_items[0].data = data;
+ select_file_menu_items[1].data = data;
efi_menu = eficonfig_create_fixed_menu(select_file_menu_items,
ARRAY_SIZE(select_file_menu_items));
if (!efi_menu)
@@ -1001,12 +988,12 @@
}
/**
- * eficonfig_select_file_handler() - handle user file selection
+ * eficonfig_process_select_file() - handle user file selection
*
* @data: pointer to the data
* Return: status code
*/
-efi_status_t eficonfig_select_file_handler(void *data)
+efi_status_t eficonfig_process_select_file(void *data)
{
size_t len;
efi_status_t ret;
@@ -1016,10 +1003,6 @@
struct eficonfig_select_file_info *tmp = NULL;
struct eficonfig_select_file_info *file_info = data;
- ret = eficonfig_display_select_file_option(file_info);
- if (ret != EFI_SUCCESS)
- return ret;
-
tmp = calloc(1, sizeof(struct eficonfig_select_file_info));
if (!tmp)
return EFI_OUT_OF_RESOURCES;
@@ -1042,11 +1025,11 @@
if (!tmp->current_volume)
return EFI_INVALID_PARAMETER;
- ret = efi_open_volume_int(tmp->current_volume, &root);
+ ret = EFI_CALL(tmp->current_volume->open_volume(tmp->current_volume, &root));
if (ret != EFI_SUCCESS)
goto out;
- ret = eficonfig_select_file(tmp, root);
+ ret = eficonfig_show_file_selection(tmp, root);
if (ret == EFI_ABORTED)
continue;
if (ret != EFI_SUCCESS)
@@ -1221,7 +1204,7 @@
utf16_utf8_strcpy(&p, val);
}
- return append_entry(efi_menu, buf, func, data);
+ return eficonfig_append_menu_entry(efi_menu, buf, func, data);
}
/**
@@ -1284,7 +1267,7 @@
utf8_utf16_strcpy(&p, devname);
u16_strlcat(file_name, file_info->current_path, len);
ret = create_boot_option_entry(efi_menu, title, file_name,
- eficonfig_select_file_handler, file_info);
+ eficonfig_process_show_file_option, file_info);
out:
free(devname);
free(file_name);
@@ -1491,7 +1474,8 @@
}
if (bo->initrd_info.dp_volume) {
- dp = create_selected_device_path(&bo->initrd_info);
+ dp = eficonfig_create_device_path(bo->initrd_info.dp_volume,
+ bo->initrd_info.current_path);
if (!dp) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
@@ -1500,7 +1484,7 @@
efi_free_pool(dp);
}
- dp = create_selected_device_path(&bo->file_info);
+ dp = eficonfig_create_device_path(bo->file_info.dp_volume, bo->file_info.current_path);
if (!dp) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
@@ -1678,7 +1662,7 @@
utf16_utf8_strcpy(&p, lo.label);
info->boot_index = boot_index;
info->selected = selected;
- ret = append_entry(efi_menu, buf, eficonfig_process_boot_selected, info);
+ ret = eficonfig_append_menu_entry(efi_menu, buf, eficonfig_process_boot_selected, info);
if (ret != EFI_SUCCESS) {
free(load_option);
free(info);
@@ -1737,7 +1721,7 @@
break;
}
- ret = append_quit_entry(efi_menu);
+ ret = eficonfig_append_quit_entry(efi_menu);
if (ret != EFI_SUCCESS)
goto out;
@@ -1813,7 +1797,7 @@
{
bool reverse;
struct list_head *pos, *n;
- struct eficonfig_boot_order *entry;
+ struct eficonfig_entry *entry;
printf(ANSI_CLEAR_CONSOLE ANSI_CURSOR_POSITION
"\n ** Change Boot Order **\n"
@@ -1829,7 +1813,7 @@
/* draw boot option list */
list_for_each_safe(pos, n, &efi_menu->list) {
- entry = list_entry(pos, struct eficonfig_boot_order, list);
+ entry = list_entry(pos, struct eficonfig_entry, list);
reverse = (entry->num == efi_menu->active);
printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
@@ -1838,13 +1822,13 @@
puts(ANSI_COLOR_REVERSE);
if (entry->num < efi_menu->count - 2) {
- if (entry->active)
+ if (((struct eficonfig_boot_order_data *)entry->data)->active)
printf("[*] ");
else
printf("[ ] ");
}
- printf("%ls", entry->description);
+ printf("%s", entry->title);
if (reverse)
puts(ANSI_COLOR_RESET);
@@ -1861,9 +1845,8 @@
{
int esc = 0;
struct list_head *pos, *n;
- struct eficonfig_boot_order *tmp;
enum bootmenu_key key = KEY_NONE;
- struct eficonfig_boot_order *entry;
+ struct eficonfig_entry *entry, *tmp;
while (1) {
bootmenu_loop(NULL, &key, &esc);
@@ -1872,11 +1855,11 @@
case KEY_PLUS:
if (efi_menu->active > 0) {
list_for_each_safe(pos, n, &efi_menu->list) {
- entry = list_entry(pos, struct eficonfig_boot_order, list);
+ entry = list_entry(pos, struct eficonfig_entry, list);
if (entry->num == efi_menu->active)
break;
}
- tmp = list_entry(pos->prev, struct eficonfig_boot_order, list);
+ tmp = list_entry(pos->prev, struct eficonfig_entry, list);
entry->num--;
tmp->num++;
list_del(&tmp->list);
@@ -1890,11 +1873,11 @@
case KEY_MINUS:
if (efi_menu->active < efi_menu->count - 3) {
list_for_each_safe(pos, n, &efi_menu->list) {
- entry = list_entry(pos, struct eficonfig_boot_order, list);
+ entry = list_entry(pos, struct eficonfig_entry, list);
if (entry->num == efi_menu->active)
break;
}
- tmp = list_entry(pos->next, struct eficonfig_boot_order, list);
+ tmp = list_entry(pos->next, struct eficonfig_entry, list);
entry->num++;
tmp->num--;
list_del(&entry->list);
@@ -1920,9 +1903,11 @@
case KEY_SPACE:
if (efi_menu->active < efi_menu->count - 2) {
list_for_each_safe(pos, n, &efi_menu->list) {
- entry = list_entry(pos, struct eficonfig_boot_order, list);
+ entry = list_entry(pos, struct eficonfig_entry, list);
if (entry->num == efi_menu->active) {
- entry->active = entry->active ? false : true;
+ struct eficonfig_boot_order_data *data = entry->data;
+
+ data->active = !data->active;
return EFI_NOT_READY;
}
}
@@ -1948,12 +1933,13 @@
static efi_status_t eficonfig_add_change_boot_order_entry(struct efimenu *efi_menu,
u32 boot_index, bool active)
{
+ char *title, *p;
efi_status_t ret;
efi_uintn_t size;
void *load_option;
struct efi_load_option lo;
u16 varname[] = u"Boot####";
- struct eficonfig_boot_order *entry;
+ struct eficonfig_boot_order_data *data;
efi_create_indexed_name(varname, sizeof(varname), "Boot", boot_index);
load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
@@ -1961,31 +1947,38 @@
return EFI_SUCCESS;
ret = efi_deserialize_load_option(&lo, load_option, &size);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ data = calloc(1, sizeof(*data));
+ if (!data) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ title = calloc(1, utf16_utf8_strlen(lo.label) + 1);
+ if (!title) {
+ free(data);
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ p = title;
+ utf16_utf8_strcpy(&p, lo.label);
+
+ data->boot_index = boot_index;
+ data->active = active;
+
+ ret = eficonfig_append_menu_entry(efi_menu, title, NULL, data);
if (ret != EFI_SUCCESS) {
- free(load_option);
- return ret;
+ free(data);
+ free(title);
+ goto out;
}
- entry = calloc(1, sizeof(struct eficonfig_boot_order));
- if (!entry) {
- free(load_option);
- return EFI_OUT_OF_RESOURCES;
- }
-
- entry->description = u16_strdup(lo.label);
- if (!entry->description) {
- free(load_option);
- free(entry);
- return EFI_OUT_OF_RESOURCES;
- }
- entry->num = efi_menu->count++;
- entry->boot_index = boot_index;
- entry->active = active;
- list_add_tail(&entry->list, &efi_menu->list);
-
+out:
free(load_option);
- return EFI_SUCCESS;
+ return ret;
}
/**
@@ -2000,8 +1993,8 @@
u16 *bootorder, efi_uintn_t num)
{
u32 i;
+ char *title;
efi_status_t ret;
- struct eficonfig_boot_order *entry;
/* list the load option in the order of BootOrder variable */
for (i = 0; i < num; i++) {
@@ -2028,27 +2021,25 @@
}
/* add "Save" and "Quit" entries */
- entry = calloc(1, sizeof(struct eficonfig_boot_order));
- if (!entry)
+ title = strdup("Save");
+ if (!title) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ ret = eficonfig_append_menu_entry(efi_menu, title, NULL, NULL);
+ if (ret != EFI_SUCCESS)
goto out;
- entry->num = efi_menu->count++;
- entry->description = u16_strdup(u"Save");
- list_add_tail(&entry->list, &efi_menu->list);
-
- entry = calloc(1, sizeof(struct eficonfig_boot_order));
- if (!entry)
+ ret = eficonfig_append_quit_entry(efi_menu);
+ if (ret != EFI_SUCCESS)
goto out;
- entry->num = efi_menu->count++;
- entry->description = u16_strdup(u"Quit");
- list_add_tail(&entry->list, &efi_menu->list);
-
efi_menu->active = 0;
return EFI_SUCCESS;
out:
- return EFI_OUT_OF_RESOURCES;
+ return ret;
}
/**
@@ -2064,7 +2055,7 @@
efi_status_t ret;
efi_uintn_t num, size;
struct list_head *pos, *n;
- struct eficonfig_boot_order *entry;
+ struct eficonfig_entry *entry;
struct efimenu *efi_menu;
efi_menu = calloc(1, sizeof(struct efimenu));
@@ -2095,9 +2086,16 @@
/* create new BootOrder */
count = 0;
list_for_each_safe(pos, n, &efi_menu->list) {
- entry = list_entry(pos, struct eficonfig_boot_order, list);
- if (entry->active)
- new_bootorder[count++] = entry->boot_index;
+ struct eficonfig_boot_order_data *data;
+
+ entry = list_entry(pos, struct eficonfig_entry, list);
+ /* exit the loop when iteration reaches "Save" */
+ if (!strncmp(entry->title, "Save", strlen("Save")))
+ break;
+
+ data = entry->data;
+ if (data->active)
+ new_bootorder[count++] = data->boot_index;
}
size = count * sizeof(u16);
@@ -2116,15 +2114,12 @@
}
}
out:
- list_for_each_safe(pos, n, &efi_menu->list) {
- entry = list_entry(pos, struct eficonfig_boot_order, list);
- list_del(&entry->list);
- free(entry->description);
- free(entry);
- }
-
free(bootorder);
- free(efi_menu);
+ list_for_each_safe(pos, n, &efi_menu->list) {
+ entry = list_entry(pos, struct eficonfig_entry, list);
+ free(entry->data);
+ }
+ eficonfig_destroy(efi_menu);
/* to stay the parent menu */
ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
@@ -2441,6 +2436,9 @@
{"Edit Boot Option", eficonfig_process_edit_boot_option},
{"Change Boot Order", eficonfig_process_change_boot_order},
{"Delete Boot Option", eficonfig_process_delete_boot_option},
+#if (CONFIG_IS_ENABLED(EFI_SECURE_BOOT) && CONFIG_IS_ENABLED(EFI_MM_COMM_TEE))
+ {"Secure Boot Configuration", eficonfig_process_secure_boot_config},
+#endif
{"Quit", eficonfig_process_quit},
};
diff --git a/cmd/eficonfig_sbkey.c b/cmd/eficonfig_sbkey.c
new file mode 100644
index 0000000..6e0bebf
--- /dev/null
+++ b/cmd/eficonfig_sbkey.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Menu-driven UEFI Secure Boot Key Maintenance
+ *
+ * Copyright (c) 2022 Masahisa Kojima, Linaro Limited
+ */
+
+#include <ansi.h>
+#include <common.h>
+#include <charset.h>
+#include <hexdump.h>
+#include <log.h>
+#include <malloc.h>
+#include <menu.h>
+#include <efi_loader.h>
+#include <efi_config.h>
+#include <efi_variable.h>
+#include <crypto/pkcs7_parser.h>
+
+struct eficonfig_sig_data {
+ struct efi_signature_list *esl;
+ struct efi_signature_data *esd;
+ struct list_head list;
+ u16 *varname;
+};
+
+enum efi_sbkey_signature_type {
+ SIG_TYPE_X509 = 0,
+ SIG_TYPE_HASH,
+ SIG_TYPE_CRL,
+ SIG_TYPE_RSA2048,
+};
+
+struct eficonfig_sigtype_to_str {
+ efi_guid_t sig_type;
+ char *str;
+ enum efi_sbkey_signature_type type;
+};
+
+static const struct eficonfig_sigtype_to_str sigtype_to_str[] = {
+ {EFI_CERT_X509_GUID, "X509", SIG_TYPE_X509},
+ {EFI_CERT_SHA256_GUID, "SHA256", SIG_TYPE_HASH},
+ {EFI_CERT_X509_SHA256_GUID, "X509_SHA256 CRL", SIG_TYPE_CRL},
+ {EFI_CERT_X509_SHA384_GUID, "X509_SHA384 CRL", SIG_TYPE_CRL},
+ {EFI_CERT_X509_SHA512_GUID, "X509_SHA512 CRL", SIG_TYPE_CRL},
+ /* U-Boot does not support the following signature types */
+/* {EFI_CERT_RSA2048_GUID, "RSA2048", SIG_TYPE_RSA2048}, */
+/* {EFI_CERT_RSA2048_SHA256_GUID, "RSA2048_SHA256", SIG_TYPE_RSA2048}, */
+/* {EFI_CERT_SHA1_GUID, "SHA1", SIG_TYPE_HASH}, */
+/* {EFI_CERT_RSA2048_SHA_GUID, "RSA2048_SHA", SIG_TYPE_RSA2048 }, */
+/* {EFI_CERT_SHA224_GUID, "SHA224", SIG_TYPE_HASH}, */
+/* {EFI_CERT_SHA384_GUID, "SHA384", SIG_TYPE_HASH}, */
+/* {EFI_CERT_SHA512_GUID, "SHA512", SIG_TYPE_HASH}, */
+};
+
+/**
+ * file_have_auth_header() - check file has EFI_VARIABLE_AUTHENTICATION_2 header
+ * @buf: pointer to file
+ * @size: file size
+ * Return: true if file has auth header, false otherwise
+ */
+static bool file_have_auth_header(void *buf, efi_uintn_t size)
+{
+ struct efi_variable_authentication_2 *auth = buf;
+
+ if (auth->auth_info.hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
+ return false;
+
+ if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
+ return false;
+
+ return true;
+}
+
+/**
+ * eficonfig_process_enroll_key() - enroll key into signature database
+ *
+ * @data: pointer to the data for each entry
+ * Return: status code
+ */
+static efi_status_t eficonfig_process_enroll_key(void *data)
+{
+ u32 attr;
+ char *buf = NULL;
+ efi_uintn_t size;
+ efi_status_t ret;
+ struct efi_file_handle *f = NULL;
+ struct efi_device_path *full_dp = NULL;
+ struct eficonfig_select_file_info file_info;
+
+ file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
+ if (!file_info.current_path) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ ret = eficonfig_process_select_file(&file_info);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ full_dp = eficonfig_create_device_path(file_info.dp_volume, file_info.current_path);
+ if (!full_dp) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ f = efi_file_from_path(full_dp);
+ if (!f) {
+ ret = EFI_NOT_FOUND;
+ goto out;
+ }
+
+ size = 0;
+ ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, NULL));
+ if (ret != EFI_BUFFER_TOO_SMALL)
+ goto out;
+
+ buf = malloc(size);
+ if (!buf) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ ret = EFI_CALL(f->getinfo(f, &efi_file_info_guid, &size, buf));
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ size = ((struct efi_file_info *)buf)->file_size;
+ free(buf);
+
+ if (!size) {
+ eficonfig_print_msg("ERROR! File is empty.");
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ buf = malloc(size);
+ if (!buf) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ ret = EFI_CALL(f->read(f, &size, buf));
+ if (ret != EFI_SUCCESS) {
+ eficonfig_print_msg("ERROR! Failed to read file.");
+ goto out;
+ }
+ if (!file_have_auth_header(buf, size)) {
+ eficonfig_print_msg("ERROR! Invalid file format. Only .auth variables is allowed.");
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ attr = EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+
+ /* PK can enroll only one certificate */
+ if (u16_strcmp(data, u"PK")) {
+ efi_uintn_t db_size = 0;
+
+ /* check the variable exists. If exists, add APPEND_WRITE attribute */
+ ret = efi_get_variable_int(data, efi_auth_var_get_guid(data), NULL,
+ &db_size, NULL, NULL);
+ if (ret == EFI_BUFFER_TOO_SMALL)
+ attr |= EFI_VARIABLE_APPEND_WRITE;
+ }
+
+ ret = efi_set_variable_int((u16 *)data, efi_auth_var_get_guid((u16 *)data),
+ attr, size, buf, false);
+ if (ret != EFI_SUCCESS)
+ eficonfig_print_msg("ERROR! Failed to update signature database");
+
+out:
+ free(file_info.current_path);
+ free(buf);
+ efi_free_pool(full_dp);
+ if (f)
+ EFI_CALL(f->close(f));
+
+ /* return to the parent menu */
+ ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
+
+ return ret;
+}
+
+/**
+ * eficonfig_process_show_siglist() - show signature list content
+ *
+ * @data: pointer to the data for each entry
+ * Return: status code
+ */
+static efi_status_t eficonfig_process_show_siglist(void *data)
+{
+ u32 i;
+ struct eficonfig_sig_data *sg = data;
+
+ puts(ANSI_CURSOR_HIDE);
+ puts(ANSI_CLEAR_CONSOLE);
+ printf(ANSI_CURSOR_POSITION, 1, 1);
+
+ printf("\n ** Show Signature Database (%ls) **\n\n"
+ " Owner GUID:\n"
+ " %pUL\n",
+ sg->varname, sg->esd->signature_owner.b);
+
+ for (i = 0; i < ARRAY_SIZE(sigtype_to_str); i++) {
+ if (!guidcmp(&sg->esl->signature_type, &sigtype_to_str[i].sig_type)) {
+ printf(" Signature Type:\n"
+ " %s\n", sigtype_to_str[i].str);
+
+ switch (sigtype_to_str[i].type) {
+ case SIG_TYPE_X509:
+ {
+ struct x509_certificate *cert_tmp;
+
+ cert_tmp = x509_cert_parse(sg->esd->signature_data,
+ sg->esl->signature_size);
+ printf(" Subject:\n"
+ " %s\n"
+ " Issuer:\n"
+ " %s\n",
+ cert_tmp->subject, cert_tmp->issuer);
+ break;
+ }
+ case SIG_TYPE_CRL:
+ {
+ u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t) -
+ sizeof(struct efi_time);
+ struct efi_time *time =
+ (struct efi_time *)((u8 *)sg->esd->signature_data +
+ hash_size);
+
+ printf(" ToBeSignedHash:\n");
+ print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1,
+ sg->esd->signature_data, hash_size, false);
+ printf(" TimeOfRevocation:\n"
+ " %d-%d-%d %02d:%02d:%02d\n",
+ time->year, time->month, time->day,
+ time->hour, time->minute, time->second);
+ break;
+ }
+ case SIG_TYPE_HASH:
+ {
+ u32 hash_size = sg->esl->signature_size - sizeof(efi_guid_t);
+
+ printf(" Hash:\n");
+ print_hex_dump(" ", DUMP_PREFIX_NONE, 16, 1,
+ sg->esd->signature_data, hash_size, false);
+ break;
+ }
+ default:
+ eficonfig_print_msg("ERROR! Unsupported format.");
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ while (tstc())
+ getchar();
+
+ printf("\n\n Press any key to continue");
+ getchar();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * prepare_signature_list_menu() - create the signature list menu entry
+ *
+ * @efimenu: pointer to the efimenu structure
+ * @varname: pointer to the variable name
+ * @db: pointer to the variable raw data
+ * @db_size: variable data size
+ * @func: callback of each entry
+ * Return: status code
+ */
+static efi_status_t prepare_signature_list_menu(struct efimenu *efi_menu, void *varname,
+ void *db, efi_uintn_t db_size,
+ eficonfig_entry_func func)
+{
+ u32 num = 0;
+ efi_uintn_t size;
+ struct eficonfig_sig_data *sg;
+ struct efi_signature_list *esl;
+ struct efi_signature_data *esd;
+ efi_status_t ret = EFI_SUCCESS;
+
+ INIT_LIST_HEAD(&efi_menu->list);
+
+ esl = db;
+ size = db_size;
+ while (size > 0) {
+ u32 remain;
+
+ esd = (struct efi_signature_data *)((u8 *)esl +
+ (sizeof(struct efi_signature_list) +
+ esl->signature_header_size));
+ remain = esl->signature_list_size - sizeof(struct efi_signature_list) -
+ esl->signature_header_size;
+ for (; remain > 0; remain -= esl->signature_size) {
+ char buf[37];
+ char *title;
+
+ if (num >= EFICONFIG_ENTRY_NUM_MAX - 1) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ sg = calloc(1, sizeof(struct eficonfig_sig_data));
+ if (!sg) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+
+ snprintf(buf, sizeof(buf), "%pUL", &esd->signature_owner);
+ title = strdup(buf);
+ if (!title) {
+ free(sg);
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+
+ sg->esl = esl;
+ sg->esd = esd;
+ sg->varname = varname;
+ ret = eficonfig_append_menu_entry(efi_menu, title, func, sg);
+ if (ret != EFI_SUCCESS) {
+ free(sg);
+ free(title);
+ goto err;
+ }
+ esd = (struct efi_signature_data *)((u8 *)esd + esl->signature_size);
+ num++;
+ }
+
+ size -= esl->signature_list_size;
+ esl = (struct efi_signature_list *)((u8 *)esl + esl->signature_list_size);
+ }
+out:
+ ret = eficonfig_append_quit_entry(efi_menu);
+err:
+ return ret;
+}
+
+/**
+ * enumerate_and_show_signature_database() - enumerate and show the signature database
+ *
+ * @data: pointer to the data for each entry
+ * Return: status code
+ */
+static efi_status_t enumerate_and_show_signature_database(void *varname)
+{
+ void *db;
+ char buf[50];
+ efi_status_t ret;
+ efi_uintn_t db_size;
+ struct efimenu *efi_menu;
+ struct list_head *pos, *n;
+ struct eficonfig_entry *entry;
+
+ db = efi_get_var(varname, efi_auth_var_get_guid(varname), &db_size);
+ if (!db) {
+ eficonfig_print_msg("There is no entry in the signature database.");
+ return EFI_NOT_FOUND;
+ }
+
+ efi_menu = calloc(1, sizeof(struct efimenu));
+ if (!efi_menu) {
+ free(db);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ret = prepare_signature_list_menu(efi_menu, varname, db, db_size,
+ eficonfig_process_show_siglist);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ snprintf(buf, sizeof(buf), " ** Show Signature Database (%ls) **", (u16 *)varname);
+ ret = eficonfig_process_common(efi_menu, buf);
+out:
+ list_for_each_safe(pos, n, &efi_menu->list) {
+ entry = list_entry(pos, struct eficonfig_entry, list);
+ free(entry->data);
+ }
+ eficonfig_destroy(efi_menu);
+ free(db);
+
+ return ret;
+}
+
+/**
+ * eficonfig_process_show_signature_database() - process show signature database
+ *
+ * @data: pointer to the data for each entry
+ * Return: status code
+ */
+static efi_status_t eficonfig_process_show_signature_database(void *data)
+{
+ efi_status_t ret;
+
+ while (1) {
+ ret = enumerate_and_show_signature_database(data);
+ if (ret != EFI_SUCCESS && ret != EFI_NOT_READY)
+ break;
+ }
+
+ /* return to the parent menu */
+ ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
+
+ return ret;
+}
+
+static struct eficonfig_item key_config_menu_items[] = {
+ {"Enroll New Key", eficonfig_process_enroll_key},
+ {"Show Signature Database", eficonfig_process_show_signature_database},
+ {"Quit", eficonfig_process_quit},
+};
+
+/**
+ * eficonfig_process_set_secure_boot_key() - display the key configuration menu
+ *
+ * @data: pointer to the data for each entry
+ * Return: status code
+ */
+static efi_status_t eficonfig_process_set_secure_boot_key(void *data)
+{
+ u32 i;
+ efi_status_t ret;
+ char header_str[32];
+ struct efimenu *efi_menu;
+
+ for (i = 0; i < ARRAY_SIZE(key_config_menu_items); i++)
+ key_config_menu_items[i].data = data;
+
+ snprintf(header_str, sizeof(header_str), " ** Configure %ls **", (u16 *)data);
+
+ while (1) {
+ efi_menu = eficonfig_create_fixed_menu(key_config_menu_items,
+ ARRAY_SIZE(key_config_menu_items));
+
+ ret = eficonfig_process_common(efi_menu, header_str);
+ eficonfig_destroy(efi_menu);
+
+ if (ret == EFI_ABORTED)
+ break;
+ }
+
+ /* return to the parent menu */
+ ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
+
+ return ret;
+}
+
+static const struct eficonfig_item secure_boot_menu_items[] = {
+ {"PK", eficonfig_process_set_secure_boot_key, u"PK"},
+ {"KEK", eficonfig_process_set_secure_boot_key, u"KEK"},
+ {"db", eficonfig_process_set_secure_boot_key, u"db"},
+ {"dbx", eficonfig_process_set_secure_boot_key, u"dbx"},
+ {"Quit", eficonfig_process_quit},
+};
+
+/**
+ * eficonfig_process_secure_boot_config() - display the key list menu
+ *
+ * @data: pointer to the data for each entry
+ * Return: status code
+ */
+efi_status_t eficonfig_process_secure_boot_config(void *data)
+{
+ efi_status_t ret;
+ struct efimenu *efi_menu;
+
+ while (1) {
+ char header_str[64];
+
+ snprintf(header_str, sizeof(header_str),
+ " ** UEFI Secure Boot Key Configuration (SecureBoot : %s) **",
+ (efi_secure_boot_enabled() ? "ON" : "OFF"));
+
+ efi_menu = eficonfig_create_fixed_menu(secure_boot_menu_items,
+ ARRAY_SIZE(secure_boot_menu_items));
+ if (!efi_menu) {
+ ret = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ ret = eficonfig_process_common(efi_menu, header_str);
+ eficonfig_destroy(efi_menu);
+
+ if (ret == EFI_ABORTED)
+ break;
+ }
+
+ /* return to the parent menu */
+ ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
+
+ return ret;
+}
diff --git a/doc/usage/cmd/cmp.rst b/doc/usage/cmd/cmp.rst
index 241320d..8d196ee 100644
--- a/doc/usage/cmd/cmp.rst
+++ b/doc/usage/cmd/cmp.rst
@@ -14,20 +14,20 @@
-----------
The cmp command is used to compare two memory areas. By default it works on
-four byte tuples. By appending .b, .w, .l, .q the size of the tuples is
-controlled:
+four byte (32-bit) values. By appending .b, .w, .l, .q the size of the
+values is controlled:
cmp.b
- compare 1 byte tuples
+ compare 1 byte (8-bit) values
cmp.w
- compare 2 byte tuples
+ compare 2 byte (16-bit) values
cmp.l
- compare 4 byte tuples
+ compare 4 byte (32-bit) values
cmp.q
- compare 8 byte tuples
+ compare 8 byte (64-bit) values
The parameters are used as follows:
diff --git a/include/efi_config.h b/include/efi_config.h
index 098cac2..fd69926 100644
--- a/include/efi_config.h
+++ b/include/efi_config.h
@@ -89,10 +89,21 @@
void eficonfig_destroy(struct efimenu *efi_menu);
efi_status_t eficonfig_process_quit(void *data);
efi_status_t eficonfig_process_common(struct efimenu *efi_menu, char *menu_header);
-efi_status_t eficonfig_select_file_handler(void *data);
+efi_status_t eficonfig_process_select_file(void *data);
efi_status_t eficonfig_get_unused_bootoption(u16 *buf,
efi_uintn_t buf_size, u32 *index);
efi_status_t eficonfig_append_bootorder(u16 index);
efi_status_t eficonfig_generate_media_device_boot_option(void);
+efi_status_t eficonfig_append_menu_entry(struct efimenu *efi_menu,
+ char *title, eficonfig_entry_func func,
+ void *data);
+efi_status_t eficonfig_append_quit_entry(struct efimenu *efi_menu);
+struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *dp_volume,
+ u16 *current_path);
+void *eficonfig_create_fixed_menu(const struct eficonfig_item *items, int count);
+#ifdef CONFIG_EFI_SECURE_BOOT
+efi_status_t eficonfig_process_secure_boot_config(void *data);
+#endif
+
#endif
diff --git a/include/efi_selftest.h b/include/efi_selftest.h
index e900cb8..7c69c3f 100644
--- a/include/efi_selftest.h
+++ b/include/efi_selftest.h
@@ -131,7 +131,7 @@
* @buf2: char string
* Return: 0 if both buffers contain equivalent strings
*/
-int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2);
+int efi_st_strcmp_16_8(const u16 *buf1, const unsigned char *buf2);
/**
* efi_st_get_config_table() - get configuration table
diff --git a/lib/efi_loader/efi_unicode_collation.c b/lib/efi_loader/efi_unicode_collation.c
index 36be798..c4c7572 100644
--- a/lib/efi_loader/efi_unicode_collation.c
+++ b/lib/efi_loader/efi_unicode_collation.c
@@ -257,7 +257,7 @@
for (i = 0; i < fat_size; ++i) {
c = (unsigned char)fat[i];
if (c > 0x80)
- c = codepage[i - 0x80];
+ c = codepage[c - 0x80];
string[i] = c;
if (!c)
break;
diff --git a/lib/efi_selftest/efi_selftest_unicode_collation.c b/lib/efi_selftest/efi_selftest_unicode_collation.c
index c63a1b5..11050a3 100644
--- a/lib/efi_selftest/efi_selftest_unicode_collation.c
+++ b/lib/efi_selftest/efi_selftest_unicode_collation.c
@@ -184,6 +184,18 @@
return EFI_ST_FAILURE;
}
+ boottime->set_mem(str, sizeof(str), 0);
+ unicode_collation_protocol->fat_to_str(unicode_collation_protocol, 13,
+ "Kafb\240tur\000xyz", str);
+ if (str[10]) {
+ efi_st_error("fat_to_str returned to many characters\n");
+ return EFI_ST_FAILURE;
+ }
+ if (efi_st_strcmp_16_8(str, "Kafb\341tur")) {
+ efi_st_error("fat_to_str returned \"%ps\"\n", str);
+ return EFI_ST_FAILURE;
+ }
+
return EFI_ST_SUCCESS;
}
diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c
index 7e03e0c..3681fa6 100644
--- a/lib/efi_selftest/efi_selftest_util.c
+++ b/lib/efi_selftest/efi_selftest_util.c
@@ -102,7 +102,7 @@
return efi_st_unknown;
}
-int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2)
+int efi_st_strcmp_16_8(const u16 *buf1, const unsigned char *buf2)
{
for (; *buf1 || *buf2; ++buf1, ++buf2) {
if (*buf1 != *buf2)
diff --git a/test/py/tests/test_eficonfig/test_eficonfig.py b/test/py/tests/test_eficonfig/test_eficonfig.py
index 3859a77..b0a6cc4 100644
--- a/test/py/tests/test_eficonfig/test_eficonfig.py
+++ b/test/py/tests/test_eficonfig/test_eficonfig.py
@@ -352,6 +352,7 @@
press_up_down_enter_and_wait(0, 1, True, 'Quit')
press_up_down_enter_and_wait(0, 0, True, 'No block device found!')
press_escape_key(False)
+ press_escape_key(False)
check_current_is_maintenance_menu()
# Return to U-Boot console
press_escape_key(True)