diff mbox series

[RFC,2/3] eficonfig: add "Show Signature Database" menu entry

Message ID 20220619052022.2694-3-masahisa.kojima@linaro.org
State Changes Requested, archived
Delegated to: Heinrich Schuchardt
Headers show
Series eficonfig: add UEFI Secure Boot key maintenance interface | expand

Commit Message

Masahisa Kojima June 19, 2022, 5:20 a.m. UTC
This commit adds the menu-driven interface to show the
signature database.

Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
---
 cmd/eficonfig_sbkey.c | 283 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 283 insertions(+)
diff mbox series

Patch

diff --git a/cmd/eficonfig_sbkey.c b/cmd/eficonfig_sbkey.c
index a5c0dbe9b3..02ab8f8218 100644
--- a/cmd/eficonfig_sbkey.c
+++ b/cmd/eficonfig_sbkey.c
@@ -17,6 +17,64 @@ 
 #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;
+	struct eficonfig_sig_data **selected;
+	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}, */
+};
+
+static void eficonfig_console_wait_enter(void)
+{
+	int esc = 0;
+	enum bootmenu_key key = KEY_NONE;
+
+	while (1) {
+		bootmenu_loop(NULL, &key, &esc);
+
+		switch (key) {
+		case KEY_SELECT:
+			return;
+		default:
+			break;
+		}
+	}
+
+	/* never happens */
+	debug("eficonfig: this should not happen");
+	return;
+}
+
 static bool is_secureboot_enabled(void)
 {
 	efi_status_t ret;
@@ -113,13 +171,238 @@  out:
 	return ret;
 }
 
+static void display_sigdata_info(struct eficonfig_sig_data *sg)
+{
+	u32 i;
+
+	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.");
+				break;
+			}
+		}
+	}
+}
+
+static void display_sigdata_header(struct eficonfig_sig_data *sg, char *str)
+{
+	puts(ANSI_CURSOR_HIDE);
+	puts(ANSI_CLEAR_CONSOLE);
+	printf(ANSI_CURSOR_POSITION, 1, 1);
+
+	*sg->selected = sg;
+	printf("\n  *** U-Boot Signature Database (%s %ls) ***\n\n"
+	       "    Owner GUID:\n"
+	       "      %pUL\n",
+	       str, sg->varname, sg->esd->signature_owner.b);
+}
+
+static efi_status_t eficonfig_process_sigdata_show(void *data)
+{
+	struct eficonfig_sig_data *sg = data;
+
+	display_sigdata_header(sg, "Show");
+	display_sigdata_info(sg);
+
+	printf("\n\n  Press ENTER to continue");
+	eficonfig_console_wait_enter();
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t prepare_signature_db_list(struct eficonfig_item **output, void *varname,
+					      void *db, efi_uintn_t db_size,
+					      eficonfig_entry_func func,
+					      struct eficonfig_sig_data **selected,
+					      struct list_head *siglist_list,
+					      u32 *count)
+{
+	u32 num = 0;
+	efi_uintn_t size;
+	struct list_head *pos, *n;
+	struct efi_signature_list *esl;
+	struct efi_signature_data *esd;
+	struct eficonfig_item *menu_item, *iter;
+	struct eficonfig_sig_data *sg;
+
+	INIT_LIST_HEAD(siglist_list);
+	esl = db;
+	size = db_size;
+
+	/*
+	 * parse the signature database and save the pointers to
+	 * efi_signature_list and efi_signature_data.
+	 * We expect the signature list is saved in correct format.
+	 */
+	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) {
+			sg = calloc(1, sizeof(struct eficonfig_sig_data));
+			if (!sg)
+				return EFI_OUT_OF_RESOURCES;
+
+			sg->esl = esl;
+			sg->esd = esd;
+			list_add_tail(&sg->list, siglist_list);
+			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);
+	}
+
+	menu_item = calloc(num + 1, sizeof(struct eficonfig_item));
+	if (!menu_item)
+		return EFI_OUT_OF_RESOURCES;
+
+	iter = menu_item;
+	list_for_each_safe(pos, n, siglist_list) {
+		char buf[40] = {0};
+		char *title;
+
+		sg = list_entry(pos, struct eficonfig_sig_data, list);
+
+		snprintf(buf, sizeof(buf), "%pUL", &sg->esd->signature_owner);
+		title = calloc(1, (strlen(buf) + 1));
+		if (!title)
+			return EFI_OUT_OF_RESOURCES;
+
+		strlcpy(title, buf, strlen(buf) + 1);
+		iter->title = title;
+		sg->selected = selected;
+		sg->varname = varname;
+		iter->func = func;
+		iter->data = sg;
+		iter++;
+	}
+
+	/* add "Quit" entry */
+	iter->title = "Quit";
+	iter->func = eficonfig_process_quit;
+	iter->data = NULL;
+	num += 1;
+
+	*count = num;
+	*output = menu_item;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t process_show_signature_db(void *varname)
+{
+	u32 i, count = 0;
+	efi_status_t ret;
+	struct eficonfig_item *menu_item = NULL, *iter;
+	void *db = NULL;
+	efi_uintn_t db_size;
+	struct list_head siglist_list;
+	struct eficonfig_sig_data *selected;
+
+	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;
+	}
+
+	ret = prepare_signature_db_list(&menu_item, varname, db, db_size,
+					eficonfig_process_sigdata_show, &selected,
+					&siglist_list, &count);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	ret = eficonfig_process_common(menu_item, count, "  ** Show Signature Database **");
+
+out:
+	if (menu_item) {
+		iter = menu_item;
+		for (i = 0; i < count - 1; iter++, i++) {
+			free(iter->title);
+			free(iter->data);
+		}
+	}
+
+	free(menu_item);
+	free(db);
+
+	return ret;
+}
+
+static efi_status_t eficonfig_process_show_signature_db(void *data)
+{
+	efi_status_t ret;
+
+	while (1) {
+		ret = process_show_signature_db(data);
+		if (ret != EFI_SUCCESS)
+			break;
+	}
+
+	/* to stay the parent menu */
+	ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
+
+	return ret;
+}
+
 static struct eficonfig_item key_config_pk_menu_items[] = {
 	{"Enroll New Key", eficonfig_process_enroll_key},
+	{"Show Signature Database", eficonfig_process_show_signature_db},
 	{"Quit", eficonfig_process_quit},
 };
 
 static struct eficonfig_item key_config_menu_items[] = {
 	{"Enroll New Key", eficonfig_process_enroll_key},
+	{"Show Signature Database", eficonfig_process_show_signature_db},
 	{"Quit", eficonfig_process_quit},
 };