diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index e50db8106..8577462d5 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -246,6 +246,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 6824a0ee4..853d879a4 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -334,6 +334,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 36ca2dbfc..afa37a9f0 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 28653a5a4..0ef888058 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -51,6 +51,8 @@ #endif #if defined(__powerpc__) #include +#include +#include #endif #ifdef __powerpc__ @@ -1043,6 +1045,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 000000000..20c49e371 --- /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 . + */ +#include +#include +#include + +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 000000000..cc2d493bb --- /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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 c445d0499..157ed57be 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -24,6 +24,9 @@ #include #include +#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 4eb207018..4b9966dd4 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 000000000..931ada224 --- /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 +#include +#include + +/* + * 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