Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:michael-chang:bsc:1218783
grub2
0002-ieee1275-Read-the-DB-and-DBX-secure-boot-v...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0002-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch of Package grub2
From 8ef821ea18ed35f5969b98f2df6a76fefb71b175 Mon Sep 17 00:00:00 2001 From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> Date: Wed, 28 Dec 2022 17:49:24 +0530 Subject: [PATCH 2/8] 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 certificates from ESL. It would be saved in the platform keystore buffer, and the appendedsig (module) would read it later to extract the certificate's details. In the following scenarios, static key mode will be activated: 1. When secure boot is enabled with static 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> Tested-by: Nageswara Sastry <rnsastry@linux.ibm.com> --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 1 + grub-core/kern/ieee1275/init.c | 12 +- grub-core/kern/ieee1275/platform_keystore.c | 377 ++++++++++++++++++++ include/grub/platform_keystore.h | 190 ++++++++++ 5 files changed, 580 insertions(+), 1 deletion(-) create mode 100644 grub-core/kern/ieee1275/platform_keystore.c create mode 100644 include/grub/platform_keystore.h diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 9d3d5f519..4630e2ba3 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -79,6 +79,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/platform_keystore.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lockdown.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index dc639dd24..4ff35afb7 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -170,6 +170,7 @@ kernel = { ieee1275 = kern/ieee1275/openfw.c; ieee1275 = term/ieee1275/console.c; ieee1275 = kern/ieee1275/init.c; + ieee1275 = kern/ieee1275/platform_keystore.c; uboot = disk/uboot/ubootdisk.c; uboot = kern/uboot/uboot.c; diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 38f1f1f6e..bb800b275 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -50,6 +50,7 @@ #include <grub/ieee1275/alloc.h> #endif #include <grub/lockdown.h> +#include <grub/platform_keystore.h> /* The maximum heap size we're going to claim at boot. Not used by sparc. */ #ifdef __i386__ @@ -915,7 +916,16 @@ grub_get_ieee1275_secure_boot (void) * We only support enforce. */ if (rc >= 0 && is_sb >= 2) - grub_lockdown (); + { + grub_printf ("secure boot enabled\n"); + rc = grub_platform_keystore_init (); + if (rc != GRUB_ERR_NONE) + grub_printf ("Warning: initialization of the platform keystore failed!\n"); + + grub_lockdown (); + } + else + grub_printf ("secure boot disabled\n"); } grub_addr_t grub_modbase; diff --git a/grub-core/kern/ieee1275/platform_keystore.c b/grub-core/kern/ieee1275/platform_keystore.c new file mode 100644 index 000000000..976e4e9b5 --- /dev/null +++ b/grub-core/kern/ieee1275/platform_keystore.c @@ -0,0 +1,377 @@ +#include <grub/mm.h> +#include <grub/ieee1275/ieee1275.h> +#include <grub/types.h> +#include <grub/misc.h> +#include <grub/lockdown.h> +#include <grub/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 -7 +#define PKS_UNPACK_ERROR 0x200 +#define PKS_UNPACK_VERSION_ERROR 0x201 + +struct pks_timestamp +{ + grub_uint16_t year; + grub_uint8_t month; + grub_uint8_t day; + grub_uint8_t hour; + grub_uint8_t minute; + grub_uint8_t second; +} GRUB_PACKED; + +struct pks_signed_var +{ + grub_uint8_t version; + struct pks_timestamp time; +} GRUB_PACKED; + +/* Platform Keystore */ +static grub_size_t pks_max_object_size; +grub_uint8_t grub_use_platform_keystore = 0; +grub_pks_t grub_platform_keystore = { .use_static_keys = 0, .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 }; + +/* converts the esl data into the ESL */ +static grub_esl_t * +grub_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; +} + +/* + * imports the GUID, esd, and its size into the pks sd buffer and + * pks sd entries from the EFI signature list. + */ +static grub_err_t +grub_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); + + if (signature != NULL) + signature = grub_realloc (signature, (entries + 1) * sizeof (grub_pks_sd_t)); + else + signature = grub_malloc (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_release_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; +} + +/* + * extracts the esd after removing the esl header from esl. + */ +static grub_err_t +grub_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 = grub_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 grub_esd_from_esl (esl_data + offset, esl_size, signature_size, &guid, + pks_sd, pks_sd_entries); +} + +/* + * imports 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 +grub_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 = grub_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; +} + +/* + * unpacking the signed secure boot variable + * return error if size too small or version mismatch + * discards timestamp, only needed in verifying updates + */ +static grub_err_t +grub_unpack_signed_variable (grub_uint8_t *indata, grub_size_t insize, + grub_uint8_t **data, grub_size_t *size) +{ + struct pks_signed_var *psv = NULL; + + /* do not permit negative or size 0 data */ + if (insize <= sizeof (struct pks_signed_var)) + return PKS_UNPACK_ERROR; + + psv = (struct pks_signed_var *) indata; + if (psv->version != 0) + return PKS_UNPACK_VERSION_ERROR; + + *data = indata + sizeof (struct pks_signed_var); + *size = insize - sizeof (struct pks_signed_var); + + return GRUB_ERR_NONE; +} + +/* + * reads the secure boot version from PKS as an object. + * caller must free result + */ +static grub_err_t +grub_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 +grub_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 +grub_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) + grub_printf ("Warning: doesn't have PKS support!\n"); + else + { + rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size); + if (rc != GRUB_ERR_NONE) + grub_printf ("Warning: PKS support is there but it has zero objects!\n"); + } + + return rc; +} + +/* + * retrieves the secure boot variable from PKS, unpacks it, reads the esd + * from ESL, and stores the information in the pks sd buffer. + */ +static grub_err_t +grub_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 *data = NULL, *esl_data = NULL; + grub_size_t data_len = 0, esl_data_size = 0; + + rc = grub_sbvar_from_pks (sbvarflags, sbvartype, &data, &data_len); + /* + * 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 + { + rc = grub_unpack_signed_variable (data, data_len, &esl_data, &esl_data_size); + if (rc != GRUB_ERR_NONE) + rc = grub_error (rc, "unpacking of signed variable %s structure (%d)", + (sbvartype == DB ? "db" : "dbx"), rc); + else + rc = grub_pks_sd_from_esl ((const grub_uint8_t *) esl_data, esl_data_size, + pks_sd, pks_sd_entries); + } + + grub_free (data); + + return rc; +} + +/* reads secure boot version (SB_VERSION) */ +static grub_err_t +grub_secure_boot_version (void) +{ + grub_err_t rc = GRUB_ERR_NONE; + grub_uint8_t *data = NULL; + grub_size_t len = 0, policy = 0; + + rc = grub_sbversion_from_pks (&data, &len, &policy); + if (rc != GRUB_ERR_NONE) + grub_printf ("Warning: SB version read failed! (%d)\n", rc); + else if (len != 1 || (*data != 1 && *data != 0)) + { + grub_printf ("Warning: found unexpected SB version! (%d)\n", *data); + rc = GRUB_ERR_INVALID_COMMAND; + } + + if (rc != GRUB_ERR_NONE) + { + grub_printf ("Warning: switch to static key!\n"); + if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) + grub_fatal ("Secure Boot locked down"); + } + else + grub_use_platform_keystore = *data; + + grub_free (data); + + return rc; +} + +/* releasing allocated memory */ +void +grub_release_platform_keystore (void) +{ + grub_size_t i = 0; + + for (i = 0; i < grub_platform_keystore.db_entries; i++) + grub_free (grub_platform_keystore.db[i].data); + + for (i = 0; i < grub_platform_keystore.dbx_entries; i++) + grub_free (grub_platform_keystore.dbx[i].data); + + grub_free (grub_platform_keystore.db); + grub_free (grub_platform_keystore.dbx); + grub_memset (&grub_platform_keystore, 0x00, sizeof (grub_pks_t)); +} + +/* initialization of the Platform Keystore */ +grub_err_t +grub_platform_keystore_init (void) +{ + grub_err_t rc = GRUB_ERR_NONE; + + grub_printf ("trying to load Platform Keystore\n"); + + rc = grub_is_support_pks (); + if (rc != GRUB_ERR_NONE) + { + grub_printf ("Warning: switch to static key!\n"); + return rc; + } + + /* SB_VERSION */ + rc = grub_secure_boot_version (); + if (rc != GRUB_ERR_NONE) + return rc; + + if (grub_use_platform_keystore) + { + grub_memset (&grub_platform_keystore, 0x00, sizeof (grub_pks_t)); + /* DB */ + rc = grub_secure_boot_variables (0, DB, &grub_platform_keystore.db, + &grub_platform_keystore.db_entries); + if ((int)rc == PKS_OBJECT_NOT_FOUND) + { + rc = GRUB_ERR_NONE; + /* DB variable won't be available by default in PKS, So, it will loads the Default Keys from ELF Note */ + grub_platform_keystore.use_static_keys = 1; + } + + if (rc == GRUB_ERR_NONE) + { + /* DBX */ + rc = grub_secure_boot_variables (0, DBX, &grub_platform_keystore.dbx, + &grub_platform_keystore.dbx_entries); + if ((int)rc == PKS_OBJECT_NOT_FOUND) + { + grub_printf ("Warning: dbx is not found!\n"); + rc = GRUB_ERR_NONE; + } + } + + } + + if (rc != GRUB_ERR_NONE) + grub_release_platform_keystore (); + + return rc; +} diff --git a/include/grub/platform_keystore.h b/include/grub/platform_keystore.h new file mode 100644 index 000000000..8cc4266c9 --- /dev/null +++ b/include/grub/platform_keystore.h @@ -0,0 +1,190 @@ +#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_UUID_SIZE 16 +#define GRUB_MAX_HASH_SIZE 64 + +typedef struct grub_uuid grub_uuid_t; +typedef struct grub_esd grub_esd_t; +typedef struct grub_esl grub_esl_t; + +/* The structure of a UUID.*/ +struct grub_uuid +{ + grub_uint8_t b[GRUB_UUID_SIZE]; +}; + +/* 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; + +/* 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; + +/* + * The GRUB_PKS_CERT_* is derived from the following files referred from edk2-staging[1] repo + * of tianocore + * + * MdePkg/Include/Guid/ImageAuthentication.h + * + * [1] https://github.com/tianocore/edk2-staging + */ + +#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 \ + } \ + } + +#define GRUB_PKS_CERT_SHA1_GUID \ + (grub_uuid_t) \ + { \ + { \ + 0x12, 0xa5, 0x6c, 0x82, 0x10, 0xcf, \ + 0xc9, 0x4a, 0xb1, 0x87, 0xbe, 0x1, \ + 0x49, 0x66, 0x31, 0xbd \ + } \ + } + +#define GRUB_PKS_CERT_SHA224_GUID \ + (grub_uuid_t) \ + { \ + { \ + 0x33, 0x52, 0x6e, 0xb, 0x5c, 0xa6, \ + 0xc9, 0x44, 0x94, 0x7, 0xd9, 0xab, \ + 0x83, 0xbf, 0xc8, 0xbd \ + } \ + } + +#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 \ + } \ + } + +#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 \ + } \ + } + +#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 \ + } \ + } + +#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 \ + } \ + } + +#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 \ + } \ + } + +#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_uint8_t use_static_keys; + 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_platform_keystore_init (void); +/* releasing allocated memory */ +void EXPORT_FUNC(grub_release_platform_keystore) (void); +extern grub_uint8_t EXPORT_VAR(grub_use_platform_keystore); +extern grub_pks_t EXPORT_VAR(grub_platform_keystore); + +#else + +#define grub_use_platform_keystore 0 +grub_pks_t grub_platform_keystore = {0, NULL, NULL, 0, 0}; +void grub_release_platform_keystore (void); + +#endif + +#endif -- 2.47.0
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor