776 lines
28 KiB
Diff
776 lines
28 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
|
||
Date: Mon, 6 Oct 2025 12:54:56 +0530
|
||
Subject: [PATCH] powerpc/ieee1275: Read the db and dbx secure boot variables
|
||
|
||
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.
|
||
|
||
If PKS is enabled, it will read secure boot variables such as db and dbx
|
||
from PKS and extract EFI Signature List (ESL) from it. The ESLs 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 management mode will be activated:
|
||
1. When Secure Boot is enabled with static key management mode
|
||
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: Key Management Mode
|
||
1 - Enable dynamic key management mode. Read the db and dbx variables from PKS,
|
||
and use them for signature verification.
|
||
0 - Enable static key management mode. Read keys from the GRUB ELF Note and
|
||
use it for signature verification.
|
||
|
||
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
|
||
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
|
||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||
---
|
||
grub-core/Makefile.am | 2 +
|
||
grub-core/Makefile.core.def | 2 +
|
||
grub-core/kern/ieee1275/ieee1275.c | 1 -
|
||
grub-core/kern/ieee1275/init.c | 4 +
|
||
grub-core/kern/powerpc/ieee1275/ieee1275.c | 137 +++++++++
|
||
.../kern/powerpc/ieee1275/platform_keystore.c | 333 +++++++++++++++++++++
|
||
include/grub/ieee1275/ieee1275.h | 3 +
|
||
include/grub/powerpc/ieee1275/ieee1275.h | 36 +++
|
||
include/grub/powerpc/ieee1275/platform_keystore.h | 123 ++++++++
|
||
9 files changed, 640 insertions(+), 1 deletion(-)
|
||
create mode 100644 grub-core/kern/powerpc/ieee1275/ieee1275.c
|
||
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 aa17239..8dd7014 100644
|
||
--- a/grub-core/Makefile.am
|
||
+++ b/grub-core/Makefile.am
|
||
@@ -247,6 +247,8 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/alloc.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/ieee1275.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 15721c5..e16013a 100644
|
||
--- a/grub-core/Makefile.core.def
|
||
+++ b/grub-core/Makefile.core.def
|
||
@@ -338,6 +338,8 @@ kernel = {
|
||
powerpc_ieee1275 = kern/powerpc/dl.c;
|
||
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
|
||
powerpc_ieee1275 = kern/lockdown.c;
|
||
+ powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.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/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c
|
||
index 36ca2db..afa37a9 100644
|
||
--- a/grub-core/kern/ieee1275/ieee1275.c
|
||
+++ b/grub-core/kern/ieee1275/ieee1275.c
|
||
@@ -23,7 +23,6 @@
|
||
|
||
#define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1)
|
||
#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0)
|
||
-#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)
|
||
|
||
|
||
|
||
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
|
||
index 0c587d3..32ee281 100644
|
||
--- a/grub-core/kern/ieee1275/init.c
|
||
+++ b/grub-core/kern/ieee1275/init.c
|
||
@@ -51,6 +51,8 @@
|
||
#endif
|
||
#if defined(__powerpc__)
|
||
#include <grub/lockdown.h>
|
||
+#include <grub/powerpc/ieee1275/ieee1275.h>
|
||
+#include <grub/powerpc/ieee1275/platform_keystore.h>
|
||
#endif
|
||
|
||
#ifdef __powerpc__
|
||
@@ -1057,6 +1059,8 @@ grub_ieee1275_get_secure_boot (void)
|
||
}
|
||
else
|
||
grub_dprintf ("ieee1275", "Secure Boot Disabled\n");
|
||
+
|
||
+ grub_pks_keystore_init ();
|
||
}
|
||
#endif /* __powerpc__ */
|
||
grub_addr_t grub_modbase;
|
||
diff --git a/grub-core/kern/powerpc/ieee1275/ieee1275.c b/grub-core/kern/powerpc/ieee1275/ieee1275.c
|
||
new file mode 100644
|
||
index 0000000..20c49e3
|
||
--- /dev/null
|
||
+++ b/grub-core/kern/powerpc/ieee1275/ieee1275.c
|
||
@@ -0,0 +1,137 @@
|
||
+/* ieee1275.c - Access the Open Firmware client interface. */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
|
||
+ * Copyright (C) 2020, 2021, 2022, 2023, 2024, 2025 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/ieee1275/ieee1275.h>
|
||
+#include <grub/powerpc/ieee1275/ieee1275.h>
|
||
+#include <grub/misc.h>
|
||
+
|
||
+grub_int32_t
|
||
+grub_ieee1275_test (const char *interface_name)
|
||
+{
|
||
+ struct test_args
|
||
+ {
|
||
+ struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
|
||
+ grub_ieee1275_cell_t name; /* The interface name. */
|
||
+ grub_ieee1275_cell_t missing;
|
||
+ } args;
|
||
+
|
||
+ INIT_IEEE1275_COMMON (&args.common, "test", 1, 1);
|
||
+ args.name = (grub_ieee1275_cell_t) interface_name;
|
||
+
|
||
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||
+ return -1;
|
||
+
|
||
+ if (args.missing == IEEE1275_CELL_INVALID)
|
||
+ return -1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+grub_int32_t
|
||
+grub_ieee1275_pks_max_object_size (grub_uint32_t *result)
|
||
+{
|
||
+ struct mos_args
|
||
+ {
|
||
+ struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
|
||
+ grub_ieee1275_cell_t size; /* The maximum object size for a PKS object. */
|
||
+ } args;
|
||
+
|
||
+ INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_MAX_OBJ_INTERFACE, 0, 1);
|
||
+
|
||
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||
+ return -1;
|
||
+
|
||
+ if (args.size == IEEE1275_CELL_INVALID || args.size == 0)
|
||
+ return -1;
|
||
+
|
||
+ *result = args.size;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+grub_int32_t
|
||
+grub_ieee1275_pks_read_object (const grub_uint32_t consumer, const char *label,
|
||
+ const grub_uint32_t label_len, const grub_uint32_t buffer_len,
|
||
+ grub_uint8_t *buffer, grub_uint32_t *data_len,
|
||
+ grub_uint32_t *policies)
|
||
+{
|
||
+ struct pks_read_args
|
||
+ {
|
||
+ struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
|
||
+ grub_ieee1275_cell_t consumer; /* The object belonging to consumer with the label. */
|
||
+ grub_ieee1275_cell_t label; /* Object label buffer logical real address. */
|
||
+ grub_ieee1275_cell_t label_len; /* The byte length of the object label. */
|
||
+ grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
|
||
+ grub_ieee1275_cell_t buffer_len; /* Length of the output buffer. */
|
||
+ grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
|
||
+ grub_ieee1275_cell_t policies; /* The object policies. */
|
||
+ grub_int32_t rc; /* The return code. */
|
||
+ } args;
|
||
+
|
||
+ INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_OBJ_INTERFACE, 5, 3);
|
||
+ args.consumer = consumer;
|
||
+ args.label_len = label_len;
|
||
+ args.buffer_len = buffer_len;
|
||
+ args.label = (grub_ieee1275_cell_t) label;
|
||
+ args.buffer = (grub_ieee1275_cell_t) buffer;
|
||
+
|
||
+ 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 args.rc;
|
||
+}
|
||
+
|
||
+grub_int32_t
|
||
+grub_ieee1275_pks_read_sbvar (const grub_uint32_t sbvar_flags, const grub_uint32_t sbvar_type,
|
||
+ const grub_uint32_t buffer_len, grub_uint8_t *buffer,
|
||
+ grub_size_t *data_len)
|
||
+{
|
||
+ struct pks_read_sbvar_args
|
||
+ {
|
||
+ struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
|
||
+ grub_ieee1275_cell_t sbvar_flags; /* The sbvar operation flags. */
|
||
+ grub_ieee1275_cell_t sbvar_type; /* The sbvar being requested. */
|
||
+ grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
|
||
+ grub_ieee1275_cell_t buffer_len; /* Length of the Output buffer. */
|
||
+ grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
|
||
+ grub_int32_t rc; /* The return code. */
|
||
+ } args;
|
||
+
|
||
+ INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_SBVAR_INTERFACE, 4, 2);
|
||
+ args.sbvar_flags = sbvar_flags;
|
||
+ args.sbvar_type = sbvar_type;
|
||
+ args.buffer_len = buffer_len;
|
||
+ args.buffer = (grub_ieee1275_cell_t) buffer;
|
||
+
|
||
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||
+ return -1;
|
||
+
|
||
+ if (args.data_len == IEEE1275_CELL_INVALID)
|
||
+ return -1;
|
||
+
|
||
+ *data_len = args.data_len;
|
||
+
|
||
+ return args.rc;
|
||
+}
|
||
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..cc2d493
|
||
--- /dev/null
|
||
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
|
||
@@ -0,0 +1,333 @@
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 2024 Free Software Foundation, Inc.
|
||
+ * Copyright (C) 2022, 2023, 2024, 2025 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/types.h>
|
||
+#include <grub/misc.h>
|
||
+#include <grub/lockdown.h>
|
||
+#include <grub/ieee1275/ieee1275.h>
|
||
+#include <grub/powerpc/ieee1275/ieee1275.h>
|
||
+#include <grub/powerpc/ieee1275/platform_keystore.h>
|
||
+
|
||
+/* PKS object maximum size. */
|
||
+static grub_uint32_t pks_max_object_size = 0;
|
||
+
|
||
+/* Platform KeyStore db and dbx. */
|
||
+static grub_pks_t pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0,
|
||
+ .dbx_entries = 0, .db_exists = true};
|
||
+/*
|
||
+ * pks_use_keystore: Key Management Modes
|
||
+ * False: Static key management (use built-in Keys). This is default.
|
||
+ * True: Dynamic key management (use Platform KeySotre).
|
||
+ */
|
||
+static bool pks_use_keystore = false;
|
||
+
|
||
+/*
|
||
+ * Reads the Globally Unique Identifier (GUID), EFI Signature Database (ESD),
|
||
+ * and its size from the Platform KeyStore EFI Signature List (ESL), then
|
||
+ * stores them into the PKS Signature Database (SD) (i.e., pks_sd buffer
|
||
+ * and pks_sd entries) in the GRUB.
|
||
+ */
|
||
+static grub_err_t
|
||
+_esl_to_esd (const grub_uint8_t *esl_data, grub_size_t esl_size,
|
||
+ const grub_size_t signature_size, const grub_packed_guid_t *guid,
|
||
+ grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
|
||
+{
|
||
+ grub_esd_t *esd;
|
||
+ grub_pks_sd_t *signature = *pks_sd;
|
||
+ grub_uint32_t entries = *pks_sd_entries;
|
||
+ grub_size_t data_size, 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_pks_free_data(). */
|
||
+ *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->signature_data, 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_uint32_t *pks_sd_entries)
|
||
+{
|
||
+ grub_packed_guid_t guid;
|
||
+ grub_esl_t *esl;
|
||
+ grub_size_t offset, esl_size, signature_size, signature_header_size;
|
||
+
|
||
+ /* Convert the ESL data into the ESL. */
|
||
+ esl = (grub_esl_t *) esl_data;
|
||
+ if (*next_esl < sizeof (grub_esl_t) || esl == NULL)
|
||
+ return grub_error (GRUB_ERR_BUG, "invalid ESL");
|
||
+
|
||
+ esl_size = grub_le_to_cpu32 (esl->signature_list_size);
|
||
+ signature_header_size = grub_le_to_cpu32 (esl->signature_header_size);
|
||
+ signature_size = grub_le_to_cpu32 (esl->signature_size);
|
||
+ grub_memcpy (&guid, &esl->signature_type, sizeof (grub_packed_guid_t));
|
||
+
|
||
+ 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 _esl_to_esd (esl_data + offset, esl_size, signature_size, &guid,
|
||
+ pks_sd, pks_sd_entries);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Import the EFI Signature Database (ESD) 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_uint32_t *pks_sd_entries)
|
||
+{
|
||
+ grub_err_t rc;
|
||
+ 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_int32_t rc;
|
||
+ grub_uint32_t outlen = 0, policy = 0;
|
||
+
|
||
+ *out = grub_malloc (pks_max_object_size);
|
||
+ if (*out == NULL)
|
||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||
+
|
||
+ rc = grub_ieee1275_pks_read_object (GRUB_PKS_CONSUMER_FW, GRUB_SB_VERSION_KEY_NAME,
|
||
+ GRUB_SB_VERSION_KEY_LEN, pks_max_object_size, *out,
|
||
+ &outlen, &policy);
|
||
+ if (rc < 0)
|
||
+ {
|
||
+ grub_free (*out);
|
||
+ return grub_error (GRUB_ERR_READ_ERROR, "SB version read failed (%d)\n", rc);
|
||
+ }
|
||
+
|
||
+ if (outlen != 1 || (**out >= 2))
|
||
+ {
|
||
+ grub_free (*out);
|
||
+ return grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version: %u\n", **out);
|
||
+ }
|
||
+
|
||
+ return GRUB_ERR_NONE;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Reads 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_sbvar_from_pks (const grub_uint32_t sbvarflags, const grub_uint32_t sbvartype,
|
||
+ grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
|
||
+{
|
||
+ grub_int32_t rc;
|
||
+ grub_err_t err = GRUB_ERR_NONE;
|
||
+ grub_uint8_t *esl_data = NULL;
|
||
+ grub_size_t esl_data_size = 0;
|
||
+
|
||
+ esl_data = grub_malloc (pks_max_object_size);
|
||
+ if (esl_data == NULL)
|
||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||
+
|
||
+ rc = grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, pks_max_object_size,
|
||
+ esl_data, &esl_data_size);
|
||
+ if (rc == IEEE1275_CELL_NOT_FOUND)
|
||
+ {
|
||
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "secure boot variable %s not found (%d)",
|
||
+ (sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
|
||
+ goto fail;
|
||
+ }
|
||
+ else if (rc < 0)
|
||
+ {
|
||
+ err = grub_error (GRUB_ERR_READ_ERROR, "secure boot variable %s reading (%d)",
|
||
+ (sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (esl_data_size > 0)
|
||
+ err = pks_sd_from_esl (esl_data, esl_data_size, pks_sd, pks_sd_entries);
|
||
+ else
|
||
+ err = GRUB_ERR_BAD_NUMBER;
|
||
+
|
||
+ fail:
|
||
+ grub_free (esl_data);
|
||
+
|
||
+ return err;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Test the availability of PKS support. If PKS support is avaialble and objects
|
||
+ * present, it reads the secure boot version (SB_VERSION) from PKS.
|
||
+ *
|
||
+ * SB_VERSION: Key Management Mode
|
||
+ * 1 - Enable dynamic key management mode. Read the db and dbx variables from PKS,
|
||
+ * and use them for signature verification.
|
||
+ * 0 - Enable static key management mode. Read keys from the GRUB ELF Note and use
|
||
+ * it for signature verification.
|
||
+ */
|
||
+static bool
|
||
+is_pks_present (void)
|
||
+{
|
||
+ grub_err_t err;
|
||
+ grub_int32_t rc;
|
||
+ grub_uint8_t *data = NULL;
|
||
+ bool ret = false;
|
||
+
|
||
+ rc = grub_ieee1275_test (GRUB_PKS_MAX_OBJ_INTERFACE);
|
||
+ if (rc < 0)
|
||
+ {
|
||
+ grub_error (GRUB_ERR_BAD_FIRMWARE, "firmware doesn't have PKS support\n");
|
||
+ return ret;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
|
||
+ if (rc < 0)
|
||
+ {
|
||
+ grub_error (GRUB_ERR_BAD_NUMBER, "PKS support is there but it has zero objects\n");
|
||
+ return ret;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ err = read_sbversion_from_pks (&data);
|
||
+ if (err != GRUB_ERR_NONE)
|
||
+ return ret;
|
||
+
|
||
+ /*
|
||
+ * If *data == 1, use dynamic key management and read the keys from the PKS.
|
||
+ * Else, use static key management and read the keys from the GRUB ELF Note.
|
||
+ */
|
||
+ ret = ((*data == 1) ? true : false);
|
||
+
|
||
+ grub_free (data);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+/* Free allocated memory. */
|
||
+void
|
||
+grub_pks_free_data (void)
|
||
+{
|
||
+ grub_size_t i;
|
||
+
|
||
+ for (i = 0; i < pks_keystore.db_entries; i++)
|
||
+ grub_free (pks_keystore.db[i].data);
|
||
+
|
||
+ for (i = 0; i < pks_keystore.dbx_entries; i++)
|
||
+ grub_free (pks_keystore.dbx[i].data);
|
||
+
|
||
+ grub_free (pks_keystore.db);
|
||
+ grub_free (pks_keystore.dbx);
|
||
+ grub_memset (&pks_keystore, 0, sizeof (grub_pks_t));
|
||
+}
|
||
+
|
||
+grub_pks_t *
|
||
+grub_pks_get_keystore (void)
|
||
+{
|
||
+ return (pks_use_keystore == true) ? &pks_keystore : NULL;
|
||
+}
|
||
+
|
||
+/* Initialization of the Platform KeyStore. */
|
||
+void
|
||
+grub_pks_keystore_init (void)
|
||
+{
|
||
+ grub_err_t rc_db, rc_dbx;
|
||
+
|
||
+ grub_dprintf ("ieee1275", "trying to load Platform KeyStore\n");
|
||
+
|
||
+ if (is_pks_present () == false)
|
||
+ {
|
||
+ grub_dprintf ("ieee1275", "Platform PKS is not available\n");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * When read db from PKS, there are three scenarios
|
||
+ * 1. db fully loaded from PKS
|
||
+ * 2. db partially loaded from PKS
|
||
+ * 3. no keys are loaded from db (if db does not exist in PKS), default to
|
||
+ * built-in keys (static keys)
|
||
+ * each of these scenarios, the db keys are checked against dbx.
|
||
+ */
|
||
+ rc_db = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DB, &pks_keystore.db, &pks_keystore.db_entries);
|
||
+ if (rc_db == GRUB_ERR_FILE_NOT_FOUND)
|
||
+ pks_keystore.db_exists = false;
|
||
+
|
||
+ /*
|
||
+ * Read dbx from PKS. If dbx is not completely loaded from PKS, then this
|
||
+ * could lead to the loading of vulnerable GRUB modules and kernel binaries.
|
||
+ * So, this should be prevented by freeing up loaded dbx and db.
|
||
+ */
|
||
+ rc_dbx = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DBX, &pks_keystore.dbx, &pks_keystore.dbx_entries);
|
||
+ if (rc_dbx == GRUB_ERR_FILE_NOT_FOUND || rc_dbx == GRUB_ERR_BAD_NUMBER)
|
||
+ rc_dbx = GRUB_ERR_NONE;
|
||
+
|
||
+ if (rc_dbx != GRUB_ERR_NONE)
|
||
+ grub_pks_free_data ();
|
||
+
|
||
+ /*
|
||
+ * At this point, it's evident that PKS infrastructure exists, so the PKS
|
||
+ * keystore must be used for validating appended signatures.
|
||
+ */
|
||
+ pks_use_keystore = true;
|
||
+}
|
||
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
|
||
index db0ec5f..17aecf2 100644
|
||
--- a/include/grub/ieee1275/ieee1275.h
|
||
+++ b/include/grub/ieee1275/ieee1275.h
|
||
@@ -24,6 +24,9 @@
|
||
#include <grub/types.h>
|
||
#include <grub/machine/ieee1275.h>
|
||
|
||
+#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)
|
||
+#define IEEE1275_CELL_NOT_FOUND ((grub_int32_t) -7)
|
||
+
|
||
#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0)
|
||
#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1)
|
||
|
||
diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h
|
||
index 4eb2070..4b9966d 100644
|
||
--- a/include/grub/powerpc/ieee1275/ieee1275.h
|
||
+++ b/include/grub/powerpc/ieee1275/ieee1275.h
|
||
@@ -28,4 +28,40 @@ typedef grub_uint32_t grub_ieee1275_cell_t;
|
||
#define PRIxGRUB_IEEE1275_CELL_T PRIxGRUB_UINT32_T
|
||
#define PRIuGRUB_IEEE1275_CELL_T PRIuGRUB_UINT32_T
|
||
|
||
+#ifdef __powerpc__
|
||
+/* The maximum object size interface name for a PKS object. */
|
||
+#define GRUB_PKS_MAX_OBJ_INTERFACE "pks-max-object-size"
|
||
+
|
||
+/* PKS read object and read sbvar interface name. */
|
||
+#define GRUB_PKS_READ_OBJ_INTERFACE "pks-read-object"
|
||
+#define GRUB_PKS_READ_SBVAR_INTERFACE "pks-read-sbvar"
|
||
+
|
||
+/* PKS read object label for secure boot version. */
|
||
+#define GRUB_SB_VERSION_KEY_NAME "SB_VERSION"
|
||
+#define GRUB_SB_VERSION_KEY_LEN (sizeof (GRUB_SB_VERSION_KEY_NAME) - 1)
|
||
+
|
||
+/* PKS consumer type for firmware. */
|
||
+#define GRUB_PKS_CONSUMER_FW ((grub_uint32_t) 1)
|
||
+
|
||
+/* PKS read secure boot variable request type for db and dbx. */
|
||
+#define GRUB_PKS_SBVAR_DB ((grub_uint32_t) 1)
|
||
+#define GRUB_PKS_SBVAR_DBX ((grub_uint32_t) 2)
|
||
+
|
||
+extern grub_int32_t
|
||
+grub_ieee1275_test (const char *interface_name);
|
||
+
|
||
+extern grub_int32_t
|
||
+grub_ieee1275_pks_max_object_size (grub_uint32_t *result);
|
||
+
|
||
+extern grub_int32_t
|
||
+grub_ieee1275_pks_read_object (const grub_uint32_t consumer, const char *label,
|
||
+ const grub_uint32_t label_len, const grub_uint32_t buffer_len,
|
||
+ grub_uint8_t *buffer, grub_uint32_t *data_len,
|
||
+ grub_uint32_t *policies);
|
||
+
|
||
+extern grub_int32_t
|
||
+grub_ieee1275_pks_read_sbvar (const grub_uint32_t sbvar_flags, const grub_uint32_t sbvar_type,
|
||
+ const grub_uint32_t buffer_len, grub_uint8_t *buffer,
|
||
+ grub_size_t *data_len);
|
||
+#endif /* __powerpc__ */
|
||
#endif /* ! GRUB_IEEE1275_MACHINE_HEADER */
|
||
diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h
|
||
new file mode 100644
|
||
index 0000000..931ada2
|
||
--- /dev/null
|
||
+++ b/include/grub/powerpc/ieee1275/platform_keystore.h
|
||
@@ -0,0 +1,123 @@
|
||
+/*
|
||
+ * 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 2022, 2023, 2024, 2025 IBM Corp.
|
||
+ */
|
||
+
|
||
+#ifndef PLATFORM_KEYSTORE_HEADER
|
||
+#define PLATFORM_KEYSTORE_HEADER 1
|
||
+
|
||
+#include <grub/symbol.h>
|
||
+#include <grub/mm.h>
|
||
+#include <grub/types.h>
|
||
+
|
||
+/*
|
||
+ * 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_packed_guid_t signature_owner;
|
||
+ /* The format of the signature is defined by the SignatureType. */
|
||
+ grub_uint8_t signature_data[];
|
||
+} GRUB_PACKED;
|
||
+typedef struct grub_esd grub_esd_t;
|
||
+
|
||
+/*
|
||
+ * 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_packed_guid_t signature_type;
|
||
+ /* Total size of the signature list, including this header. */
|
||
+ grub_uint32_t signature_list_size;
|
||
+ /* Size of the signature header which precedes the array of signatures. */
|
||
+ grub_uint32_t signature_header_size;
|
||
+ /* Size of each signature.*/
|
||
+ grub_uint32_t signature_size;
|
||
+} GRUB_PACKED;
|
||
+typedef struct grub_esl grub_esl_t;
|
||
+
|
||
+/* The structure of a PKS Signature Database (SD). */
|
||
+struct grub_pks_sd
|
||
+{
|
||
+ grub_packed_guid_t guid; /* Signature type. */
|
||
+ grub_uint8_t *data; /* Signature data. */
|
||
+ grub_size_t data_size; /* Size of signature data. */
|
||
+} GRUB_PACKED;
|
||
+typedef struct grub_pks_sd grub_pks_sd_t;
|
||
+
|
||
+/* The structure of a Platform KeyStore (PKS). */
|
||
+struct grub_pks
|
||
+{
|
||
+ grub_pks_sd_t *db; /* Signature database. */
|
||
+ grub_pks_sd_t *dbx; /* Forbidden signature database. */
|
||
+ grub_uint32_t db_entries; /* Size of signature database. */
|
||
+ grub_uint32_t dbx_entries;/* Size of forbidden signature database. */
|
||
+ bool db_exists; /* Flag to indicate if the db exists or not in PKS. */
|
||
+};
|
||
+typedef struct grub_pks grub_pks_t;
|
||
+
|
||
+#if defined(__powerpc__)
|
||
+/* Initialization of the Platform Keystore. */
|
||
+extern void
|
||
+grub_pks_keystore_init (void);
|
||
+
|
||
+/* Platform KeyStore db and dbx. */
|
||
+extern grub_pks_t *
|
||
+EXPORT_FUNC (grub_pks_get_keystore) (void);
|
||
+
|
||
+/* Free allocated memory. */
|
||
+extern void
|
||
+EXPORT_FUNC (grub_pks_free_data) (void);
|
||
+#else
|
||
+static inline grub_pks_t *
|
||
+grub_pks_get_keystore (void)
|
||
+{
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static inline void
|
||
+grub_pks_free_data (void)
|
||
+{
|
||
+}
|
||
+#endif /* __powerpc__ */
|
||
+#endif
|