ieee1275: Appended signature support

Resolves: #RHEL-24742
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
This commit is contained in:
Nicolas Frayer 2025-05-21 22:45:29 +02:00
parent 4946e4fb22
commit 4b6a3a3027
12 changed files with 6021 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:35 +0530
Subject: [PATCH] ieee1275: Platform Keystore (PKS) Support
enhancing the infrastructure to enable the Platform Keystore (PKS) feature,
which provides access to the SB VERSION, DB, and DBX secure boot variables
from PKS.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/Makefile.core.def | 1 +
grub-core/kern/powerpc/ieee1275/ieee1275.c | 140 +++++++++++++++++++++++++++++
include/grub/powerpc/ieee1275/ieee1275.h | 14 +++
3 files changed, 155 insertions(+)
create mode 100644 grub-core/kern/powerpc/ieee1275/ieee1275.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 3740330..05b9c8d 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -320,6 +320,7 @@ kernel = {
extra_dist = video/sis315_init.c;
mips_loongson = commands/keylayouts.c;
+ powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.c;
powerpc_ieee1275 = kern/powerpc/cache.S;
powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
diff --git a/grub-core/kern/powerpc/ieee1275/ieee1275.c b/grub-core/kern/powerpc/ieee1275/ieee1275.c
new file mode 100644
index 0000000..f685afc
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/ieee1275.c
@@ -0,0 +1,140 @@
+/* of.c - Access the Open Firmware client interface. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/misc.h>
+
+#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) - 1)
+
+int
+grub_ieee1275_test (const char *name, grub_ieee1275_cell_t *missing)
+{
+ struct test_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t name;
+ grub_ieee1275_cell_t missing;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "test", 1, 1);
+ args.name = (grub_ieee1275_cell_t) name;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.missing == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *missing = args.missing;
+
+ return 0;
+}
+
+int
+grub_ieee1275_pks_max_object_size (grub_size_t *result)
+{
+ struct mos_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t size;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "pks-max-object-size", 0, 1);
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.size == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *result = args.size;
+
+ return 0;
+}
+
+int
+grub_ieee1275_pks_read_object (grub_uint8_t consumer, grub_uint8_t *label,
+ grub_size_t label_len, grub_uint8_t *buffer,
+ grub_size_t buffer_len, grub_size_t *data_len,
+ grub_uint32_t *policies)
+{
+ struct pks_read_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t consumer;
+ grub_ieee1275_cell_t label;
+ grub_ieee1275_cell_t label_len;
+ grub_ieee1275_cell_t buffer;
+ grub_ieee1275_cell_t buffer_len;
+ grub_ieee1275_cell_t data_len;
+ grub_ieee1275_cell_t policies;
+ grub_ieee1275_cell_t rc;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "pks-read-object", 5, 3);
+ args.consumer = (grub_ieee1275_cell_t) consumer;
+ args.label = (grub_ieee1275_cell_t) label;
+ args.label_len = (grub_ieee1275_cell_t) label_len;
+ args.buffer = (grub_ieee1275_cell_t) buffer;
+ args.buffer_len = (grub_ieee1275_cell_t) buffer_len;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.data_len == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *data_len = args.data_len;
+ *policies = args.policies;
+
+ return (int) args.rc;
+}
+
+int
+grub_ieee1275_pks_read_sbvar (grub_uint8_t sbvarflags, grub_uint8_t sbvartype,
+ grub_uint8_t *buffer, grub_size_t buffer_len,
+ grub_size_t *data_len)
+{
+ struct pks_read_sbvar_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t sbvarflags;
+ grub_ieee1275_cell_t sbvartype;
+ grub_ieee1275_cell_t buffer;
+ grub_ieee1275_cell_t buffer_len;
+ grub_ieee1275_cell_t data_len;
+ grub_ieee1275_cell_t rc;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "pks-read-sbvar", 4, 2);
+ args.sbvarflags = (grub_ieee1275_cell_t) sbvarflags;
+ args.sbvartype = (grub_ieee1275_cell_t) sbvartype;
+ args.buffer = (grub_ieee1275_cell_t) buffer;
+ args.buffer_len = (grub_ieee1275_cell_t) buffer_len;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.data_len == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *data_len = args.data_len;
+
+ return (int) args.rc;
+}
diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h
index 3c7683f..45c7b16 100644
--- a/include/grub/powerpc/ieee1275/ieee1275.h
+++ b/include/grub/powerpc/ieee1275/ieee1275.h
@@ -25,4 +25,18 @@
#define GRUB_IEEE1275_CELL_SIZEOF 4
typedef grub_uint32_t grub_ieee1275_cell_t;
+int EXPORT_FUNC (grub_ieee1275_test) (const char *name,
+ grub_ieee1275_cell_t *missing);
+
+int grub_ieee1275_pks_max_object_size (grub_size_t *result);
+
+int grub_ieee1275_pks_read_object (grub_uint8_t consumer, grub_uint8_t *label,
+ grub_size_t label_len, grub_uint8_t *buffer,
+ grub_size_t buffer_len, grub_size_t *data_len,
+ grub_uint32_t *policies);
+
+int grub_ieee1275_pks_read_sbvar (grub_uint8_t sbvarflags, grub_uint8_t sbvartype,
+ grub_uint8_t *buffer, grub_size_t buffer_len,
+ grub_size_t *data_len);
+
#endif /* ! GRUB_IEEE1275_MACHINE_HEADER */

View File

@ -0,0 +1,686 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:36 +0530
Subject: [PATCH] ieee1275: Read the DB and DBX secure boot variables
If secure boot is enabled with PKS, it will read secure boot variables
such as db and dbx from PKS and extract ESL's from it.
The ESL's would be saved in the platform keystore buffer, and
the appendedsig (module) would read it later to extract
the certificate's details from ESL.
In the following scenarios, static key mode will be activated:
1. When Secure Boot is enabled with static keys
2. When SB Version is unavailable but Secure Boot is enabled
3. When PKS support is unavailable but Secure Boot is enabled
Note:-
SB Version - Secure Boot mode
1 - PKS
0 - static key (embeded key)
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 1 +
grub-core/kern/ieee1275/init.c | 15 +-
.../kern/powerpc/ieee1275/platform_keystore.c | 332 +++++++++++++++++++++
include/grub/powerpc/ieee1275/platform_keystore.h | 225 ++++++++++++++
include/grub/types.h | 8 +
6 files changed, 580 insertions(+), 2 deletions(-)
create mode 100644 grub-core/kern/powerpc/ieee1275/platform_keystore.c
create mode 100644 include/grub/powerpc/ieee1275/platform_keystore.h
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index dd49939..a398a04 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -245,6 +245,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/platform_keystore.h
endif
if COND_sparc64_ieee1275
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 05b9c8d..218068b 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -325,6 +325,7 @@ kernel = {
powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
powerpc_ieee1275 = kern/lockdown.c;
+ powerpc_ieee1275 = kern/powerpc/ieee1275/platform_keystore.c;
sparc64_ieee1275 = kern/sparc64/cache.S;
sparc64_ieee1275 = kern/sparc64/dl.c;
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index bb791f8..b853f04 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -47,6 +47,8 @@
#include <grub/machine/kernel.h>
#endif
#include <grub/lockdown.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
/* The maximum heap size we're going to claim at boot. Not used by sparc. */
#ifdef __i386__
@@ -956,7 +958,7 @@ grub_get_ieee1275_secure_boot (void)
{
grub_ieee1275_phandle_t root;
int rc;
- grub_uint32_t is_sb;
+ grub_uint32_t is_sb = 0;
grub_ieee1275_finddevice ("/", &root);
@@ -972,7 +974,16 @@ grub_get_ieee1275_secure_boot (void)
* We only support enforce.
*/
if (rc >= 0 && is_sb >= 2)
- grub_lockdown ();
+ {
+ grub_dprintf ("ieee1275", "Secure Boot Enabled\n");
+ rc = grub_pks_keystore_init ();
+ if (rc != GRUB_ERR_NONE)
+ grub_error (rc, "Initialization of the Platform Keystore failed!\n");
+
+ grub_lockdown ();
+ }
+ else
+ grub_dprintf ("ieee1275", "Secure Boot Disabled\n");
}
grub_addr_t grub_modbase;
diff --git a/grub-core/kern/powerpc/ieee1275/platform_keystore.c b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
new file mode 100644
index 0000000..cf1d055
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
@@ -0,0 +1,332 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2024 IBM Corporation
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/lockdown.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
+
+#define PKS_CONSUMER_FW 1
+#define SB_VERSION_KEY_NAME ((grub_uint8_t *) "SB_VERSION")
+#define SB_VERSION_KEY_LEN 10
+#define DB 1
+#define DBX 2
+#define PKS_OBJECT_NOT_FOUND ((grub_err_t) - 7)
+
+/* Platform Keystore */
+static grub_size_t pks_max_object_size;
+grub_uint8_t grub_pks_use_keystore = 0;
+grub_pks_t grub_pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 };
+
+/* Convert the esl data into the ESL */
+static grub_esl_t *
+convert_to_esl (const grub_uint8_t *esl_data, const grub_size_t esl_data_size)
+{
+ grub_esl_t *esl = NULL;
+
+ if (esl_data_size < sizeof (grub_esl_t) || esl_data == NULL)
+ return esl;
+
+ esl = (grub_esl_t *) esl_data;
+
+ return esl;
+}
+
+/*
+ * Import the GUID, esd, and its size into the pks sd buffer and
+ * pks sd entries from the EFI signature list.
+ */
+static grub_err_t
+esd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size,
+ const grub_size_t signature_size, const grub_uuid_t *guid,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_esd_t *esd = NULL;
+ grub_pks_sd_t *signature = *pks_sd;
+ grub_size_t entries = *pks_sd_entries;
+ grub_size_t data_size = 0, offset = 0;
+
+ /* reads the esd from esl */
+ while (esl_size > 0)
+ {
+ esd = (grub_esd_t *) (esl_data + offset);
+ data_size = signature_size - sizeof (grub_esd_t);
+
+ signature = grub_realloc (signature, (entries + 1) * sizeof (grub_pks_sd_t));
+ if (signature == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ signature[entries].data = grub_malloc (data_size * sizeof (grub_uint8_t));
+ if (signature[entries].data == NULL)
+ {
+ /*
+ * allocated memory will be freed by
+ * grub_free_platform_keystore
+ */
+ *pks_sd = signature;
+ *pks_sd_entries = entries + 1;
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ }
+
+ grub_memcpy (signature[entries].data, esd->signaturedata, data_size);
+ signature[entries].data_size = data_size;
+ signature[entries].guid = *guid;
+ entries++;
+ esl_size -= signature_size;
+ offset += signature_size;
+ }
+
+ *pks_sd = signature;
+ *pks_sd_entries = entries;
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Extract the esd after removing the esl header from esl.
+ */
+static grub_err_t
+esl_to_esd (const grub_uint8_t *esl_data, grub_size_t *next_esl,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_uuid_t guid = { 0 };
+ grub_esl_t *esl = NULL;
+ grub_size_t offset = 0, esl_size = 0,
+ signature_size = 0, signature_header_size = 0;
+
+ esl = convert_to_esl (esl_data, *next_esl);
+ if (esl == NULL)
+ return grub_error (GRUB_ERR_BUG, "invalid ESL");
+
+ esl_size = grub_le_to_cpu32 (esl->signaturelistsize);
+ signature_header_size = grub_le_to_cpu32 (esl->signatureheadersize);
+ signature_size = grub_le_to_cpu32 (esl->signaturesize);
+ guid = esl->signaturetype;
+
+ if (esl_size < sizeof (grub_esl_t) || esl_size > *next_esl)
+ return grub_error (GRUB_ERR_BUG, "invalid ESL size (%u)\n", esl_size);
+
+ *next_esl = esl_size;
+ offset = sizeof (grub_esl_t) + signature_header_size;
+ esl_size = esl_size - offset;
+
+ return esd_from_esl (esl_data + offset, esl_size, signature_size, &guid,
+ pks_sd, pks_sd_entries);
+}
+
+/*
+ * Import the EFI signature data and the number of esd from the esl
+ * into the pks sd buffer and pks sd entries.
+ */
+static grub_err_t
+pks_sd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t next_esl = esl_size;
+
+ do
+ {
+ rc = esl_to_esd (esl_data, &next_esl, pks_sd, pks_sd_entries);
+ if (rc != GRUB_ERR_NONE)
+ break;
+
+ esl_data += next_esl;
+ esl_size -= next_esl;
+ next_esl = esl_size;
+ }
+ while (esl_size > 0);
+
+ return rc;
+}
+
+/*
+ * Read the secure boot version from PKS as an object.
+ * caller must free result
+ */
+static grub_err_t
+read_sbversion_from_pks (grub_uint8_t **out, grub_size_t *outlen, grub_size_t *policy)
+{
+ *out = grub_malloc (pks_max_object_size);
+ if (*out == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ return grub_ieee1275_pks_read_object (PKS_CONSUMER_FW, SB_VERSION_KEY_NAME,
+ SB_VERSION_KEY_LEN, *out, pks_max_object_size,
+ outlen, policy);
+}
+
+/*
+ * reads the secure boot variable from PKS.
+ * caller must free result
+ */
+static grub_err_t
+read_sbvar_from_pks (const grub_uint8_t sbvarflags, const grub_uint8_t sbvartype,
+ grub_uint8_t **out, grub_size_t *outlen)
+{
+ *out = grub_malloc (pks_max_object_size);
+ if (*out == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ return grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, *out,
+ pks_max_object_size, outlen);
+}
+
+/* Test the availability of PKS support. */
+static grub_err_t
+is_support_pks (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_ieee1275_cell_t missing = 0;
+
+ rc = grub_ieee1275_test ("pks-max-object-size", &missing);
+ if (rc != GRUB_ERR_NONE || (int) missing == -1)
+ rc = grub_error (GRUB_ERR_BAD_FIRMWARE, "Firmware doesn't have PKS support!\n");
+ else
+ {
+ rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
+ if (rc != GRUB_ERR_NONE)
+ rc = grub_error (GRUB_ERR_BAD_NUMBER, "PKS support is there but it has zero objects!\n");
+ }
+
+ return rc;
+}
+
+/*
+ * Retrieve the secure boot variable from PKS, unpacks it, read the esd
+ * from ESL, and store the information in the pks sd buffer.
+ */
+static grub_err_t
+read_secure_boot_variables (const grub_uint8_t sbvarflags, const grub_uint8_t sbvartype,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_uint8_t *esl_data = NULL;
+ grub_size_t esl_data_size = 0;
+
+ rc = read_sbvar_from_pks (sbvarflags, sbvartype, &esl_data, &esl_data_size);
+ /*
+ * at this point we have SB_VERSION, so any error is worth
+ * at least some user-visible info
+ */
+ if (rc != GRUB_ERR_NONE)
+ rc = grub_error (rc, "secure boot variable %s reading (%d)",
+ (sbvartype == DB ? "db" : "dbx"), rc);
+ else if (esl_data_size != 0)
+ rc = pks_sd_from_esl ((const grub_uint8_t *) esl_data, esl_data_size,
+ pks_sd, pks_sd_entries);
+ grub_free (esl_data);
+
+ return rc;
+}
+
+/* reads secure boot version (SB_VERSION) and it supports following
+ * SB_VERSION
+ * 1 - PKS
+ * 0 - static key (embeded key)
+ */
+static grub_err_t
+get_secure_boot_version (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_uint8_t *data = NULL;
+ grub_size_t len = 0, policy = 0;
+
+ rc = read_sbversion_from_pks (&data, &len, &policy);
+ if (rc != GRUB_ERR_NONE)
+ rc = grub_error (GRUB_ERR_READ_ERROR, "SB version read failed! (%d)\n", rc);
+ else if (len != 1 || (*data >= 2))
+ rc = grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version! (%d)\n", *data);
+
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_printf ("Switch to Static Key!\n");
+ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
+ grub_fatal ("Secure Boot locked down");
+ }
+ else
+ grub_pks_use_keystore = *data;
+
+ grub_free (data);
+
+ return rc;
+}
+
+/* Free allocated memory */
+void
+grub_pks_free_keystore (void)
+{
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.db_entries; i++)
+ grub_free (grub_pks_keystore.db[i].data);
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ grub_free (grub_pks_keystore.dbx[i].data);
+
+ grub_free (grub_pks_keystore.db);
+ grub_free (grub_pks_keystore.dbx);
+ grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t));
+}
+
+/* Initialization of the Platform Keystore */
+grub_err_t
+grub_pks_keystore_init (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+
+ grub_dprintf ("ieee1275", "trying to load Platform Keystore\n");
+
+ rc = is_support_pks ();
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_printf ("Switch to Static Key!\n");
+ return rc;
+ }
+
+ /* SB_VERSION */
+ rc = get_secure_boot_version ();
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+
+ if (grub_pks_use_keystore)
+ {
+ grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t));
+ /* DB */
+ rc = read_secure_boot_variables (0, DB, &grub_pks_keystore.db, &grub_pks_keystore.db_entries);
+ if (rc == GRUB_ERR_NONE)
+ {
+ /* DBX */
+ rc = read_secure_boot_variables (0, DBX, &grub_pks_keystore.dbx, &grub_pks_keystore.dbx_entries);
+ if (rc == PKS_OBJECT_NOT_FOUND)
+ {
+ grub_dprintf ("ieee1275", "dbx is not found in PKS\n");
+ rc = GRUB_ERR_NONE;
+ }
+ }
+
+ }
+
+ if (rc != GRUB_ERR_NONE)
+ grub_pks_free_keystore ();
+
+ return rc;
+}
diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h
new file mode 100644
index 0000000..0641adb
--- /dev/null
+++ b/include/grub/powerpc/ieee1275/platform_keystore.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This
+ * program and the accompanying materials are licensed and made available
+ * under the terms and conditions of the 2-Clause BSD License which
+ * accompanies this distribution.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * https://github.com/tianocore/edk2-staging (edk2-staging repo of tianocore),
+ * the ImageAuthentication.h file under it, and here's the copyright and license.
+ *
+ * MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * Copyright 2024 IBM Corp.
+ */
+
+#ifndef __PLATFORM_KEYSTORE_H__
+#define __PLATFORM_KEYSTORE_H__
+
+#include <grub/symbol.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+
+#if __GNUC__ >= 9
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+#endif
+
+#define GRUB_MAX_HASH_SIZE 64
+
+typedef struct grub_esd grub_esd_t;
+typedef struct grub_esl grub_esl_t;
+
+/*
+ * It is derived from EFI_SIGNATURE_DATA
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * The structure of an EFI signature database (ESD).*/
+struct grub_esd
+{
+ /*
+ * An identifier which identifies the agent which added
+ * the signature to the list.
+ */
+ grub_uuid_t signatureowner;
+ /* The format of the signature is defined by the SignatureType.*/
+ grub_uint8_t signaturedata[];
+} GRUB_PACKED;
+
+/*
+ * It is derived from EFI_SIGNATURE_LIST
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * The structure of an EFI signature list (ESL).*/
+struct grub_esl
+{
+ /* Type of the signature. GUID signature types are defined in below.*/
+ grub_uuid_t signaturetype;
+ /* Total size of the signature list, including this header.*/
+ grub_uint32_t signaturelistsize;
+ /*
+ * Size of the signature header which precedes
+ * the array of signatures.
+ */
+ grub_uint32_t signatureheadersize;
+ /* Size of each signature.*/
+ grub_uint32_t signaturesize;
+} GRUB_PACKED;
+
+/*
+ * It is derived from EFI_CERT_X509_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, \
+ 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, \
+ 0x5c, 0x2b, 0xf0, 0x72 \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_SHA256_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_SHA256_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50, \
+ 0x92, 0x40, 0xac, 0xa9, 0x41, 0xf9, \
+ 0x36, 0x93, 0x43, 0x28 \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_SHA384_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_SHA384_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x07, 0x53, 0x3e, 0xff, 0xd0, 0x9f, \
+ 0xc9, 0x48, 0x85, 0xf1, 0x8a, 0xd5, \
+ 0x6c, 0x70, 0x1e, 0x1 \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_SHA512_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_SHA512_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0xae, 0x0f, 0x3e, 0x09, 0xc4, 0xa6, \
+ 0x50, 0x4f, 0x9f, 0x1b, 0xd4, 0x1e, \
+ 0x2b, 0x89, 0xc1, 0x9a \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_X509_SHA256_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_SHA256_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x92, 0xa4, 0xd2, 0x3b, 0xc0, 0x96, \
+ 0x79, 0x40, 0xb4, 0x20, 0xfc, 0xf9, \
+ 0x8e, 0xf1, 0x03, 0xed \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_X509_SHA384_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_SHA384_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x6e, 0x87, 0x76, 0x70, 0xc2, 0x80, \
+ 0xe6, 0x4e, 0xaa, 0xd2, 0x28, 0xb3, \
+ 0x49, 0xa6, 0x86, 0x5b \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_X509_SHA512_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_SHA512_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x63, 0xbf, 0x6d, 0x44, 0x02, 0x25, \
+ 0xda, 0x4c, 0xbc, 0xfa, 0x24, 0x65, \
+ 0xd2, 0xb0, 0xfe, 0x9d \
+ } \
+ }
+
+typedef struct grub_pks_sd grub_pks_sd_t;
+typedef struct grub_pks grub_pks_t;
+
+/* The structure of a PKS signature data.*/
+struct grub_pks_sd
+{
+ grub_uuid_t guid; /* signature type */
+ grub_uint8_t *data; /* signature data */
+ grub_size_t data_size; /* size of signature data */
+} GRUB_PACKED;
+
+/* The structure of a PKS.*/
+struct grub_pks
+{
+ grub_pks_sd_t *db; /* signature database */
+ grub_pks_sd_t *dbx; /* forbidden signature database */
+ grub_size_t db_entries; /* size of signature database */
+ grub_size_t dbx_entries; /* size of forbidden signature database */
+} GRUB_PACKED;
+
+#ifdef __powerpc__
+
+/* Initialization of the Platform Keystore */
+grub_err_t grub_pks_keystore_init (void);
+/* Free allocated memory */
+void EXPORT_FUNC(grub_pks_free_keystore) (void);
+extern grub_uint8_t EXPORT_VAR(grub_pks_use_keystore);
+extern grub_pks_t EXPORT_VAR(grub_pks_keystore);
+
+#else
+
+#define grub_pks_use_keystore 0
+grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0};
+void grub_pks_free_keystore (void);
+
+#endif
+
+#endif
diff --git a/include/grub/types.h b/include/grub/types.h
index 1587ff4..bfa7af9 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -345,4 +345,12 @@ static inline void grub_set_unaligned64 (void *ptr, grub_uint64_t val)
dd->d = val;
}
+#define GRUB_UUID_SIZE 16
+typedef struct grub_uuid grub_uuid_t;
+/* The structure of a UUID.*/
+struct grub_uuid
+{
+ grub_uint8_t b[GRUB_UUID_SIZE];
+};
+
#endif /* ! GRUB_TYPES_HEADER */

View File

@ -0,0 +1,764 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:37 +0530
Subject: [PATCH] appendedsig: The creation of trusted and distrusted lists
The trusted certificates and binary hashes, distrusted certificates and
binary/certificate hashes will be extracted from the platform keystore buffer
if Secure Boot is enabled with PKS.
In order to verify the integrity of the kernel, the extracted data
needs to be stored stored in the buffer db and dbx.
The trusted certificates will be extracted from the grub ELFNOTE if Secure Boot is
enabled with static key. In order to verify the integerity of the kernel,
the extracted data needs to be stored in the buffer db.
Note:-
If neither the trusted certificate nor binary hash exists in the distrusted list (dbx),
rejects it while extracting certificate/binary hash from the platform keystore buffer.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 584 +++++++++++++++++++++++++--
grub-core/kern/file.c | 34 ++
include/grub/file.h | 1 +
3 files changed, 577 insertions(+), 42 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index f4eefe5..994852f 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -34,7 +34,7 @@
#include <grub/libtasn1.h>
#include <grub/env.h>
#include <grub/lockdown.h>
-
+#include <grub/powerpc/ieee1275/platform_keystore.h>
#include "appendedsig.h"
GRUB_MOD_LICENSE ("GPLv3+");
@@ -64,8 +64,23 @@ struct grub_appended_signature
struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */
};
-/* Trusted certificates for verifying appended signatures */
-struct x509_certificate *grub_trusted_key;
+/* This represents a trusted/distrusted list*/
+struct grub_database
+{
+ struct x509_certificate *keys; /* Certificates */
+ grub_size_t key_entries; /* Number of certificates */
+ grub_uint8_t **signatures; /* Certificate/binary hashes */
+ grub_size_t *signature_size; /* Size of certificate/binary hashes */
+ grub_size_t signature_entries; /* Number of certificate/binary hashes */
+};
+
+/* Trusted list */
+struct grub_database db = {.keys = NULL, .key_entries = 0, .signatures = NULL,
+ .signature_size = NULL, .signature_entries = 0};
+
+/* Distrusted list */
+struct grub_database dbx = {.signatures = NULL, .signature_size = NULL,
+ .signature_entries = 0};
/*
* Force gcry_rsa to be a module dependency.
@@ -87,6 +102,13 @@ struct x509_certificate *grub_trusted_key;
* also resolves our concerns about loading from the filesystem.
*/
extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
+extern gcry_md_spec_t _gcry_digest_spec_sha224;
+extern gcry_md_spec_t _gcry_digest_spec_sha384;
+
+/* Free trusted list memory */
+static void free_trusted_list (void);
+/* Free distrusted list memory */
+static void free_distrusted_list (void);
static enum
{
@@ -95,6 +117,204 @@ static enum
check_sigs_forced = 2
} check_sigs = check_sigs_no;
+/*
+ * GUID can be used to determine the hashing function and
+ * generate the hash using determined hashing function.
+ */
+static grub_err_t
+get_hash (const grub_uuid_t *guid, const grub_uint8_t *data, const grub_size_t data_size,
+ grub_uint8_t *hash, grub_size_t *hash_size)
+{
+ gcry_md_spec_t *hash_func = NULL;
+
+ if (guid == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "GUID is null");
+
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha256;
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha384;
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha512;
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Unsupported GUID for hash");
+
+ grub_memset (hash, 0, GRUB_MAX_HASH_SIZE);
+ grub_crypto_hash (hash_func, hash, data, data_size);
+ *hash_size = hash_func->mdlen;
+
+ return GRUB_ERR_NONE;
+}
+
+/* Add the certificate/binary hash into the trusted/distrusted list */
+static grub_err_t
+add_hash (const grub_uint8_t **data, const grub_size_t data_size,
+ grub_uint8_t ***signature_list, grub_size_t **signature_size_list,
+ grub_size_t *signature_list_entries)
+{
+ grub_uint8_t **signatures = *signature_list;
+ grub_size_t *signature_size = *signature_size_list;
+ grub_size_t signature_entries = *signature_list_entries;
+
+ if (*data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate/binary hash data/size is null");
+
+ signatures = grub_realloc (signatures, sizeof (grub_uint8_t *) * (signature_entries + 1));
+ signature_size = grub_realloc (signature_size,
+ sizeof (grub_size_t) * (signature_entries + 1));
+
+ if (signatures == NULL || signature_size == NULL)
+ {
+ /*
+ * allocated memory will be freed by
+ * free_trusted_list/free_distrusted_list
+ */
+ if (signatures != NULL)
+ {
+ *signature_list = signatures;
+ *signature_list_entries = signature_entries + 1;
+ }
+
+ if (signature_size != NULL)
+ *signature_size_list = signature_size;
+
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ }
+
+ signatures[signature_entries] = (grub_uint8_t *) *data;
+ signature_size[signature_entries] = data_size;
+ signature_entries++;
+ *data = NULL;
+
+ *signature_list = signatures;
+ *signature_size_list = signature_size;
+ *signature_list_entries = signature_entries;
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+is_x509 (const grub_uuid_t *guid)
+{
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_UUID_SIZE) == 0)
+ return GRUB_ERR_NONE;
+
+ return GRUB_ERR_UNKNOWN_COMMAND;
+}
+
+static int
+is_cert_match (const struct x509_certificate *distrusted_cert,
+ const struct x509_certificate *db_cert)
+{
+
+ if (grub_memcmp (distrusted_cert->subject, db_cert->subject, db_cert->subject_len) == 0
+ && grub_memcmp (distrusted_cert->serial, db_cert->serial, db_cert->serial_len) == 0
+ && grub_memcmp (distrusted_cert->mpis[0], db_cert->mpis[0], sizeof (db_cert->mpis[0])) == 0
+ && grub_memcmp (distrusted_cert->mpis[1], db_cert->mpis[1], sizeof (db_cert->mpis[1])) == 0)
+ return GRUB_ERR_NONE;
+
+ return GRUB_ERR_UNKNOWN_COMMAND;
+}
+
+/*
+ * Verify the certificate against the certificate from platform keystore buffer's
+ * distrusted list.
+ */
+static grub_err_t
+is_distrusted_cert (const struct x509_certificate *db_cert)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0;
+ struct x509_certificate *distrusted_cert = NULL;
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data == NULL)
+ continue;
+
+ if (is_x509 (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+ {
+ distrusted_cert = grub_zalloc (sizeof (struct x509_certificate));
+ if (distrusted_cert == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = parse_x509_certificate (grub_pks_keystore.dbx[i].data,
+ grub_pks_keystore.dbx[i].data_size, distrusted_cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_free (distrusted_cert);
+ continue;
+ }
+
+ if (is_cert_match (distrusted_cert, db_cert) == GRUB_ERR_NONE)
+ {
+ grub_printf ("Warning: a trusted certificate CN='%s' is ignored "
+ "because it is on the distrusted list (dbx).\n", db_cert->subject);
+ grub_free (grub_pks_keystore.dbx[i].data);
+ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof (grub_pks_sd_t));
+ certificate_release (distrusted_cert);
+ grub_free (distrusted_cert);
+ return GRUB_ERR_ACCESS_DENIED;
+ }
+
+ certificate_release (distrusted_cert);
+ grub_free (distrusted_cert);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/* Add the certificate into the trusted/distrusted list */
+static grub_err_t
+add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
+ struct grub_database *database, const grub_size_t is_db)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t key_entries = database->key_entries;
+ struct x509_certificate *cert = NULL;
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate data/size is null");
+
+ cert = grub_zalloc (sizeof (struct x509_certificate));
+ if (cert == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = parse_x509_certificate (data, data_size, cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_dprintf ("appendedsig", "skipping %s certificate (%d)\n",
+ (is_db ? "trusted":"distrusted"), rc);
+ grub_free (cert);
+ return rc;
+ }
+
+ if (is_db)
+ {
+ rc = is_distrusted_cert (cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ certificate_release (cert);
+ grub_free (cert);
+ return rc;
+ }
+ }
+
+ grub_dprintf ("appendedsig", "add a %s certificate CN='%s'\n",
+ (is_db ? "trusted":"distrusted"), cert->subject);
+
+ key_entries++;
+ cert->next = database->keys;
+ database->keys = cert;
+ database->key_entries = key_entries;
+
+ return rc;
+}
+
static const char *
grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
@@ -248,7 +468,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
struct pkcs7_signerInfo *si;
int i;
- if (!grub_trusted_key)
+ if (!db.key_entries)
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
err = extract_appended_signature (buf, bufsize, &sig);
@@ -279,7 +499,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
datasize, i, hash[0], hash[1], hash[2], hash[3]);
err = GRUB_ERR_BAD_SIGNATURE;
- for (pk = grub_trusted_key; pk; pk = pk->next)
+ for (pk = db.keys; pk; pk = pk->next)
{
rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
if (rc)
@@ -376,16 +596,16 @@ grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char *
if (cert_num == 1)
{
- cert = grub_trusted_key;
- grub_trusted_key = cert->next;
+ cert = db.keys;
+ db.keys = cert->next;
certificate_release (cert);
grub_free (cert);
return GRUB_ERR_NONE;
}
i = 2;
- prev = grub_trusted_key;
- cert = grub_trusted_key->next;
+ prev = db.keys;
+ cert = db.keys->next;
while (cert)
{
if (i == cert_num)
@@ -432,8 +652,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **ar
}
grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject);
- cert->next = grub_trusted_key;
- grub_trusted_key = cert;
+ cert->next = db.keys;
+ db.keys = cert;
return GRUB_ERR_NONE;
}
@@ -446,7 +666,7 @@ grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute
int cert_num = 1;
grub_size_t i;
- for (cert = grub_trusted_key; cert; cert = cert->next)
+ for (cert = db.keys; cert; cert = cert->next)
{
grub_printf (N_("Certificate %d:\n"), cert_num);
@@ -539,6 +759,274 @@ static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read };
static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust;
+/*
+ * Verify the trusted certificate against the certificate hashes from platform keystore buffer's
+ * distrusted list.
+ */
+static grub_err_t
+is_distrusted_cert_hash (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0, cert_hash_size = 0;
+ grub_uint8_t cert_hash[GRUB_MAX_HASH_SIZE] = { 0 };
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted certificate data/size is null");
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data == NULL ||
+ grub_pks_keystore.dbx[i].data_size == 0)
+ continue;
+
+ rc = get_hash (&grub_pks_keystore.dbx[i].guid, data, data_size,
+ cert_hash, &cert_hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (cert_hash_size == grub_pks_keystore.dbx[i].data_size &&
+ grub_memcmp (grub_pks_keystore.dbx[i].data, cert_hash, cert_hash_size) == 0)
+ {
+ grub_printf ("Warning: a trusted certificate (%02x%02x%02x%02x) is ignored "
+ "because this certificate hash is on the distrusted list (dbx).\n",
+ cert_hash[0], cert_hash[1], cert_hash[2], cert_hash[3]);
+ grub_free (grub_pks_keystore.dbx[i].data);
+ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof (grub_pks_keystore.dbx[i]));
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Verify the trusted binary hash against the platform keystore buffer's
+ * distrusted list.
+ */
+static grub_err_t
+is_distrusted_binary_hash (const grub_uint8_t *binary_hash,
+ const grub_size_t binary_hash_size)
+{
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data == NULL ||
+ grub_pks_keystore.dbx[i].data_size == 0)
+ continue;
+
+ if (binary_hash_size == grub_pks_keystore.dbx[i].data_size &&
+ grub_memcmp (grub_pks_keystore.dbx[i].data, binary_hash, binary_hash_size) == 0)
+ {
+ grub_printf ("Warning: a trusted binary hash (%02x%02x%02x%02x) is ignored"
+ " because it is on the distrusted list (dbx).\n",
+ binary_hash[0], binary_hash[1], binary_hash[2], binary_hash[3]);
+ grub_free (grub_pks_keystore.dbx[i].data);
+ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof(grub_pks_keystore.dbx[i]));
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Extract the binary hashes from the platform keystore buffer,
+ * and add it to the trusted list if it does not exist in the distrusted list.
+ */
+static grub_err_t
+add_trusted_binary_hash (const grub_uint8_t **data, const grub_size_t data_size)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+
+ if (*data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted binary hash data/size is null");
+
+ rc = is_distrusted_binary_hash (*data, data_size);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+
+ rc = add_hash (data, data_size, &db.signatures, &db.signature_size,
+ &db.signature_entries);
+ return rc;
+}
+
+static int
+is_hash (const grub_uuid_t *guid)
+{
+ /* GUID type of the binary hash */
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0)
+ return GRUB_ERR_NONE;
+
+ /* GUID type of the certificate hash */
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0)
+ return GRUB_ERR_NONE;
+
+ return GRUB_ERR_UNKNOWN_COMMAND;
+}
+
+/*
+ * Extract the x509 certificates/binary hashes from the platform keystore buffer,
+ * parse it, and add it to the trusted list.
+ */
+static grub_err_t
+create_trusted_list (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.db_entries; i++)
+ {
+ if (is_hash (&grub_pks_keystore.db[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = add_trusted_binary_hash ((const grub_uint8_t **)
+ &grub_pks_keystore.db[i].data,
+ grub_pks_keystore.db[i].data_size);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else if (is_x509 (&grub_pks_keystore.db[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = is_distrusted_cert_hash (grub_pks_keystore.db[i].data,
+ grub_pks_keystore.db[i].data_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ rc = add_certificate (grub_pks_keystore.db[i].data,
+ grub_pks_keystore.db[i].data_size, &db, 1);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ else if (rc != GRUB_ERR_NONE)
+ continue;
+ }
+ else
+ grub_dprintf ("appendedsig", "unsupported signature data type and "
+ "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Extract the certificates, certificate/binary hashes out of the platform keystore buffer,
+ * and add it to the distrusted list.
+ */
+static grub_err_t
+create_distrusted_list (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data != NULL ||
+ grub_pks_keystore.dbx[i].data_size > 0)
+ {
+ if (is_x509 (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = add_certificate (grub_pks_keystore.dbx[i].data,
+ grub_pks_keystore.dbx[i].data_size, &dbx, 0);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else if (is_hash (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = add_hash ((const grub_uint8_t **) &grub_pks_keystore.dbx[i].data,
+ grub_pks_keystore.dbx[i].data_size,
+ &dbx.signatures, &dbx.signature_size,
+ &dbx.signature_entries);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+ }
+ else
+ grub_dprintf ("appendedsig", "unsupported signature data type and "
+ "skipping distrusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Extract the x509 certificates from the ELF note header,
+ * parse it, and add it to the trusted list.
+ */
+static grub_err_t
+build_static_trusted_list (const struct grub_module_header *header)
+{
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_file pseudo_file;
+ grub_uint8_t *cert_data = NULL;
+ grub_ssize_t cert_data_size = 0;
+
+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
+ pseudo_file.fs = &pseudo_fs;
+ pseudo_file.size = header->size - sizeof (struct grub_module_header);
+ pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
+
+ grub_dprintf ("appendedsig", "found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
+ pseudo_file.size);
+
+ err = grub_read_file (&pseudo_file, &cert_data, &cert_data_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = add_certificate (cert_data, cert_data_size, &db, 1);
+ grub_free (cert_data);
+
+ return err;
+}
+
+/* releasing memory */
+static void
+free_trusted_list (void)
+{
+ struct x509_certificate *cert;
+ grub_size_t i = 0;
+
+ while (db.keys != NULL)
+ {
+ cert = db.keys;
+ db.keys = db.keys->next;
+ certificate_release (cert);
+ grub_free (cert);
+ }
+
+ for (i = 0; i < db.signature_entries; i++)
+ grub_free (db.signatures[i]);
+
+ grub_free (db.signatures);
+ grub_free (db.signature_size);
+ grub_memset (&db, 0, sizeof (db));
+}
+
+/* releasing memory */
+static void
+free_distrusted_list (void)
+{
+ struct x509_certificate *cert;
+ grub_size_t i = 0;
+
+ while (dbx.keys != NULL)
+ {
+ cert = dbx.keys;
+ dbx.keys = dbx.keys->next;
+ certificate_release (cert);
+ grub_free (cert);
+ }
+
+ for (i = 0; i < dbx.signature_entries; i++)
+ grub_free (dbx.signatures[i]);
+
+ grub_free (dbx.signatures);
+ grub_free (dbx.signature_size);
+ grub_memset (&dbx, 0, sizeof (dbx));
+}
+
GRUB_MOD_INIT (appendedsig)
{
int rc;
@@ -548,7 +1036,6 @@ GRUB_MOD_INIT (appendedsig)
if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
check_sigs = check_sigs_forced;
- grub_trusted_key = NULL;
grub_register_variable_hook ("check_appended_signatures", grub_env_read_sec, grub_env_write_sec);
grub_env_export ("check_appended_signatures");
@@ -556,37 +1043,50 @@ GRUB_MOD_INIT (appendedsig)
if (rc)
grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, asn1_strerror (rc));
- FOR_MODULES (header)
- {
- struct grub_file pseudo_file;
- struct x509_certificate *pk = NULL;
- grub_err_t err;
+ if (!grub_pks_use_keystore && check_sigs == check_sigs_forced)
+ {
+ FOR_MODULES (header)
+ {
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_X509_PUBKEY)
+ continue;
- /* Not an X.509 certificate, skip. */
- if (header->type != OBJ_TYPE_X509_PUBKEY)
- continue;
+ rc = build_static_trusted_list (header);
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ grub_error (rc, "static trusted list creation failed");
+ }
+ else
+ grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
+ db.key_entries);
+ }
+ }
+ else if (grub_pks_use_keystore && check_sigs == check_sigs_forced)
+ {
+ rc = create_trusted_list ();
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ grub_error (rc, "trusted list creation failed");
+ }
+ else
+ {
+ rc = create_distrusted_list ();
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (rc, "distrusted list creation failed");
+ }
+ else
+ grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " keys.\n"
+ "the distrusted list now has %" PRIuGRUB_SIZE " keys.\n",
+ db.signature_entries + db.key_entries, dbx.signature_entries);
+ }
- grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
- pseudo_file.fs = &pseudo_fs;
- pseudo_file.size = header->size - sizeof (struct grub_module_header);
- pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
-
- grub_dprintf ("appendedsig", "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
- pseudo_file.size);
-
- pk = grub_zalloc (sizeof (struct x509_certificate));
- if (!pk)
- grub_fatal ("Out of memory loading initial certificates");
-
- err = read_cert_from_file (&pseudo_file, pk);
- if (err != GRUB_ERR_NONE)
- grub_fatal ("Error loading initial key: %s", grub_errmsg);
-
- grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
-
- pk->next = grub_trusted_key;
- grub_trusted_key = pk;
- }
+ grub_pks_free_keystore ();
+ }
cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
N_("Add X509_CERTIFICATE to trusted certificates."));
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 58fae17..fa73c04 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -256,3 +256,37 @@ grub_file_seek (grub_file_t file, grub_off_t offset)
return old;
}
+
+grub_err_t
+grub_read_file (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size)
+{
+ grub_uint8_t *buffer = NULL;
+ grub_ssize_t read_size = 0;
+ grub_off_t total_read_size = 0;
+ grub_off_t file_size = grub_file_size (file);
+
+ if (file_size == GRUB_FILE_SIZE_UNKNOWN)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("could not determine the size of the file."));
+
+ buffer = grub_zalloc (file_size);
+ if (buffer == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+
+ while (total_read_size < file_size)
+ {
+ read_size = grub_file_read (file, &buffer[total_read_size], file_size - total_read_size);
+ if (read_size < 0)
+ {
+ grub_free (buffer);
+ return grub_error (GRUB_ERR_READ_ERROR, N_("unable to read the file"));
+ }
+
+ total_read_size += read_size;
+ }
+
+ *data = buffer;
+ *data_size = total_read_size;
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/file.h b/include/grub/file.h
index d678de0..27e1a88 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -217,6 +217,7 @@ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf,
grub_size_t len);
grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset);
grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file);
+grub_err_t EXPORT_FUNC(grub_read_file) (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size);
/* Return value of grub_file_size() in case file size is unknown. */
#define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL

View File

@ -0,0 +1,250 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:38 +0530
Subject: [PATCH] appendedsig: While verifying the kernel, use trusted and
distrusted lists
To verify the kernel's signature: verify the kernel binary against lists of binary hashes
that are either distrusted or trusted. If it is not list in either trusted or distrusted hashes list
then the trusted keys from the trusted key list are used to verify the signature.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 193 +++++++++++++++++++--------
1 file changed, 139 insertions(+), 54 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 994852f..07d6b39 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -454,6 +454,83 @@ extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize,
return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
}
+static grub_err_t
+get_binary_hash (const grub_size_t binary_hash_size, const grub_uint8_t *data,
+ const grub_size_t data_size, grub_uint8_t *hash, grub_size_t *hash_size)
+{
+ grub_uuid_t guid = { 0 };
+
+ /* support SHA256, SHA384 and SHA512 for binary hash */
+ if (binary_hash_size == 32)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE);
+ else if (binary_hash_size == 48)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE);
+ else if (binary_hash_size == 64)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE);
+ else
+ {
+ grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and skipping binary hash\n",
+ binary_hash_size);
+ return GRUB_ERR_UNKNOWN_COMMAND;
+ }
+
+ return get_hash (&guid, data, data_size, hash, hash_size);
+}
+
+/*
+ * Verify binary hash against the list of binary hashes that are distrusted
+ * and trusted.
+ * The following errors can occur:
+ * - GRUB_ERR_BAD_SIGNATURE: indicates that the hash is distrusted.
+ * - GRUB_ERR_NONE: the hash is trusted, since it was found in the trusted hashes list
+ * - GRUB_ERR_EOF: the hash could not be found in the hashes list
+ */
+static grub_err_t
+verify_binary_hash (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0, hash_size = 0;
+ grub_uint8_t hash[GRUB_MAX_HASH_SIZE] = { 0 };
+
+ for (i = 0; i < dbx.signature_entries; i++)
+ {
+ rc = get_binary_hash (dbx.signature_size[i], data, data_size, hash, &hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (hash_size == dbx.signature_size[i] &&
+ grub_memcmp (dbx.signatures[i], hash, hash_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "the binary hash (%02x%02x%02x%02x) was listed as distrusted\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ for (i = 0; i < db.signature_entries; i++)
+ {
+ rc = get_binary_hash (db.signature_size[i], data, data_size, hash, &hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (hash_size == db.signature_size[i] &&
+ grub_memcmp (db.signatures[i], hash, hash_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "verified with a trusted binary hash (%02x%02x%02x%02x)\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ return GRUB_ERR_NONE;
+ }
+ }
+
+ return GRUB_ERR_EOF;
+}
+
+
+/*
+ * Verify the kernel's integrity, the trusted key will be used from
+ * the trusted key list. If it fails, verify it against the list of binary hashes
+ * that are distrusted and trusted.
+ */
static grub_err_t
grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
{
@@ -463,12 +540,12 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
unsigned char *hash;
gcry_mpi_t hashmpi;
gcry_err_code_t rc;
- struct x509_certificate *pk;
+ struct x509_certificate *cert;
struct grub_appended_signature sig;
struct pkcs7_signerInfo *si;
int i;
- if (!db.key_entries)
+ if (!db.key_entries && !db.signature_entries)
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
err = extract_appended_signature (buf, bufsize, &sig);
@@ -476,69 +553,77 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
return err;
datasize = bufsize - sig.signature_len;
-
- for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
+ err = verify_binary_hash (buf, datasize);
+ if (err != GRUB_ERR_EOF && err != GRUB_ERR_NONE)
{
- /*
- * This could be optimised in a couple of ways:
- * - we could only compute hashes once per hash type
- * - we could track signer information and only verify where IDs match
- * For now we do the naive O(trusted keys * pkcs7 signers) approach.
- */
- si = &sig.pkcs7.signerInfos[i];
- context = grub_zalloc (si->hash->contextsize);
- if (!context)
- return grub_errno;
-
- si->hash->init (context);
- si->hash->write (context, buf, datasize);
- si->hash->final (context);
- hash = si->hash->read (context);
-
- grub_dprintf ("appendedsig", "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n",
- datasize, i, hash[0], hash[1], hash[2], hash[3]);
-
- err = GRUB_ERR_BAD_SIGNATURE;
- for (pk = db.keys; pk; pk = pk->next)
+ err = grub_error (err, N_("failed to verify binary-hash/signature with any trusted binary-hash/key\n"));
+ pkcs7_signedData_release (&sig.pkcs7);
+ return err;
+ }
+ else if (err == GRUB_ERR_EOF)
+ {
+ /* Binary hash was not found in trusted and distrusted list: check signature now */
+ for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
{
- rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
- if (rc)
- {
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("Error padding hash for RSA verification: %d"), rc);
- grub_free (context);
- goto cleanup;
- }
+ /*
+ * This could be optimised in a couple of ways:
+ * - we could only compute hashes once per hash type
+ * - we could track signer information and only verify where IDs match
+ * For now we do the naive O(db.keys * pkcs7 signers) approach.
+ */
+ si = &sig.pkcs7.signerInfos[i];
+ context = grub_zalloc (si->hash->contextsize);
+ if (context == NULL)
+ return grub_errno;
- rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
- gcry_mpi_release (hashmpi);
+ si->hash->init (context);
+ si->hash->write (context, buf, datasize);
+ si->hash->final (context);
+ hash = si->hash->read (context);
- if (rc == 0)
- {
- grub_dprintf ("appendedsig", "verify signer %d with key '%s' succeeded\n",
- i, pk->subject);
- err = GRUB_ERR_NONE;
- break;
- }
+ grub_dprintf ("appendedsig",
+ "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n",
+ datasize, i, hash[0], hash[1], hash[2], hash[3]);
- grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
- i, pk->subject, rc);
- }
+ err = GRUB_ERR_BAD_SIGNATURE;
+ for (cert = db.keys; cert; cert = cert->next)
+ {
+ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, cert->mpis[0]);
+ if (rc != 0)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("Error padding hash for RSA verification: %d"), rc);
+ grub_free (context);
+ pkcs7_signedData_release (&sig.pkcs7);
+ return err;
+ }
- grub_free (context);
+ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, cert->mpis, NULL, NULL);
+ gcry_mpi_release (hashmpi);
+ if (rc == 0)
+ {
+ grub_dprintf ("appendedsig", "verify signer %d with key '%s' succeeded\n",
+ i, cert->subject);
+ err = GRUB_ERR_NONE;
+ break;
+ }
- if (err == GRUB_ERR_NONE)
- break;
+ grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
+ i, cert->subject, rc);
+ }
+ grub_free (context);
+ if (err == GRUB_ERR_NONE)
+ break;
+ }
}
- /* If we didn't verify, provide a neat message */
- if (err != GRUB_ERR_NONE)
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("Failed to verify signature against a trusted key"));
-
-cleanup:
pkcs7_signedData_release (&sig.pkcs7);
+ if (err != GRUB_ERR_NONE)
+ err = grub_error (err, N_("failed to verify signature with any trusted key\n"));
+ else
+ grub_dprintf ("appendedsig", "successfully verified the signature with a trusted key\n");
+
return err;
}

View File

@ -0,0 +1,107 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:39 +0530
Subject: [PATCH] powerpc_ieee1275: set use_static_keys flag
Introduce the use_static_keys flag to indicate that static keys are to be used
rather than keys from the PKS storage's DB variable. This variable is set when
Secure Boot is enabled with PKS but the DB variable is not present in the PKS storage.
The appendedsig module would use this variable to extract the default DB keys from
the ELF note and store the keys found there in the trustedlist.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/kern/powerpc/ieee1275/platform_keystore.c | 16 +++++++++++++++-
grub-core/term/tparm.c | 1 -
include/grub/powerpc/ieee1275/platform_keystore.h | 11 ++++++-----
include/grub/types.h | 2 ++
4 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/grub-core/kern/powerpc/ieee1275/platform_keystore.c b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
index cf1d055..a83fcf7 100644
--- a/grub-core/kern/powerpc/ieee1275/platform_keystore.c
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
@@ -34,7 +34,11 @@
/* Platform Keystore */
static grub_size_t pks_max_object_size;
grub_uint8_t grub_pks_use_keystore = 0;
-grub_pks_t grub_pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 };
+grub_pks_t grub_pks_keystore = { .db = NULL,
+ .dbx = NULL,
+ .db_entries = 0,
+ .dbx_entries = 0,
+ .use_static_keys = false };
/* Convert the esl data into the ESL */
static grub_esl_t *
@@ -312,6 +316,16 @@ grub_pks_keystore_init (void)
grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t));
/* DB */
rc = read_secure_boot_variables (0, DB, &grub_pks_keystore.db, &grub_pks_keystore.db_entries);
+ if (rc == PKS_OBJECT_NOT_FOUND)
+ {
+ rc = GRUB_ERR_NONE;
+ /*
+ * DB variable won't be available by default in PKS.
+ * So, it will load the Default Keys from ELF Note
+ */
+ grub_pks_keystore.use_static_keys = true;
+ }
+
if (rc == GRUB_ERR_NONE)
{
/* DBX */
diff --git a/grub-core/term/tparm.c b/grub-core/term/tparm.c
index fb5b15a..f2db325 100644
--- a/grub-core/term/tparm.c
+++ b/grub-core/term/tparm.c
@@ -46,7 +46,6 @@
/*
* Common/troublesome character definitions
*/
-typedef char grub_bool_t;
#ifndef FALSE
# define FALSE (0)
#endif
diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h
index 0641adb..870fb8c 100644
--- a/include/grub/powerpc/ieee1275/platform_keystore.h
+++ b/include/grub/powerpc/ieee1275/platform_keystore.h
@@ -199,10 +199,11 @@ struct grub_pks_sd
/* The structure of a PKS.*/
struct grub_pks
{
- grub_pks_sd_t *db; /* signature database */
- grub_pks_sd_t *dbx; /* forbidden signature database */
- grub_size_t db_entries; /* size of signature database */
- grub_size_t dbx_entries; /* size of forbidden signature database */
+ grub_pks_sd_t *db; /* signature database */
+ grub_pks_sd_t *dbx; /* forbidden signature database */
+ grub_size_t db_entries; /* size of signature database */
+ grub_size_t dbx_entries; /* size of forbidden signature database */
+ grub_bool_t use_static_keys;/* flag to indicate use of static keys */
} GRUB_PACKED;
#ifdef __powerpc__
@@ -217,7 +218,7 @@ extern grub_pks_t EXPORT_VAR(grub_pks_keystore);
#else
#define grub_pks_use_keystore 0
-grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0};
+grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0, false};
void grub_pks_free_keystore (void);
#endif
diff --git a/include/grub/types.h b/include/grub/types.h
index bfa7af9..32ca225 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -353,4 +353,6 @@ struct grub_uuid
grub_uint8_t b[GRUB_UUID_SIZE];
};
+typedef char grub_bool_t;
+
#endif /* ! GRUB_TYPES_HEADER */

View File

@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:40 +0530
Subject: [PATCH] appendedsig: Reads the default DB keys from ELF Note
If Secure Boot is enabled with PKS and the use_static_keys flag is set,
then read the DB default keys from the ELF note and store them in the trusted list buffer.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 56 ++++++++++++++++++++--------
1 file changed, 40 insertions(+), 16 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 07d6b39..f51942b 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -1041,7 +1041,7 @@ create_distrusted_list (void)
* parse it, and add it to the trusted list.
*/
static grub_err_t
-build_static_trusted_list (const struct grub_module_header *header)
+build_static_trusted_list (const struct grub_module_header *header, const grub_bool_t is_pks)
{
grub_err_t err = GRUB_ERR_NONE;
struct grub_file pseudo_file;
@@ -1060,6 +1060,13 @@ build_static_trusted_list (const struct grub_module_header *header)
if (err != GRUB_ERR_NONE)
return err;
+ if (is_pks)
+ {
+ err = is_distrusted_cert_hash (cert_data, cert_data_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
err = add_certificate (cert_data, cert_data_size, &db, 1);
grub_free (cert_data);
@@ -1112,6 +1119,22 @@ free_distrusted_list (void)
grub_memset (&dbx, 0, sizeof (dbx));
}
+static grub_err_t
+load_static_keys (const struct grub_module_header *header, const grub_bool_t is_pks)
+{
+ int rc = GRUB_ERR_NONE;
+ FOR_MODULES (header)
+ {
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_X509_PUBKEY)
+ continue;
+ rc = build_static_trusted_list (header, is_pks);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+ }
+ return rc;
+}
+
GRUB_MOD_INIT (appendedsig)
{
int rc;
@@ -1130,26 +1153,27 @@ GRUB_MOD_INIT (appendedsig)
if (!grub_pks_use_keystore && check_sigs == check_sigs_forced)
{
- FOR_MODULES (header)
+ rc = load_static_keys (header, false);
+ if (rc != GRUB_ERR_NONE)
{
- /* Not an ELF module, skip. */
- if (header->type != OBJ_TYPE_X509_PUBKEY)
- continue;
-
- rc = build_static_trusted_list (header);
- if (rc != GRUB_ERR_NONE)
- {
- free_trusted_list ();
- grub_error (rc, "static trusted list creation failed");
- }
- else
- grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
- db.key_entries);
+ free_trusted_list ();
+ grub_error (rc, "static trusted list creation failed");
}
+ else
+ grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
+ db.key_entries);
}
else if (grub_pks_use_keystore && check_sigs == check_sigs_forced)
{
- rc = create_trusted_list ();
+ if (grub_pks_keystore.use_static_keys)
+ {
+ grub_printf ("Warning: db variable is not available at PKS and using a static keys "
+ "as a default key in trusted list\n");
+ rc = load_static_keys (header, grub_pks_keystore.use_static_keys);
+ }
+ else
+ rc = create_trusted_list ();
+
if (rc != GRUB_ERR_NONE)
{
free_trusted_list ();

View File

@ -0,0 +1,660 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:41 +0530
Subject: [PATCH] appendedsig: The grub command's trusted and distrusted
support
To support the following trusted and distrusted commands
1. trusted_list:
It will show the list of trusted certificates and binary hashes
2. distrusted_list:
It will show the list of distrusted certificates and binary/certificate hashes
3. trusted_certificate:
It will add the trusted certificate to the trusted list
4. trusted_signature:
It will add the certificate/binary hash to the trusted list
5. distrusted_certificate:
It will remove the trusted certificate from trsuted list
6. distrusted_signature:
It will add the certificate/binary hash to the distrsuted list
Note:-
The addition/deletion of trusted certificates and binary hashes
are not allowed in grub command prompt while secure boot is enabled.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 528 ++++++++++++++++++---------
1 file changed, 356 insertions(+), 172 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index f51942b..b8548f8 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -117,6 +117,36 @@ static enum
check_sigs_forced = 2
} check_sigs = check_sigs_no;
+enum
+{
+ OPTION_BINARY_HASH = 0,
+ OPTION_CERT_HASH = 1
+};
+
+static const struct grub_arg_option options[] =
+{
+ {"binary-hash", 'b', 0, N_("hash file of the binary."), 0, ARG_TYPE_NONE},
+ {"cert-hash", 'c', 1, N_("hash file of the certificate."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+};
+
+static void
+print_hex (const grub_uint8_t *data, const grub_size_t length)
+{
+ grub_size_t i, count = 0;
+ for (i = 0; i < length-1; i++)
+ {
+ grub_printf ("%02x:", data[i]);
+ count++;
+ if (count == 16)
+ {
+ grub_printf ("\n\t ");
+ count = 0;
+ }
+ }
+ grub_printf ("%02x\n", data[i]);
+}
+
/*
* GUID can be used to determine the hashing function and
* generate the hash using determined hashing function.
@@ -344,72 +374,6 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const cha
return grub_strdup (grub_env_read_sec (NULL, NULL));
}
-static grub_err_t
-file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
-{
- grub_off_t full_file_size;
- grub_size_t file_size, total_read_size = 0;
- grub_ssize_t read_size;
-
- full_file_size = grub_file_size (file);
- if (full_file_size == GRUB_FILE_SIZE_UNKNOWN)
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("Cannot read a file of unknown size into a buffer"));
-
- if (full_file_size > GRUB_SIZE_MAX)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- N_("File is too large to read: %" PRIuGRUB_UINT64_T " bytes"),
- full_file_size);
-
- file_size = (grub_size_t) full_file_size;
-
- *buf = grub_malloc (file_size);
- if (!*buf)
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- N_("Could not allocate file data buffer size %" PRIuGRUB_SIZE),
- file_size);
-
- while (total_read_size < file_size)
- {
- read_size = grub_file_read (file, *buf + total_read_size, file_size - total_read_size);
-
- if (read_size < 0)
- {
- grub_free (*buf);
- return grub_errno;
- }
- else if (read_size == 0)
- {
- grub_free (*buf);
- return grub_error (GRUB_ERR_IO,
- N_("Could not read full file size "
- "(%" PRIuGRUB_SIZE "), only %" PRIuGRUB_SIZE " bytes read"),
- file_size, total_read_size);
- }
-
- total_read_size += read_size;
- }
- *len = file_size;
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
-{
- grub_err_t err;
- grub_uint8_t *buf;
- grub_size_t file_size;
-
- err = file_read_all (f, &buf, &file_size);
- if (err != GRUB_ERR_NONE)
- return err;
-
- err = parse_x509_certificate (buf, file_size, certificate);
- grub_free (buf);
-
- return err;
-}
-
static grub_err_t
extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize,
struct grub_appended_signature *sig)
@@ -630,143 +594,345 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
static grub_err_t
grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
{
- grub_file_t f;
grub_err_t err = GRUB_ERR_NONE;
- grub_uint8_t *data;
- grub_size_t file_size;
+ grub_file_t signed_file = NULL;
+ grub_uint8_t *signed_data = NULL;
+ grub_ssize_t signed_data_size = 0;
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ if (argc != 1)
+ {
+ grub_printf (N_("a signed file is expected\n"
+ "Example:\n\tverify_appended <SIGNED FILE>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
- f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
- if (!f)
+ signed_file = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (signed_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("unable to open a signed file"));
+
+ err = grub_read_file (signed_file, &signed_data, &signed_data_size);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_file_close (signed_file);
+ return err;
+ }
+
+ grub_file_close (signed_file);
+ err = grub_verify_appended_signature (signed_data, signed_data_size);
+ grub_free (signed_data);
+
+ return err;
+}
+
+static grub_err_t
+grub_cmd_trusted_list (grub_command_t cmd __attribute__((unused)),
+ int argc __attribute__((unused)), char **args __attribute__((unused)))
+{
+ struct x509_certificate *cert = NULL;
+ grub_size_t i = 0, cert_num = 1;
+
+ for (cert = db.keys; cert; cert = cert->next)
+ {
+ grub_printf (N_("trusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num);
+ grub_printf (N_("\tserial: "));
+
+ for (i = 0; i < cert->serial_len - 1; i++)
+ grub_printf ("%02x:", cert->serial[i]);
+
+ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_printf ("\tCN: %s\n\n", cert->subject);
+ cert_num++;
+ }
+
+ for (i = 0; i < db.signature_entries; i++)
+ {
+ grub_printf (N_("trusted binary hash %" PRIuGRUB_SIZE ":\n"), i+1);
+ grub_printf (N_("\thash: "));
+ print_hex (db.signatures[i], db.signature_size[i]);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_distrusted_list (grub_command_t cmd __attribute__((unused)),
+ int argc __attribute__((unused)),
+ char **args __attribute__((unused)))
+{
+ struct x509_certificate *cert = NULL;
+ grub_size_t i = 0, cert_num = 1;
+
+ for (cert = dbx.keys; cert; cert = cert->next)
+ {
+ grub_printf (N_("distrusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num);
+ grub_printf (N_("\tserial: "));
+
+ for (i = 0; i < cert->serial_len - 1; i++)
+ grub_printf ("%02x:", cert->serial[i]);
+
+ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_printf ("\tCN: %s\n\n", cert->subject);
+ cert_num++;
+ }
+
+ for (i = 0; i < dbx.signature_entries; i++)
+ {
+ grub_printf (N_("distrusted certificate/binary hash %" PRIuGRUB_SIZE ":\n"), i+1);
+ grub_printf (N_("\thash: "));
+ print_hex (dbx.signatures[i], dbx.signature_size[i]);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_trusted_cert (grub_command_t cmd __attribute__((unused)),
+ int argc, char **args)
+{
+ grub_err_t err = GRUB_ERR_NONE;
+ grub_file_t cert_file = NULL;
+ grub_uint8_t *cert_data = NULL;
+ grub_ssize_t cert_data_size = 0;
+
+ if (argc != 1)
{
- err = grub_errno;
- goto cleanup;
+ grub_printf (N_("a trusted X.509 certificate file is expected\n"
+ "Example:\n\ttrusted_certificate <CERT FILE>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
}
- err = file_read_all (f, &data, &file_size);
+ if (check_sigs == check_sigs_forced)
+ {
+ grub_printf ("Warning: since secure boot is enabled, "
+ "adding of trusted X.509 certificate is not permitted!\n");
+ return grub_errno;
+ }
+
+ if (grub_strlen (args[0]) == 0)
+ return grub_error (GRUB_ERR_BAD_FILENAME,
+ N_("missing trusted X.509 certificate file"));
+
+ cert_file = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST |
+ GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (cert_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("unable to open the trusted X.509 certificate file"));
+
+ err = grub_read_file (cert_file, &cert_data, &cert_data_size);
if (err != GRUB_ERR_NONE)
- goto cleanup;
+ {
+ grub_file_close (cert_file);
+ return err;
+ }
- err = grub_verify_appended_signature (data, file_size);
+ grub_file_close (cert_file);
+ err = add_certificate (cert_data, cert_data_size, &db, 1);
+ if (err != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (err, "adding of trusted certificate failed");
+ }
- grub_free (data);
+ grub_free (cert_data);
-cleanup:
- if (f)
- grub_file_close (f);
return err;
}
static grub_err_t
-grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+grub_cmd_trusted_hash (grub_command_t cmd __attribute__((unused)), int argc, char**args)
{
- unsigned long cert_num, i;
- struct x509_certificate *cert, *prev;
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_file_t hash_file = NULL;
+ grub_uint8_t *hash_data = NULL;
+ grub_ssize_t hash_data_size = 0;
if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
+ {
+ grub_printf (N_("a trusted binary hash file is expected\n"
+ "Example:\n\ttrusted_signature <BINARY HASH FILE>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (check_sigs == check_sigs_forced)
+ {
+ grub_printf ("Warning: since secure boot is enabled, "
+ "adding of trusted binary hash is not permitted!\n");
+ return grub_errno;
+ }
+
+ if (grub_strlen (args[0]) == 0)
+ return grub_error (GRUB_ERR_BAD_FILENAME, N_("missing trusted binary hash file"));
+
+ hash_file = grub_file_open (args[0], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (hash_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("unable to open the trusted binary hash file"));
+
+ rc = grub_read_file (hash_file, &hash_data, &hash_data_size);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_file_close (hash_file);
+ return rc;
+ }
+
+ grub_file_close (hash_file);
+
+ grub_dprintf ("appendedsig", "adding a trusted binary hash %s\n with size of %" PRIuGRUB_SIZE "\n",
+ hash_data, hash_data_size);
+
+ /* only accept SHA256, SHA384 and SHA512 binary hash */
+ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("unacceptable trusted binary hash type"));
+
+ rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &db.signatures,
+ &db.signature_size, &db.signature_entries);
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (rc, "adding of trusted binary hash failed");
+ }
+
+ grub_free (hash_data);
+
+ return rc;
+}
+
+static grub_err_t
+grub_cmd_distrusted_cert (grub_command_t cmd __attribute__((unused)), int argc, char **args)
+{
+ grub_size_t cert_num = 0, i = 1;
+ struct x509_certificate *current_cert = db.keys;
+ struct x509_certificate *previous_cert = db.keys;
+
+ if (argc != 1)
+ {
+ grub_printf (N_("trusted certificate number is expected\n"
+ "Example:\n\tdistrusted_certificate <CERT_NUMER>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (check_sigs == check_sigs_forced)
+ {
+ grub_printf ("Warning: since secure boot is enabled, "
+ "removing of trusted certificate is not permitted!\n");
+ return grub_errno;
+ }
- grub_errno = GRUB_ERR_NONE;
cert_num = grub_strtoul (args[0], NULL, 10);
- if (grub_errno != GRUB_ERR_NONE)
- return grub_errno;
-
if (cert_num < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("Certificate number too small - numbers start at 1"));
+ N_("trusted certificate number should to begin with 1"));
- if (cert_num == 1)
- {
- cert = db.keys;
- db.keys = cert->next;
+ if (cert_num > db.key_entries)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("trusted certificate number should not exceed %" PRIuGRUB_SIZE ""),
+ db.key_entries);
+ else if (cert_num < db.key_entries)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("there is no certificate on the trusted list. so, not permitted"));
- certificate_release (cert);
- grub_free (cert);
- return GRUB_ERR_NONE;
- }
- i = 2;
- prev = db.keys;
- cert = db.keys->next;
- while (cert)
+ for (i = 1; i < db.key_entries; i++)
{
- if (i == cert_num)
+ if (cert_num == 1)
+ {
+ previous_cert = current_cert->next;
+ break;
+ }
+ else if (cert_num == i)
{
- prev->next = cert->next;
- certificate_release (cert);
- grub_free (cert);
- return GRUB_ERR_NONE;
+ previous_cert->next = current_cert->next;
+ break;
}
- i++;
- prev = cert;
- cert = cert->next;
+
+ previous_cert = current_cert;
+ current_cert = current_cert->next;
}
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("No certificate number %lu found - only %lu certificates in the store"),
- cert_num, i - 1);
+ certificate_release (current_cert);
+ grub_free (current_cert);
+
+ return GRUB_ERR_NONE;
}
static grub_err_t
-grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+grub_cmd_distrusted_hash (grub_extcmd_context_t ctxt, int argc, char **args)
{
- grub_file_t certf;
- struct x509_certificate *cert = NULL;
- grub_err_t err;
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_file_t hash_file = NULL;
+ grub_uint8_t *hash_data = NULL;
+ grub_ssize_t hash_data_size = 0;
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-
- certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
- if (!certf)
- return grub_errno;
-
- cert = grub_zalloc (sizeof (struct x509_certificate));
- if (!cert)
- return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Could not allocate memory for certificate"));
+ if (argc != 2)
+ {
+ grub_printf (N_("a distrusted certificate/binary hash file is expected\n"
+ "Example:\n\tdistrusted_signature [option] <FILE>\n"
+ "option:\n[-b|--binary-hash] FILE [BINARY HASH FILE]\n"
+ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
- err = read_cert_from_file (certf, cert);
- grub_file_close (certf);
- if (err != GRUB_ERR_NONE)
+ if (check_sigs == check_sigs_forced)
{
- grub_free (cert);
- return err;
+ grub_printf ("Warning: since secure boot is enabled, "
+ "adding of distrusted certificate/binary hash is not permitted!\n");
+ return grub_errno;
}
- grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject);
- cert->next = db.keys;
- db.keys = cert;
+ if (!ctxt->state[OPTION_BINARY_HASH].set && !ctxt->state[OPTION_CERT_HASH].set)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing options and use --help to konw"));
- return GRUB_ERR_NONE;
-}
+ if (grub_strlen (args[1]) == 0)
+ return grub_error (GRUB_ERR_BAD_FILENAME,
+ N_("missing distrusted certificate/binary hash file"));
-static grub_err_t
-grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
-{
- struct x509_certificate *cert;
- int cert_num = 1;
- grub_size_t i;
+ hash_file = grub_file_open (args[1], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (hash_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("unable to open the distrusted certificate/binary hash file"));
- for (cert = db.keys; cert; cert = cert->next)
+ rc = grub_read_file (hash_file, &hash_data, &hash_data_size);
+ if (rc != GRUB_ERR_NONE)
{
- grub_printf (N_("Certificate %d:\n"), cert_num);
+ grub_file_close (hash_file);
+ return rc;
+ }
- grub_printf (N_("\tSerial: "));
- for (i = 0; i < cert->serial_len - 1; i++)
- {
- grub_printf ("%02x:", cert->serial[i]);
- }
- grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_file_close (hash_file);
- grub_printf ("\tCN: %s\n\n", cert->subject);
- cert_num++;
+ grub_dprintf ("appendedsig", "adding a distrusted certificate/binary hash %s\n"
+ " with size of %" PRIuGRUB_SIZE "\n", hash_data, hash_data_size);
+
+ if (ctxt->state[OPTION_BINARY_HASH].set)
+ {
+ /* only accept SHA256, SHA384 and SHA512 binary hash */
+ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("unacceptable distrusted binary hash type"));
+ }
+ else if (ctxt->state[OPTION_CERT_HASH].set)
+ {
+ /* only accept SHA256, SHA384 and SHA512 certificate hash */
+ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("unacceptable distrusted certificate hash type"));
}
- return GRUB_ERR_NONE;
+ rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &dbx.signatures,
+ &dbx.signature_size, &dbx.signature_entries);
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (rc, "adding of distrusted binary/certificate hash failed");
+ }
+
+ grub_free (hash_data);
+
+ return rc;
}
static grub_err_t
@@ -842,8 +1008,6 @@ pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
/* Filesystem descriptor. */
static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read };
-static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust;
-
/*
* Verify the trusted certificate against the certificate hashes from platform keystore buffer's
* distrusted list.
@@ -1135,6 +1299,10 @@ load_static_keys (const struct grub_module_header *header, const grub_bool_t is_
return rc;
}
+static grub_extcmd_t cmd_distrusted_hash;
+static grub_command_t cmd_verify, cmd_trusted_list, cmd_trusted_cert, cmd_trusted_hash,
+ cmd_distrusted_list, cmd_distrusted_cert;
+
GRUB_MOD_INIT (appendedsig)
{
int rc;
@@ -1196,17 +1364,31 @@ GRUB_MOD_INIT (appendedsig)
grub_pks_free_keystore ();
}
-
- cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
- N_("Add X509_CERTIFICATE to trusted certificates."));
- cmd_list = grub_register_command ("list_certificates", grub_cmd_list, 0,
- N_("Show the list of trusted x509 certificates."));
+ cmd_trusted_cert = grub_register_command ("trusted_certificate", grub_cmd_trusted_cert,
+ N_("X509_CERTIFICATE"),
+ N_("Add X509_CERTIFICATE to trusted list."));
+ cmd_trusted_hash = grub_register_command ("trusted_signature", grub_cmd_trusted_hash,
+ N_("BINARY HASH FILE"),
+ N_("Add trusted BINARY HASH to trusted list."));
+ cmd_distrusted_cert = grub_register_command ("distrusted_certificate", grub_cmd_distrusted_cert,
+ N_("CERT_NUMBER"),
+ N_("Remove CERT_NUMBER (as listed by list_trusted)"
+ " from trusted list."));
+ cmd_distrusted_hash = grub_register_extcmd ("distrusted_signature", grub_cmd_distrusted_hash, 0,
+ N_("[-b|--binary-hash] FILE [BINARY HASH FILE]\n"
+ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]"),
+ N_("Add distrusted CERTFICATE/BINARY HASH "
+ "to distrusted list."),
+ options);
+ cmd_trusted_list = grub_register_command ("trusted_list", grub_cmd_trusted_list, 0,
+ N_("Show the list of trusted x509 certificates and"
+ " trusted binary hashes."));
+ cmd_distrusted_list = grub_register_command ("distrusted_list", grub_cmd_distrusted_list, 0,
+ N_("Show the list of distrusted certificates and"
+ " certificate/binary hashes"));
cmd_verify = grub_register_command ("verify_appended", grub_cmd_verify_signature, N_("FILE"),
- N_("Verify FILE against the trusted x509 certificates."));
- cmd_distrust = grub_register_command ("distrust_certificate", grub_cmd_distrust,
- N_("CERT_NUMBER"),
- N_("Remove CERT_NUMBER (as listed by list_certificates)"
- " from trusted certificates."));
+ N_("Verify FILE against the trusted x509 certificates/"
+ "trusted binary hashes."));
grub_verifier_register (&grub_appendedsig_verifier);
grub_dl_set_persistent (mod);
@@ -1218,10 +1400,12 @@ GRUB_MOD_FINI (appendedsig)
* grub_dl_set_persistent should prevent this from actually running, but
* it does still run under emu.
*/
-
grub_verifier_unregister (&grub_appendedsig_verifier);
grub_unregister_command (cmd_verify);
- grub_unregister_command (cmd_list);
- grub_unregister_command (cmd_trust);
- grub_unregister_command (cmd_distrust);
+ grub_unregister_command (cmd_trusted_list);
+ grub_unregister_command (cmd_distrusted_list);
+ grub_unregister_command (cmd_trusted_cert);
+ grub_unregister_command (cmd_distrusted_cert);
+ grub_unregister_command (cmd_trusted_hash);
+ grub_unregister_extcmd (cmd_distrusted_hash);
}

View File

@ -0,0 +1,210 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:42 +0530
Subject: [PATCH] appendedsig: documentation
This explains how static and dynamic key appended signatures can be used to form part of
a secure boot chain, and documents the commands and variables introduced.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
docs/grub.texi | 109 +++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 74 insertions(+), 35 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 72cf517..a4ae8cd 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4016,7 +4016,9 @@ you forget a command, you can run the command @command{help}
* date:: Display or set current date and time
* devicetree:: Load a device tree blob
* distrust:: Remove a pubkey from trusted keys
-* distrust_certificate:: Remove a certificate from the list of trusted certificates
+* distrusted_certificate:: Remove a certificate from the trusted list
+* distrusted_list:: List distrusted certificates and binary/certificate hashes
+* distrusted_signature:: Add a binary hash to the distrusted list
* drivemap:: Map a drive to another
* echo:: Display a line of text
* eval:: Evaluate agruments as GRUB commands
@@ -4033,7 +4035,6 @@ you forget a command, you can run the command @command{help}
* keystatus:: Check key modifier status
* linux:: Load a Linux kernel
* linux16:: Load a Linux kernel (16-bit mode)
-* list_certificates:: List trusted certificates
* list_env:: List variables in environment block
* list_trusted:: List trusted public keys
* load_env:: Load variables from environment block
@@ -4072,7 +4073,9 @@ you forget a command, you can run the command @command{help}
* test:: Check file types and compare values
* true:: Do nothing, successfully
* trust:: Add public key to list of trusted keys
-* trust_certificate:: Add an x509 certificate to the list of trusted certificates
+* trusted_certificate:: Add an x509 certificate to the trusted list
+* trusted_list:: List trusted certificates and binary hashes
+* trusted_signature:: Add a binary hash to the trusted list.
* unset:: Unset an environment variable
@comment * vbeinfo:: List available video modes
* verify_appended:: Verify appended digital signature
@@ -4416,16 +4419,15 @@ These keys are used to validate signatures when environment variable
GPG-style digital signatures}, for more information.
@end deffn
+@node distrusted_certificate
+@subsection distrusted_certificate
-@node distrust_certificate
-@subsection distrust_certificate
-
-@deffn Command distrust_certificate cert_number
+@deffn Command distrusted_certificate cert_number
Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of
trusted x509 certificates for verifying appended signatures.
@var{cert_number} is the certificate number as listed by
-@command{list_certificates} (@pxref{list_certificates}).
+@command{trusted_list} (@pxref{trusted_list}).
These certificates are used to validate appended signatures when environment
variable @code{check_appended_signatures} is set to @code{enforce} or
@@ -4434,6 +4436,27 @@ variable @code{check_appended_signatures} is set to @code{enforce} or
@xref{Using appended signatures} for more information.
@end deffn
+@node distrusted_list
+@subsection distrusted_list
+
+@deffn Command distrusted_list
+List all the distrusted x509 certificates and binary/certificate hashes.
+The output is a numbered list of certificates and binary/certificate hashes,
+showing the certificate's serial number and Common Name.
+@end deffn
+
+@node distrusted_signature
+@subsection distrusted_signature
+
+@deffn Command distrusted_signature
+Read a binary hash from the file @var{binary hash file}
+and add it to GRUB's internal distrusted list. These hash are used to
+restrict validation of linux image integrity using trusted list if appended
+signatures validation failed when the environment variable
+@code{check_appended_signatures} is set to @code{enforce}.
+
+See @xref{Using appended signatures} for more information.
+@end deffn
@node drivemap
@subsection drivemap
@@ -4691,22 +4714,6 @@ for the sake of convenience.
This command is only available on x86 systems.
@end deffn
-
-@node list_certificates
-@subsection list_certificates
-
-@deffn Command list_certificates
-List all x509 certificates trusted by GRUB for validating appended signatures.
-The output is a numbered list of certificates, showing the certificate's serial
-number and Common Name.
-
-The certificate number can be used as an argument to
-@command{distrust_certificate} (@pxref{distrust_certificate}).
-
-See @xref{Using appended signatures} for more information.
-@end deffn
-
-
@node list_env
@subsection list_env
@@ -5540,10 +5547,10 @@ information.
@end deffn
-@node trust_certificate
-@subsection trust_certificate
+@node trusted_certificate
+@subsection trusted_certificate
-@deffn Command trust_certificate x509_certificate
+@deffn Command trusted_certificate x509_certificate
Read an DER-formatted x509 certificate from the file @var{x509_certificate}
and add it to GRUB's internal list of trusted x509 certificates. These
certificates are used to validate appended signatures when the environment
@@ -5551,7 +5558,7 @@ variable @code{check_appended_signatures} is set to @code{enforce} or
@code{forced}.
Note that if @code{check_appended_signatures} is set to @code{enforce} or
-@code{forced} when @command{trust_certificate} is executed, then
+@code{forced} when @command{trusted_certificate} is executed, then
@var{x509_certificate} must itself bear an appended signature. (It is not
sufficient that @var{x509_certificate} be signed by a trusted certificate
according to the x509 rules: grub does not include support for validating
@@ -5560,6 +5567,32 @@ signatures within x509 certificates themselves.)
See @xref{Using appended signatures} for more information.
@end deffn
+@node trusted_list
+@subsection trusted_list
+
+@deffn Command trusted_list
+List all x509 certificates and binary hases trusted by GRUB for validating
+appended signatures. The output is a numbered list of certificates and binary
+hashes, showing the certificate's serial number and Common Name.
+
+The certificate number can be used as an argument to
+@command{distrusted_certificate} (@pxref{distrusted_certificate}).
+
+See @xref{Using appended signatures} for more information.
+@end deffn
+
+@node trusted_signature
+@subsection trusted_signature
+
+@deffn Command trust_signature
+Read a binary hash from the file @var{binary hash file}
+and add it to GRUB's internal trusted list. These binary hash are used to
+validate linux image integrity if appended signatures validation failed
+when the environment variable @code{check_appended_signatures} is set
+to @code{enforce}.
+
+See @xref{Using appended signatures} for more information.
+@end deffn
@node unset
@subsection unset
@@ -5584,9 +5617,8 @@ only on PC BIOS platforms.
@deffn Command verify_appended file
Verifies an appended signature on @var{file} against the trusted certificates
-known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and
-@pxref{distrust_certificate}).
-
+known to GRUB (See @pxref{trusted_list}, @pxref{trusted_certificate}, and
+@pxref{distrusted_certificate}).
Exit code @code{$?} is set to 0 if the signature validates
successfully. If validation fails, it is set to a non-zero value.
See @xref{Using appended signatures}, for more information.
@@ -6183,10 +6215,17 @@ with an appended signature ends with the magic string:
where @code{\n} represents the line-feed character, @code{0x0a}.
-Certificates can be managed at boot time using the @pxref{trust_certificate},
-@pxref{distrust_certificate} and @pxref{list_certificates} commands.
-Certificates can also be built in to the core image using the @code{--x509}
-parameter to @command{grub-install} or @command{grub-mkimage}.
+For static key, Certificates will be built in to the core image using
+the @code{--x509} parameter to @command{grub-install} or @command{grub-mkimage}.
+it can allow to list the trusted certificates and binary hashes at boot time using
+@pxref{trusted_list} and list distrusted certificates and binary/certificate hashes
+at boot time using @pxref{distrusted_list} commands.
+
+For dynamic key, loads the signature database (DB) and forbidden
+signature database (DBX) from platform keystore (PKS) and it can allow to list
+the trusted certificates and binary hashes at boot time using @pxref{trusted_list}
+and list distrusted certificates and binary/certificate hashes at boot time using
+@pxref{distrusted_list} commands.
A file can be explictly verified using the @pxref{verify_appended} command.

View File

@ -0,0 +1,301 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 22 Jul 2022 02:16:33 -0500
Subject: [PATCH] efi: Add efitextmode command for getting/setting the text
mode resolution
This command is meant to behave similarly to the "mode" command of the EFI
Shell application. In addition to allowing mode selection by giving the
number of columns and rows as arguments, the command allows specifying the
mode number to select the mode. Also supported are the arguments "min" and
"max", which set the mode to the minimum and maximum mode respectively as
calculated by the columns * rows of that mode.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 42 ++++++++++
grub-core/Makefile.core.def | 6 ++
grub-core/commands/efi/efitextmode.c | 155 +++++++++++++++++++++++++++++++++++
include/grub/efi/api.h | 6 ++
include/grub/err.h | 1 +
5 files changed, 210 insertions(+)
create mode 100644 grub-core/commands/efi/efitextmode.c
diff --git a/docs/grub.texi b/docs/grub.texi
index a4ae8cd..2677059 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4021,6 +4021,7 @@ you forget a command, you can run the command @command{help}
* distrusted_signature:: Add a binary hash to the distrusted list
* drivemap:: Map a drive to another
* echo:: Display a line of text
+* efitextmode:: Set/Get text output mode resolution
* eval:: Evaluate agruments as GRUB commands
* export:: Export an environment variable
* false:: Do nothing, unsuccessfully
@@ -4527,6 +4528,47 @@ character will print that character.
@end deffn
+@node efitextmode
+@subsection efitextmode
+
+@deffn Command efitextmode [min | max | <mode_num> | <cols> <rows>]
+When used with no arguments displays all available text output modes. The
+set mode determines the columns and rows of the text display when in
+text mode. An asterisk, @samp{*}, will be at the end of the line of the
+currently set mode.
+
+If given a single parameter, it must be @samp{min}, @samp{max}, or a mode
+number given by the listing when run with no arguments. These arguments set
+the mode to the minimum, maximum, and particular mode respectively.
+
+Otherwise, the command must be given two numerical arguments specifying the
+columns and rows of the desired mode. Specifying a columns and rows
+combination that corresponds to no supported mode, will return error, but
+otherwise have no effect.
+
+By default GRUB will start in whatever mode the EFI firmware defaults to.
+There are firmwares known to set up the default mode such that output
+behaves strangely, for example the cursor in the GRUB shell never reaches
+the bottom of the screen or, when typing characters at the prompt,
+characters from previous command output are overwritten. Setting the mode
+may fix this.
+
+The EFI specification says that mode 0 must be available and have
+columns and rows of 80 and 25 respectively. Mode 1 may be defined and if
+so must have columns and rows of 80 and 50 respectively. Any other modes
+may have columns and rows arbitrarily defined by the firmware. This means
+that a mode with columns and rows of 100 and 31 on one firmware may be
+a different mode number on a different firmware or not exist at all.
+Likewise, mode number 2 on one firmware may have a different number of
+columns and rows than mode 2 on a different firmware. So one should not
+rely on a particular mode number or a mode of a certain number of columns
+and rows existing on all firmwares, except for mode 0.
+
+Note: This command is only available on EFI platforms and is similar to
+EFI shell "mode" command.
+@end deffn
+
+
@node eval
@subsection eval
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 218068b..4588fa7 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -844,6 +844,12 @@ module = {
enable = efi;
};
+module = {
+ name = efitextmode;
+ efi = commands/efi/efitextmode.c;
+ enable = efi;
+};
+
module = {
name = blocklist;
common = commands/blocklist.c;
diff --git a/grub-core/commands/efi/efitextmode.c b/grub-core/commands/efi/efitextmode.c
new file mode 100644
index 0000000..3679f6b
--- /dev/null
+++ b/grub-core/commands/efi/efitextmode.c
@@ -0,0 +1,155 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Set/Get UEFI text output mode resolution.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_efi_set_mode (grub_efi_simple_text_output_interface_t *o,
+ grub_efi_int32_t mode)
+{
+ grub_efi_status_t status;
+
+ if (mode != o->mode->mode)
+ {
+ status = efi_call_2 (o->set_mode, o, mode);
+ if (status == GRUB_EFI_SUCCESS)
+ ;
+ else if (status == GRUB_EFI_DEVICE_ERROR)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("device error: could not set requested mode"));
+ else if (status == GRUB_EFI_UNSUPPORTED)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("invalid mode: number not valid"));
+ else
+ return grub_error (GRUB_ERR_BAD_FIRMWARE,
+ N_("unexpected EFI error number: `%u'"),
+ (unsigned) status);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_efitextmode (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_efi_simple_text_output_interface_t *o = grub_efi_system_table->con_out;
+ unsigned long mode;
+ const char *p = NULL;
+ grub_err_t err;
+ grub_efi_uintn_t columns, rows;
+ grub_efi_int32_t i;
+
+ if (o == NULL)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("no UEFI output console interface"));
+
+ if (o->mode == NULL)
+ return grub_error (GRUB_ERR_BUG, N_("no mode struct for UEFI output console"));
+
+ if (argc > 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("at most two arguments expected"));
+
+ if (argc == 0)
+ {
+ grub_printf_ (N_("Available modes for console output device.\n"));
+
+ for (i = 0; i < o->mode->max_mode; i++)
+ if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i,
+ &columns, &rows))
+ grub_printf_ (N_(" [%" PRIuGRUB_EFI_UINT32_T "] Col %5"
+ PRIuGRUB_EFI_UINTN_T " Row %5" PRIuGRUB_EFI_UINTN_T
+ " %c\n"),
+ i, columns, rows, (i == o->mode->mode) ? '*' : ' ');
+ }
+ else if (argc == 1)
+ {
+ if (grub_strcmp (args[0], "min") == 0)
+ mode = 0;
+ else if (grub_strcmp (args[0], "max") == 0)
+ mode = o->mode->max_mode - 1;
+ else
+ {
+ mode = grub_strtoul (args[0], &p, 0);
+
+ if (*args[0] == '\0' || *p != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("non-numeric or invalid mode `%s'"), args[0]);
+ }
+
+ if (mode < (unsigned long) o->mode->max_mode)
+ {
+ err = grub_efi_set_mode (o, (grub_efi_int32_t) mode);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("invalid mode: `%lu' is greater than maximum mode `%lu'"),
+ mode, (unsigned long) o->mode->max_mode);
+ }
+ else if (argc == 2)
+ {
+ grub_efi_uintn_t u_columns, u_rows;
+
+ u_columns = (grub_efi_uintn_t) grub_strtoul (args[0], &p, 0);
+
+ if (*args[0] == '\0' || *p != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("non-numeric or invalid columns number `%s'"), args[0]);
+
+ u_rows = (grub_efi_uintn_t) grub_strtoul (args[1], &p, 0);
+
+ if (*args[1] == '\0' || *p != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("non-numeric or invalid rows number `%s'"), args[1]);
+
+ for (i = 0; i < o->mode->max_mode; i++)
+ if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i,
+ &columns, &rows))
+ if (u_columns == columns && u_rows == rows)
+ return grub_efi_set_mode (o, (grub_efi_int32_t) i);
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("no mode found with requested columns and rows"));
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+GRUB_MOD_INIT (efitextmode)
+{
+ cmd = grub_register_command ("efitextmode", grub_cmd_efitextmode,
+ N_("[min | max | <mode_num> | <cols> <rows>]"),
+ N_("Get or set EFI text mode."));
+}
+
+GRUB_MOD_FINI (efitextmode)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 464842b..f224037 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -545,9 +545,13 @@ typedef char grub_efi_boolean_t;
#if GRUB_CPU_SIZEOF_VOID_P == 8
typedef grub_int64_t grub_efi_intn_t;
typedef grub_uint64_t grub_efi_uintn_t;
+#define PRIxGRUB_EFI_UINTN_T PRIxGRUB_UINT64_T
+#define PRIuGRUB_EFI_UINTN_T PRIuGRUB_UINT64_T
#else
typedef grub_int32_t grub_efi_intn_t;
typedef grub_uint32_t grub_efi_uintn_t;
+#define PRIxGRUB_EFI_UINTN_T PRIxGRUB_UINT32_T
+#define PRIuGRUB_EFI_UINTN_T PRIuGRUB_UINT32_T
#endif
typedef grub_int8_t grub_efi_int8_t;
typedef grub_uint8_t grub_efi_uint8_t;
@@ -555,6 +559,8 @@ typedef grub_int16_t grub_efi_int16_t;
typedef grub_uint16_t grub_efi_uint16_t;
typedef grub_int32_t grub_efi_int32_t;
typedef grub_uint32_t grub_efi_uint32_t;
+#define PRIxGRUB_EFI_UINT32_T PRIxGRUB_UINT32_T
+#define PRIuGRUB_EFI_UINT32_T PRIuGRUB_UINT32_T
typedef grub_int64_t grub_efi_int64_t;
typedef grub_uint64_t grub_efi_uint64_t;
typedef grub_uint8_t grub_efi_char8_t;
diff --git a/include/grub/err.h b/include/grub/err.h
index 905a6df..7530f58 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -73,6 +73,7 @@ typedef enum
GRUB_ERR_NET_NO_DOMAIN,
GRUB_ERR_EOF,
GRUB_ERR_BAD_SIGNATURE,
+ GRUB_ERR_BAD_FIRMWARE,
GRUB_ERR_STILL_REFERENCED,
GRUB_ERR_RECURSION_DEPTH
}

View File

@ -463,3 +463,13 @@ Patch0463: 0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch
Patch0464: 0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch Patch0464: 0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch
Patch0465: 0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch Patch0465: 0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch
Patch0466: 0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch Patch0466: 0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch
Patch0467: 0467-appended-sig-sync-d-with-upstream-code.patch
Patch0468: 0468-ieee1275-Platform-Keystore-PKS-Support.patch
Patch0469: 0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch
Patch0470: 0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch
Patch0471: 0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch
Patch0472: 0472-powerpc_ieee1275-set-use_static_keys-flag.patch
Patch0473: 0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch
Patch0474: 0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch
Patch0475: 0475-appendedsig-documentation.patch
Patch0476: 0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch

View File

@ -16,7 +16,7 @@
Name: grub2 Name: grub2
Epoch: 1 Epoch: 1
Version: 2.06 Version: 2.06
Release: 107%{?dist} Release: 108%{?dist}
Summary: Bootloader with support for Linux, Multiboot and more Summary: Bootloader with support for Linux, Multiboot and more
License: GPLv3+ License: GPLv3+
URL: http://www.gnu.org/software/grub/ URL: http://www.gnu.org/software/grub/
@ -547,6 +547,10 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
%endif %endif
%changelog %changelog
* Wed May 21 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-108
- ieee1275: Appended signature support
- Resolves: #RHEL-24742
* Wed May 14 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-107 * Wed May 14 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-107
- Remove BLS fake config in case of kernel removal - Remove BLS fake config in case of kernel removal
- Resolves: #RHEL-83915 - Resolves: #RHEL-83915