All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC
@ 2024-12-18 14:56 Sudhakar Kuppusamy
  2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
                   ` (20 more replies)
  0 siblings, 21 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

Linux on Power LPAR secure boot ensures the integrity of the Linux boot
stack. The hypervisor and partition firmware are part of the core root of
trust. The partition firmware verifies the signature on the GRUB image
before handing control to GRUB. Similarly, GRUB verifies the signature on
the kernel image before booting the OS. This ensures that every image
running at the boot time is verified and trusted. UEFI platforms relies
on PECOFF based signature scheme. Since Power is not a UEFI platform, an
alternative mechanism is needed. Power already uses appended signatures
on the Linux Kernel, and is now extended to sign the grub as well.

Linux on Power also allows multiple signers, and if any one of the
signature passes, then the image passes the validation. Appended signature
scheme uses CMS structure to contain signatures. On Power, the multiple
signature support relies on the multiple signers features already supported
by CMS standards. It does require that all the signers should sign at the
same time and are not allowed to add or remove the signatures randomly.

By default, Linux LPAR secure boot uses static key management[1]. This means
that each image embeds the keys it needs to verify the image it loads.
For example, the keys used to verify the GRUB image are built into the
firmware image. Similarly, the keys used for verifying the kernel image
are built into the GRUB image. These are pre-defined keys and they cannot
be modified at runtime. The drawback of this approach is that key rotations
results in both firmware and OS updates. This is where dynamic key
management is useful.

An admin can switch from static keys to dynamic keys by coordinating with
Hardware Management Console(HMC) admin and enabling the required flags
for the given LPAR.

The dynamic key management relies on the Platform KeyStore(PKS)[2] storage
allocation for each LPAR with individually managed access controls to
store sensitive information securely. Once switched to dynamic keys, HMC
advertises this flag to the PowerVM, which then initializes the PKS
with the default secvars. It also creates a variable SB_VERSION that
represents the secure boot key management mode. The default secvars are
used by Partition firmware, grub and the linux kernel to reads keys for
verification. These secvars can be managed by user interface exposed via
linux kernel. The linux kernel already supports this interface and
it is available in the upstream kernel.

This patchset adds the appended signature support both for signing and
verification and the key management to the grub component. The whole
patchset can be split into following four main parts:

The series has following four main parts:

1.) Sign grub.elf with an appended signature. (Patches 1 - 3)

These patches provide some infrastructure and documentation for
signing grub's core.elf with a Linux-kernel-module style appended
signature.

An appended signature is a 'dumb' signature over the contents of a
file. (It is distinct from schemes like Authenticode that are aware of
the structure of the file and only sign certain parts.) The signature
is wrapped in a PKCS#7 message, and is appended to the signed file
along with some metadata and a magic string. The signatures are
validated against a public key which is usually provided as an x509
certificate.

Because some platforms, such as powerpc-ieee1275, may load grub from a
raw disk partition rather than a filesystem, we extend grub-install to
add an ELF note that allows us to specify the size and location of the
signature.

2.) Enable appended signature verification using builtin keys (Patches 4 - 10).

Part of a secure boot chain is allowing grub to verify the boot
kernel. For UEFI platforms, this is usually delegated to the
shim. However, for platforms that do not implement UEFI, an
alternative scheme is required.

This part teaches grub how to verify Linux kernel-style appended
signatures. Kernels on powerpc are already signed with this scheme and
can be verified by IMA for kexec.

As PKCS#7 messages and x509 certificates are both based on ASN.1, we
import libtasn1 to parse them. Because ASN.1 isn't self-documenting,
we import from GNUTLS the information we need to navigate their
structure.

This section is composed of the following patches:

 - patch 4 is a small fix to allow persistent modules to work on the
   emu target.

 - patches 5 and 6 are small refactorings.

 - patch 7 allows x509 certificates to be built in to the grub core
   in much the same way as PGP keys.

 - patch 8 brings in the code from GNUTLS that allows us to parse
   PKCS#7 and x509 with libtasn1.

 - patch 9 is our PKCS#7 and x509 parser. They're minimal and fairly
   strict parsers that extract only the bits we need to verify the
   signatures.

 - patch 10 is the guts of the appended signature verifier. It uses
   the verifier infrastructure like pgp, and adds a number of
   user-friendly commands that mirror the pgp module.

 - patch 11 adds tests, and patch 12 adds documentation.

3.) Enable lockdown if secure boot is enabled (Patch 13)

If the 'ibm,secure-boot' property of the root node is 2 or greater,
enter lockdown.The main appended signature module now tests for lockdown to
enter 'forced' mode.

4.) Enable accessing keys dynamically from Platform KeyStore (Patch 14 - 21)

This part teaches grub how to read db and dbx variables from platform keystore
using client interface call then load keys from those two variable, and use it
to verify Linux kernel.

This section is composed of the following patches:

 - patch 14 is an exposes an interface in ieee1275 for reading secure boot variable
   db and dbx from Platform Keystore.

 - patch 15 is a read secure boot variables such as db and dbx from PKS and extract certificates from ESL.

 - patch 16 is creates the trusted and distrusted lists.

 - patch 17 is verify the kernel using trusted and distrusted lists

 - patch 18 sets the use_static_keys flag if DB not available in PKS,
   and patch 19  is reads the DB default keys from ELF Note and
   store it in trusted lists if use_static_keys flag is set.

 - patch 20 adds trusted and distrusted commands, and patch 21 adds documentation.


[1]https://www.ibm.com/docs/en/linux-on-systems?topic=servers-guest-secure-boot-static-keys
[2]https://community.ibm.com/community/user/power/blogs/chris-engel1/2020/11/20/powervm-introduces-the-platform-keystore

Alastair D'Silva (1):
  grub-install: support embedding x509 certificates

Daniel Axtens (11):
  docs/grub: Document signing grub under UEFI
  docs/grub: Document signing grub with an appended signature
  dl: provide a fake grub_dl_set_persistent for the emu target
  pgp: factor out rsa_pad
  crypto: move storage for grub_crypto_pk_* to crypto.c
  appended signatures: import GNUTLS's ASN.1 description files
  appended signatures: parse PKCS#7 signedData and X.509 certificates
  appended signatures: support verifying appended signatures
  appended signatures: verification tests
  appended signatures: documentation
  ieee1275: enter lockdown based on /ibm,secure-boot

Rashmica Gupta (1):
  powerpc-ieee1275: Add support for signing grub with an appended
    signature

Sudhakar Kuppusamy (8):
  ieee1275: Platform Keystore (PKS) Support
  ieee1275: Read the DB and DBX secure boot variables
  appendedsig: The creation of trusted and distrusted lists
  appendedsig: While verifying the kernel, use trusted and distrusted
    lists
  ieee1275: set use_static_keys flag
  appendedsig: Reads the default DB keys from ELF Note
  appendedsig: The grub command's trusted and distrusted support
  appendedsig: documentation

 docs/grub.texi                                |  295 +++-
 grub-core/Makefile.am                         |    1 +
 grub-core/Makefile.core.def                   |   30 +
 grub-core/commands/appendedsig/appendedsig.c  | 1455 +++++++++++++++++
 grub-core/commands/appendedsig/appendedsig.h  |  110 ++
 grub-core/commands/appendedsig/asn1util.c     |   99 ++
 .../commands/appendedsig/gnutls_asn1_tab.c    |  121 ++
 grub-core/commands/appendedsig/pkcs7.c        |  473 ++++++
 .../commands/appendedsig/pkix_asn1_tab.c      |  484 ++++++
 grub-core/commands/appendedsig/x509.c         |  981 +++++++++++
 grub-core/commands/pgp.c                      |   34 +-
 grub-core/kern/ieee1275/ieee1275.c            |  117 ++
 grub-core/kern/ieee1275/init.c                |   38 +
 grub-core/kern/ieee1275/platform_keystore.c   |  350 ++++
 grub-core/lib/crypto.c                        |    4 +
 grub-core/lib/pkcs1_v15.c                     |   59 +
 grub-core/tests/appended_signature_test.c     |  258 +++
 grub-core/tests/appended_signatures.h         |  975 +++++++++++
 grub-core/tests/lib/functional_test.c         |    1 +
 include/grub/dl.h                             |   11 +
 include/grub/file.h                           |    2 +
 include/grub/ieee1275/ieee1275.h              |   14 +
 include/grub/kernel.h                         |    2 +
 include/grub/lockdown.h                       |    3 +-
 include/grub/pkcs1_v15.h                      |   27 +
 include/grub/platform_keystore.h              |  235 +++
 include/grub/util/install.h                   |   10 +-
 include/grub/util/mkimage.h                   |    4 +-
 util/grub-install-common.c                    |   34 +-
 util/grub-mkimage.c                           |   25 +-
 util/grub-mkimagexx.c                         |   38 +-
 util/mkimage.c                                |   39 +-
 32 files changed, 6260 insertions(+), 69 deletions(-)
 create mode 100644 grub-core/commands/appendedsig/appendedsig.c
 create mode 100644 grub-core/commands/appendedsig/appendedsig.h
 create mode 100644 grub-core/commands/appendedsig/asn1util.c
 create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
 create mode 100644 grub-core/commands/appendedsig/pkcs7.c
 create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c
 create mode 100644 grub-core/commands/appendedsig/x509.c
 create mode 100644 grub-core/kern/ieee1275/platform_keystore.c
 create mode 100644 grub-core/lib/pkcs1_v15.c
 create mode 100644 grub-core/tests/appended_signature_test.c
 create mode 100644 grub-core/tests/appended_signatures.h
 create mode 100644 include/grub/pkcs1_v15.h
 create mode 100644 include/grub/platform_keystore.h

-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 14:58   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 02/21] docs/grub: Document signing grub under UEFI Sudhakar Kuppusamy
                   ` (19 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Rashmica Gupta, Sudhakar Kuppusamy

From: Rashmica Gupta <rashmica.g@gmail.com>

Add infrastructure to allow firmware to verify the integrity of grub
by use of a Linux-kernel-module-style appended signature. We initially
target powerpc-ieee1275, but the code should be extensible to other
platforms.

Usually these signatures are appended to a file without modifying the
ELF file itself. (This is what the 'sign-file' tool does, for example.)
The verifier loads the signed file from the file system and looks at the
end of the file for the appended signature. However, on powerpc-ieee1275
platforms, the bootloader is often stored directly in the PReP partition
as raw bytes without a file-system. This makes determining the location
of an appended signature more difficult.

To address this, we add a new ELF note.

The name field of shall be the string "Appended-Signature", zero-padded
to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
for the string "ASig"). It must be the final section in the ELF binary.

The description shall contain the appended signature structure as defined
by the Linux kernel. The description will also be padded to be a multiple
of 4 bytes. The padding shall be added before the appended signature
structure (not at the end) so that the final bytes of a signed ELF file
are the appended signature magic.

A subsequent patch documents how to create a grub core.img validly signed
under this scheme.

Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 include/grub/util/install.h |  7 +++++--
 include/grub/util/mkimage.h |  4 ++--
 util/grub-install-common.c  | 15 ++++++++++++---
 util/grub-mkimage.c         | 11 +++++++++++
 util/grub-mkimagexx.c       | 38 ++++++++++++++++++++++++++++++++++++-
 util/mkimage.c              |  6 +++---
 6 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 5c0a52ca2..3aabc4285 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -69,6 +69,8 @@
       N_("disable shim_lock verifier"), 0 },				\
   { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
     N_("disabled command line interface access"), 0 },			\
+  { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
+    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
   { "verbose", 'v', 0, 0,						\
     N_("print verbose messages."), 1 }
 
@@ -132,7 +134,8 @@ enum grub_install_options {
   GRUB_INSTALL_OPTIONS_DTB,
   GRUB_INSTALL_OPTIONS_SBAT,
   GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
-  GRUB_INSTALL_OPTIONS_DISABLE_CLI
+  GRUB_INSTALL_OPTIONS_DISABLE_CLI,
+  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
 };
 
 extern char *grub_install_source_directory;
@@ -192,7 +195,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
 			     size_t npubkeys,
 			     char *config_path,
 			     const struct grub_install_image_target_desc *image_target,
-			     int note,
+			     int note, size_t appsig_size,
 			     grub_compression_t comp, const char *dtb_file,
 			     const char *sbat_path, const int disable_shim_lock,
 			     const int disable_cli);
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
index 9d74f82c5..0d40383eb 100644
--- a/include/grub/util/mkimage.h
+++ b/include/grub/util/mkimage.h
@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
 			   const struct grub_install_image_target_desc *image_target);
 void
 grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
-			     int note, char *sbat, char **core_img, size_t *core_size,
+			     int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
 			     Elf32_Addr target_addr,
 			     struct grub_mkimage_layout *layout);
 void
 grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
-			     int note, char *sbat, char **core_img, size_t *core_size,
+			     int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
 			     Elf64_Addr target_addr,
 			     struct grub_mkimage_layout *layout);
 
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 22bccb6a3..22f0e56cb 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -467,10 +467,12 @@ static char *sbat;
 static int disable_shim_lock;
 static grub_compression_t compression;
 static int disable_cli;
+static size_t appsig_size;
 
 int
 grub_install_parse (int key, char *arg)
 {
+  const char *end;
   switch (key)
     {
     case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
@@ -571,6 +573,12 @@ grub_install_parse (int key, char *arg)
       grub_util_error (_("Unrecognized compression `%s'"), arg);
     case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
       return 1;
+    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
+      grub_errno = 0;
+      appsig_size = grub_strtol (arg, &end, 10);
+      if (grub_errno)
+        return 0;
+      return 1;
     default:
       return 0;
     }
@@ -683,9 +691,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
   *p = '\0';
 
   grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
-		  " --format '%s' --compression '%s'%s%s%s%s\n",
+		  " --format '%s' --compression '%s'"
+		  " --appended-signature-size %zu %s %s %s %s\n",
 		  dir, prefix, outname,
-		  mkimage_target, compnames[compression],
+		  mkimage_target, compnames[compression], appsig_size,
 		  note ? " --note" : "",
 		  disable_shim_lock ? " --disable-shim-lock" : "",
 		  disable_cli ? " --disable-cli" : "", s);
@@ -698,7 +707,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
   grub_install_generate_image (dir, prefix, fp, outname,
 			       modules.entries, memdisk_path,
 			       pubkeys, npubkeys, config_path, tgt,
-			       note, compression, dtb, sbat,
+			       note, appsig_size, compression, dtb, sbat,
 			       disable_shim_lock, disable_cli);
   while (dc--)
     grub_install_pop_module ();
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index 547f7310f..6c5063ac2 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -84,6 +84,7 @@ static struct argp_option options[] = {
   {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
   {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
   {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
+  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
   { 0, 0, 0, 0, 0, 0 }
 };
@@ -130,6 +131,7 @@ struct arguments
   int note;
   int disable_shim_lock;
   int disable_cli;
+  size_t appsig_size;
   const struct grub_install_image_target_desc *image_target;
   grub_compression_t comp;
 };
@@ -140,6 +142,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
   /* Get the input argument from argp_parse, which we
      know is a pointer to our arguments structure. */
   struct arguments *arguments = state->input;
+  const char* end;
 
   switch (key)
     {
@@ -172,6 +175,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
       arguments->note = 1;
       break;
 
+    case 'S':
+      grub_errno = 0;
+      arguments->appsig_size = grub_strtol (arg, &end, 10);
+      if (grub_errno)
+        return 0;
+      break;
+
     case 'm':
       if (arguments->memdisk)
 	free (arguments->memdisk);
@@ -330,6 +340,7 @@ main (int argc, char *argv[])
 			       arguments.memdisk, arguments.pubkeys,
 			       arguments.npubkeys, arguments.config,
 			       arguments.image_target, arguments.note,
+			       arguments.appsig_size,
 			       arguments.comp, arguments.dtb,
 			       arguments.sbat, arguments.disable_shim_lock,
 			       arguments.disable_cli);
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index 448862b2e..6fe348e5b 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -115,6 +115,14 @@ struct grub_sbat_note {
   char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
 };
 
+#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
+#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
+struct grub_appended_signature_note
+{
+  Elf32_Nhdr header;
+  char name[ALIGN_UP (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
+};
+
 static int
 is_relocatable (const struct grub_install_image_target_desc *image_target)
 {
@@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
 
 void
 SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
-				    int note, char *sbat, char **core_img, size_t *core_size,
+				    int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
 				    Elf_Addr target_addr,
 				    struct grub_mkimage_layout *layout)
 {
@@ -237,6 +245,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
       footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
     }
 
+  if (appsig_size)
+    {
+      phnum++;
+      footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+    }
+
   if (image_target->id != IMAGE_LOONGSON_ELF)
     phnum += 2;
 
@@ -527,6 +541,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
       phdr->p_filesz = grub_host_to_target32 (note_size);
       phdr->p_memsz = 0;
       phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
+      footer += note_size;
+      footer_offset += note_size;
+    }
+
+  if (appsig_size)
+    {
+      int note_size = ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+      struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) footer;
+      note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
+      /* needs to sit at the end, so we round this up and sign some zero padding */
+      note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP (appsig_size, 4));
+      note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
+      strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
+      phdr++;
+      phdr->p_type = grub_host_to_target32 (PT_NOTE);
+      phdr->p_flags = grub_host_to_target32 (PF_R);
+      phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+      phdr->p_vaddr = 0;
+      phdr->p_paddr = 0;
+      phdr->p_filesz = grub_host_to_target32 (note_size);
+      phdr->p_memsz = 0;
+      phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
     }
 
   {
diff --git a/util/mkimage.c b/util/mkimage.c
index b46df2909..f5c59f563 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -885,7 +885,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
 			     char *memdisk_path, char **pubkey_paths,
 			     size_t npubkeys, char *config_path,
 			     const struct grub_install_image_target_desc *image_target,
-			     int note, grub_compression_t comp, const char *dtb_path,
+			     int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path,
 			     const char *sbat_path, int disable_shim_lock,
 			     int disable_cli)
 {
@@ -1833,10 +1833,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
 	else
 	  target_addr = image_target->link_addr;
 	if (image_target->voidp_sizeof == 4)
-	  grub_mkimage_generate_elf32 (image_target, note, sbat, &core_img, &core_size,
+	  grub_mkimage_generate_elf32 (image_target, note, sbat, appsig_size, &core_img, &core_size,
 				       target_addr, &layout);
 	else
-	  grub_mkimage_generate_elf64 (image_target, note, sbat, &core_img, &core_size,
+	  grub_mkimage_generate_elf64 (image_target, note, sbat, appsig_size, &core_img, &core_size,
 				       target_addr, &layout);
       }
       break;
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 02/21] docs/grub: Document signing grub under UEFI
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
  2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 15:00   ` Stefan Berger
  2024-12-18 14:56 ` [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature Sudhakar Kuppusamy
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

Before adding information about how grub is signed with an appended
signature scheme, it's worth adding some information about how it
can currently be signed for UEFI.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 docs/grub.texi | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 200e747af..c07d5d0dc 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -8572,6 +8572,7 @@ environment variables and commands are listed in the same order.
 * Measured Boot::                    Measuring boot components
 * Lockdown::                         Lockdown when booting on a secure setup
 * TPM2 key protector::               Managing disk key with TPM2 key protector
+* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
 @end menu
 
 @node Authentication and authorisation
@@ -8652,7 +8653,7 @@ commands.
 
 GRUB's @file{core.img} can optionally provide enforcement that all files
 subsequently read from disk are covered by a valid digital signature.
-This document does @strong{not} cover how to ensure that your
+This section does @strong{not} cover how to ensure that your
 platform's firmware (e.g., Coreboot) validates @file{core.img}.
 
 If environment variable @code{check_signatures}
@@ -9119,6 +9120,21 @@ command through the swtpm control channel.
 # @kbd{swtpm_ioctl -s --unix swtpm-state/ctrl}
 @end example
 
+@node Signing GRUB itself
+@section Signing GRUB itself
+To ensure a complete secure-boot chain, there must be a way for the code that
+loads GRUB to verify the integrity of the core image.
+This is ultimately platform-specific and individual platforms can define their
+own mechanisms. However, there are general-purpose mechanisms that can be used
+with GRUB.
+@section Signing GRUB for UEFI secure boot
+On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
+with a tool such as @command{pesign} or @command{sbsign}. Refer to the
+suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
+image works under UEFI secure boot and can maintain the secure-boot chain. It
+will also be necessary to enrol the public key used into a relevant firmware
+key database.
+
 @node Platform limitations
 @chapter Platform limitations
 
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
  2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
  2024-12-18 14:56 ` [PATCH v1 02/21] docs/grub: Document signing grub under UEFI Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 15:04   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target Sudhakar Kuppusamy
                   ` (17 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

Signing grub for firmware that verifies an appended signature is a
bit fiddly. I don't want people to have to figure it out from scratch
so document it here.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/docs/grub.texi b/docs/grub.texi
index c07d5d0dc..6e483298d 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -9135,6 +9135,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It
 will also be necessary to enrol the public key used into a relevant firmware
 key database.
 
+@section Signing GRUB with an appended signature
+
+The @file{core.img} itself can be signed with a Linux kernel module-style
+appended signature.
+
+To support IEEE1275 platforms where the boot image is often loaded directly
+from a disk partition rather than from a file system, the @file{core.img}
+can specify the size and location of the appended signature with an ELF
+note added by @command{grub-install}.
+
+An image can be signed this way using the @command{sign-file} command from
+the Linux kernel:
+
+@example
+@group
+# grub.key is your private key and certificate.der is your public key
+
+# Determine the size of the appended signature. It depends on the signing
+# certificate and the hash algorithm
+touch empty
+sign-file SHA256 grub.key certificate.der empty empty.sig
+SIG_SIZE=`stat -c '%s' empty.sig`
+rm empty empty.sig
+
+# Build a grub image with $SIG_SIZE reserved for the signature
+grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
+
+# Replace the reserved size with a signature:
+# cut off the last $SIG_SIZE bytes with truncate's minus modifier
+truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
+# sign the trimmed file with an appended signature, restoring the correct size
+sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
+
+# Don't forget to install the signed image as required
+# (e.g. on powerpc-ieee1275, to the PReP partition)
+@end group
+@end example
+
+As with UEFI secure boot, it is necessary to build in the required modules,
+or sign them separately.
+
+
 @node Platform limitations
 @chapter Platform limitations
 
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (2 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 15:06   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 05/21] pgp: factor out rsa_pad Sudhakar Kuppusamy
                   ` (16 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

Trying to start grub-emu with a module that calls grub_dl_set_persistent
will crash because grub-emu fakes modules and passes NULL to the module
init function.

Provide an empty function for the emu case.

Fixes: ee7808e2197c (dl: Add support for persistent modules)
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 include/grub/dl.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/grub/dl.h b/include/grub/dl.h
index 750fc8d3d..fb4476797 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -242,11 +242,22 @@ grub_dl_get (const char *name)
   return 0;
 }
 
+#ifdef GRUB_MACHINE_EMU
+/*
+ * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT.
+ * So we fake this out to avoid a NULL deref.
+ */
+static inline void
+grub_dl_set_persistent (grub_dl_t mod __attribute__((unused)))
+{
+}
+#else
 static inline void
 grub_dl_set_persistent (grub_dl_t mod)
 {
   mod->persistent = 1;
 }
+#endif
 
 static inline int
 grub_dl_is_persistent (grub_dl_t mod)
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 05/21] pgp: factor out rsa_pad
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (3 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 15:11   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
                   ` (15 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
We want to use it in other RSA signature verification applications.

I considered and rejected putting it in lib/crypto.c. That file doesn't
currently require any MPI functions, but rsa_pad does. That's not so
much of a problem for the grub kernel and modules, but crypto.c also
gets built into all the grub utilities. So - despite the utils not
using any asymmetric ciphers -  we would need to built the entire MPI
infrastructure in to them.

A better and simpler solution is just to spin rsa_pad out into its own
PKCS#1 v1.5 module.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/Makefile.core.def |  8 +++++
 grub-core/commands/pgp.c    | 28 ++----------------
 grub-core/lib/pkcs1_v15.c   | 59 +++++++++++++++++++++++++++++++++++++
 include/grub/pkcs1_v15.h    | 27 +++++++++++++++++
 4 files changed, 96 insertions(+), 26 deletions(-)
 create mode 100644 grub-core/lib/pkcs1_v15.c
 create mode 100644 include/grub/pkcs1_v15.h

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f70e02e69..60db2adc5 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2540,6 +2540,14 @@ module = {
   cppflags = '$(CPPFLAGS_GCRY)';
 };
 
+module = {
+  name = pkcs1_v15;
+  common = lib/pkcs1_v15.c;
+
+  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+  cppflags = '$(CPPFLAGS_GCRY)';
+};
+
 module = {
   name = all_video;
   common = lib/fake_module.c;
diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
index c6766f044..b084dc9a2 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -24,6 +24,7 @@
 #include <grub/file.h>
 #include <grub/command.h>
 #include <grub/crypto.h>
+#include <grub/pkcs1_v15.h>
 #include <grub/i18n.h>
 #include <grub/gcrypt/gcrypt.h>
 #include <grub/pubkey.h>
@@ -411,32 +412,7 @@ static int
 rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
 	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
 {
-  grub_size_t tlen, emlen, fflen;
-  grub_uint8_t *em, *emptr;
-  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
-  int ret;
-  tlen = hash->mdlen + hash->asnlen;
-  emlen = (nbits + 7) / 8;
-  if (emlen < tlen + 11)
-    return 1;
-
-  em = grub_malloc (emlen);
-  if (!em)
-    return 1;
-
-  em[0] = 0x00;
-  em[1] = 0x01;
-  fflen = emlen - tlen - 3;
-  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
-    *emptr = 0xff;
-  *emptr++ = 0x00;
-  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
-  emptr += hash->asnlen;
-  grub_memcpy (emptr, hval, hash->mdlen);
-
-  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
-  grub_free (em);
-  return ret;
+  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
 }
 
 struct grub_pubkey_context
diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
new file mode 100644
index 000000000..dbacd563d
--- /dev/null
+++ b/grub-core/lib/pkcs1_v15.c
@@ -0,0 +1,59 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  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/dl.h>
+#include <grub/gcrypt/gcrypt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/*
+ * Given a hash value 'hval', of hash specification 'hash', perform
+ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
+ * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
+ */
+gcry_err_code_t
+grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
+		     const gcry_md_spec_t * hash, gcry_mpi_t mod)
+{
+  grub_size_t tlen, emlen, fflen;
+  grub_uint8_t *em, *emptr;
+  unsigned nbits = gcry_mpi_get_nbits (mod);
+  int ret;
+  tlen = hash->mdlen + hash->asnlen;
+  emlen = (nbits + 7) / 8;
+  if (emlen < tlen + 11)
+    return GPG_ERR_TOO_SHORT;
+
+  em = grub_malloc (emlen);
+  if (!em)
+    return 1;
+
+  em[0] = 0x00;
+  em[1] = 0x01;
+  fflen = emlen - tlen - 3;
+  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
+    *emptr = 0xff;
+  *emptr++ = 0x00;
+  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
+  emptr += hash->asnlen;
+  grub_memcpy (emptr, hval, hash->mdlen);
+
+  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
+  grub_free (em);
+  return ret;
+}
diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
new file mode 100644
index 000000000..5c338c84a
--- /dev/null
+++ b/include/grub/pkcs1_v15.h
@@ -0,0 +1,27 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  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/>.
+ */
+
+/*
+ * Given a hash value 'hval', of hash specification 'hash', perform
+ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
+ * (See RFC 8017 s 9.2)
+ */
+gcry_err_code_t
+grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
+		     const gcry_md_spec_t * hash, gcry_mpi_t mod);
+
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (4 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 05/21] pgp: factor out rsa_pad Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 15:13   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 07/21] grub-install: support embedding x509 certificates Sudhakar Kuppusamy
                   ` (14 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the
pgp module is a bit quirky.

include/grub/crypto.h contains:
  extern struct gcry_pk_spec *grub_crypto_pk_rsa;

commands/pgp.c contains the actual storage:
  struct gcry_pk_spec *grub_crypto_pk_rsa;

And the module itself saves to the storage in pgp.c:
  GRUB_MOD_INIT(gcry_rsa)
  {
    grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa;
  }

This is annoying: gcry_rsa now has a dependency on pgp!

We want to be able to bring in gcry_rsa without bringing in PGP,
so move the storage to crypto.c.

Previously, gcry_rsa depended on pgp and mpi. Now it depends on
crypto and mpi. As pgp depends on crypto, this doesn't add any new
module dependencies using the PGP verfier.

[FWIW, the story is different for the symmetric ciphers. cryptodisk
and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name()
to get a cipher handle. That depends on grub_ciphers being populated
by people calling grub_cipher_register. import_gcry.py ensures that the
symmetric ciphers call it.]

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/commands/pgp.c | 4 ----
 grub-core/lib/crypto.c   | 4 ++++
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
index b084dc9a2..a45c2213c 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -147,10 +147,6 @@ const char *hashes[] = {
   [0x0b] = "sha224"
 };
 
-struct gcry_pk_spec *grub_crypto_pk_dsa;
-struct gcry_pk_spec *grub_crypto_pk_ecdsa;
-struct gcry_pk_spec *grub_crypto_pk_rsa;
-
 static int
 dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
 	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
index 396f76410..d53ddbe2c 100644
--- a/grub-core/lib/crypto.c
+++ b/grub-core/lib/crypto.c
@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
       }
 }
 
+struct gcry_pk_spec *grub_crypto_pk_dsa;
+struct gcry_pk_spec *grub_crypto_pk_ecdsa;
+struct gcry_pk_spec *grub_crypto_pk_rsa;
+
 void
 grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
 		  grub_size_t inlen)
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 07/21] grub-install: support embedding x509 certificates
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (5 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-27 16:08   ` Stefan Berger
  2025-01-24 10:45   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files Sudhakar Kuppusamy
                   ` (13 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Alastair D'Silva, Sudhakar Kuppusamy

From: Alastair D'Silva <alastair@d-silva.org>

To support verification of appended signatures, we need a way to
embed the necessary public keys. Existing appended signature schemes
in the Linux kernel use X.509 certificates, so allow certificates to
be embedded in the grub core image in the same way as PGP keys.

Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/commands/pgp.c    |  2 +-
 include/grub/kernel.h       |  2 ++
 include/grub/util/install.h |  3 +++
 util/grub-install-common.c  | 19 ++++++++++++++++++-
 util/grub-mkimage.c         | 14 ++++++++++++--
 util/mkimage.c              | 33 +++++++++++++++++++++++++++++++--
 6 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
index a45c2213c..847a5046a 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
     grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
 
     /* Not an ELF module, skip.  */
-    if (header->type != OBJ_TYPE_PUBKEY)
+    if (header->type != OBJ_TYPE_GPG_PUBKEY)
       continue;
 
     pseudo_file.fs = &pseudo_fs;
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index 6121c1e66..5c5ac129d 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -29,6 +29,8 @@ enum
   OBJ_TYPE_CONFIG,
   OBJ_TYPE_PREFIX,
   OBJ_TYPE_PUBKEY,
+  OBJ_TYPE_GPG_PUBKEY,
+  OBJ_TYPE_X509_PUBKEY,
   OBJ_TYPE_DTB,
   OBJ_TYPE_DISABLE_SHIM_LOCK,
   OBJ_TYPE_DISABLE_CLI
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 3aabc4285..52a667c37 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -69,6 +69,8 @@
       N_("disable shim_lock verifier"), 0 },				\
   { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
     N_("disabled command line interface access"), 0 },			\
+  { "x509key",   'x', N_("FILE"), 0,					\
+      N_("embed FILE as an x509 certificate for signature checking"), 0}, \
   { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
     "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
   { "verbose", 'v', 0, 0,						\
@@ -193,6 +195,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
 			     const char *outname, char *mods[],
 			     char *memdisk_path, char **pubkey_paths,
 			     size_t npubkeys,
+			     char **x509key_paths, size_t nx509keys,
 			     char *config_path,
 			     const struct grub_install_image_target_desc *image_target,
 			     int note, size_t appsig_size,
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 22f0e56cb..29c45e26e 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -463,6 +463,8 @@ handle_install_list (struct install_list *il, const char *val,
 
 static char **pubkeys;
 static size_t npubkeys;
+static char **x509keys;
+static size_t nx509keys;
 static char *sbat;
 static int disable_shim_lock;
 static grub_compression_t compression;
@@ -510,6 +512,10 @@ grub_install_parse (int key, char *arg)
     case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
       disable_cli = 1;
       return 1;
+    case 'x':
+      x509keys = xrealloc (x509keys, sizeof (x509keys[0]) * (nx509keys + 1));
+      x509keys[nx509keys++] = xstrdup (arg);
+      return 1;
 
     case GRUB_INSTALL_OPTIONS_VERBOSITY:
       verbosity++;
@@ -640,6 +646,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
     slen += sizeof (" --pubkey ''") + grub_strlen (*pk);
 
+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
+    slen += sizeof (" --x509key ''") + grub_strlen (*pk);
+
   for (md = modules.entries; *md; md++)
     slen += sizeof (" ''") + grub_strlen (*md);
 
@@ -680,6 +689,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
       *p++ = '\'';
     }
 
+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
+    {
+      p = grub_stpcpy (p, "--x509key '");
+      p = grub_stpcpy (p, *pk);
+      *p++ = '\'';
+      *p++ = ' ';
+    }
+
   for (md = modules.entries; *md; md++)
     {
       *p++ = ' ';
@@ -706,7 +723,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
 
   grub_install_generate_image (dir, prefix, fp, outname,
 			       modules.entries, memdisk_path,
-			       pubkeys, npubkeys, config_path, tgt,
+			       pubkeys, npubkeys,  x509keys, nx509keys, config_path, tgt,
 			       note, appsig_size, compression, dtb, sbat,
 			       disable_shim_lock, disable_cli);
   while (dc--)
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index 6c5063ac2..1f958e04b 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -75,7 +75,8 @@ static struct argp_option options[] = {
    /* TRANSLATORS: "embed" is a verb (command description).  "*/
   {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
    /* TRANSLATORS: "embed" is a verb (command description).  "*/
-  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0},
+  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0},
+  {"x509key",     'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
   /* TRANSLATORS: NOTE is a name of segment.  */
   {"note",   'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
   {"output",  'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
@@ -125,6 +126,8 @@ struct arguments
   char *dtb;
   char **pubkeys;
   size_t npubkeys;
+  char **x509keys;
+  size_t nx509keys;
   char *font;
   char *config;
   char *sbat;
@@ -208,6 +211,12 @@ argp_parser (int key, char *arg, struct argp_state *state)
       arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg);
       break;
 
+    case 'x':
+      arguments->x509keys = xrealloc (arguments->x509keys,
+                                      sizeof (arguments->x509keys[0]) * (arguments->nx509keys + 1));
+      arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
+      break;
+
     case 'c':
       if (arguments->config)
 	free (arguments->config);
@@ -338,7 +347,8 @@ main (int argc, char *argv[])
   grub_install_generate_image (arguments.dir, arguments.prefix, fp,
 			       arguments.output, arguments.modules,
 			       arguments.memdisk, arguments.pubkeys,
-			       arguments.npubkeys, arguments.config,
+			       arguments.npubkeys, arguments.x509keys,
+			       arguments.nx509keys, arguments.config,
 			       arguments.image_target, arguments.note,
 			       arguments.appsig_size,
 			       arguments.comp, arguments.dtb,
diff --git a/util/mkimage.c b/util/mkimage.c
index f5c59f563..7076d632b 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -883,7 +883,7 @@ void
 grub_install_generate_image (const char *dir, const char *prefix,
 			     FILE *out, const char *outname, char *mods[],
 			     char *memdisk_path, char **pubkey_paths,
-			     size_t npubkeys, char *config_path,
+			     size_t npubkeys, char **x509key_paths, size_t nx509keys, char *config_path,
 			     const struct grub_install_image_target_desc *image_target,
 			     int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path,
 			     const char *sbat_path, int disable_shim_lock,
@@ -929,6 +929,18 @@ grub_install_generate_image (const char *dir, const char *prefix,
       }
   }
 
+  {
+    size_t i;
+    for (i = 0; i < nx509keys; i++)
+      {
+        size_t curs;
+        curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
+        grub_util_info ("the size of x509 public key %u is 0x%" GRUB_HOST_PRIxLONG_LONG,
+                        (unsigned) i, (unsigned long long) curs);
+        total_module_size += curs + sizeof (struct grub_module_header);
+      }
+  }
+
   if (memdisk_path)
     {
       memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
@@ -1053,7 +1065,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
 	curs = grub_util_get_image_size (pubkey_paths[i]);
 
 	header = (struct grub_module_header *) (kernel_img + offset);
-	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
+	header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY);
 	header->size = grub_host_to_target32 (curs + sizeof (*header));
 	offset += sizeof (*header);
 
@@ -1062,6 +1074,23 @@ grub_install_generate_image (const char *dir, const char *prefix,
       }
   }
 
+  {
+    size_t i;
+    for (i = 0; i < nx509keys; i++)
+      {
+        size_t curs;
+        struct grub_module_header *header;
+
+        curs = grub_util_get_image_size (x509key_paths[i]);
+        header = (struct grub_module_header *) (kernel_img + offset);
+        header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
+        header->size = grub_host_to_target32 (curs + sizeof (*header));
+        offset += sizeof (*header);
+        grub_util_load_image (x509key_paths[i], kernel_img + offset);
+        offset += ALIGN_ADDR (curs);
+      }
+  }
+
   if (memdisk_path)
     {
       struct grub_module_header *header;
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (6 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 07/21] grub-install: support embedding x509 certificates Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-28 19:02   ` Stefan Berger
  2025-01-24 10:47   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates Sudhakar Kuppusamy
                   ` (12 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

In order to parse PKCS#7 messages and X.509 certificates with libtasn1,
we need some information about how they are encoded.

We get these from GNUTLS, which has the benefit that they support the
features we need and are well tested.

The GNUTLS files are from:

- https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/gnutls_asn1_tab.c
- https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/pkix_asn1_tab.c

The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing
us to import it without issue.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 .../commands/appendedsig/gnutls_asn1_tab.c    | 121 +++++
 .../commands/appendedsig/pkix_asn1_tab.c      | 484 ++++++++++++++++++
 2 files changed, 605 insertions(+)
 create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
 create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c

diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
new file mode 100644
index 000000000..ddd1314e6
--- /dev/null
+++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
@@ -0,0 +1,121 @@
+#include <grub/mm.h>
+#include <grub/libtasn1.h>
+
+const asn1_static_node gnutls_asn1_tab[] = {
+  { "GNUTLS", 536872976, NULL },
+  { NULL, 1073741836, NULL },
+  { "RSAPublicKey", 1610612741, NULL },
+  { "modulus", 1073741827, NULL },
+  { "publicExponent", 3, NULL },
+  { "RSAPrivateKey", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "modulus", 1073741827, NULL },
+  { "publicExponent", 1073741827, NULL },
+  { "privateExponent", 1073741827, NULL },
+  { "prime1", 1073741827, NULL },
+  { "prime2", 1073741827, NULL },
+  { "exponent1", 1073741827, NULL },
+  { "exponent2", 1073741827, NULL },
+  { "coefficient", 1073741827, NULL },
+  { "otherPrimeInfos", 16386, "OtherPrimeInfos"},
+  { "ProvableSeed", 1610612741, NULL },
+  { "algorithm", 1073741836, NULL },
+  { "seed", 7, NULL },
+  { "OtherPrimeInfos", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "OtherPrimeInfo"},
+  { "OtherPrimeInfo", 1610612741, NULL },
+  { "prime", 1073741827, NULL },
+  { "exponent", 1073741827, NULL },
+  { "coefficient", 3, NULL },
+  { "AlgorithmIdentifier", 1610612741, NULL },
+  { "algorithm", 1073741836, NULL },
+  { "parameters", 541081613, NULL },
+  { "algorithm", 1, NULL },
+  { "DigestInfo", 1610612741, NULL },
+  { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
+  { "digest", 7, NULL },
+  { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
+  { "DSAPublicKey", 1073741827, NULL },
+  { "DSAParameters", 1610612741, NULL },
+  { "p", 1073741827, NULL },
+  { "q", 1073741827, NULL },
+  { "g", 3, NULL },
+  { "DSASignatureValue", 1610612741, NULL },
+  { "r", 1073741827, NULL },
+  { "s", 3, NULL },
+  { "DSAPrivateKey", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "p", 1073741827, NULL },
+  { "q", 1073741827, NULL },
+  { "g", 1073741827, NULL },
+  { "Y", 1073741827, NULL },
+  { "priv", 3, NULL },
+  { "DHParameter", 1610612741, NULL },
+  { "prime", 1073741827, NULL },
+  { "base", 1073741827, NULL },
+  { "privateValueLength", 16387, NULL },
+  { "ECParameters", 1610612754, NULL },
+  { "namedCurve", 12, NULL },
+  { "ECPrivateKey", 1610612741, NULL },
+  { "Version", 1073741827, NULL },
+  { "privateKey", 1073741831, NULL },
+  { "parameters", 1610637314, "ECParameters"},
+  { NULL, 2056, "0"},
+  { "publicKey", 536895494, NULL },
+  { NULL, 2056, "1"},
+  { "PrincipalName", 1610612741, NULL },
+  { "name-type", 1610620931, NULL },
+  { NULL, 2056, "0"},
+  { "name-string", 536879115, NULL },
+  { NULL, 1073743880, "1"},
+  { NULL, 27, NULL },
+  { "KRB5PrincipalName", 1610612741, NULL },
+  { "realm", 1610620955, NULL },
+  { NULL, 2056, "0"},
+  { "principalName", 536879106, "PrincipalName"},
+  { NULL, 2056, "1"},
+  { "RSAPSSParameters", 1610612741, NULL },
+  { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
+  { NULL, 2056, "0"},
+  { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
+  { NULL, 2056, "1"},
+  { "saltLength", 1610653699, NULL },
+  { NULL, 1073741833, "20"},
+  { NULL, 2056, "2"},
+  { "trailerField", 536911875, NULL },
+  { NULL, 1073741833, "1"},
+  { NULL, 2056, "3"},
+  { "GOSTParameters", 1610612741, NULL },
+  { "publicKeyParamSet", 1073741836, NULL },
+  { "digestParamSet", 16396, NULL },
+  { "GOSTParametersOld", 1610612741, NULL },
+  { "publicKeyParamSet", 1073741836, NULL },
+  { "digestParamSet", 1073741836, NULL },
+  { "encryptionParamSet", 16396, NULL },
+  { "GOSTPrivateKey", 1073741831, NULL },
+  { "GOSTPrivateKeyOld", 1073741827, NULL },
+  { "IssuerSignTool", 1610612741, NULL },
+  { "signTool", 1073741858, NULL },
+  { "cATool", 1073741858, NULL },
+  { "signToolCert", 1073741858, NULL },
+  { "cAToolCert", 34, NULL },
+  { "Gost28147-89-EncryptedKey", 1610612741, NULL },
+  { "encryptedKey", 1073741831, NULL },
+  { "maskKey", 1610637319, NULL },
+  { NULL, 4104, "0"},
+  { "macKey", 7, NULL },
+  { "SubjectPublicKeyInfo", 1610612741, NULL },
+  { "algorithm", 1073741826, "AlgorithmIdentifier"},
+  { "subjectPublicKey", 6, NULL },
+  { "GostR3410-TransportParameters", 1610612741, NULL },
+  { "encryptionParamSet", 1073741836, NULL },
+  { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
+  { NULL, 4104, "0"},
+  { "ukm", 7, NULL },
+  { "GostR3410-KeyTransport", 536870917, NULL },
+  { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
+  { "transportParameters", 536895490, "GostR3410-TransportParameters"},
+  { NULL, 4104, "0"},
+  { NULL, 0, NULL }
+};
diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
new file mode 100644
index 000000000..adef69d95
--- /dev/null
+++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
@@ -0,0 +1,484 @@
+#include <grub/mm.h>
+#include <grub/libtasn1.h>
+
+const asn1_static_node pkix_asn1_tab[] = {
+  { "PKIX1", 536875024, NULL },
+  { NULL, 1073741836, NULL },
+  { "PrivateKeyUsagePeriod", 1610612741, NULL },
+  { "notBefore", 1610637349, NULL },
+  { NULL, 4104, "0"},
+  { "notAfter", 536895525, NULL },
+  { NULL, 4104, "1"},
+  { "AuthorityKeyIdentifier", 1610612741, NULL },
+  { "keyIdentifier", 1610637319, NULL },
+  { NULL, 4104, "0"},
+  { "authorityCertIssuer", 1610637314, "GeneralNames"},
+  { NULL, 4104, "1"},
+  { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"},
+  { NULL, 4104, "2"},
+  { "SubjectKeyIdentifier", 1073741831, NULL },
+  { "KeyUsage", 1073741830, NULL },
+  { "DirectoryString", 1610612754, NULL },
+  { "teletexString", 1612709918, NULL },
+  { "MAX", 524298, "1"},
+  { "printableString", 1612709919, NULL },
+  { "MAX", 524298, "1"},
+  { "universalString", 1612709920, NULL },
+  { "MAX", 524298, "1"},
+  { "utf8String", 1612709922, NULL },
+  { "MAX", 524298, "1"},
+  { "bmpString", 1612709921, NULL },
+  { "MAX", 524298, "1"},
+  { "ia5String", 538968093, NULL },
+  { "MAX", 524298, "1"},
+  { "SubjectAltName", 1073741826, "GeneralNames"},
+  { "GeneralNames", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "GeneralName"},
+  { "GeneralName", 1610612754, NULL },
+  { "otherName", 1610620930, "AnotherName"},
+  { NULL, 4104, "0"},
+  { "rfc822Name", 1610620957, NULL },
+  { NULL, 4104, "1"},
+  { "dNSName", 1610620957, NULL },
+  { NULL, 4104, "2"},
+  { "x400Address", 1610620941, NULL },
+  { NULL, 4104, "3"},
+  { "directoryName", 1610620939, NULL },
+  { NULL, 1073743880, "4"},
+  { NULL, 2, "RelativeDistinguishedName"},
+  { "ediPartyName", 1610620941, NULL },
+  { NULL, 4104, "5"},
+  { "uniformResourceIdentifier", 1610620957, NULL },
+  { NULL, 4104, "6"},
+  { "iPAddress", 1610620935, NULL },
+  { NULL, 4104, "7"},
+  { "registeredID", 536879116, NULL },
+  { NULL, 4104, "8"},
+  { "AnotherName", 1610612741, NULL },
+  { "type-id", 1073741836, NULL },
+  { "value", 541073421, NULL },
+  { NULL, 1073743880, "0"},
+  { "type-id", 1, NULL },
+  { "IssuerAltName", 1073741826, "GeneralNames"},
+  { "BasicConstraints", 1610612741, NULL },
+  { "cA", 1610645508, NULL },
+  { NULL, 131081, NULL },
+  { "pathLenConstraint", 537411587, NULL },
+  { "0", 10, "MAX"},
+  { "CRLDistributionPoints", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "DistributionPoint"},
+  { "DistributionPoint", 1610612741, NULL },
+  { "distributionPoint", 1610637314, "DistributionPointName"},
+  { NULL, 2056, "0"},
+  { "reasons", 1610637314, "ReasonFlags"},
+  { NULL, 4104, "1"},
+  { "cRLIssuer", 536895490, "GeneralNames"},
+  { NULL, 4104, "2"},
+  { "DistributionPointName", 1610612754, NULL },
+  { "fullName", 1610620930, "GeneralNames"},
+  { NULL, 4104, "0"},
+  { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"},
+  { NULL, 4104, "1"},
+  { "ReasonFlags", 1073741830, NULL },
+  { "ExtKeyUsageSyntax", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 12, NULL },
+  { "AuthorityInfoAccessSyntax", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "AccessDescription"},
+  { "AccessDescription", 1610612741, NULL },
+  { "accessMethod", 1073741836, NULL },
+  { "accessLocation", 2, "GeneralName"},
+  { "Attribute", 1610612741, NULL },
+  { "type", 1073741836, NULL },
+  { "values", 536870927, NULL },
+  { NULL, 13, NULL },
+  { "AttributeTypeAndValue", 1610612741, NULL },
+  { "type", 1073741836, NULL },
+  { "value", 13, NULL },
+  { "Name", 1610612754, NULL },
+  { "rdnSequence", 536870923, NULL },
+  { NULL, 2, "RelativeDistinguishedName"},
+  { "DistinguishedName", 1610612747, NULL },
+  { NULL, 2, "RelativeDistinguishedName"},
+  { "RelativeDistinguishedName", 1612709903, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "AttributeTypeAndValue"},
+  { "Certificate", 1610612741, NULL },
+  { "tbsCertificate", 1073741826, "TBSCertificate"},
+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signature", 6, NULL },
+  { "TBSCertificate", 1610612741, NULL },
+  { "version", 1610653699, NULL },
+  { NULL, 1073741833, "0"},
+  { NULL, 2056, "0"},
+  { "serialNumber", 1073741826, "CertificateSerialNumber"},
+  { "signature", 1073741826, "AlgorithmIdentifier"},
+  { "issuer", 1073741826, "Name"},
+  { "validity", 1073741826, "Validity"},
+  { "subject", 1073741826, "Name"},
+  { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
+  { "issuerUniqueID", 1610637314, "UniqueIdentifier"},
+  { NULL, 4104, "1"},
+  { "subjectUniqueID", 1610637314, "UniqueIdentifier"},
+  { NULL, 4104, "2"},
+  { "extensions", 536895490, "Extensions"},
+  { NULL, 2056, "3"},
+  { "CertificateSerialNumber", 1073741827, NULL },
+  { "Validity", 1610612741, NULL },
+  { "notBefore", 1073741826, "Time"},
+  { "notAfter", 2, "Time"},
+  { "Time", 1610612754, NULL },
+  { "utcTime", 1073741860, NULL },
+  { "generalTime", 37, NULL },
+  { "UniqueIdentifier", 1073741830, NULL },
+  { "SubjectPublicKeyInfo", 1610612741, NULL },
+  { "algorithm", 1073741826, "AlgorithmIdentifier"},
+  { "subjectPublicKey", 6, NULL },
+  { "Extensions", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "Extension"},
+  { "Extension", 1610612741, NULL },
+  { "extnID", 1073741836, NULL },
+  { "critical", 1610645508, NULL },
+  { NULL, 131081, NULL },
+  { "extnValue", 7, NULL },
+  { "CertificateList", 1610612741, NULL },
+  { "tbsCertList", 1073741826, "TBSCertList"},
+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signature", 6, NULL },
+  { "TBSCertList", 1610612741, NULL },
+  { "version", 1073758211, NULL },
+  { "signature", 1073741826, "AlgorithmIdentifier"},
+  { "issuer", 1073741826, "Name"},
+  { "thisUpdate", 1073741826, "Time"},
+  { "nextUpdate", 1073758210, "Time"},
+  { "revokedCertificates", 1610629131, NULL },
+  { NULL, 536870917, NULL },
+  { "userCertificate", 1073741826, "CertificateSerialNumber"},
+  { "revocationDate", 1073741826, "Time"},
+  { "crlEntryExtensions", 16386, "Extensions"},
+  { "crlExtensions", 536895490, "Extensions"},
+  { NULL, 2056, "0"},
+  { "AlgorithmIdentifier", 1610612741, NULL },
+  { "algorithm", 1073741836, NULL },
+  { "parameters", 541081613, NULL },
+  { "algorithm", 1, NULL },
+  { "Dss-Sig-Value", 1610612741, NULL },
+  { "r", 1073741827, NULL },
+  { "s", 3, NULL },
+  { "Dss-Parms", 1610612741, NULL },
+  { "p", 1073741827, NULL },
+  { "q", 1073741827, NULL },
+  { "g", 3, NULL },
+  { "pkcs-7-ContentInfo", 1610612741, NULL },
+  { "contentType", 1073741836, NULL },
+  { "content", 541073421, NULL },
+  { NULL, 1073743880, "0"},
+  { "contentType", 1, NULL },
+  { "pkcs-7-DigestInfo", 1610612741, NULL },
+  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "digest", 7, NULL },
+  { "pkcs-7-SignedData", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"},
+  { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
+  { "certificates", 1610637314, "pkcs-7-CertificateSet"},
+  { NULL, 4104, "0"},
+  { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
+  { NULL, 4104, "1"},
+  { "signerInfos", 2, "pkcs-7-SignerInfos"},
+  { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
+  { NULL, 2, "AlgorithmIdentifier"},
+  { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
+  { "eContentType", 1073741836, NULL },
+  { "eContent", 536895501, NULL },
+  { NULL, 2056, "0"},
+  { "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
+  { NULL, 13, NULL },
+  { "pkcs-7-CertificateChoices", 1610612754, NULL },
+  { "certificate", 13, NULL },
+  { "pkcs-7-CertificateSet", 1610612751, NULL },
+  { NULL, 2, "pkcs-7-CertificateChoices"},
+  { "IssuerAndSerialNumber", 1610612741, NULL },
+  { "issuer", 1073741826, "Name"},
+  { "serialNumber", 2, "CertificateSerialNumber"},
+  { "pkcs-7-SignerInfo", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "sid", 1073741826, "SignerIdentifier"},
+  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signedAttrs", 1610637314, "SignedAttributes"},
+  { NULL, 4104, "0"},
+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signature", 1073741831, NULL },
+  { "unsignedAttrs", 536895490, "SignedAttributes"},
+  { NULL, 4104, "1"},
+  { "SignedAttributes", 1612709903, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "Attribute"},
+  { "SignerIdentifier", 1610612754, NULL },
+  { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
+  { "subjectKeyIdentifier", 536879111, NULL },
+  { NULL, 4104, "0"},
+  { "pkcs-7-SignerInfos", 1610612751, NULL },
+  { NULL, 2, "pkcs-7-SignerInfo"},
+  { "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "subject", 1073741826, "Name"},
+  { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
+  { "attributes", 536879106, "Attributes"},
+  { NULL, 4104, "0"},
+  { "Attributes", 1610612751, NULL },
+  { NULL, 2, "Attribute"},
+  { "pkcs-10-CertificationRequest", 1610612741, NULL },
+  { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"},
+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signature", 6, NULL },
+  { "pkcs-9-at-challengePassword", 1879048204, NULL },
+  { "iso", 1073741825, "1"},
+  { "member-body", 1073741825, "2"},
+  { "us", 1073741825, "840"},
+  { "rsadsi", 1073741825, "113549"},
+  { "pkcs", 1073741825, "1"},
+  { NULL, 1073741825, "9"},
+  { NULL, 1, "7"},
+  { "pkcs-9-challengePassword", 1610612754, NULL },
+  { "printableString", 1073741855, NULL },
+  { "utf8String", 34, NULL },
+  { "pkcs-9-localKeyId", 1073741831, NULL },
+  { "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "privateKey", 1073741831, NULL },
+  { "attributes", 536895490, "Attributes"},
+  { NULL, 4104, "0"},
+  { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
+  { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "encryptedData", 2, "pkcs-8-EncryptedData"},
+  { "pkcs-8-EncryptedData", 1073741831, NULL },
+  { "pkcs-5-des-CBC-params", 1612709895, NULL },
+  { NULL, 1048586, "8"},
+  { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
+  { NULL, 1048586, "8"},
+  { "pkcs-5-aes128-CBC-params", 1612709895, NULL },
+  { NULL, 1048586, "16"},
+  { "pkcs-5-aes192-CBC-params", 1612709895, NULL },
+  { NULL, 1048586, "16"},
+  { "pkcs-5-aes256-CBC-params", 1612709895, NULL },
+  { NULL, 1048586, "16"},
+  { "Gost28147-89-Parameters", 1610612741, NULL },
+  { "iv", 1073741831, NULL },
+  { "encryptionParamSet", 12, NULL },
+  { "pkcs-5-PBE-params", 1610612741, NULL },
+  { "salt", 1073741831, NULL },
+  { "iterationCount", 3, NULL },
+  { "pkcs-5-PBES2-params", 1610612741, NULL },
+  { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
+  { "encryptionScheme", 2, "AlgorithmIdentifier"},
+  { "pkcs-5-PBKDF2-params", 1610612741, NULL },
+  { "salt", 1610612754, NULL },
+  { "specified", 1073741831, NULL },
+  { "otherSource", 2, "AlgorithmIdentifier"},
+  { "iterationCount", 1611137027, NULL },
+  { "1", 10, "MAX"},
+  { "keyLength", 1611153411, NULL },
+  { "1", 10, "MAX"},
+  { "prf", 16386, "AlgorithmIdentifier"},
+  { "pkcs-12-PFX", 1610612741, NULL },
+  { "version", 1610874883, NULL },
+  { "v3", 1, "3"},
+  { "authSafe", 1073741826, "pkcs-7-ContentInfo"},
+  { "macData", 16386, "pkcs-12-MacData"},
+  { "pkcs-12-PbeParams", 1610612741, NULL },
+  { "salt", 1073741831, NULL },
+  { "iterations", 3, NULL },
+  { "pkcs-12-MacData", 1610612741, NULL },
+  { "mac", 1073741826, "pkcs-7-DigestInfo"},
+  { "macSalt", 1073741831, NULL },
+  { "iterations", 536903683, NULL },
+  { NULL, 9, "1"},
+  { "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
+  { NULL, 2, "pkcs-7-ContentInfo"},
+  { "pkcs-12-SafeContents", 1610612747, NULL },
+  { NULL, 2, "pkcs-12-SafeBag"},
+  { "pkcs-12-SafeBag", 1610612741, NULL },
+  { "bagId", 1073741836, NULL },
+  { "bagValue", 1614815245, NULL },
+  { NULL, 1073743880, "0"},
+  { "badId", 1, NULL },
+  { "bagAttributes", 536887311, NULL },
+  { NULL, 2, "Attribute"},
+  { "pkcs-12-CertBag", 1610612741, NULL },
+  { "certId", 1073741836, NULL },
+  { "certValue", 541073421, NULL },
+  { NULL, 1073743880, "0"},
+  { "certId", 1, NULL },
+  { "pkcs-12-CRLBag", 1610612741, NULL },
+  { "crlId", 1073741836, NULL },
+  { "crlValue", 541073421, NULL },
+  { NULL, 1073743880, "0"},
+  { "crlId", 1, NULL },
+  { "pkcs-12-SecretBag", 1610612741, NULL },
+  { "secretTypeId", 1073741836, NULL },
+  { "secretValue", 541073421, NULL },
+  { NULL, 1073743880, "0"},
+  { "secretTypeId", 1, NULL },
+  { "pkcs-7-Data", 1073741831, NULL },
+  { "pkcs-7-EncryptedData", 1610612741, NULL },
+  { "version", 1073741827, NULL },
+  { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"},
+  { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
+  { NULL, 4104, "1"},
+  { "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
+  { "contentType", 1073741836, NULL },
+  { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
+  { "encryptedContent", 536895495, NULL },
+  { NULL, 4104, "0"},
+  { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
+  { "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "Attribute"},
+  { "ProxyCertInfo", 1610612741, NULL },
+  { "pCPathLenConstraint", 1611153411, NULL },
+  { "0", 10, "MAX"},
+  { "proxyPolicy", 2, "ProxyPolicy"},
+  { "ProxyPolicy", 1610612741, NULL },
+  { "policyLanguage", 1073741836, NULL },
+  { "policy", 16391, NULL },
+  { "certificatePolicies", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "PolicyInformation"},
+  { "PolicyInformation", 1610612741, NULL },
+  { "policyIdentifier", 1073741836, NULL },
+  { "policyQualifiers", 538984459, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "PolicyQualifierInfo"},
+  { "PolicyQualifierInfo", 1610612741, NULL },
+  { "policyQualifierId", 1073741836, NULL },
+  { "qualifier", 541065229, NULL },
+  { "policyQualifierId", 1, NULL },
+  { "CPSuri", 1073741853, NULL },
+  { "UserNotice", 1610612741, NULL },
+  { "noticeRef", 1073758210, "NoticeReference"},
+  { "explicitText", 16386, "DisplayText"},
+  { "NoticeReference", 1610612741, NULL },
+  { "organization", 1073741826, "DisplayText"},
+  { "noticeNumbers", 536870923, NULL },
+  { NULL, 3, NULL },
+  { "DisplayText", 1610612754, NULL },
+  { "ia5String", 1612709917, NULL },
+  { "200", 524298, "1"},
+  { "visibleString", 1612709923, NULL },
+  { "200", 524298, "1"},
+  { "bmpString", 1612709921, NULL },
+  { "200", 524298, "1"},
+  { "utf8String", 538968098, NULL },
+  { "200", 524298, "1"},
+  { "OCSPRequest", 1610612741, NULL },
+  { "tbsRequest", 1073741826, "TBSRequest"},
+  { "optionalSignature", 536895490, "Signature"},
+  { NULL, 2056, "0"},
+  { "TBSRequest", 1610612741, NULL },
+  { "version", 1610653699, NULL },
+  { NULL, 1073741833, "0"},
+  { NULL, 2056, "0"},
+  { "requestorName", 1610637314, "GeneralName"},
+  { NULL, 2056, "1"},
+  { "requestList", 1610612747, NULL },
+  { NULL, 2, "Request"},
+  { "requestExtensions", 536895490, "Extensions"},
+  { NULL, 2056, "2"},
+  { "Signature", 1610612741, NULL },
+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signature", 1073741830, NULL },
+  { "certs", 536895499, NULL },
+  { NULL, 1073743880, "0"},
+  { NULL, 2, "Certificate"},
+  { "Request", 1610612741, NULL },
+  { "reqCert", 1073741826, "CertID"},
+  { "singleRequestExtensions", 536895490, "Extensions"},
+  { NULL, 2056, "0"},
+  { "CertID", 1610612741, NULL },
+  { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "issuerNameHash", 1073741831, NULL },
+  { "issuerKeyHash", 1073741831, NULL },
+  { "serialNumber", 2, "CertificateSerialNumber"},
+  { "OCSPResponse", 1610612741, NULL },
+  { "responseStatus", 1073741826, "OCSPResponseStatus"},
+  { "responseBytes", 536895490, "ResponseBytes"},
+  { NULL, 2056, "0"},
+  { "OCSPResponseStatus", 1610874901, NULL },
+  { "successful", 1073741825, "0"},
+  { "malformedRequest", 1073741825, "1"},
+  { "internalError", 1073741825, "2"},
+  { "tryLater", 1073741825, "3"},
+  { "sigRequired", 1073741825, "5"},
+  { "unauthorized", 1, "6"},
+  { "ResponseBytes", 1610612741, NULL },
+  { "responseType", 1073741836, NULL },
+  { "response", 7, NULL },
+  { "BasicOCSPResponse", 1610612741, NULL },
+  { "tbsResponseData", 1073741826, "ResponseData"},
+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
+  { "signature", 1073741830, NULL },
+  { "certs", 536895499, NULL },
+  { NULL, 1073743880, "0"},
+  { NULL, 2, "Certificate"},
+  { "ResponseData", 1610612741, NULL },
+  { "version", 1610653699, NULL },
+  { NULL, 1073741833, "0"},
+  { NULL, 2056, "0"},
+  { "responderID", 1073741826, "ResponderID"},
+  { "producedAt", 1073741861, NULL },
+  { "responses", 1610612747, NULL },
+  { NULL, 2, "SingleResponse"},
+  { "responseExtensions", 536895490, "Extensions"},
+  { NULL, 2056, "1"},
+  { "ResponderID", 1610612754, NULL },
+  { "byName", 1610620939, NULL },
+  { NULL, 1073743880, "1"},
+  { NULL, 2, "RelativeDistinguishedName"},
+  { "byKey", 536879111, NULL },
+  { NULL, 2056, "2"},
+  { "SingleResponse", 1610612741, NULL },
+  { "certID", 1073741826, "CertID"},
+  { "certStatus", 1073741826, "CertStatus"},
+  { "thisUpdate", 1073741861, NULL },
+  { "nextUpdate", 1610637349, NULL },
+  { NULL, 2056, "0"},
+  { "singleExtensions", 536895490, "Extensions"},
+  { NULL, 2056, "1"},
+  { "CertStatus", 1610612754, NULL },
+  { "good", 1610620948, NULL },
+  { NULL, 4104, "0"},
+  { "revoked", 1610620930, "RevokedInfo"},
+  { NULL, 4104, "1"},
+  { "unknown", 536879106, "UnknownInfo"},
+  { NULL, 4104, "2"},
+  { "RevokedInfo", 1610612741, NULL },
+  { "revocationTime", 1073741861, NULL },
+  { "revocationReason", 537157653, NULL },
+  { NULL, 1073743880, "0"},
+  { "unspecified", 1, "0"},
+  { "UnknownInfo", 1073741844, NULL },
+  { "NameConstraints", 1610612741, NULL },
+  { "permittedSubtrees", 1610637314, "GeneralSubtrees"},
+  { NULL, 4104, "0"},
+  { "excludedSubtrees", 536895490, "GeneralSubtrees"},
+  { NULL, 4104, "1"},
+  { "GeneralSubtrees", 1612709899, NULL },
+  { "MAX", 1074266122, "1"},
+  { NULL, 2, "GeneralSubtree"},
+  { "GeneralSubtree", 1610612741, NULL },
+  { "base", 1073741826, "GeneralName"},
+  { "minimum", 1610653699, NULL },
+  { NULL, 1073741833, "0"},
+  { NULL, 4104, "0"},
+  { "maximum", 536895491, NULL },
+  { NULL, 4104, "1"},
+  { "TlsFeatures", 536870923, NULL },
+  { NULL, 3, NULL },
+  { NULL, 0, NULL }
+};
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (7 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-28 19:46   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 10/21] appended signatures: support verifying appended signatures Sudhakar Kuppusamy
                   ` (11 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Javier Martinez Canillas, Michal Suchanek,
	Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

This code allows us to parse:

 - PKCS#7 signedData messages. Only a single signerInfo is supported,
   which is all that the Linux sign-file utility supports creating
   out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
   Any certificate embedded in the PKCS#7 message will be ignored.

 - X.509 certificates: at least enough to verify the signatures on the
   PKCS#7 messages. We expect that the certificates embedded in grub will
   be leaf certificates, not CA certificates. The parser enforces this.

 - X.509 certificates support the Extended Key Usage extension and handle
   it by verifying that the certificate has a single purpose, that is code
   signing. This is required because Red Hat certificates have both Key
   Usage and Extended Key Usage extensions present.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> # EKU support
Reported-by: Michal Suchanek <msuchanek@suse.com> # key usage issue
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/commands/appendedsig/appendedsig.h | 110 +++
 grub-core/commands/appendedsig/asn1util.c    |  99 ++
 grub-core/commands/appendedsig/pkcs7.c       | 473 +++++++++
 grub-core/commands/appendedsig/x509.c        | 981 +++++++++++++++++++
 4 files changed, 1663 insertions(+)
 create mode 100644 grub-core/commands/appendedsig/appendedsig.h
 create mode 100644 grub-core/commands/appendedsig/asn1util.c
 create mode 100644 grub-core/commands/appendedsig/pkcs7.c
 create mode 100644 grub-core/commands/appendedsig/x509.c

diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
new file mode 100644
index 000000000..fa59302c8
--- /dev/null
+++ b/grub-core/commands/appendedsig/appendedsig.h
@@ -0,0 +1,110 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ *  Copyright (C) 2020, 2022 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/crypto.h>
+#include <grub/libtasn1.h>
+
+extern asn1_node _gnutls_gnutls_asn;
+extern asn1_node _gnutls_pkix_asn;
+
+#define MAX_OID_LEN 32
+
+/*
+ * One or more x509 certificates.
+ * We do limited parsing: extracting only the serial, CN and RSA public key.
+ */
+struct x509_certificate
+{
+  struct x509_certificate *next;
+  grub_uint8_t *serial;
+  grub_size_t serial_len;
+  char *subject;
+  grub_size_t subject_len;
+  /* We only support RSA public keys. This encodes [modulus, publicExponent] */
+  gcry_mpi_t mpis[2];
+};
+
+/*
+ * A PKCS#7 signedData signerInfo.
+ */
+struct pkcs7_signerInfo
+{
+  const gcry_md_spec_t *hash;
+  gcry_mpi_t sig_mpi;
+};
+
+/*
+ * A PKCS#7 signedData message.
+ * We make no attempt to match intelligently, so we don't save any info about
+ * the signer.
+ */
+struct pkcs7_signedData
+{
+  int signerInfo_count;
+  struct pkcs7_signerInfo *signerInfos;
+};
+
+/* Do libtasn1 init */
+int
+asn1_init (void);
+
+/*
+ * Import a DER-encoded certificate at 'data', of size 'size'.
+ * Place the results into 'results', which must be already allocated.
+ */
+grub_err_t
+parse_x509_certificate (const void *data, grub_size_t size, struct x509_certificate *results);
+
+/*
+ * Release all the storage associated with the x509 certificate.
+ * If the caller dynamically allocated the certificate, it must free it.
+ * The caller is also responsible for maintenance of the linked list.
+ */
+void
+certificate_release (struct x509_certificate *cert);
+
+/*
+ * Parse a PKCS#7 message, which must be a signedData message.
+ * The message must be in 'sigbuf' and of size 'data_size'. The result is
+ * placed in 'msg', which must already be allocated.
+ */
+grub_err_t
+parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg);
+
+/*
+ * Release all the storage associated with the PKCS#7 message.
+ * If the caller dynamically allocated the message, it must free it.
+ */
+void
+pkcs7_signedData_release (struct pkcs7_signedData *msg);
+
+/*
+ * Read a value from an ASN1 node, allocating memory to store it.
+ * It will work for anything where the size libtasn1 returns is right:
+ *  - Integers
+ *  - Octet strings
+ *  - DER encoding of other structures
+ * It will _not_ work for things where libtasn1 size requires adjustment:
+ *  - Strings that require an extra NULL byte at the end
+ *  - Bit strings because libtasn1 returns the length in bits, not bytes.
+ *
+ * If the function returns a non-NULL value, the caller must free it.
+ */
+void *
+grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size);
diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
new file mode 100644
index 000000000..609d0ecf2
--- /dev/null
+++ b/grub-core/commands/appendedsig/asn1util.c
@@ -0,0 +1,99 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ *  Copyright (C) 2020, 2022 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/libtasn1.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/crypto.h>
+#include <grub/misc.h>
+#include <grub/gcrypt/gcrypt.h>
+
+#include "appendedsig.h"
+
+asn1_node _gnutls_gnutls_asn = NULL;
+asn1_node _gnutls_pkix_asn = NULL;
+
+extern const asn1_static_node gnutls_asn1_tab[];
+extern const asn1_static_node pkix_asn1_tab[];
+
+/*
+ * Read a value from an ASN1 node, allocating memory to store it.
+ * It will work for anything where the size libtasn1 returns is right:
+ *  - Integers
+ *  - Octet strings
+ *  - DER encoding of other structures
+ * It will _not_ work for things where libtasn1 size requires adjustment:
+ *  - Strings that require an extra NULL byte at the end
+ *  - Bit strings because libtasn1 returns the length in bits, not bytes.
+ * If the function returns a non-NULL value, the caller must free it.
+ */
+void *
+grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size)
+{
+  int result;
+  grub_uint8_t *tmpstr = NULL;
+  int tmpstr_size = 0;
+
+  result = asn1_read_value (node, name, NULL, &tmpstr_size);
+  if (result != ASN1_MEM_ERROR)
+    {
+      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
+                     _("Reading size of %s did not return expected status: %s"),
+                     friendly_name, asn1_strerror (result));
+      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
+      return NULL;
+    }
+
+  tmpstr = grub_malloc (tmpstr_size);
+  if (tmpstr == NULL)
+    {
+      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
+                     "Could not allocate memory to store %s", friendly_name);
+      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
+      return NULL;
+    }
+
+  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
+  if (result != ASN1_SUCCESS)
+    {
+      grub_free (tmpstr);
+      grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error reading %s: %s",
+                     friendly_name, asn1_strerror (result));
+      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
+      return NULL;
+    }
+
+  *content_size = tmpstr_size;
+
+  return tmpstr;
+}
+
+int
+asn1_init (void)
+{
+  int res;
+  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
+  if (res != ASN1_SUCCESS)
+    {
+      return res;
+    }
+  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
+  return res;
+}
diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c
new file mode 100644
index 000000000..61e560854
--- /dev/null
+++ b/grub-core/commands/appendedsig/pkcs7.c
@@ -0,0 +1,473 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ *  Copyright (C) 2020, 2022 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 "appendedsig.h"
+#include <grub/misc.h>
+#include <grub/crypto.h>
+#include <grub/gcrypt/gcrypt.h>
+#include <sys/types.h>
+
+static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+/*
+ * RFC 5652 s 5.1
+ */
+static const char *signedData_oid = "1.2.840.113549.1.7.2";
+
+/*
+ * RFC 4055 s 2.1
+ */
+static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
+static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
+
+static grub_err_t
+process_content (grub_uint8_t *content, int size, struct pkcs7_signedData *msg)
+{
+  int res;
+  asn1_node signed_part;
+  grub_err_t err = GRUB_ERR_NONE;
+  char algo_oid[MAX_OID_LEN];
+  int algo_oid_size = sizeof (algo_oid);
+  int algo_count;
+  int signer_count;
+  int i;
+  char version;
+  int version_size = sizeof (version);
+  grub_uint8_t *result_buf;
+  int result_size = 0;
+  int crls_size = 0;
+  gcry_error_t gcry_err;
+  bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
+  char *da_path;
+  char *si_sig_path;
+  char *si_da_path;
+
+  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part);
+  if (res != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for PKCS#7 signed "
+                         "part.");
+    }
+
+  res = asn1_der_decoding2 (&signed_part, content, &size,
+                            ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (res != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "Error reading PKCS#7 signed data: %s", asn1_error);
+      goto cleanup_signed_part;
+    }
+
+  /*
+   * SignedData ::= SEQUENCE {
+   *     version CMSVersion,
+   *     digestAlgorithms DigestAlgorithmIdentifiers,
+   *     encapContentInfo EncapsulatedContentInfo,
+   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
+   *     signerInfos SignerInfos }
+   */
+
+  /* version per the algo in 5.1, must be 1 */
+  res = asn1_read_value (signed_part, "version", &version, &version_size);
+  if (res != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading signedData version: %s",
+                        asn1_strerror (res));
+      goto cleanup_signed_part;
+    }
+
+  if (version != 1)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "Unexpected signature version v%d, only v1 supported", version);
+      goto cleanup_signed_part;
+    }
+
+  /*
+   * digestAlgorithms DigestAlgorithmIdentifiers
+   *
+   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
+   *
+   * RFC 4055 s 2.1:
+   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
+   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
+   *
+   * We only support 1 element in the set, and we do not check parameters atm.
+   */
+  res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
+  if (res != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of digest algorithms: %s",
+                        asn1_strerror (res));
+      goto cleanup_signed_part;
+    }
+
+  if (algo_count <= 0)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "A minimum of 1 digest algorithm is required");
+      goto cleanup_signed_part;
+    }
+
+  if (algo_count > 2)
+    {
+      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                        "A maximum of 2 digest algorithms are supported");
+      goto cleanup_signed_part;
+    }
+
+  sha256_in_da = false;
+  sha512_in_da = false;
+
+  for (i = 0; i < algo_count; i++)
+    {
+      da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1);
+      if (!da_path)
+        {
+          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                            "Could not allocate path for digest algorithm "
+                            "parsing path");
+          goto cleanup_signed_part;
+        }
+
+      algo_oid_size = sizeof (algo_oid);
+      res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size);
+      if (res != ASN1_SUCCESS)
+        {
+          err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading digest algorithm: %s",
+                            asn1_strerror (res));
+          grub_free (da_path);
+          goto cleanup_signed_part;
+        }
+
+      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
+        {
+          if (!sha512_in_da)
+            {
+              sha512_in_da = true;
+            }
+          else
+            {
+              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                                "SHA-512 specified twice in digest algorithm "
+                                "list");
+              grub_free (da_path);
+              goto cleanup_signed_part;
+            }
+        }
+      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
+        {
+          if (!sha256_in_da)
+            {
+              sha256_in_da = true;
+            }
+          else
+            {
+              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                                "SHA-256 specified twice in digest algorithm "
+                                "list");
+              grub_free (da_path);
+              goto cleanup_signed_part;
+            }
+        }
+      else
+        {
+          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
+                            algo_oid);
+          grub_free (da_path);
+          goto cleanup_signed_part;
+        }
+
+      grub_free (da_path);
+    }
+
+  /* at this point, at least one of sha{256,512}_in_da must be true */
+
+  /*
+   * We ignore the certificates, but we don't permit CRLs.
+   * A CRL entry might be revoking the certificate we're using, and we have
+   * no way of dealing with that at the moment.
+   */
+  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
+  if (res != ASN1_ELEMENT_NOT_FOUND)
+    {
+      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                        "PKCS#7 messages with embedded CRLs are not supported");
+      goto cleanup_signed_part;
+    }
+
+  /* read the signatures */
+
+  res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count);
+  if (res != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of signers: %s",
+                        asn1_strerror (res));
+      goto cleanup_signed_part;
+    }
+
+  if (signer_count <= 0)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "A minimum of 1 signer is required");
+      goto cleanup_signed_part;
+    }
+
+  msg->signerInfos = grub_calloc (signer_count, sizeof (struct pkcs7_signerInfo));
+  if (!msg->signerInfos)
+    {
+      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                        "Could not allocate space for %d signers", signer_count);
+      goto cleanup_signed_part;
+    }
+
+  msg->signerInfo_count = 0;
+  for (i = 0; i < signer_count; i++)
+    {
+      si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
+      if (!si_da_path)
+        {
+          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate path for signer %d's digest algorithm parsing path",
+                            i);
+          goto cleanup_signerInfos;
+        }
+
+      algo_oid_size = sizeof (algo_oid);
+      res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size);
+      if (res != ASN1_SUCCESS)
+        {
+          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                            "Error reading signer %d's digest algorithm: %s", i,
+                            asn1_strerror (res));
+          grub_free (si_da_path);
+          goto cleanup_signerInfos;
+        }
+
+      grub_free (si_da_path);
+
+      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
+        {
+          if (!sha512_in_da)
+            {
+              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d claims a SHA-512 signature "
+                                "which was not specified in the outer DigestAlgorithms", i);
+              goto cleanup_signerInfos;
+            }
+          else
+            {
+              sha512_in_si = true;
+              msg->signerInfos[i].hash =
+                      grub_crypto_lookup_md_by_name ("sha512");
+            }
+        }
+      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
+        {
+          if (!sha256_in_da)
+            {
+              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d claims a SHA-256 signature "
+                                "which was not specified in the outer DigestAlgorithms", i);
+              goto cleanup_signerInfos;
+            }
+          else
+            {
+              sha256_in_si = true;
+              msg->signerInfos[i].hash =
+                      grub_crypto_lookup_md_by_name ("sha256");
+            }
+        }
+      else
+        {
+          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                            "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
+                            algo_oid);
+          goto cleanup_signerInfos;
+        }
+
+      if (!msg->signerInfos[i].hash)
+        {
+          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                            "Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid);
+          goto cleanup_signerInfos;
+        }
+
+      si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1);
+      if (!si_sig_path)
+        {
+          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                            "Could not allocate path for signer %d's signature parsing path", i);
+          goto cleanup_signerInfos;
+        }
+
+      result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path,
+                                                "signature data", &result_size);
+      grub_free (si_sig_path);
+
+      if (!result_buf)
+        {
+          err = grub_errno;
+          goto cleanup_signerInfos;
+        }
+
+      gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi), GCRYMPI_FMT_USG,
+                                result_buf, result_size, NULL);
+
+      grub_free (result_buf);
+
+      if (gcry_err != GPG_ERR_NO_ERROR)
+        {
+          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                            "Error loading signature %d into MPI structure: %d",
+                            i, gcry_err);
+          goto cleanup_signerInfos;
+        }
+
+      /*
+       * use msg->signerInfo_count to track fully populated signerInfos so we
+       * know how many we need to clean up
+       */
+      msg->signerInfo_count++;
+    }
+
+  /*
+   * Final consistency check of signerInfo.*.digestAlgorithm vs
+   * digestAlgorithms.*.algorithm. An algorithm must be present in both
+   * digestAlgorithms and signerInfo or in neither. We have already checked
+   * for an algorithm in signerInfo that is not in digestAlgorithms, here we
+   * check for algorithms in digestAlgorithms but not in signerInfos.
+   */
+  if (sha512_in_da && !sha512_in_si)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "SHA-512 specified in DigestAlgorithms but did not "
+                        "appear in SignerInfos");
+      goto cleanup_signerInfos;
+    }
+
+  if (sha256_in_da && !sha256_in_si)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "SHA-256 specified in DigestAlgorithms but did not "
+                        "appear in SignerInfos");
+      goto cleanup_signerInfos;
+    }
+
+  asn1_delete_structure (&signed_part);
+  return GRUB_ERR_NONE;
+
+cleanup_signerInfos:
+  for (i = 0; i < msg->signerInfo_count; i++)
+    gcry_mpi_release (msg->signerInfos[i].sig_mpi);
+  grub_free (msg->signerInfos);
+cleanup_signed_part:
+  asn1_delete_structure (&signed_part);
+  return err;
+}
+
+grub_err_t
+parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg)
+{
+  int res;
+  asn1_node content_info;
+  grub_err_t err = GRUB_ERR_NONE;
+  char content_oid[MAX_OID_LEN];
+  grub_uint8_t *content;
+  int content_size;
+  int content_oid_size = sizeof (content_oid);
+  int size;
+
+  if (data_size > GRUB_INT_MAX)
+    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 message "
+                                              "where data size > INT_MAX");
+  size = (int) data_size;
+
+  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info);
+  if (res != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for PKCS#7 data: %s",
+                         asn1_strerror (res));
+    }
+
+  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
+                            ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING,
+                            asn1_error);
+  if (res != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "Error decoding PKCS#7 message DER: %s", asn1_error);
+      goto cleanup;
+    }
+
+  /*
+   * ContentInfo ::= SEQUENCE {
+   *     contentType ContentType,
+   *     content [0] EXPLICIT ANY DEFINED BY contentType }
+   *
+   * ContentType ::= OBJECT IDENTIFIER
+   */
+  res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size);
+  if (res != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7 content type: %s",
+                        asn1_strerror (res));
+      goto cleanup;
+    }
+
+  /* OID for SignedData defined in 5.1 */
+  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
+    {
+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+                        "Unexpected content type in PKCS#7 message: OID %s", content_oid);
+      goto cleanup;
+    }
+
+  content = grub_asn1_allocate_and_read (content_info, "content",
+                                         "PKCS#7 message content", &content_size);
+  if (!content)
+    {
+      err = grub_errno;
+      goto cleanup;
+    }
+
+  err = process_content (content, content_size, msg);
+  grub_free (content);
+
+cleanup:
+  asn1_delete_structure (&content_info);
+  return err;
+}
+
+/*
+ * Release all the storage associated with the PKCS#7 message.
+ * If the caller dynamically allocated the message, it must free it.
+ */
+void
+pkcs7_signedData_release (struct pkcs7_signedData *msg)
+{
+  grub_ssize_t i;
+
+  for (i = 0; i < msg->signerInfo_count; i++)
+    {
+      gcry_mpi_release (msg->signerInfos[i].sig_mpi);
+    }
+  grub_free (msg->signerInfos);
+}
diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
new file mode 100644
index 000000000..eb9a1ca0f
--- /dev/null
+++ b/grub-core/commands/appendedsig/x509.c
@@ -0,0 +1,981 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ *  Copyright (C) 2020, 2022 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/libtasn1.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/crypto.h>
+#include <grub/misc.h>
+#include <grub/gcrypt/gcrypt.h>
+
+#include "appendedsig.h"
+
+static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+/*
+ * RFC 3279 2.3.1  RSA Keys
+ */
+static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
+
+/*
+ * RFC 5280 Appendix A
+ */
+static const char *commonName_oid = "2.5.4.3";
+
+/*
+ * RFC 5280 4.2.1.3 Key Usage
+ */
+static const char *keyUsage_oid = "2.5.29.15";
+
+static const grub_uint8_t digitalSignatureUsage = 0x80;
+
+/*
+ * RFC 5280 4.2.1.9 Basic Constraints
+ */
+static const char *basicConstraints_oid = "2.5.29.19";
+
+/*
+ * RFC 5280 4.2.1.12 Extended Key Usage
+ */
+static const char *extendedKeyUsage_oid = "2.5.29.37";
+static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
+
+/*
+ * RFC 3279 2.3.1
+ *
+ *  The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
+ *
+ *     RSAPublicKey ::= SEQUENCE {
+ *        modulus            INTEGER,    -- n
+ *        publicExponent     INTEGER  }  -- e
+ *
+ *  where modulus is the modulus n, and publicExponent is the public
+ *  exponent e.
+ */
+static grub_err_t
+grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct x509_certificate *certificate)
+{
+  int result;
+  asn1_node spk = NULL;
+  grub_uint8_t *m_data, *e_data;
+  int m_size, e_size;
+  grub_err_t err = GRUB_ERR_NONE;
+  gcry_error_t gcry_err;
+
+  result = asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Cannot create storage for public key ASN.1 data");
+    }
+
+  result = asn1_der_decoding2 (&spk, der, &dersize, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Cannot decode certificate public key DER: %s", asn1_error);
+      goto cleanup;
+    }
+
+  m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
+  if (!m_data)
+    {
+      err = grub_errno;
+      goto cleanup;
+    }
+
+  e_data = grub_asn1_allocate_and_read (spk, "publicExponent",
+                                        "RSA public exponent", &e_size);
+  if (!e_data)
+    {
+      err = grub_errno;
+      goto cleanup_m_data;
+    }
+
+  /*
+   * convert m, e to mpi
+   *
+   * nscanned is not set for FMT_USG, it's only set for FMT_PGP,
+   * so we can't verify it
+   */
+  gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, NULL);
+  if (gcry_err != GPG_ERR_NO_ERROR)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Error loading RSA modulus into MPI structure: %d", gcry_err);
+      goto cleanup_e_data;
+    }
+
+  gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, NULL);
+  if (gcry_err != GPG_ERR_NO_ERROR)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Error loading RSA exponent into MPI structure: %d", gcry_err);
+      goto cleanup_m_mpi;
+    }
+
+  grub_free (e_data);
+  grub_free (m_data);
+  asn1_delete_structure (&spk);
+  return GRUB_ERR_NONE;
+
+cleanup_m_mpi:
+  gcry_mpi_release (certificate->mpis[0]);
+cleanup_e_data:
+  grub_free (e_data);
+cleanup_m_data:
+  grub_free (m_data);
+cleanup:
+  asn1_delete_structure (&spk);
+  return err;
+}
+
+/*
+ * RFC 5280:
+ *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
+ *       algorithm            AlgorithmIdentifier,
+ *       subjectPublicKey     BIT STRING  }
+ *
+ * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
+ * only support RSA Encryption.
+ */
+
+static grub_err_t
+grub_x509_read_subject_public_key (asn1_node asn, struct x509_certificate *results)
+{
+  int result;
+  grub_err_t err;
+  const char *algo_name =
+          "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
+  const char *params_name =
+          "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
+  const char *pk_name = "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
+  char algo_oid[MAX_OID_LEN];
+  int algo_size = sizeof (algo_oid);
+  char params_value[2];
+  int params_size = sizeof (params_value);
+  grub_uint8_t *key_data = NULL;
+  int key_size = 0;
+  unsigned int key_type;
+
+  /* algorithm: see notes for rsaEncryption_oid */
+  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key algorithm: %s",
+                         asn1_strerror (result));
+    }
+
+  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) != 0)
+    {
+      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                         "Unsupported x509 public key algorithm: %s", algo_oid);
+    }
+
+  /*
+   * RFC 3279 2.3.1
+   * The rsaEncryption OID is intended to be used in the algorithm field
+   * of a value of type AlgorithmIdentifier.  The parameters field MUST
+   * have ASN.1 type NULL for this algorithm identifier.
+   */
+  result = asn1_read_value (asn, params_name, params_value, &params_size);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key parameters: %s",
+                         asn1_strerror (result));
+    }
+
+  if (params_value[0] != ASN1_TAG_NULL)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                         "Invalid x509 public key parameters: expected NULL");
+    }
+
+  /*
+   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of the BIT
+   * STRING subjectPublicKey.
+   */
+  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
+  if (result != ASN1_MEM_ERROR)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of x509 public key: %s",
+                         asn1_strerror (result));
+    }
+  if (key_type != ASN1_ETYPE_BIT_STRING)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1 type when reading x509 public key: %x",
+                         key_type);
+    }
+
+  /* length is in bits */
+  key_size = (key_size + 7) / 8;
+
+  key_data = grub_malloc (key_size);
+  if (!key_data)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Out of memory for x509 public key");
+    }
+
+  result = asn1_read_value (asn, pk_name, key_data, &key_size);
+  if (result != ASN1_SUCCESS)
+    {
+      grub_free (key_data);
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                         "Error reading public key data");
+    }
+  key_size = (key_size + 7) / 8;
+
+  err = grub_parse_rsa_pubkey (key_data, key_size, results);
+  grub_free (key_data);
+
+  return err;
+}
+
+/* Decode a string as defined in Appendix A */
+static grub_err_t
+decode_string (char *der, int der_size, char **string, grub_size_t *string_size)
+{
+  asn1_node strasn;
+  int result;
+  char *choice;
+  int choice_size = 0;
+  int tmp_size = 0;
+  grub_err_t err = GRUB_ERR_NONE;
+
+  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for certificate: %s",
+                         asn1_strerror (result));
+    }
+
+  result = asn1_der_decoding2 (&strasn, der, &der_size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Could not parse DER for DirectoryString: %s", asn1_error);
+      goto cleanup;
+    }
+
+  choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", &choice_size);
+  if (!choice)
+    {
+      err = grub_errno;
+      goto cleanup;
+    }
+
+  if (grub_strncmp ("utf8String", choice, choice_size) == 0)
+    {
+      result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
+      if (result != ASN1_MEM_ERROR)
+        {
+          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s",
+                            asn1_strerror (result));
+          goto cleanup_choice;
+        }
+    }
+  else if (grub_strncmp ("printableString", choice, choice_size) == 0)
+    {
+      result = asn1_read_value (strasn, "printableString", NULL, &tmp_size);
+      if (result != ASN1_MEM_ERROR)
+        {
+          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s",
+                            asn1_strerror (result));
+          goto cleanup_choice;
+        }
+    }
+  else
+    {
+      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and printable DirectoryStrings are supported, got %s",
+                        choice);
+      goto cleanup_choice;
+    }
+
+  /* read size does not include trailing null */
+  tmp_size++;
+
+  *string = grub_malloc (tmp_size);
+  if (!*string)
+    {
+      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                        "Cannot allocate memory for DirectoryString contents");
+      goto cleanup_choice;
+    }
+
+  result = asn1_read_value (strasn, choice, *string, &tmp_size);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s in DirectoryString: %s",
+                        choice, asn1_strerror (result));
+      grub_free (*string);
+      goto cleanup_choice;
+    }
+  *string_size = tmp_size + 1;
+  (*string)[tmp_size] = '\0';
+
+cleanup_choice:
+  grub_free (choice);
+cleanup:
+  asn1_delete_structure (&strasn);
+  return err;
+}
+
+/*
+ * TBSCertificate  ::=  SEQUENCE  {
+ *       version         [0]  EXPLICIT Version DEFAULT v1,
+ * ...
+ *
+ * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+ */
+static grub_err_t
+check_version (asn1_node certificate)
+{
+  int rc;
+  const char *name = "tbsCertificate.version";
+  grub_uint8_t version;
+  int len = sizeof (version);
+
+  rc = asn1_read_value (certificate, name, &version, &len);
+
+  /* require version 3 */
+  if (rc != ASN1_SUCCESS || len != 1)
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                       "Error reading certificate version");
+
+  if (version != 0x02)
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x",
+                       version);
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * This is an X.501 Name, which is complex.
+ *
+ * For simplicity, we extract only the CN.
+ */
+static grub_err_t
+read_name (asn1_node asn, const char *name_path, char **name, grub_size_t *name_size)
+{
+  int seq_components, set_components;
+  int result;
+  int i, j;
+  char *top_path, *set_path, *type_path, *val_path;
+  char type[MAX_OID_LEN];
+  int type_len = sizeof (type);
+  int string_size = 0;
+  char *string_der;
+  grub_err_t err;
+
+  *name = NULL;
+
+  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
+  if (!top_path)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                       "Could not allocate memory for %s name parsing path", name_path);
+
+  result = asn1_number_of_elements (asn, top_path, &seq_components);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name components: %s",
+                        asn1_strerror (result));
+      goto cleanup;
+    }
+
+  for (i = 1; i <= seq_components; i++)
+    {
+      set_path = grub_xasprintf ("%s.?%d", top_path, i);
+      if (!set_path)
+        {
+          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name set parsing path",
+                            name_path);
+          goto cleanup_set;
+        }
+      /* this brings us, hopefully, to a set */
+      result = asn1_number_of_elements (asn, set_path, &set_components);
+      if (result != ASN1_SUCCESS)
+        {
+          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name sub-components components (element %d): %s",
+                            i, asn1_strerror (result));
+          goto cleanup_set;
+        }
+      for (j = 1; j <= set_components; j++)
+        {
+          type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
+          if (!type_path)
+            {
+              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component type path",
+                                name_path);
+              goto cleanup_set;
+            }
+          type_len = sizeof (type);
+          result = asn1_read_value (asn, type_path, type, &type_len);
+          if (result != ASN1_SUCCESS)
+            {
+              err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading %s name component type: %s",
+                                name_path, asn1_strerror (result));
+              goto cleanup_type;
+            }
+
+          if (grub_strncmp (type, commonName_oid, type_len) != 0)
+            {
+              grub_free (type_path);
+              continue;
+            }
+
+          val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
+          if (!val_path)
+            {
+              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component value path",
+                                name_path);
+              goto cleanup_set;
+            }
+
+          string_der = grub_asn1_allocate_and_read (asn, val_path, name_path, &string_size);
+          if (!string_der)
+            {
+              err = grub_errno;
+              goto cleanup_val_path;
+            }
+
+          err = decode_string (string_der, string_size, name, name_size);
+          if (err)
+            goto cleanup_string;
+
+          grub_free (string_der);
+          grub_free (type_path);
+          grub_free (val_path);
+          break;
+        }
+      grub_free (set_path);
+
+      if (*name)
+        break;
+    }
+
+  grub_free (top_path);
+
+  return GRUB_ERR_NONE;
+
+cleanup_string:
+  grub_free (string_der);
+cleanup_val_path:
+  grub_free (val_path);
+cleanup_type:
+  grub_free (type_path);
+cleanup_set:
+  grub_free (set_path);
+cleanup:
+  grub_free (top_path);
+  return err;
+}
+
+/*
+ * Verify the Key Usage extension.
+ * We require the Digital signature usage.
+ */
+static grub_err_t
+verify_key_usage (grub_uint8_t *value, int value_size)
+{
+  asn1_node usageasn;
+  int result;
+  grub_err_t err = GRUB_ERR_NONE;
+  grub_uint8_t usage = 0xff;
+  int usage_size = sizeof (usage_size);
+
+  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for key usage");
+    }
+
+  result = asn1_der_decoding2 (&usageasn, value, &value_size,
+                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Error parsing DER for Key Usage: %s", asn1_error);
+      goto cleanup;
+    }
+
+  result = asn1_read_value (usageasn, "", &usage, &usage_size);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key Usage value: %s",
+                        asn1_strerror (result));
+      goto cleanup;
+    }
+
+  if (!(usage & digitalSignatureUsage))
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Key Usage (0x%x) missing Digital Signature usage", usage);
+      goto cleanup;
+    }
+
+cleanup:
+  asn1_delete_structure (&usageasn);
+  return err;
+}
+
+/*
+ * BasicConstraints ::= SEQUENCE {
+ *       cA                      BOOLEAN DEFAULT FALSE,
+ *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
+ */
+static grub_err_t
+verify_basic_constraints (grub_uint8_t *value, int value_size)
+{
+  asn1_node basicasn;
+  int result;
+  grub_err_t err = GRUB_ERR_NONE;
+  char cA[6]; /* FALSE or TRUE */
+  int cA_size = sizeof (cA);
+
+  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", &basicasn);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for Basic "
+                         "Constraints");
+    }
+
+  result = asn1_der_decoding2 (&basicasn, value, &value_size,
+                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Error parsing DER for Basic Constraints: %s", asn1_error);
+      goto cleanup;
+    }
+
+  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
+  if (result == ASN1_ELEMENT_NOT_FOUND)
+    {
+      /* Not present, default is False, so this is OK */
+      err = GRUB_ERR_NONE;
+      goto cleanup;
+    }
+  else if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic Constraints cA value: %s",
+                        asn1_strerror (result));
+      goto cleanup;
+    }
+
+  /* The certificate must not be a CA certificate */
+  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", cA);
+      goto cleanup;
+    }
+
+cleanup:
+  asn1_delete_structure (&basicasn);
+  return err;
+}
+
+/*
+ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ *
+ * KeyPurposeId ::= OBJECT IDENTIFIER
+ */
+static grub_err_t
+verify_extended_key_usage (grub_uint8_t *value, int value_size)
+{
+  asn1_node extendedasn;
+  int result, count;
+  grub_err_t err = GRUB_ERR_NONE;
+  char usage[MAX_OID_LEN];
+  int usage_size = sizeof (usage);
+
+  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", &extendedasn);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for Extended Key "
+                         "Usage");
+    }
+
+  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
+                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Error parsing DER for Extended Key Usage: %s", asn1_error);
+      goto cleanup;
+    }
+
+  /*
+   * If EKUs are present, there must be exactly 1 usage and it must be a
+   * codeSigning usage. (If we get to this point, we are parsing an EKU
+   * extension and therefore must have a usage. The code that makes having an
+   * EKU extension optional is in verify_extensions.)
+   */
+  result = asn1_number_of_elements (extendedasn, "", &count);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of Extended Key Usages: %s",
+                        asn1_strerror (result));
+      goto cleanup;
+    }
+
+  if (count != 1)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usages: %d, 1 expected",
+                        count);
+      goto cleanup;
+    }
+
+  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Extended Key Usage: %s",
+                        asn1_strerror (result));
+      goto cleanup;
+    }
+
+  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Unexpected Extended Key Usage OID, got: %s", usage);
+      goto cleanup;
+    }
+
+cleanup:
+  asn1_delete_structure (&extendedasn);
+  return err;
+}
+
+/*
+ * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension  ::=  SEQUENCE  {
+ *      extnID      OBJECT IDENTIFIER,
+ *      critical    BOOLEAN DEFAULT FALSE,
+ *      extnValue   OCTET STRING
+ *                  -- contains the DER encoding of an ASN.1 value
+ *                  -- corresponding to the extension type identified
+ *                  -- by extnID
+ * }
+ *
+ * A certificate must:
+ *  - contain the Digital Signature usage only
+ *  - not be a CA
+ *  - contain no extended usages, or only a code signing extended usage
+ *  - not contain any other critical extensions (RFC 5280 s 4.2)
+ */
+static grub_err_t
+verify_extensions (asn1_node cert)
+{
+  int result;
+  int ext, num_extensions = 0;
+  int usage_present = 0, constraints_present = 0, extended_usage_present = 0;
+  char *oid_path, *critical_path, *value_path;
+  char extnID[MAX_OID_LEN];
+  int extnID_size;
+  grub_err_t err;
+  char critical[6]; /* we get either "TRUE" or "FALSE" */
+  int critical_size;
+  grub_uint8_t *value;
+  int value_size;
+
+  result = asn1_number_of_elements (cert, "tbsCertificate.extensions", &num_extensions);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of extensions: %s",
+                         asn1_strerror (result));
+    }
+
+  if (num_extensions < 2)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Insufficient number of extensions for "
+                         "certificate, need at least 2, got %d",
+                         num_extensions);
+    }
+
+  for (ext = 1; ext <= num_extensions; ext++)
+    {
+      oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);
+
+      extnID_size = sizeof (extnID);
+      result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
+      if (result != ASN1_SUCCESS)
+        {
+          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension OID: %s",
+                            asn1_strerror (result));
+          goto cleanup_oid_path;
+        }
+
+      critical_path = grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);
+      critical_size = sizeof (critical);
+      result = asn1_read_value (cert, critical_path, critical, &critical_size);
+      if (result == ASN1_ELEMENT_NOT_FOUND)
+        {
+          critical[0] = '\0';
+        }
+      else if (result != ASN1_SUCCESS)
+        {
+          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension criticality: %s",
+                            asn1_strerror (result));
+          goto cleanup_critical_path;
+        }
+
+      value_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);
+      value = grub_asn1_allocate_and_read (cert, value_path,
+                                           "certificate extension value", &value_size);
+      if (!value)
+        {
+          err = grub_errno;
+          goto cleanup_value_path;
+        }
+
+      /*
+       * Now we must see if we recognise the OID.
+       * If we have an unrecognised critical extension we MUST bail.
+       */
+      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
+        {
+          err = verify_key_usage (value, value_size);
+          if (err != GRUB_ERR_NONE)
+            {
+              goto cleanup_value;
+            }
+          usage_present++;
+        }
+      else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
+        {
+          err = verify_basic_constraints (value, value_size);
+          if (err != GRUB_ERR_NONE)
+            {
+              goto cleanup_value;
+            }
+          constraints_present++;
+        }
+      else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
+        {
+          err = verify_extended_key_usage (value, value_size);
+          if (err != GRUB_ERR_NONE)
+            {
+              goto cleanup_value;
+            }
+          extended_usage_present++;
+        }
+      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
+        {
+          /*
+           * per the RFC, we must not process a certificate with
+           * a critical extension we do not understand.
+           */
+          err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                            "Unhandled critical x509 extension with OID %s", extnID);
+          goto cleanup_value;
+        }
+
+      grub_free (value);
+      grub_free (value_path);
+      grub_free (critical_path);
+      grub_free (oid_path);
+    }
+
+  if (usage_present != 1)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Key Usage extensions "
+                         "- expected 1, got %d", usage_present);
+    }
+  if (constraints_present != 1)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of basic constraints extensions "
+                         "- expected 1, got %d", constraints_present);
+    }
+  if (extended_usage_present > 1)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usage extensions "
+                         "- expected 0 or 1, got %d", extended_usage_present);
+    }
+  return GRUB_ERR_NONE;
+
+cleanup_value:
+  grub_free (value);
+cleanup_value_path:
+  grub_free (value_path);
+cleanup_critical_path:
+  grub_free (critical_path);
+cleanup_oid_path:
+  grub_free (oid_path);
+  return err;
+}
+
+/*
+ * Parse a certificate whose DER-encoded form is in @data, of size @data_size.
+ * Return the results in @results, which must point to an allocated x509 certificate.
+ */
+grub_err_t
+parse_x509_certificate (const void *data, grub_size_t data_size, struct x509_certificate *results)
+{
+  int result = 0;
+  asn1_node cert;
+  grub_err_t err;
+  int size;
+  int tmp_size;
+
+  if (data_size > GRUB_INT_MAX)
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                       "Cannot parse a certificate where data size > INT_MAX");
+  size = (int) data_size;
+
+  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
+  if (result != ASN1_SUCCESS)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                         "Could not create ASN.1 structure for certificate: %s",
+                         asn1_strerror (result));
+    }
+
+  result = asn1_der_decoding2 (&cert, data, &size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+  if (result != ASN1_SUCCESS)
+    {
+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "Could not parse DER for certificate: %s", asn1_error);
+      goto cleanup;
+    }
+
+  /*
+   * TBSCertificate  ::=  SEQUENCE {
+   *     version         [0]  EXPLICIT Version DEFAULT v1
+   */
+  err = check_version (cert);
+  if (err != GRUB_ERR_NONE)
+    {
+      goto cleanup;
+    }
+
+  /*
+   * serialNumber         CertificateSerialNumber,
+   *
+   * CertificateSerialNumber  ::=  INTEGER
+   */
+  results->serial = grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
+                                                 "certificate serial number", &tmp_size);
+  if (!results->serial)
+    {
+      err = grub_errno;
+      goto cleanup;
+    }
+  /*
+   * It's safe to cast the signed int to an unsigned here, we know
+   * length is non-negative
+   */
+  results->serial_len = tmp_size;
+
+  /*
+   * signature            AlgorithmIdentifier,
+   *
+   * We don't load the signature or issuer at the moment,
+   * as we don't attempt x509 verification.
+   */
+
+  /*
+   * issuer               Name,
+   *
+   * The RFC only requires the serial number to be unique within
+   * issuers, so to avoid ambiguity we _technically_ ought to make
+   * this available.
+   */
+
+  /*
+   * validity             Validity,
+   *
+   * Validity ::= SEQUENCE {
+   *     notBefore      Time,
+   *     notAfter       Time }
+   *
+   * We can't validate this reasonably, we have no true time source on several
+   * platforms. For now we do not parse them.
+   */
+
+  /*
+   * subject              Name,
+   *
+   * This is an X501 name, we parse out just the CN.
+   */
+  err = read_name (cert, "tbsCertificate.subject", &results->subject, &results->subject_len);
+  if (err != GRUB_ERR_NONE)
+    goto cleanup_serial;
+
+  /*
+   * TBSCertificate  ::=  SEQUENCE  {
+   *    ...
+   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
+   *    ...
+   */
+  err = grub_x509_read_subject_public_key (cert, results);
+  if (err != GRUB_ERR_NONE)
+    goto cleanup_name;
+
+  /*
+   * TBSCertificate  ::=  SEQUENCE  {
+   *    ...
+   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
+   *                         -- If present, version MUST be v3
+   * }
+   */
+
+  err = verify_extensions (cert);
+  if (err != GRUB_ERR_NONE)
+    goto cleanup_mpis;
+
+  /*
+   * We do not read or check the signature on the certificate:
+   * as discussed we do not try to validate the certificate but trust
+   * it implictly.
+   */
+
+  asn1_delete_structure (&cert);
+  return GRUB_ERR_NONE;
+
+cleanup_mpis:
+  gcry_mpi_release (results->mpis[0]);
+  gcry_mpi_release (results->mpis[1]);
+cleanup_name:
+  grub_free (results->subject);
+cleanup_serial:
+  grub_free (results->serial);
+cleanup:
+  asn1_delete_structure (&cert);
+  return err;
+}
+
+/*
+ * Release all the storage associated with the x509 certificate.
+ * If the caller dynamically allocated the certificate, it must free it.
+ * The caller is also responsible for maintenance of the linked list.
+ */
+void
+certificate_release (struct x509_certificate *cert)
+{
+  grub_free (cert->subject);
+  grub_free (cert->serial);
+  gcry_mpi_release (cert->mpis[0]);
+  gcry_mpi_release (cert->mpis[1]);
+}
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 10/21] appended signatures: support verifying appended signatures
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (8 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-29 16:37   ` Stefan Berger
  2025-02-06  6:10   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 11/21] appended signatures: verification tests Sudhakar Kuppusamy
                   ` (10 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

Building on the parsers and the ability to embed x509 certificates, as
well as the existing gcrypt functionality, add a module for verifying
appended signatures.

This includes a verifier that requires that Linux kernels and grub modules
have appended signatures, and commands to manage the list of trusted
certificates for verification.

Verification must be enabled by setting check_appended_signatures. If
GRUB is locked down when the module is loaded, verification will be
enabled and locked automatically.

As with the PGP verifier, it is not a complete secure-boot solution:
other mechanisms, such as a password or lockdown, must be used to ensure
that a user cannot drop to the grub shell and disable verification.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/Makefile.core.def                   |  14 +
 grub-core/commands/appendedsig/appendedsig.c  | 620 ++++++++++++++++++
 grub-core/commands/appendedsig/appendedsig.h  |   2 +-
 grub-core/commands/appendedsig/asn1util.c     |   2 +-
 .../commands/appendedsig/gnutls_asn1_tab.c    |   2 +-
 .../commands/appendedsig/pkix_asn1_tab.c      |   2 +-
 grub-core/commands/appendedsig/x509.c         |   2 +-
 include/grub/file.h                           |   2 +
 8 files changed, 641 insertions(+), 5 deletions(-)
 create mode 100644 grub-core/commands/appendedsig/appendedsig.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 60db2adc5..d693986c6 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -979,6 +979,20 @@ module = {
   cppflags = '-I$(srcdir)/lib/posix_wrap';
 };
 
+module = {
+  name = appendedsig;
+  common = commands/appendedsig/appendedsig.c;
+  common = commands/appendedsig/x509.c;
+  common = commands/appendedsig/pkcs7.c;
+  common = commands/appendedsig/asn1util.c;
+  common = commands/appendedsig/gnutls_asn1_tab.c;
+  common = commands/appendedsig/pkix_asn1_tab.c;
+
+  // posix wrapper required for gcry to get sys/types.h
+  cflags = '$(CFLAGS_POSIX)';
+  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/libtasn1-grub';
+};
+
 module = {
   name = hdparm;
   common = commands/hdparm.c;
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
new file mode 100644
index 000000000..5c82b96a4
--- /dev/null
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -0,0 +1,620 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc.
+ *  Copyright (C) 2020, 2021, 2022 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/command.h>
+#include <grub/crypto.h>
+#include <grub/pkcs1_v15.h>
+#include <grub/i18n.h>
+#include <grub/gcrypt/gcrypt.h>
+#include <grub/kernel.h>
+#include <grub/extcmd.h>
+#include <grub/verify.h>
+#include <libtasn1.h>
+#include <grub/env.h>
+#include <grub/lockdown.h>
+
+#include "appendedsig.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+const char magic[] = "~Module signature appended~\n";
+
+/*
+ * This structure is extracted from scripts/sign-file.c in the linux kernel
+ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
+ */
+struct module_signature
+{
+  grub_uint8_t algo;       /* Public-key crypto algorithm [0] */
+  grub_uint8_t hash;       /* Digest algorithm [0] */
+  grub_uint8_t id_type;    /* Key identifier type [PKEY_ID_PKCS7] */
+  grub_uint8_t signer_len; /* Length of signer's name [0] */
+  grub_uint8_t key_id_len; /* Length of key identifier [0] */
+  grub_uint8_t __pad[3];
+  grub_uint32_t sig_len;   /* Length of signature data */
+} GRUB_PACKED;
+
+/* This represents an entire, parsed, appended signature */
+struct grub_appended_signature
+{
+  grub_size_t signature_len;            /* Length of PKCS#7 data + metadata + magic */
+  struct module_signature sig_metadata; /* Module signature metadata */
+  struct pkcs7_signedData pkcs7;        /* Parsed PKCS#7 data */
+};
+
+/* Trusted certificates for verifying appended signatures */
+struct x509_certificate *grub_trusted_key;
+
+/*
+ * Force gcry_rsa to be a module dependency.
+ *
+ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built
+ * in if you add 'appendedsig' to grub-install --modules. You would need to
+ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when
+ * we only support RSA.
+ *
+ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the
+ * the filesystem after we install the verifier - we won't be able to verify
+ * it without having it already present. We also shouldn't load it before we
+ * install the verifier, because that would mean it wouldn't be verified - an
+ * attacker could insert any code they wanted into the module.
+ *
+ * So instead, reference the internal symbol from gcry_rsa. That creates a
+ * direct dependency on gcry_rsa, so it will be built in when this module
+ * is built in. Being built in (assuming the core image is itself signed!)
+ * also resolves our concerns about loading from the filesystem.
+ */
+extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
+
+static enum
+{
+  check_sigs_no = 0,
+  check_sigs_enforce = 1,
+  check_sigs_forced = 2
+} check_sigs = check_sigs_no;
+
+static const char *
+grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
+                   const char *val __attribute__ ((unused)))
+{
+  if (check_sigs == check_sigs_forced)
+    return "forced";
+  else if (check_sigs == check_sigs_enforce)
+    return "enforce";
+  else
+    return "no";
+}
+
+static char *
+grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const char *val)
+{
+  /* Do not allow the value to be changed if set to forced */
+  if (check_sigs == check_sigs_forced)
+    return grub_strdup ("forced");
+
+  if ((*val == '2') || (*val == 'f'))
+    check_sigs = check_sigs_forced;
+  else if ((*val == '1') || (*val == 'e'))
+    check_sigs = check_sigs_enforce;
+  else if ((*val == '0') || (*val == 'n'))
+    check_sigs = check_sigs_no;
+
+  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)
+{
+  grub_size_t pkcs7_size;
+  grub_size_t remaining_len;
+  const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic);
+
+  if (bufsize < grub_strlen (magic))
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for signature magic"));
+
+  if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic)))
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Missing or invalid signature magic"));
+
+  remaining_len = bufsize - grub_strlen (magic);
+
+  if (remaining_len < sizeof (struct module_signature))
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for signature metadata"));
+
+  appsigdata -= sizeof (struct module_signature);
+
+  /* extract the metadata */
+  grub_memcpy (&(sig->sig_metadata), appsigdata, sizeof (struct module_signature));
+
+  remaining_len -= sizeof (struct module_signature);
+
+  if (sig->sig_metadata.id_type != 2)
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type"));
+
+  pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len);
+
+  if (pkcs7_size > remaining_len)
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for PKCS#7 message"));
+
+  grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size);
+
+  sig->signature_len = grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size;
+
+  /* rewind pointer and parse pkcs7 data */
+  appsigdata -= pkcs7_size;
+
+  return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
+}
+
+static grub_err_t
+grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
+{
+  grub_err_t err = GRUB_ERR_NONE;
+  grub_size_t datasize;
+  void *context;
+  unsigned char *hash;
+  gcry_mpi_t hashmpi;
+  gcry_err_code_t rc;
+  struct x509_certificate *pk;
+  struct grub_appended_signature sig;
+  struct pkcs7_signerInfo *si;
+  int i;
+
+  if (!grub_trusted_key)
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
+
+  err = extract_appended_signature (buf, bufsize, &sig);
+  if (err != GRUB_ERR_NONE)
+    return err;
+
+  datasize = bufsize - sig.signature_len;
+
+  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
+    {
+      /*
+       * 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 = grub_trusted_key; pk; pk = pk->next)
+        {
+          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;
+            }
+
+          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
+          gcry_mpi_release (hashmpi);
+
+          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", "verify signer %d with key '%s' failed with %d\n",
+                        i, pk->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);
+
+  return err;
+}
+
+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;
+
+  if (argc < 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+  grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
+
+  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+  if (!f)
+    {
+      err = grub_errno;
+      goto cleanup;
+    }
+
+  err = file_read_all (f, &data, &file_size);
+  if (err != GRUB_ERR_NONE)
+    goto cleanup;
+
+  err = grub_verify_appended_signature (data, file_size);
+
+  grub_free (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)
+{
+  unsigned long cert_num, i;
+  struct x509_certificate *cert, *prev;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
+
+  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"));
+
+  if (cert_num == 1)
+    {
+      cert = grub_trusted_key;
+      grub_trusted_key = cert->next;
+
+      certificate_release (cert);
+      grub_free (cert);
+      return GRUB_ERR_NONE;
+    }
+  i = 2;
+  prev = grub_trusted_key;
+  cert = grub_trusted_key->next;
+  while (cert)
+    {
+      if (i == cert_num)
+        {
+          prev->next = cert->next;
+          certificate_release (cert);
+          grub_free (cert);
+          return GRUB_ERR_NONE;
+        }
+      i++;
+      prev = cert;
+      cert = 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);
+}
+
+static grub_err_t
+grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+  grub_file_t certf;
+  struct x509_certificate *cert = NULL;
+  grub_err_t err;
+
+  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"));
+
+  err = read_cert_from_file (certf, cert);
+  grub_file_close (certf);
+  if (err != GRUB_ERR_NONE)
+    {
+      grub_free (cert);
+      return err;
+    }
+  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject);
+
+  cert->next = grub_trusted_key;
+  grub_trusted_key = cert;
+
+  return GRUB_ERR_NONE;
+}
+
+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;
+
+  for (cert = grub_trusted_key; cert; cert = cert->next)
+    {
+      grub_printf (N_("Certificate %d:\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++;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+appendedsig_init (grub_file_t io __attribute__ ((unused)), enum grub_file_type type,
+                  void **context __attribute__ ((unused)), enum grub_verify_flags *flags)
+{
+  if (check_sigs == check_sigs_no)
+    {
+      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+      return GRUB_ERR_NONE;
+    }
+
+  switch (type & GRUB_FILE_TYPE_MASK)
+    {
+      case GRUB_FILE_TYPE_CERTIFICATE_TRUST:
+        /*
+         * This is a certificate to add to trusted keychain.
+         *
+         * This needs to be verified or blocked. Ideally we'd write an x509
+         * verifier, but we lack the hubris required to take this on. Instead,
+         * require that it have an appended signature.
+         */
+
+        /* Fall through */
+
+      case GRUB_FILE_TYPE_LINUX_KERNEL:
+      case GRUB_FILE_TYPE_GRUB_MODULE:
+        /*
+         * Appended signatures are only defined for ELF binaries.
+         * Out of an abundance of caution, we only verify Linux kernels and
+         * GRUB modules at this point.
+         */
+        *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
+        return GRUB_ERR_NONE;
+
+      case GRUB_FILE_TYPE_ACPI_TABLE:
+      case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
+        /*
+         * It is possible to use appended signature verification without
+         * lockdown - like the PGP verifier. When combined with an embedded
+         * config file in a signed grub binary, this could still be a meaningful
+         * secure-boot chain - so long as it isn't subverted by something like a
+         * rouge ACPI table or DT image. Defer them explicitly.
+         */
+        *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
+        return GRUB_ERR_NONE;
+
+      default:
+        *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+        return GRUB_ERR_NONE;
+    }
+}
+
+static grub_err_t
+appendedsig_write (void *ctxt __attribute__ ((unused)), void *buf, grub_size_t size)
+{
+  return grub_verify_appended_signature (buf, size);
+}
+
+struct grub_file_verifier grub_appendedsig_verifier = {
+  .name = "appendedsig",
+  .init = appendedsig_init,
+  .write = appendedsig_write,
+};
+
+static grub_ssize_t
+pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
+{
+  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
+  return 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;
+
+GRUB_MOD_INIT (appendedsig)
+{
+  int rc;
+  struct grub_module_header *header;
+
+  /* If in lockdown, immediately enter forced mode */
+  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");
+
+  rc = asn1_init ();
+  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;
+
+    /* Not an X.509 certificate, skip. */
+    if (header->type != OBJ_TYPE_X509_PUBKEY)
+      continue;
+
+    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;
+  }
+
+  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_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."));
+
+  grub_verifier_register (&grub_appendedsig_verifier);
+  grub_dl_set_persistent (mod);
+}
+
+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);
+}
diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
index fa59302c8..60ee0f2fa 100644
--- a/grub-core/commands/appendedsig/appendedsig.h
+++ b/grub-core/commands/appendedsig/appendedsig.h
@@ -18,7 +18,7 @@
  */
 
 #include <grub/crypto.h>
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
 
 extern asn1_node _gnutls_gnutls_asn;
 extern asn1_node _gnutls_pkix_asn;
diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
index 609d0ecf2..a2c46724a 100644
--- a/grub-core/commands/appendedsig/asn1util.c
+++ b/grub-core/commands/appendedsig/asn1util.c
@@ -17,7 +17,7 @@
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
 #include <grub/types.h>
 #include <grub/err.h>
 #include <grub/mm.h>
diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
index ddd1314e6..8c4eb81d7 100644
--- a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
+++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
@@ -1,5 +1,5 @@
 #include <grub/mm.h>
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
 
 const asn1_static_node gnutls_asn1_tab[] = {
   { "GNUTLS", 536872976, NULL },
diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
index adef69d95..8eeeac047 100644
--- a/grub-core/commands/appendedsig/pkix_asn1_tab.c
+++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
@@ -1,5 +1,5 @@
 #include <grub/mm.h>
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
 
 const asn1_static_node pkix_asn1_tab[] = {
   { "PKIX1", 536875024, NULL },
diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
index eb9a1ca0f..b113ac38b 100644
--- a/grub-core/commands/appendedsig/x509.c
+++ b/grub-core/commands/appendedsig/x509.c
@@ -17,7 +17,7 @@
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
 #include <grub/types.h>
 #include <grub/err.h>
 #include <grub/mm.h>
diff --git a/include/grub/file.h b/include/grub/file.h
index a5bf3a792..d678de063 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -80,6 +80,8 @@ enum grub_file_type
     GRUB_FILE_TYPE_PUBLIC_KEY,
     /* File holding public key to add to trused keys.  */
     GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
+    /* File holding x509 certificiate to add to trusted keys.  */
+    GRUB_FILE_TYPE_CERTIFICATE_TRUST,
     /* File of which we intend to print a blocklist to the user.  */
     GRUB_FILE_TYPE_PRINT_BLOCKLIST,
     /* File we intend to use for test loading or testing speed.  */
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 11/21] appended signatures: verification tests
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (9 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 10/21] appended signatures: support verifying appended signatures Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-30 15:39   ` Stefan Berger
  2025-02-14 10:27   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 12/21] appended signatures: documentation Sudhakar Kuppusamy
                   ` (9 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

These tests are run through all_functional_test and test a range
of commands and behaviours.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/Makefile.core.def               |   6 +
 grub-core/tests/appended_signature_test.c | 258 ++++++
 grub-core/tests/appended_signatures.h     | 975 ++++++++++++++++++++++
 grub-core/tests/lib/functional_test.c     |   1 +
 4 files changed, 1240 insertions(+)
 create mode 100644 grub-core/tests/appended_signature_test.c
 create mode 100644 grub-core/tests/appended_signatures.h

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index d693986c6..9cf4a6009 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2194,6 +2194,12 @@ module = {
   common = tests/setjmp_test.c;
 };
 
+module = {
+  name = appended_signature_test;
+  common = tests/appended_signature_test.c;
+  common = tests/appended_signatures.h;
+};
+
 module = {
   name = signature_test;
   common = tests/signature_test.c;
diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c
new file mode 100644
index 000000000..3d5b97391
--- /dev/null
+++ b/grub-core/tests/appended_signature_test.c
@@ -0,0 +1,258 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ *  Copyright (C) 2020, 2022 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/time.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/env.h>
+#include <grub/test.h>
+#include <grub/mm.h>
+#include <grub/procfs.h>
+#include <grub/file.h>
+
+#include "appended_signatures.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define PROC_FILE(identifier, file_name)                                    \
+  static char *get_##identifier (grub_size_t *sz)                           \
+  {                                                                         \
+    char *ret;                                                              \
+                                                                            \
+    *sz = identifier##_len;                                                 \
+    ret = grub_malloc (*sz);                                                \
+    if (ret)                                                                \
+      grub_memcpy (ret, identifier, *sz);                                   \
+    return ret;                                                             \
+  }                                                                         \
+                                                                            \
+  static struct grub_procfs_entry identifier##_entry = { .name = file_name, \
+                                                         .get_contents = get_##identifier };
+
+#define DEFINE_TEST_CASE(case_name) PROC_FILE (case_name, #case_name)
+
+#define DO_TEST(case_name, is_valid)                       \
+  {                                                        \
+    grub_procfs_register (#case_name, &case_name##_entry); \
+    do_verify ("(proc)/" #case_name, is_valid);            \
+    grub_procfs_unregister (&case_name##_entry);           \
+  }
+
+DEFINE_TEST_CASE (hi_signed);
+DEFINE_TEST_CASE (hi_signed_sha256);
+DEFINE_TEST_CASE (hj_signed);
+DEFINE_TEST_CASE (short_msg);
+DEFINE_TEST_CASE (unsigned_msg);
+DEFINE_TEST_CASE (hi_signed_2nd);
+DEFINE_TEST_CASE (hi_double);
+DEFINE_TEST_CASE (hi_double_extended);
+
+PROC_FILE (certificate_der, "certificate.der")
+PROC_FILE (certificate2_der, "certificate2.der")
+PROC_FILE (certificate_printable_der, "certificate_printable.der")
+PROC_FILE (certificate_eku_der, "certificate_eku.der")
+
+static void
+do_verify (const char *f, int is_valid)
+{
+  grub_command_t cmd;
+  char *args[] = { (char *) f, NULL };
+  grub_err_t err;
+
+  cmd = grub_command_find ("verify_appended");
+  if (!cmd)
+    {
+      grub_test_assert (0, "can't find command `%s'", "verify_appended");
+      return;
+    }
+  err = (cmd->func) (cmd, 1, args);
+  if (is_valid)
+    {
+      grub_test_assert (err == GRUB_ERR_NONE, "verification of %s failed: %d: %s",
+                        f, grub_errno, grub_errmsg);
+    }
+  else
+    {
+      grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE,
+                        "verification of %s unexpectedly succeeded", f);
+    }
+  grub_errno = GRUB_ERR_NONE;
+}
+
+static void
+appended_signature_test (void)
+{
+  grub_command_t cmd_trust, cmd_distrust;
+  char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
+  char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
+  char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", NULL };
+  char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL };
+  char *distrust_args[] = { (char *) "1", NULL };
+  char *distrust2_args[] = { (char *) "2", NULL };
+  grub_err_t err;
+
+  grub_procfs_register ("certificate.der", &certificate_der_entry);
+  grub_procfs_register ("certificate2.der", &certificate2_der_entry);
+  grub_procfs_register ("certificate_printable.der", &certificate_printable_der_entry);
+  grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry);
+
+  cmd_trust = grub_command_find ("trust_certificate");
+  if (!cmd_trust)
+    {
+      grub_test_assert (0, "can't find command `%s'", "trust_certificate");
+      return;
+    }
+  grub_errno = GRUB_ERR_NONE;
+  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
+
+  grub_test_assert (err == GRUB_ERR_NONE, "loading certificate failed: %d: %s",
+                    grub_errno, grub_errmsg);
+
+  /* If we have no certificate the remainder of the tests are meaningless */
+  if (err != GRUB_ERR_NONE)
+    return;
+
+  /*
+   * Reload the command: this works around some 'interesting' behaviour in the
+   * dynamic command dispatcher. The first time you call cmd->func you get a
+   * dispatcher that loads the module, finds the real cmd, calls it, and then
+   * releases some internal storage. This means it's not safe to call a second
+   * time and we need to reload it.
+   */
+  cmd_trust = grub_command_find ("trust_certificate");
+
+  /* hi, signed with key 1, SHA-512 */
+  DO_TEST (hi_signed, 1);
+
+  /* hi, signed with key 1, SHA-256 */
+  DO_TEST (hi_signed_sha256, 1);
+
+  /* hi, key 1, SHA-512, second byte corrupted */
+  DO_TEST (hj_signed, 0);
+
+  /* message too short for a signature */
+  DO_TEST (short_msg, 0);
+
+  /* lorem ipsum */
+  DO_TEST (unsigned_msg, 0);
+
+  /* hi, signed with both keys, SHA-512 */
+  DO_TEST (hi_double, 1);
+
+  /*
+   * hi, signed with both keys and with empty space to test we haven't broken
+   * support for adding more signatures after the fact
+   */
+  DO_TEST (hi_double_extended, 1);
+
+  /*
+   * in enforcing mode, we shouldn't be able to load a certificate that isn't
+   * signed by an existing trusted key.
+   *
+   * However, procfs files automatically skip the verification test, so we can't
+   * easily test this.
+   */
+
+  /*
+   * verify that testing with 2 trusted certs works
+   */
+  DO_TEST (hi_signed_2nd, 0);
+
+  err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
+
+  grub_test_assert (err == GRUB_ERR_NONE, "loading certificate 2 failed: %d: %s",
+                    grub_errno, grub_errmsg);
+
+  if (err != GRUB_ERR_NONE)
+    return;
+
+  DO_TEST (hi_signed_2nd, 1);
+  DO_TEST (hi_signed, 1);
+  DO_TEST (hi_double, 1);
+  DO_TEST (hi_double_extended, 1);
+
+  /*
+   * Check certificate removal. They're added to the _top_ of the list and
+   * removed by position in the list. Current the list looks like [#2, #1].
+   *
+   * First test removing the second certificate in the list, which is
+   * certificate #1, giving us just [#2].
+   */
+  cmd_distrust = grub_command_find ("distrust_certificate");
+  if (!cmd_distrust)
+    {
+      grub_test_assert (0, "can't find command `%s'", "distrust_certificate");
+      return;
+    }
+
+  err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args);
+  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 failed: %d: %s",
+                    grub_errno, grub_errmsg);
+  DO_TEST (hi_signed_2nd, 1);
+  DO_TEST (hi_signed, 0);
+  DO_TEST (hi_double, 1);
+
+  /*
+   * Now reload certificate #1. This will make the list look like [#1, #2]
+   */
+  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
+
+  grub_test_assert (err == GRUB_ERR_NONE, "reloading certificate 1 failed: %d: %s",
+                    grub_errno, grub_errmsg);
+  DO_TEST (hi_signed, 1);
+
+  /* Remove the first certificate in the list, giving us just [#2] */
+  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
+  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 (first time) failed: %d: %s",
+                    grub_errno, grub_errmsg);
+  DO_TEST (hi_signed_2nd, 1);
+  DO_TEST (hi_signed, 0);
+
+  /*
+   * Remove the first certificate again, giving an empty list.
+   *
+   * verify_appended should fail if there are no certificates to verify against.
+   */
+  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
+  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 (second time) failed: %d: %s",
+                    grub_errno, grub_errmsg);
+  DO_TEST (hi_signed_2nd, 0);
+  DO_TEST (hi_double, 0);
+
+  /*
+   * Lastly, check a certificate that uses printableString rather than
+   * utf8String loads properly, and that a certificate with an appropriate
+   * extended key usage loads.
+   */
+  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
+  grub_test_assert (err == GRUB_ERR_NONE, "trusting printable certificate failed: %d: %s",
+                    grub_errno, grub_errmsg);
+
+  err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku);
+  grub_test_assert (err == GRUB_ERR_NONE, "trusting certificate with extended key usage failed: %d: %s",
+                    grub_errno, grub_errmsg);
+
+  grub_procfs_unregister (&certificate_der_entry);
+  grub_procfs_unregister (&certificate2_der_entry);
+  grub_procfs_unregister (&certificate_printable_der_entry);
+  grub_procfs_unregister (&certificate_eku_der_entry);
+}
+
+GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
new file mode 100644
index 000000000..c6aa12d86
--- /dev/null
+++ b/grub-core/tests/appended_signatures.h
@@ -0,0 +1,975 @@
+unsigned char certificate_der[] = {
+  0x30, 0x82, 0x05, 0x5d, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
+  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+  0x05, 0x00, 0x30, 0x3d, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04,
+  0x03, 0x0c, 0x32, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65,
+  0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
+  0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+  0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 0x30,
+  0x36, 0x32, 0x39, 0x30, 0x38, 0x33, 0x36, 0x31, 0x33, 0x5a, 0x18, 0x0f,
+  0x32, 0x31, 0x32, 0x31, 0x30, 0x36, 0x30, 0x35, 0x30, 0x38, 0x33, 0x36,
+  0x31, 0x33, 0x5a, 0x30, 0x33, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55,
+  0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70,
+  0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
+  0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67,
+  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, 0x22,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
+  0x02, 0x82, 0x02, 0x01, 0x00, 0xb9, 0x09, 0xb2, 0xf6, 0x24, 0x34, 0xdc,
+  0x62, 0xe6, 0x4e, 0xee, 0x04, 0xdb, 0x29, 0xdc, 0x94, 0xcc, 0xee, 0x8a,
+  0x5b, 0xc3, 0x9e, 0x06, 0xba, 0xa7, 0x9b, 0xa4, 0x5f, 0x15, 0x59, 0x8e,
+  0xb8, 0x6e, 0x3c, 0xeb, 0x2e, 0xf2, 0xac, 0x21, 0x42, 0xbd, 0x30, 0xa1,
+  0x39, 0xe5, 0xb9, 0x4f, 0xa0, 0x53, 0xd5, 0x42, 0xdc, 0x8a, 0x87, 0x30,
+  0x38, 0x93, 0x44, 0x80, 0x3b, 0x1a, 0x7e, 0x9e, 0x8e, 0x3e, 0xea, 0x45,
+  0xa0, 0x11, 0x8b, 0xfb, 0x78, 0xe4, 0xbc, 0x65, 0x6b, 0x73, 0xea, 0x6e,
+  0xdf, 0x7c, 0x5b, 0x63, 0x7e, 0x5b, 0x0a, 0x1c, 0xe6, 0x76, 0x19, 0xb5,
+  0x01, 0xde, 0xf6, 0x65, 0x51, 0x30, 0x0a, 0x56, 0x69, 0x69, 0xe8, 0x20,
+  0xf9, 0x13, 0xf1, 0xbf, 0x6f, 0xdd, 0xce, 0x94, 0x96, 0x6e, 0x63, 0xd6,
+  0xfa, 0xa4, 0x91, 0x5f, 0xb3, 0x9c, 0xc7, 0xfa, 0xa9, 0xff, 0x66, 0x5f,
+  0xf3, 0xab, 0x5e, 0xdf, 0x4e, 0xca, 0x11, 0xcf, 0xbf, 0xf8, 0xad, 0x65,
+  0xb1, 0x49, 0x8b, 0xe9, 0x2a, 0xad, 0x7d, 0xf3, 0x0b, 0xfa, 0x5b, 0x6a,
+  0x6a, 0x20, 0x12, 0x77, 0xef, 0x4b, 0xb6, 0xbe, 0x92, 0xba, 0x14, 0x9c,
+  0x5e, 0xea, 0xdc, 0x56, 0x6d, 0x92, 0xd3, 0x64, 0x22, 0xf6, 0x12, 0xe8,
+  0x7d, 0x5e, 0x9c, 0xd6, 0xf9, 0x75, 0x68, 0x7f, 0x8f, 0xd3, 0x6e, 0x05,
+  0x94, 0x91, 0x4f, 0xa1, 0xd6, 0x50, 0x72, 0x3b, 0x11, 0x1f, 0x28, 0x13,
+  0xe8, 0x25, 0x6b, 0xdf, 0xff, 0x72, 0x46, 0x25, 0xe9, 0x05, 0x6f, 0x02,
+  0xc7, 0x1e, 0xc9, 0xcf, 0x99, 0xe9, 0xa7, 0xe2, 0xae, 0xbc, 0xc1, 0x22,
+  0x32, 0x73, 0x2d, 0xa3, 0x70, 0x8f, 0xa7, 0x8d, 0xbf, 0x5f, 0x74, 0x05,
+  0x1b, 0x5e, 0xfe, 0x97, 0x3c, 0xe7, 0x3b, 0x86, 0x0d, 0xf6, 0x38, 0xdb,
+  0xd2, 0x39, 0x47, 0x82, 0x00, 0x44, 0x6c, 0x7b, 0x40, 0x24, 0x0b, 0x3a,
+  0xd4, 0x19, 0x31, 0xba, 0x4e, 0x8e, 0xa3, 0x33, 0xa6, 0x78, 0xef, 0x72,
+  0x9f, 0x06, 0x37, 0x01, 0x9b, 0x79, 0x0d, 0x04, 0xbf, 0xba, 0xd5, 0x1f,
+  0x27, 0xdc, 0x85, 0xbb, 0xef, 0xd2, 0x60, 0xda, 0xa0, 0x3f, 0x66, 0xce,
+  0x9f, 0xa2, 0x7e, 0xa8, 0x8d, 0xee, 0x14, 0x4b, 0xcb, 0x93, 0xf1, 0x38,
+  0xac, 0x4f, 0xd8, 0x29, 0xf3, 0x6f, 0xd4, 0xfd, 0x4d, 0x34, 0x77, 0x58,
+  0x99, 0xdb, 0x16, 0xc1, 0xd0, 0xc7, 0x43, 0x41, 0x70, 0xc4, 0xad, 0x01,
+  0x29, 0x65, 0x22, 0x43, 0x00, 0x6f, 0xb3, 0x00, 0x27, 0x38, 0xc1, 0x4f,
+  0xda, 0x28, 0x96, 0x42, 0xdc, 0xbc, 0x3e, 0x34, 0x8e, 0x14, 0xb8, 0xf3,
+  0x86, 0x4a, 0xea, 0x16, 0x90, 0xf9, 0x0e, 0x9e, 0x8f, 0x66, 0x0c, 0xbf,
+  0x29, 0xd3, 0x8f, 0xfc, 0x4d, 0x38, 0x68, 0xe2, 0xe7, 0x64, 0x32, 0x47,
+  0xdd, 0x56, 0xc9, 0xe4, 0x47, 0x9f, 0x18, 0x89, 0xfc, 0x30, 0x7a, 0xae,
+  0x63, 0xe4, 0xec, 0x93, 0x04, 0xd4, 0x61, 0xe7, 0xbf, 0x0a, 0x06, 0x29,
+  0xc2, 0xa6, 0xd5, 0x53, 0x5d, 0x65, 0x6d, 0x4a, 0xd0, 0xb7, 0x68, 0x4d,
+  0x46, 0x0a, 0xb5, 0xff, 0x52, 0x5e, 0x92, 0x7e, 0x75, 0x08, 0xa4, 0x63,
+  0x0a, 0x6c, 0x31, 0x7a, 0xaa, 0x0c, 0x52, 0xf4, 0x2e, 0xcd, 0x08, 0xeb,
+  0xb3, 0xbd, 0xad, 0x8b, 0x8b, 0x9b, 0x8d, 0x71, 0x42, 0x30, 0x8e, 0xc7,
+  0xfd, 0xec, 0xb7, 0xe6, 0x26, 0x96, 0xf2, 0x74, 0x1b, 0x78, 0x95, 0x22,
+  0x14, 0xf3, 0xc9, 0xd3, 0x79, 0x11, 0xd9, 0xb7, 0x4d, 0x0d, 0x61, 0x60,
+  0x5c, 0x47, 0x50, 0xf3, 0xca, 0x84, 0x4c, 0x5c, 0x30, 0x2c, 0x6a, 0x18,
+  0x26, 0xb0, 0xf3, 0xd1, 0x15, 0x19, 0x39, 0xc3, 0x23, 0x13, 0x0f, 0x9c,
+  0x97, 0x2b, 0x97, 0x93, 0xf9, 0xf8, 0x18, 0x9b, 0x4a, 0x4d, 0xd6, 0xd3,
+  0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c,
+  0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
+  0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07,
+  0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+  0x8f, 0xba, 0x8b, 0xf5, 0xf4, 0x77, 0xb2, 0xa4, 0x19, 0xef, 0x43, 0xb1,
+  0x8b, 0x03, 0x4b, 0x45, 0x47, 0xb5, 0x2a, 0x48, 0x30, 0x1f, 0x06, 0x03,
+  0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x59, 0x1c, 0xb5,
+  0x52, 0x62, 0x83, 0x05, 0x3b, 0x41, 0x4c, 0x63, 0x4d, 0x5b, 0xf4, 0x8c,
+  0xe6, 0xd7, 0xda, 0x87, 0x54, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+  0x00, 0x36, 0x2d, 0x0a, 0xcb, 0x49, 0x54, 0x75, 0xd7, 0xca, 0x21, 0x86,
+  0xae, 0x40, 0x0f, 0x63, 0x10, 0x35, 0xfd, 0xbc, 0xba, 0x28, 0x31, 0x33,
+  0x07, 0x08, 0x64, 0x03, 0x6c, 0xd3, 0xd5, 0xf7, 0xb7, 0x79, 0x11, 0x0c,
+  0xa8, 0x9e, 0xfd, 0x34, 0xa2, 0xba, 0x77, 0x15, 0x15, 0x2d, 0x2c, 0x96,
+  0xae, 0x47, 0xbb, 0x82, 0x89, 0x09, 0x7f, 0xd1, 0x95, 0x69, 0x9b, 0xfe,
+  0xd7, 0x6f, 0x4e, 0x68, 0xf6, 0xe7, 0x5f, 0x54, 0xa1, 0x3a, 0xeb, 0xa4,
+  0xbf, 0x7a, 0xb6, 0x7f, 0xaa, 0xd8, 0xd7, 0x99, 0xcb, 0xae, 0x88, 0x6d,
+  0x7a, 0xf3, 0xfa, 0x9e, 0x44, 0x2f, 0x30, 0xa8, 0xe6, 0xb9, 0x75, 0xa0,
+  0x82, 0xd6, 0xb0, 0xe3, 0x03, 0xb3, 0x12, 0xa3, 0xdc, 0xb9, 0x4d, 0x93,
+  0xd4, 0x30, 0xea, 0xce, 0x96, 0x92, 0x07, 0xf8, 0xba, 0xe4, 0x0f, 0x41,
+  0xe3, 0x04, 0xaa, 0x8c, 0x07, 0x1a, 0x34, 0x60, 0xfc, 0xc0, 0x05, 0xd2,
+  0x5a, 0xa8, 0x66, 0xef, 0xe0, 0x94, 0xc5, 0x2f, 0x0f, 0xff, 0xdc, 0x70,
+  0xfb, 0xe2, 0x9d, 0x61, 0x51, 0x25, 0x02, 0xff, 0x4b, 0x69, 0xfd, 0x66,
+  0xb9, 0xeb, 0x0c, 0xc8, 0x50, 0xd3, 0xb1, 0x08, 0x1e, 0x09, 0x54, 0x87,
+  0xe8, 0xa3, 0x4b, 0xef, 0x0c, 0x32, 0x0a, 0x6c, 0xec, 0x27, 0x22, 0xba,
+  0x7f, 0xdc, 0x52, 0x27, 0x31, 0x14, 0x9a, 0xa8, 0xf7, 0xf9, 0xeb, 0xc8,
+  0xb5, 0x8d, 0x12, 0xed, 0x94, 0xab, 0x3d, 0x9a, 0xfb, 0x4e, 0x04, 0x05,
+  0xd2, 0x3c, 0x7c, 0x8a, 0xed, 0x46, 0x1b, 0x7c, 0xb5, 0x6c, 0x40, 0xb8,
+  0xc1, 0xbf, 0xb0, 0xd2, 0x93, 0x8e, 0xa8, 0x0f, 0xde, 0x78, 0xf3, 0x8c,
+  0xd8, 0x9f, 0xf8, 0xdc, 0xa1, 0x23, 0x20, 0x40, 0x17, 0xb4, 0xdb, 0xb7,
+  0x09, 0x74, 0xa7, 0x80, 0xc2, 0x12, 0xd9, 0x76, 0x79, 0x5b, 0x71, 0xa9,
+  0x6c, 0xd4, 0x57, 0x48, 0xe8, 0xfe, 0xc5, 0xc2, 0x6e, 0xe7, 0x83, 0x5a,
+  0x07, 0xf0, 0x33, 0xc1, 0xc1, 0x1d, 0x34, 0xd4, 0xc8, 0xb0, 0xb7, 0xdb,
+  0xeb, 0xe9, 0xe3, 0x59, 0xdc, 0x7f, 0x36, 0x58, 0xa9, 0xb8, 0x52, 0xdd,
+  0xf9, 0xfd, 0x1c, 0x22, 0x2f, 0x93, 0x3d, 0x53, 0x89, 0x80, 0xde, 0xa2,
+  0xb5, 0xa5, 0x36, 0xbd, 0xc3, 0x92, 0x03, 0xf3, 0x93, 0xc8, 0xc7, 0x4a,
+  0x0b, 0x8b, 0x62, 0xfe, 0xd0, 0xf8, 0x0d, 0x7a, 0x32, 0xb4, 0x39, 0x1a,
+  0xb7, 0x4e, 0xaa, 0xc4, 0x33, 0x32, 0x90, 0x8c, 0xab, 0xd4, 0xae, 0xa5,
+  0xa4, 0x85, 0xcf, 0xba, 0xe1, 0x1b, 0x26, 0x7f, 0x74, 0x02, 0x12, 0x09,
+  0x89, 0x56, 0xe4, 0xe7, 0x9d, 0x91, 0xde, 0x88, 0xe7, 0x1c, 0xed, 0x80,
+  0x05, 0xa8, 0x58, 0x9a, 0x3e, 0x16, 0x97, 0xd5, 0xbc, 0x54, 0xcc, 0xf0,
+  0x32, 0xf2, 0x93, 0x09, 0x94, 0x9f, 0x3c, 0xd9, 0x58, 0xca, 0x68, 0x0b,
+  0xde, 0x3f, 0x73, 0x64, 0xb7, 0xf4, 0xd7, 0x5f, 0x2b, 0xe7, 0x7b, 0x06,
+  0xca, 0xb1, 0x3e, 0xed, 0xd2, 0xb9, 0x29, 0xc1, 0x95, 0x87, 0xad, 0xd6,
+  0x63, 0x69, 0xb8, 0x1f, 0x70, 0xdb, 0xeb, 0xc7, 0x11, 0x7d, 0xe2, 0x99,
+  0x64, 0x6a, 0xf5, 0x3f, 0x30, 0x74, 0x5f, 0x2a, 0x21, 0xda, 0xef, 0x44,
+  0x1d, 0xad, 0x97, 0xa1, 0xfe, 0x14, 0xa7, 0x88, 0x99, 0xd0, 0x1e, 0xb0,
+  0x61, 0x88, 0x09, 0xc9, 0xfa, 0xd1, 0xb3, 0xcb, 0x1d, 0x76, 0x04, 0xbe,
+  0x06, 0x44, 0xd2, 0x30, 0x5e, 0x95, 0x4b, 0x96, 0xc0, 0xd6, 0xbe, 0xd0,
+  0x4d, 0xf2, 0xf4, 0x71, 0x72, 0xa9, 0xbd, 0x07, 0x4f, 0xbc, 0xb3, 0x78,
+  0xb4, 0x8a, 0x44, 0xbd, 0x58, 0xd5, 0x21, 0xb6, 0x47, 0x9c, 0x88, 0x1f,
+  0xbc, 0xbd, 0x54, 0xfa, 0x1d, 0x49, 0xec, 0x51, 0xd9, 0x43, 0x49, 0x9c,
+  0x0c, 0xfa, 0x18, 0xdb, 0xeb, 0x05, 0x77, 0xa2, 0x9a
+};
+unsigned int certificate_der_len = 1377;
+
+unsigned char hi_signed[] = {
+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82,
+  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
+  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d,
+  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47,
+  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
+  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
+  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
+  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
+  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77,
+  0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03,
+  0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e,
+  0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52,
+  0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01,
+  0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75,
+  0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1,
+  0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d,
+  0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e,
+  0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f,
+  0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae,
+  0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5,
+  0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a,
+  0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33,
+  0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2,
+  0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9,
+  0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70,
+  0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67,
+  0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a,
+  0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3,
+  0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33,
+  0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4,
+  0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1,
+  0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26,
+  0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41,
+  0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda,
+  0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3,
+  0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98,
+  0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5,
+  0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e,
+  0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe,
+  0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c,
+  0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6,
+  0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5,
+  0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f,
+  0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb,
+  0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0,
+  0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4,
+  0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b,
+  0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52,
+  0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f,
+  0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c,
+  0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17,
+  0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
+  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
+  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
+};
+unsigned int hi_signed_len = 739;
+
+unsigned char hj_signed[] = {
+  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82,
+  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
+  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d,
+  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47,
+  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
+  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
+  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
+  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
+  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77,
+  0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03,
+  0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e,
+  0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52,
+  0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01,
+  0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75,
+  0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1,
+  0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d,
+  0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e,
+  0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f,
+  0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae,
+  0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5,
+  0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a,
+  0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33,
+  0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2,
+  0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9,
+  0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70,
+  0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67,
+  0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a,
+  0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3,
+  0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33,
+  0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4,
+  0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1,
+  0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26,
+  0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41,
+  0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda,
+  0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3,
+  0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98,
+  0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5,
+  0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e,
+  0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe,
+  0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c,
+  0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6,
+  0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5,
+  0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f,
+  0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb,
+  0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0,
+  0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4,
+  0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b,
+  0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52,
+  0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f,
+  0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c,
+  0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17,
+  0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
+  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
+  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
+};
+unsigned int hj_signed_len = 739;
+
+unsigned char hi_signed_sha256[] = {
+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82,
+  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
+  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d,
+  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47,
+  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
+  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
+  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
+  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
+  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0x96, 0x02, 0x7b, 0xa4, 0x07,
+  0xa7, 0x39, 0x8d, 0xa6, 0x0b, 0xde, 0x33, 0xdd, 0xf8, 0xec, 0x24, 0x5d,
+  0x06, 0x81, 0xe7, 0x3c, 0x2d, 0x0c, 0x53, 0xfb, 0x7e, 0x5a, 0xf3, 0xee,
+  0xe5, 0x4c, 0x7c, 0xf7, 0xe7, 0x8f, 0x36, 0x62, 0x35, 0xb8, 0x99, 0xc3,
+  0xeb, 0x85, 0x1d, 0x2e, 0x40, 0x6e, 0x2a, 0xb4, 0x3a, 0x76, 0x48, 0x4f,
+  0x8b, 0x29, 0xd4, 0x9e, 0x5c, 0xd2, 0x41, 0x4d, 0xc1, 0x72, 0x0f, 0x97,
+  0xe0, 0x7d, 0x88, 0xed, 0x1a, 0xb0, 0xde, 0x1b, 0x21, 0xa6, 0x0c, 0x19,
+  0xd8, 0xb0, 0x12, 0x54, 0x7b, 0xd8, 0x19, 0x03, 0xbd, 0x77, 0x83, 0x23,
+  0xeb, 0xeb, 0x68, 0x0a, 0x7b, 0x3a, 0x4d, 0x25, 0x44, 0xe1, 0x64, 0x8d,
+  0x43, 0x5a, 0x1c, 0x9f, 0x74, 0x79, 0x31, 0x3f, 0xc7, 0x8e, 0xae, 0xe1,
+  0xf9, 0x1e, 0x54, 0x12, 0x36, 0x85, 0xf2, 0x55, 0xba, 0x42, 0x60, 0x64,
+  0x25, 0x9f, 0x73, 0x62, 0x42, 0xd2, 0x1c, 0x5e, 0x39, 0x4f, 0x7d, 0x91,
+  0xb8, 0xf9, 0x59, 0x3c, 0x13, 0x6b, 0x84, 0x76, 0x6d, 0x8a, 0xc3, 0xcb,
+  0x2d, 0x14, 0x27, 0x16, 0xdc, 0x20, 0x2c, 0xbc, 0x6b, 0xc9, 0xda, 0x9f,
+  0xef, 0xe2, 0x2d, 0xc3, 0x83, 0xd8, 0xf9, 0x94, 0x18, 0xbc, 0xfe, 0x8f,
+  0xa9, 0x44, 0xad, 0xff, 0x1b, 0xcb, 0x86, 0x30, 0x96, 0xa8, 0x3c, 0x7a,
+  0x4b, 0x73, 0x1b, 0xa9, 0xc3, 0x3b, 0xaa, 0xd7, 0x44, 0xa8, 0x4d, 0xd6,
+  0x92, 0xb6, 0x00, 0x04, 0x09, 0x05, 0x4a, 0x95, 0x02, 0x90, 0x19, 0x8c,
+  0x9a, 0xa5, 0xee, 0x58, 0x24, 0xb0, 0xca, 0x5e, 0x6f, 0x73, 0xdb, 0xf5,
+  0xa1, 0xf4, 0xf0, 0xa9, 0xeb, 0xe4, 0xdc, 0x55, 0x9f, 0x8f, 0x7a, 0xd0,
+  0xf7, 0xb6, 0xaa, 0xa6, 0xb5, 0xb4, 0xab, 0xb8, 0x65, 0xad, 0x12, 0x32,
+  0x1c, 0xe6, 0x99, 0x71, 0x93, 0xe8, 0xb4, 0x1e, 0x21, 0x27, 0x52, 0xea,
+  0x8c, 0xc8, 0x79, 0x96, 0x2e, 0x48, 0x60, 0x57, 0x1c, 0x7d, 0x8c, 0x0d,
+  0x07, 0xa7, 0x12, 0x83, 0x0a, 0x76, 0x6a, 0x64, 0xed, 0xbe, 0x8d, 0xaf,
+  0xdf, 0x51, 0x05, 0xdd, 0xf2, 0xd3, 0xb8, 0x93, 0xa9, 0x13, 0xa5, 0x96,
+  0xe8, 0xfa, 0x82, 0x02, 0x18, 0x71, 0x7a, 0x71, 0xbb, 0x39, 0x6f, 0x85,
+  0xee, 0x16, 0x82, 0x27, 0x42, 0x9f, 0x83, 0xc8, 0xab, 0x6a, 0x3b, 0x99,
+  0xba, 0x38, 0x92, 0x38, 0xae, 0x59, 0xfa, 0xaa, 0x40, 0x2b, 0x52, 0x95,
+  0xca, 0x5e, 0xe1, 0x9b, 0x00, 0xbd, 0xb9, 0x63, 0x25, 0x8d, 0xc7, 0x22,
+  0xaf, 0xe5, 0x67, 0x76, 0x91, 0xf4, 0xda, 0xc9, 0x7e, 0x9e, 0xec, 0x9b,
+  0x1f, 0x7d, 0x3b, 0xfe, 0xa1, 0x20, 0x52, 0xac, 0xd0, 0xe5, 0xa6, 0xf1,
+  0xfd, 0x4c, 0x08, 0x59, 0x7d, 0x50, 0xbb, 0x0c, 0xcf, 0xd8, 0xb6, 0x0f,
+  0xc7, 0x19, 0xcb, 0x7a, 0x96, 0x6f, 0x0f, 0x6c, 0x71, 0x56, 0x72, 0xd1,
+  0x06, 0x29, 0x0f, 0x08, 0xa2, 0x46, 0x3e, 0x58, 0x42, 0xc4, 0x8c, 0xe0,
+  0x6e, 0xe9, 0x37, 0xd5, 0x2f, 0x74, 0x36, 0x1d, 0x14, 0xcb, 0x10, 0x0e,
+  0x7d, 0x67, 0xbd, 0x38, 0x0e, 0xa4, 0x27, 0x1d, 0x3c, 0x78, 0x4d, 0x0d,
+  0x15, 0x42, 0x70, 0x20, 0xe0, 0x1d, 0x83, 0x6c, 0x4d, 0xf1, 0x02, 0xa1,
+  0x51, 0xc4, 0xc5, 0x5d, 0x69, 0x90, 0x58, 0x82, 0x94, 0x50, 0x36, 0x22,
+  0xb3, 0xa4, 0x15, 0x77, 0xdc, 0x44, 0xb0, 0x50, 0xa2, 0x3f, 0xd0, 0x0e,
+  0x1b, 0xfc, 0xf4, 0x5b, 0x3b, 0x7d, 0x63, 0x94, 0x22, 0xf3, 0x87, 0x0a,
+  0x41, 0x8a, 0x27, 0x48, 0xcb, 0x6c, 0xfd, 0x70, 0x66, 0x5f, 0x11, 0x6f,
+  0x74, 0x2c, 0x42, 0xaf, 0x74, 0x45, 0x3f, 0x0c, 0x03, 0xc8, 0x80, 0xe2,
+  0x71, 0x08, 0x93, 0xbd, 0x4d, 0x18, 0x78, 0x1e, 0x8e, 0xb9, 0x3a, 0xd6,
+  0x1a, 0xde, 0xf9, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
+  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
+  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
+};
+unsigned int hi_signed_sha256_len = 739;
+
+unsigned char short_msg[] = {
+  0x68, 0x69, 0x0a
+};
+unsigned int short_msg_len = 3;
+
+unsigned char unsigned_msg[] = {
+  0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70,
+  0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65,
+  0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20,
+  0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20,
+  0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
+  0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69,
+  0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75,
+  0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d,
+  0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20,
+  0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71,
+  0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65,
+  0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76,
+  0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74,
+  0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73,
+  0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f,
+  0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61,
+  0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74,
+  0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20,
+  0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70,
+  0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
+  0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75,
+  0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70,
+  0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20,
+  0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67,
+  0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61,
+  0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75,
+  0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f,
+  0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20,
+  0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75,
+  0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69,
+  0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e,
+  0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71,
+  0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c,
+  0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d,
+  0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20,
+  0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d,
+  0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65,
+  0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63,
+  0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64,
+  0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75,
+  0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d,
+  0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20,
+  0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20,
+  0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f,
+  0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20,
+  0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65,
+  0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
+  0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20,
+  0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65,
+  0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e,
+  0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63,
+  0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c,
+  0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73,
+  0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61,
+  0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69,
+  0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69,
+  0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
+  0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61,
+  0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75,
+  0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20,
+  0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65,
+  0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69,
+  0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61,
+  0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73,
+  0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c,
+  0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63,
+  0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20,
+  0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75,
+  0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75,
+  0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f,
+  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75,
+  0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72,
+  0x3f, 0x0a
+};
+unsigned int unsigned_msg_len = 866;
+
+unsigned char certificate2_der[] = {
+  0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
+  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30,
+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+  0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04,
+  0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20,
+  0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
+  0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+  0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+  0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38,
+  0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32,
+  0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a,
+  0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+  0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65,
+  0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
+  0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02,
+  0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+  0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
+  0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e,
+  0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3,
+  0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93,
+  0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca,
+  0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19,
+  0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a,
+  0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14,
+  0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29,
+  0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55,
+  0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37,
+  0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb,
+  0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70,
+  0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34,
+  0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24,
+  0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6,
+  0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f,
+  0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89,
+  0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca,
+  0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc,
+  0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26,
+  0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0,
+  0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a,
+  0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63,
+  0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4,
+  0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb,
+  0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7,
+  0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8,
+  0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04,
+  0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c,
+  0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2,
+  0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24,
+  0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66,
+  0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51,
+  0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b,
+  0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2,
+  0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1,
+  0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c,
+  0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73,
+  0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41,
+  0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98,
+  0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe,
+  0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5,
+  0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24,
+  0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30,
+  0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30,
+  0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02,
+  0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+  0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1,
+  0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06,
+  0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94,
+  0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb,
+  0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
+  0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf,
+  0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64,
+  0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b,
+  0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12,
+  0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d,
+  0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91,
+  0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d,
+  0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60,
+  0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c,
+  0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4,
+  0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1,
+  0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79,
+  0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd,
+  0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a,
+  0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7,
+  0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60,
+  0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70,
+  0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba,
+  0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70,
+  0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75,
+  0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d,
+  0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda,
+  0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86,
+  0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e,
+  0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11,
+  0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9,
+  0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95,
+  0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f,
+  0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20,
+  0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48,
+  0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac,
+  0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b,
+  0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75,
+  0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71,
+  0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e,
+  0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a,
+  0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6,
+  0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59,
+  0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91,
+  0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88,
+  0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87,
+  0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19,
+  0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48
+};
+unsigned int certificate2_der_len = 1366;
+
+unsigned char hi_signed_2nd[] = {
+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82,
+  0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
+  0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
+  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
+  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
+  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
+  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
+  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
+  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
+  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
+  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
+  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
+  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
+  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
+  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
+  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
+  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
+  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
+  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
+  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
+  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
+  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
+  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
+  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
+  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
+  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
+  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
+  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
+  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
+  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
+  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
+  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
+  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
+  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
+  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
+  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
+  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
+  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
+  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
+  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
+  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
+  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
+  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
+  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
+  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
+  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
+  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
+  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
+  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
+  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
+  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
+  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
+  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5,
+  0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e,
+  0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64,
+  0x65, 0x64, 0x7e, 0x0a
+};
+unsigned int hi_signed_2nd_len = 736;
+
+unsigned char hi_double[] = {
+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 0x82,
+  0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x04,
+  0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
+  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
+  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
+  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
+  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
+  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
+  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
+  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
+  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
+  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
+  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
+  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
+  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
+  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
+  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
+  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
+  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
+  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
+  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
+  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
+  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
+  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
+  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
+  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
+  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
+  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
+  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
+  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
+  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
+  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
+  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
+  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
+  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
+  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
+  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
+  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
+  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
+  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
+  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
+  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
+  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
+  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
+  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
+  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
+  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
+  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
+  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
+  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
+  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
+  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
+  0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 0x31,
+  0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 0x72,
+  0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
+  0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x65,
+  0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+  0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+  0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a,
+  0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 0x0b,
+  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30,
+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+  0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 0x97,
+  0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 0xdf,
+  0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 0x77,
+  0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 0x55,
+  0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 0xc2,
+  0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 0x88,
+  0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 0xd1,
+  0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 0xe3,
+  0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 0x45,
+  0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 0x86,
+  0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 0xcd,
+  0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 0x27,
+  0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 0xf1,
+  0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 0x1a,
+  0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 0x8d,
+  0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 0xc5,
+  0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 0xa1,
+  0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 0x04,
+  0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 0x9a,
+  0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 0x1c,
+  0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 0xd6,
+  0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 0xe9,
+  0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 0x60,
+  0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 0x83,
+  0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 0xd7,
+  0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 0x35,
+  0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 0x0f,
+  0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 0xa0,
+  0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 0xaa,
+  0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 0xe2,
+  0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 0xc3,
+  0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 0x24,
+  0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 0xe6,
+  0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 0x5e,
+  0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 0x74,
+  0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 0x3b,
+  0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 0x8a,
+  0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 0xdc,
+  0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 0x83,
+  0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 0x21,
+  0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 0x51,
+  0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 0x19,
+  0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 0x35,
+  0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x05, 0x33, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69,
+  0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65,
+  0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
+};
+unsigned int hi_double_len = 1374;
+
+unsigned char hi_double_extended[] = {
+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48,
+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 0x82,
+  0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x04,
+  0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
+  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
+  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
+  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
+  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
+  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
+  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
+  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
+  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
+  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
+  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
+  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
+  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
+  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
+  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
+  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
+  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
+  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
+  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
+  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
+  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
+  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
+  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
+  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
+  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
+  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
+  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
+  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
+  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
+  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
+  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
+  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
+  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
+  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
+  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
+  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
+  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
+  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
+  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
+  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
+  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
+  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
+  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
+  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
+  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
+  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
+  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
+  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
+  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
+  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
+  0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 0x31,
+  0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 0x72,
+  0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
+  0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x65,
+  0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+  0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+  0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a,
+  0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 0x0b,
+  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30,
+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+  0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 0x97,
+  0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 0xdf,
+  0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 0x77,
+  0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 0x55,
+  0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 0xc2,
+  0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 0x88,
+  0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 0xd1,
+  0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 0xe3,
+  0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 0x45,
+  0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 0x86,
+  0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 0xcd,
+  0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 0x27,
+  0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 0xf1,
+  0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 0x1a,
+  0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 0x8d,
+  0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 0xc5,
+  0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 0xa1,
+  0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 0x04,
+  0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 0x9a,
+  0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 0x1c,
+  0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 0xd6,
+  0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 0xe9,
+  0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 0x60,
+  0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 0x83,
+  0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 0xd7,
+  0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 0x35,
+  0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 0x0f,
+  0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 0xa0,
+  0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 0xaa,
+  0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 0xe2,
+  0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 0xc3,
+  0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 0x24,
+  0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 0xe6,
+  0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 0x5e,
+  0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 0x74,
+  0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 0x3b,
+  0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 0x8a,
+  0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 0xdc,
+  0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 0x83,
+  0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 0x21,
+  0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 0x51,
+  0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 0x19,
+  0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 0x35,
+  0x23, 0x2d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x05, 0x34, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
+  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
+  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
+};
+unsigned int hi_double_extended_len = 1375;
+
+unsigned char certificate_printable_der[] = {
+  0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55,
+  0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
+  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
+  0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30,
+  0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31,
+  0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35,
+  0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30,
+  0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20,
+  0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42,
+  0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20,
+  0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+  0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15,
+  0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2,
+  0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b,
+  0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b,
+  0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11,
+  0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d,
+  0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74,
+  0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d,
+  0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39,
+  0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4,
+  0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b,
+  0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b,
+  0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20,
+  0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf,
+  0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c,
+  0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b,
+  0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e,
+  0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf,
+  0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5,
+  0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f,
+  0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34,
+  0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01,
+  0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
+  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03,
+  0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06,
+  0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca,
+  0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d,
+  0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+  0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed,
+  0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3,
+  0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+  0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d,
+  0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19,
+  0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6,
+  0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd,
+  0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47,
+  0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03,
+  0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d,
+  0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93,
+  0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9,
+  0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c,
+  0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1,
+  0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d,
+  0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf,
+  0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93,
+  0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1,
+  0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae,
+  0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5,
+  0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25,
+  0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49,
+  0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64,
+  0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67,
+  0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56,
+  0xd2
+};
+unsigned int certificate_printable_der_len = 829;
+
+unsigned char certificate_eku_der[] = {
+  0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+  0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
+  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
+  0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86,
+  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63,
+  0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74,
+  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32,
+  0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33,
+  0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a,
+  0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+  0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63,
+  0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67,
+  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20,
+  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
+  0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65,
+  0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+  0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15,
+  0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85,
+  0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06,
+  0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5,
+  0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76,
+  0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd,
+  0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c,
+  0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9,
+  0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78,
+  0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29,
+  0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb,
+  0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09,
+  0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6,
+  0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27,
+  0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7,
+  0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55,
+  0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68,
+  0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90,
+  0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62,
+  0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16,
+  0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b,
+  0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01,
+  0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
+  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03,
+  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
+  0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c,
+  0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
+  0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c,
+  0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f,
+  0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55,
+  0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab,
+  0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4,
+  0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+  0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+  0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9,
+  0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef,
+  0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29,
+  0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b,
+  0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf,
+  0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32,
+  0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9,
+  0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74,
+  0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb,
+  0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0,
+  0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24,
+  0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06,
+  0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57,
+  0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61,
+  0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21,
+  0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1,
+  0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81,
+  0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3,
+  0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e,
+  0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd,
+  0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21,
+  0x89, 0xa0, 0x55, 0xf7
+};
+unsigned int certificate_eku_der_len = 916;
diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
index 38e981f2c..23048919d 100644
--- a/grub-core/tests/lib/functional_test.c
+++ b/grub-core/tests/lib/functional_test.c
@@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)),
   grub_dl_load ("xnu_uuid_test");
   grub_dl_load ("pbkdf2_test");
   grub_dl_load ("signature_test");
+  grub_dl_load ("appended_signature_test");
   grub_dl_load ("sleep_test");
   grub_dl_load ("bswap_test");
   grub_dl_load ("ctz_test");
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 12/21] appended signatures: documentation
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (10 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 11/21] appended signatures: verification tests Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-30 15:50   ` Stefan Berger
  2025-02-14 10:39   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot Sudhakar Kuppusamy
                   ` (8 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

This explains how appended signatures can be used to form part of
a secure boot chain, and documents the commands and variables
introduced.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 docs/grub.texi | 185 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 167 insertions(+), 18 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 6e483298d..f71ce9ffc 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3274,6 +3274,7 @@ These variables have special meaning to GRUB.
 
 @menu
 * biosnum::
+* check_appended_signatures::
 * check_signatures::
 * chosen::
 * cmdpath::
@@ -3336,12 +3337,16 @@ this.
 For an alternative approach which also changes BIOS drive mappings for the
 chain-loaded system, @pxref{drivemap}.
 
+@node check_appended_signatures
+@subsection check_appended_signatures
+This variable controls whether GRUB enforces appended signature validation on
+certain loaded files. @xref{Using appended signatures}.
 
 @node check_signatures
 @subsection check_signatures
 
-This variable controls whether GRUB enforces digital signature
-validation on loaded files. @xref{Using digital signatures}.
+This variable controls whether GRUB enforces GPG-style digital signature
+validation on loaded files. @xref{Using GPG-style digital signatures}.
 
 @node chosen
 @subsection chosen
@@ -6377,6 +6382,7 @@ 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
 * drivemap::                    Map a drive to another
 * echo::                        Display a line of text
 * efitextmode::                 Set/Get text output mode resolution
@@ -6395,6 +6401,7 @@ you forget a command, you can run the command @command{help}
 * hexdump::                     Show raw contents of a file or memory
 * insmod::                      Insert a module
 * keystatus::                   Check key modifier status
+* 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
@@ -6435,8 +6442,10 @@ you forget a command, you can run the command @command{help}
 * tpm2_key_protector_clear::    Clear the TPM2 key protector
 * 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
 * unset::                       Unset an environment variable
 @comment * vbeinfo::                     List available video modes
+* verify_appended::             Verify appended digital signature
 * verify_detached::             Verify detached digital signature
 * videoinfo::                   List available video modes
 * wrmsr::                       Write values to model-specific registers
@@ -6778,7 +6787,24 @@ These keys are used to validate signatures when environment variable
 @code{check_signatures} is set to @code{enforce}
 (@pxref{check_signatures}), and by some invocations of
 @command{verify_detached} (@pxref{verify_detached}).  @xref{Using
-digital signatures}, for more information.
+GPG-style digital signatures}, for more information.
+@end deffn
+
+@node distrust_certificate
+@subsection distrust_certificate
+
+@deffn Command distrust_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}).
+
+These certificates are used to validate appended signatures when environment
+variable @code{check_appended_signatures} is set to @code{enforce}
+(@pxref{check_appended_signatures}), and by @command{verify_appended}
+(@pxref{verify_appended}). See @xref{Using appended signatures} for more
+information.
 @end deffn
 
 @node drivemap
@@ -7169,6 +7195,19 @@ without any options, the @command{keystatus} command returns true if and
 only if checking key modifier status is supported.
 @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
@@ -7189,7 +7228,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of
 @code{gpg --fingerprint}).  The least significant four bytes (last
 eight hexadecimal digits) can be used as an argument to
 @command{distrust} (@pxref{distrust}).
-@xref{Using digital signatures}, for more information about uses for
+@xref{Using GPG-style digital signatures}, for more information about uses for
 these keys.
 @end deffn
 
@@ -7224,8 +7263,11 @@ When used with care, @option{--skip-sig} and the whitelist enable an
 administrator to configure a system to boot only signed
 configurations, but to allow the user to select from among multiple
 configurations, and to enable ``one-shot'' boot attempts and
-``savedefault'' behavior.  @xref{Using digital signatures}, for more
+``savedefault'' behavior.  @xref{Using GPG-style digital signatures}, for more
 information.
+Extra care should be taken when combining this command with appended signatures
+(@pxref{Using appended signatures}), as this file is not validated by an
+appended signature and could set @code{check_appended_signatures=no}.
 @end deffn
 
 
@@ -7596,7 +7638,7 @@ read.  It is possible to modify a digitally signed environment block
 file from within GRUB using this command, such that its signature will
 no longer be valid on subsequent boots.  Care should be taken in such
 advanced configurations to avoid rendering the system
-unbootable. @xref{Using digital signatures}, for more information.
+unbootable. @xref{Using GPG-style digital signatures}, for more information.
 @end deffn
 
 
@@ -8064,11 +8106,30 @@ signatures when environment variable @code{check_signatures} is set to
 must itself be properly signed.  The @option{--skip-sig} option can be
 used to disable signature-checking when reading @var{pubkey_file}
 itself. It is expected that @option{--skip-sig} is useful for testing
-and manual booting. @xref{Using digital signatures}, for more
+and manual booting. @xref{Using GPG-style digital signatures}, for more
 information.
 @end deffn
 
 
+@node trust_certificate
+@subsection trust_certificate
+
+@deffn Command trust_certificate x509_certificate
+Read a 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
+variable @code{check_appended_signatures} is set to @code{enforce}.
+
+Note that if @code{check_appended_signatures} is set to @code{enforce}
+when @command{trust_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 signatures within x509
+certificates themselves.)
+
+See @xref{Using appended signatures} for more information.
+@end deffn
+
 @node unset
 @subsection unset
 
@@ -8087,6 +8148,18 @@ only on PC BIOS platforms.
 @end deffn
 @end ignore
 
+@node verify_appended
+@subsection verify_appended
+
+@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}).
+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.
+@end deffn
 
 @node verify_detached
 @subsection verify_detached
@@ -8105,7 +8178,7 @@ tried.
 
 Exit code @code{$?} is set to 0 if the signature validates
 successfully.  If validation fails, it is set to a non-zero value.
-@xref{Using digital signatures}, for more information.
+@xref{Using GPG-style digital signatures}, for more information.
 @end deffn
 
 @node videoinfo
@@ -8565,14 +8638,15 @@ environment variables and commands are listed in the same order.
 @chapter Security
 
 @menu
-* Authentication and authorisation:: Users and access control
-* Using digital signatures::         Booting digitally signed code
-* UEFI secure boot and shim::        Booting digitally signed PE files
-* Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
-* Measured Boot::                    Measuring boot components
-* Lockdown::                         Lockdown when booting on a secure setup
-* TPM2 key protector::               Managing disk key with TPM2 key protector
-* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
+* Authentication and authorisation::   Users and access control
+* Using GPG-style digital signatures:: Booting digitally signed code
+* Using appended signatures::          An alternative approach to booting digitally signed code
+* UEFI secure boot and shim::          Booting digitally signed PE files
+* Secure Boot Advanced Targeting::     Embedded information for generation number based revocation
+* Measured Boot::                      Measuring boot components
+* Lockdown::                           Lockdown when booting on a secure setup
+* TPM2 key protector::                 Managing disk key with TPM2 key protector
+* Signing GRUB itself::                Ensuring the integrity of the GRUB core image
 @end menu
 
 @node Authentication and authorisation
@@ -8648,8 +8722,8 @@ generating configuration files with authentication.  You can use
 adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
 commands.
 
-@node Using digital signatures
-@section Using digital signatures in GRUB
+@node Using GPG-style digital signatures
+@section Using GPG-style digital signatures in GRUB
 
 GRUB's @file{core.img} can optionally provide enforcement that all files
 subsequently read from disk are covered by a valid digital signature.
@@ -8732,6 +8806,81 @@ or BIOS) configuration to cause the machine to boot from a different
 (attacker-controlled) device.  GRUB is at best only one link in a
 secure boot chain.
 
+@node Using appended signatures
+@section Using appended signatures in GRUB
+
+GRUB supports verifying Linux-style 'appended signatures' for secure boot.
+Appended signatures are PKCS#7 messages containing a signature over the
+contents of a file, plus some metadata, appended to the end of a file. A file
+with an appended signature ends with the magic string:
+
+@example
+~Module signature appended~\n
+@end example
+
+where @code{\n} represents the carriage-return character, @code{0x0a}.
+
+To enable appended signature verification, load the appendedsig module and an
+x509 certificate for verification. Building the appendedsig module into the
+core grub image is recommended.
+
+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}.
+A file can be explictly verified using the @pxref{verify_appended} command.
+
+Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported,
+and only RSA signatures are supported.
+
+A file can be signed with the @command{sign-file} utility supplied with the
+Linux kernel source. For example, if you have @code{signing.key} as the private
+key and @code{certificate.der} as the x509 certificate containing the public key:
+
+@example
+sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
+@end example
+
+Enforcement of signature verification is controlled by the
+@code{check_appended_signatures} variable. Verification will only take place
+when files are loaded if the variable is set to @code{enforce}. If a
+certificate is built into the grub core image with the @code{--x509} parameter,
+the variable will be automatically set to @code{enforce} when the appendedsig
+module is loaded.
+
+Unlike GPG-style signatures, not all files loaded by GRUB are required to be
+signed. Once verification is turned on, the following file types must carry
+appended signatures:
+
+@enumerate
+@item Linux, Multiboot, BSD, XNU and Plan9 kernels
+@item Grub modules, except those built in to the core image
+@item Any new certificate files to be trusted
+@end enumerate
+
+ACPI tables and Device Tree images will not be checked for appended signatures
+but must be verified by another mechanism such as GPG-style signatures before
+they will be loaded.
+
+No attempt is made to validate any other file type. In particular,
+chain-loaded binaries are not verified - if your platform supports
+chain-loading and this cannot be disabled, consider an alternative secure
+boot mechanism.
+
+As with GPG-style appended signatures, signature checking does @strong{not}
+stop an attacker with console access from dropping manually to the GRUB
+console and executing:
+
+@example
+set check_appended_signatures=no
+@end example
+
+Refer to the section on password-protecting GRUB (@pxref{Authentication
+and authorisation}) for more information on preventing this.
+
+Additionally, special care must be taken around the @command{loadenv} command,
+which can be used to turn off @code{check_appended_signature}.
+
 @node UEFI secure boot and shim
 @section UEFI secure boot and shim support
 
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (11 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 12/21] appended signatures: documentation Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-30 22:02   ` Stefan Berger
  2025-02-06  6:23   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support Sudhakar Kuppusamy
                   ` (7 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

From: Daniel Axtens <dja@axtens.net>

If the 'ibm,secure-boot' property of the root node is 2 or greater,
enter lockdown.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 docs/grub.texi                 |  4 ++--
 grub-core/Makefile.core.def    |  1 +
 grub-core/kern/ieee1275/init.c | 28 ++++++++++++++++++++++++++++
 include/grub/lockdown.h        |  3 ++-
 4 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index f71ce9ffc..6b634f111 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -8959,8 +8959,8 @@ platforms.
 @section Lockdown when booting on a secure setup
 
 The GRUB can be locked down when booted on a secure boot environment, for example
-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will
-be restricted and some operations/commands cannot be executed.
+if UEFI or Power secure boot is enabled. On a locked down configuration, the
+GRUB will be restricted and some operations/commands cannot be executed.
 
 The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
 Otherwise it does not exit.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 9cf4a6009..1ed55b0e3 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -331,6 +331,7 @@ kernel = {
   powerpc_ieee1275 = kern/powerpc/cache.S;
   powerpc_ieee1275 = kern/powerpc/dl.c;
   powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
+  powerpc_ieee1275 = kern/lockdown.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 dfbd0b899..59984b605 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -49,6 +49,7 @@
 #if defined(__powerpc__) || defined(__i386__)
 #include <grub/ieee1275/alloc.h>
 #endif
+#include <grub/lockdown.h>
 
 /* The maximum heap size we're going to claim at boot. Not used by sparc. */
 #ifdef __i386__
@@ -953,6 +954,31 @@ grub_parse_cmdline (void)
     }
 }
 
+static void
+grub_get_ieee1275_secure_boot (void)
+{
+  grub_ieee1275_phandle_t root;
+  int rc;
+  grub_uint32_t is_sb;
+
+  grub_ieee1275_finddevice ("/", &root);
+
+  rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb,
+                                           sizeof (is_sb), 0);
+
+  /*
+   * ibm,secure-boot:
+   * 0 - disabled
+   * 1 - audit
+   * 2 - enforce
+   * 3 - enforce + OS-specific behaviour
+   *
+   * We only support enforce.
+   */
+  if (rc >= 0 && is_sb >= 2)
+    grub_lockdown ();
+}
+
 grub_addr_t grub_modbase;
 
 void
@@ -978,6 +1004,8 @@ grub_machine_init (void)
 #else
   grub_install_get_time_ms (grub_rtc_get_time_ms);
 #endif
+
+  grub_get_ieee1275_secure_boot ();
 }
 
 void
diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
index 40531fa82..ebfee4bf0 100644
--- a/include/grub/lockdown.h
+++ b/include/grub/lockdown.h
@@ -24,7 +24,8 @@
 #define GRUB_LOCKDOWN_DISABLED       0
 #define GRUB_LOCKDOWN_ENABLED        1
 
-#ifdef GRUB_MACHINE_EFI
+#if defined(GRUB_MACHINE_EFI) || \
+    (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
 extern void
 EXPORT_FUNC (grub_lockdown) (void);
 extern int
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (12 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-30 22:14   ` Stefan Berger
  2025-02-06  9:09   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables Sudhakar Kuppusamy
                   ` (6 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

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>
---
 grub-core/kern/ieee1275/ieee1275.c | 117 +++++++++++++++++++++++++++++
 include/grub/ieee1275/ieee1275.h   |  14 ++++
 2 files changed, 131 insertions(+)

diff --git a/grub-core/kern/ieee1275/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c
index 36ca2dbfc..8d0048844 100644
--- a/grub-core/kern/ieee1275/ieee1275.c
+++ b/grub-core/kern/ieee1275/ieee1275.c
@@ -807,3 +807,120 @@ grub_ieee1275_get_block_size (grub_ieee1275_ihandle_t ihandle)
 
   return args.size;
 }
+
+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/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
index c445d0499..edd8cd0eb 100644
--- a/include/grub/ieee1275/ieee1275.h
+++ b/include/grub/ieee1275/ieee1275.h
@@ -230,6 +230,20 @@ char *EXPORT_FUNC(grub_ieee1275_encode_uint4) (grub_ieee1275_ihandle_t ihandle,
                                              grub_size_t *size);
 int EXPORT_FUNC(grub_ieee1275_get_block_size) (grub_ieee1275_ihandle_t ihandle);
 
+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);
+
 grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size);
 
 int
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (13 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-30 23:01   ` Stefan Berger
                     ` (2 more replies)
  2024-12-18 14:56 ` [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists Sudhakar Kuppusamy
                   ` (5 subsequent siblings)
  20 siblings, 3 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

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>
---
 grub-core/Makefile.am                       |   1 +
 grub-core/Makefile.core.def                 |   1 +
 grub-core/kern/ieee1275/init.c              |  14 +-
 grub-core/kern/ieee1275/platform_keystore.c | 337 ++++++++++++++++++++
 include/grub/platform_keystore.h            | 233 ++++++++++++++
 5 files changed, 584 insertions(+), 2 deletions(-)
 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 e50db8106..afb25dc4f 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 1ed55b0e3..2fd060123 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 59984b605..7d96c38f3 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__
@@ -959,7 +960,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);
 
@@ -976,7 +977,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..1c564d5da
--- /dev/null
+++ b/grub-core/kern/ieee1275/platform_keystore.c
@@ -0,0 +1,337 @@
+/*
+ *  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/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 ((grub_err_t) -7)
+
+/* Platform Keystore */
+static grub_size_t pks_max_object_size;
+grub_uint8_t grub_use_platform_keystore = 0;
+grub_pks_t grub_platform_keystore = { .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;
+}
+
+/*
+ * reads the secure boot version from PKS as an object.
+ * caller must free result
+ */
+static grub_err_t
+grub_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
+grub_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
+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_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 = grub_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 = grub_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) */
+static grub_err_t
+grub_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 = grub_read_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_get_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_read_secure_boot_variables (0, DB, &grub_platform_keystore.db,
+                                            &grub_platform_keystore.db_entries);
+      if (rc == GRUB_ERR_NONE)
+        {
+          /* DBX */
+          rc = grub_read_secure_boot_variables (0, DBX, &grub_platform_keystore.dbx,
+                                                &grub_platform_keystore.dbx_entries);
+          if (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..7a7378926
--- /dev/null
+++ b/include/grub/platform_keystore.h
@@ -0,0 +1,233 @@
+/*
+ * 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_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];
+};
+
+/*
+ * 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_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 = {NULL, NULL, 0, 0};
+void grub_release_platform_keystore (void);
+
+#endif
+
+#endif
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (14 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-31 17:21   ` Stefan Berger
  2025-02-07  6:39   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 17/21] appendedsig: While verifying the kernel, use " Sudhakar Kuppusamy
                   ` (4 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

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 integerity of the kernel, the extracted data
would be 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 would be stored in the buffer db.

Note:-

if the trusted certificate nor binary hash exists in the distrusted list (DBX),
rejected it while extracting it from the platform keystore buffer.

Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/commands/appendedsig/appendedsig.c | 636 +++++++++++++++++--
 1 file changed, 592 insertions(+), 44 deletions(-)

diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 5c82b96a4..31649e800 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -34,7 +34,7 @@
 #include <libtasn1.h>
 #include <grub/env.h>
 #include <grub/lockdown.h>
-
+#include <grub/platform_keystore.h>
 #include "appendedsig.h"
 
 GRUB_MOD_LICENSE ("GPLv3+");
@@ -64,9 +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 grub_db = {.keys = NULL, .key_entries = 0, .signatures = NULL,
+                                .signature_size = NULL, .signature_entries = 0};
 
+/* Distrusted list */
+struct grub_database grub_dbx = {.signatures = NULL, .signature_size = NULL,
+                                 .signature_entries = 0};
 /*
  * Force gcry_rsa to be a module dependency.
  *
@@ -87,6 +101,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;
+
+/* releasing trusted list memory */
+static void grub_release_trusted_list (void);
+/* releasing distrusted list memory */
+static void grub_release_distrusted_list (void);
 
 static enum
 {
@@ -95,6 +116,248 @@ 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
+grub_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_ERR_UNKNOWN_COMMAND;
+
+  grub_memset (hash, 0x00, GRUB_MAX_HASH_SIZE);
+  grub_crypto_hash (hash_func, hash, data, data_size);
+  *hash_size =  hash_func->mdlen;
+
+  return GRUB_ERR_NONE;
+}
+
+/* adding the certificate/binary hash into the trusted/distrusted list */
+static grub_err_t
+grub_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");
+
+  if (signatures == NULL && signature_size == NULL)
+    {
+      signatures = grub_zalloc (sizeof (grub_uint8_t *));
+      signature_size = grub_zalloc (sizeof (grub_size_t));
+    }
+  else
+    {
+      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
+       * grub_release_trusted_list/grub_release_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 grub_err_t
+grub_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 grub_err_t
+grub_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, if it is present, return a bad signature.
+ * else, no errors.
+ */
+static grub_err_t
+grub_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_platform_keystore.dbx_entries; i++)
+    {
+      if (grub_platform_keystore.dbx[i].data == NULL &&
+          grub_platform_keystore.dbx[i].data_size == 0)
+        continue;
+
+      if (grub_is_x509 (&grub_platform_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_platform_keystore.dbx[i].data,
+                                       grub_platform_keystore.dbx[i].data_size, distrusted_cert);
+          if (rc != GRUB_ERR_NONE)
+            {
+              grub_free (distrusted_cert);
+              continue;
+            }
+
+          if (grub_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_platform_keystore.dbx[i].data);
+              grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof (grub_pks_sd_t));
+              certificate_release (distrusted_cert);
+              grub_free (distrusted_cert);
+              return GRUB_ERR_BAD_SIGNATURE;
+            }
+
+          certificate_release (distrusted_cert);
+          grub_free (distrusted_cert);
+        }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/* adding the certificate into the trusted/distrusted list */
+static grub_err_t
+grub_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_printf ("Warning: skipping %s certificate (%d)\n",
+                   (is_db ? "trusted":"distrused"), rc);
+      grub_free (cert);
+      return rc;
+    }
+
+  if (is_db)
+    {
+      rc = grub_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":"distrused"), cert->subject);
+
+  key_entries++;
+  cert->next = database->keys;
+  database->keys = cert;
+  database->key_entries = key_entries;
+
+  return rc;
+}
+
+static 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 parse the unknown 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;
+}
+
 static const char *
 grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
                    const char *val __attribute__ ((unused)))
@@ -248,7 +511,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 (!grub_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 +542,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 = grub_db.keys; pk; pk = pk->next)
         {
           rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
           if (rc)
@@ -376,16 +639,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 = grub_db.keys;
+      grub_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 = grub_db.keys;
+  cert = grub_db.keys->next;
   while (cert)
     {
       if (i == cert_num)
@@ -432,8 +695,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 = grub_db.keys;
+  grub_db.keys = cert;
 
   return GRUB_ERR_NONE;
 }
@@ -446,7 +709,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 = grub_db.keys; cert; cert = cert->next)
     {
       grub_printf (N_("Certificate %d:\n"), cert_num);
 
@@ -539,6 +802,280 @@ 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, if it is present, return a bad signature.
+ * else, no errors.
+ */
+static grub_err_t
+grub_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_platform_keystore.dbx_entries; i++)
+    {
+      if (grub_platform_keystore.dbx[i].data == NULL &&
+          grub_platform_keystore.dbx[i].data_size == 0)
+        continue;
+
+      rc = grub_get_hash (&grub_platform_keystore.dbx[i].guid, data, data_size,
+                          cert_hash, &cert_hash_size);
+      if (rc != GRUB_ERR_NONE)
+        continue;
+
+      if (cert_hash_size == grub_platform_keystore.dbx[i].data_size &&
+          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
+          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof (grub_pks_sd_t));
+          return GRUB_ERR_BAD_SIGNATURE;
+        }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * verify the trusted binary hash against the platform keystore buffer's
+ * distrusted list, if it is present, return a bad signature.
+ * else, no errors.
+ */
+static grub_err_t
+grub_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_platform_keystore.dbx_entries; i++)
+    {
+      if (grub_platform_keystore.dbx[i].data == NULL &&
+          grub_platform_keystore.dbx[i].data_size == 0)
+        continue;
+
+      if (binary_hash_size == grub_platform_keystore.dbx[i].data_size &&
+          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
+          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof (grub_pks_sd_t));
+          return GRUB_ERR_BAD_SIGNATURE;
+        }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * extracts the binary hashes from the platform keystore buffer,
+ * and adds it to the trusted list if not exists in distrusted list.
+ */
+static grub_err_t
+grub_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 = grub_is_distrusted_binary_hash (*data, data_size);
+  if (rc != GRUB_ERR_NONE)
+    return rc;
+
+  rc = grub_add_hash (data, data_size, &grub_db.signatures, &grub_db.signature_size,
+                      &grub_db.signature_entries);
+  return rc;
+}
+
+static grub_err_t
+grub_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;
+}
+
+/*
+ * extracts the x509 certificates/binary hashes from the platform keystore buffer,
+ * parses it, and adds it to the trusted list.
+ */
+static grub_err_t
+grub_create_trusted_list (void)
+{
+  grub_err_t rc = GRUB_ERR_NONE;
+  grub_size_t i = 0;
+
+  for (i = 0; i < grub_platform_keystore.db_entries; i++)
+    {
+      if (grub_is_hash (&grub_platform_keystore.db[i].guid) == GRUB_ERR_NONE)
+        {
+          rc = grub_add_trusted_binary_hash ((const grub_uint8_t **)
+                                             &grub_platform_keystore.db[i].data,
+                                             grub_platform_keystore.db[i].data_size);
+          if (rc == GRUB_ERR_OUT_OF_MEMORY)
+            return rc;
+
+          continue;
+        }
+      else if (grub_is_x509 (&grub_platform_keystore.db[i].guid) == GRUB_ERR_NONE)
+        {
+
+          rc = grub_is_distrusted_cert_hash (grub_platform_keystore.db[i].data,
+                                             grub_platform_keystore.db[i].data_size);
+          if (rc != GRUB_ERR_NONE)
+            continue;
+
+          rc = grub_add_certificate (grub_platform_keystore.db[i].data,
+                                     grub_platform_keystore.db[i].data_size, &grub_db, 1);
+          if (rc == GRUB_ERR_OUT_OF_MEMORY)
+            return rc;
+          else if (rc != GRUB_ERR_NONE)
+            continue;
+        }
+      else
+        grub_printf ("Warning: unsupported signature data type and "
+                     "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * extracts the certificates, certificate/binary hashes out of the platform keystore buffer,
+ * and adds it to the distrusted list.
+ */
+static grub_err_t
+grub_create_distrusted_list (void)
+{
+  grub_err_t rc = GRUB_ERR_NONE;
+  grub_size_t i = 0;
+
+  for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
+    {
+      if (grub_platform_keystore.dbx[i].data != NULL &&
+          grub_platform_keystore.dbx[i].data_size > 0)
+        {
+          if (grub_is_x509 (&grub_platform_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+            {
+              rc = grub_add_certificate (grub_platform_keystore.dbx[i].data,
+                                         grub_platform_keystore.dbx[i].data_size, &grub_dbx, 0);
+              if (rc == GRUB_ERR_OUT_OF_MEMORY)
+                return rc;
+            }
+          else if (grub_is_hash (&grub_platform_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+            {
+              rc = grub_add_hash ((const grub_uint8_t **) &grub_platform_keystore.dbx[i].data,
+                                  grub_platform_keystore.dbx[i].data_size,
+                                  &grub_dbx.signatures, &grub_dbx.signature_size,
+                                  &grub_dbx.signature_entries);
+              if (rc != GRUB_ERR_NONE)
+                return rc;
+            }
+          else
+            grub_printf ("Warning: unsupported signature data type and "
+                         "skipping distrusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
+        }
+    }
+
+  return rc;
+}
+
+/*
+ * extracts the x509 certificates from the ELF note header,
+ * parses it, and adds it to the trusted list.
+ */
+static grub_err_t
+grub_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 = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
+  if (cert_data != NULL)
+    grub_free (cert_data);
+
+  return err;
+}
+
+/* releasing memory */
+static void
+grub_release_trusted_list (void)
+{
+  struct x509_certificate *cert;
+  grub_size_t i = 0;
+
+  while (grub_db.keys != NULL)
+    {
+      cert = grub_db.keys;
+      grub_db.keys = grub_db.keys->next;
+      certificate_release (cert);
+      grub_free (cert);
+    }
+
+  for (i = 0; i < grub_db.signature_entries; i++)
+    grub_free (grub_db.signatures[i]);
+
+  grub_free (grub_db.signatures);
+  grub_free (grub_db.signature_size);
+  grub_memset (&grub_db, 0x00, sizeof (grub_db));
+}
+
+/* releasing memory */
+static void
+grub_release_distrusted_list (void)
+{
+  struct x509_certificate *cert;
+  grub_size_t i = 0;
+
+  while (grub_dbx.keys != NULL)
+    {
+      cert = grub_dbx.keys;
+      grub_dbx.keys = grub_dbx.keys->next;
+      certificate_release (cert);
+      grub_free (cert);
+    }
+
+  for (i = 0; i < grub_dbx.signature_entries; i++)
+    grub_free (grub_dbx.signatures[i]);
+
+  grub_free (grub_dbx.signatures);
+  grub_free (grub_dbx.signature_size);
+  grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
+}
+
 GRUB_MOD_INIT (appendedsig)
 {
   int rc;
@@ -548,7 +1085,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,39 +1092,51 @@ 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;
-
-    /* Not an X.509 certificate, skip. */
-    if (header->type != OBJ_TYPE_X509_PUBKEY)
-      continue;
-
-    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);
+  if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
+    {
+      FOR_MODULES (header)
+        {
+          /* Not an ELF module, skip.  */
+          if (header->type != OBJ_TYPE_X509_PUBKEY)
+            continue;
 
-    grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
+          rc = grub_build_static_trusted_list (header);
+          if (rc != GRUB_ERR_NONE)
+            {
+              grub_release_trusted_list ();
+              grub_error (rc, "static trusted list creation failed");
+            }
+          else
+            grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
+                         grub_db.key_entries);
+        }
+    }
+  else if (grub_use_platform_keystore && check_sigs == check_sigs_forced)
+    {
+      rc = grub_create_trusted_list ();
+      if (rc != GRUB_ERR_NONE)
+        {
+          grub_release_trusted_list ();
+          grub_error (rc, "trusted list creation failed");
+        }
+      else
+        {
+          rc = grub_create_distrusted_list ();
+          if (rc != GRUB_ERR_NONE)
+            {
+              grub_release_trusted_list ();
+              grub_release_distrusted_list ();
+              grub_error (rc, "distrusted list creation failed");
+            }
+          else
+            grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " keys.\n"
+                         "appendedsig: the distrusted list now has %" PRIuGRUB_SIZE " keys.\n",
+                         grub_db.signature_entries + grub_db.key_entries,
+                         grub_dbx.signature_entries);
+        }
 
-    pk->next = grub_trusted_key;
-    grub_trusted_key = pk;
-  }
+      grub_release_platform_keystore ();
+    }
 
   cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
                                      N_("Add X509_CERTIFICATE to trusted certificates."));
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 17/21] appendedsig: While verifying the kernel, use trusted and distrusted lists
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (15 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2024-12-31 17:37   ` Stefan Berger
  2025-02-07  6:44   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 18/21] ieee1275: set use_static_keys flag Sudhakar Kuppusamy
                   ` (3 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

To verify the kernel's: verify the kernel binary against list of binary hashes
that are distrusted and trusted. If it is not listed in both trusted and distrusted,
the trusted keys from trusted key list used to verify the signature.

Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/commands/appendedsig/appendedsig.c | 188 +++++++++++++------
 1 file changed, 133 insertions(+), 55 deletions(-)

diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 31649e800..8b084087e 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -497,6 +497,81 @@ 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
+grub_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 grub_get_hash (&guid, data, data_size, hash, hash_size);
+}
+
+/*
+ * verify binary hash against the list of binary hashes that are distrusted
+ * and trusted.
+ */
+static grub_err_t
+grub_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 < grub_dbx.signature_entries; i++)
+    {
+      rc = grub_get_binary_hash (grub_dbx.signature_size[i], data, data_size,
+                                 hash, &hash_size);
+      if (rc != GRUB_ERR_NONE)
+        continue;
+
+      if (hash_size == grub_dbx.signature_size[i] &&
+          grub_memcmp (grub_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 < grub_db.signature_entries; i++)
+    {
+      rc = grub_get_binary_hash (grub_db.signature_size[i], data, data_size,
+                                 hash, &hash_size);
+      if (rc != GRUB_ERR_NONE)
+        continue;
+
+      if (hash_size == grub_db.signature_size[i] &&
+          grub_memcmp (grub_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)
 {
@@ -506,12 +581,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 (!grub_db.key_entries)
+  if (!grub_db.key_entries && !grub_db.signature_entries)
     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
 
   err = extract_appended_signature (buf, bufsize, &sig);
@@ -520,68 +595,71 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
 
   datasize = bufsize - sig.signature_len;
 
-  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
+  err = grub_verify_binary_hash (buf, datasize);
+  if (err == GRUB_ERR_EOF)
     {
-      /*
-       * 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 = grub_db.keys; pk; pk = pk->next)
+      for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
         {
-          rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
-          if (rc)
+          /*
+           * 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(grub_db.keys * pkcs7 signers) approach.
+           */
+          si = &sig.pkcs7.signerInfos[i];
+          context = grub_zalloc (si->hash->contextsize);
+          if (context == NULL)
+            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 (cert = grub_db.keys; cert; cert = cert->next)
             {
-              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
-                                N_("Error padding hash for RSA verification: %d"), rc);
-              grub_free (context);
-              goto cleanup;
+              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;
+                }
+
+              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;
+                }
+
+              grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
+                            i, cert->subject, rc);
             }
 
-          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
-          gcry_mpi_release (hashmpi);
-
-          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", "verify signer %d with key '%s' failed with %d\n",
-                        i, pk->subject, rc);
-        }
-
-      grub_free (context);
-
-      if (err == GRUB_ERR_NONE)
-        break;
+          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_printf ("appendedsig: successfully verified the signature with a trusted key\n");
+
   return err;
 }
 
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 18/21] ieee1275: set use_static_keys flag
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (16 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 17/21] appendedsig: While verifying the kernel, use " Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2025-01-02 13:22   ` Stefan Berger
  2025-02-07  6:46   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note Sudhakar Kuppusamy
                   ` (2 subsequent siblings)
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

if secure boot enabled with PKS, it set the use_static_keys flag
when DB variable is not present in PKS storage and the appendedsig (module)
would use it later to extract the default DB key's from ELF Note and
store it in trustedlist.

Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/kern/ieee1275/platform_keystore.c | 15 ++++++++++++++-
 include/grub/platform_keystore.h            | 12 +++++++-----
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/grub-core/kern/ieee1275/platform_keystore.c b/grub-core/kern/ieee1275/platform_keystore.c
index 1c564d5da..ddc11afd9 100644
--- a/grub-core/kern/ieee1275/platform_keystore.c
+++ b/grub-core/kern/ieee1275/platform_keystore.c
@@ -34,7 +34,11 @@
 /* Platform Keystore */
 static grub_size_t pks_max_object_size;
 grub_uint8_t grub_use_platform_keystore = 0;
-grub_pks_t grub_platform_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 };
+grub_pks_t grub_platform_keystore = { .db = NULL,
+                                      .dbx = NULL,
+                                      .db_entries = 0,
+                                      .dbx_entries = 0,
+                                      .use_static_keys = 0 };
 
 /* converts the esl data into the ESL */
 static grub_esl_t *
@@ -316,6 +320,15 @@ grub_platform_keystore_init (void)
       /* DB */
       rc = grub_read_secure_boot_variables (0, DB, &grub_platform_keystore.db,
                                             &grub_platform_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 loads the Default Keys from ELF Note */
+          grub_platform_keystore.use_static_keys = 1;
+        }
+
       if (rc == GRUB_ERR_NONE)
         {
           /* DBX */
diff --git a/include/grub/platform_keystore.h b/include/grub/platform_keystore.h
index 7a7378926..b333db7fd 100644
--- a/include/grub/platform_keystore.h
+++ b/include/grub/platform_keystore.h
@@ -49,6 +49,7 @@
 #define GRUB_UUID_SIZE 16
 #define GRUB_MAX_HASH_SIZE 64
 
+typedef grub_uint8_t grub_bool_t;
 typedef struct grub_uuid grub_uuid_t;
 typedef struct grub_esd grub_esd_t;
 typedef struct grub_esl grub_esl_t;
@@ -207,10 +208,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__
@@ -225,7 +227,7 @@ extern grub_pks_t EXPORT_VAR(grub_platform_keystore);
 #else
 
 #define grub_use_platform_keystore	0
-grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0};
+grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0, 0};
 void grub_release_platform_keystore (void);
 
 #endif
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (17 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 18/21] ieee1275: set use_static_keys flag Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2025-01-02 13:19   ` Stefan Berger
  2025-02-07  6:54   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 20/21] appendedsig: The grub command's trusted and distrusted support Sudhakar Kuppusamy
  2024-12-18 14:56 ` [PATCH v1 21/21] appendedsig: documentation Sudhakar Kuppusamy
  20 siblings, 2 replies; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

if secure boot enabled with PKS and set use_static_keys flag, it
reads the DB default keys from ELF Note and store it in trusted list buffer.

Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/commands/appendedsig/appendedsig.c | 58 ++++++++++++++------
 1 file changed, 41 insertions(+), 17 deletions(-)

diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 8b084087e..9a9f4ef1c 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -1082,7 +1082,7 @@ grub_create_distrusted_list (void)
  * parses it, and adds it to the trusted list.
  */
 static grub_err_t
-grub_build_static_trusted_list (const struct grub_module_header *header)
+grub_build_static_trusted_list (const struct grub_module_header *header, const grub_bool_t mode)
 {
   grub_err_t err = GRUB_ERR_NONE;
   struct grub_file pseudo_file;
@@ -1101,7 +1101,14 @@ grub_build_static_trusted_list (const struct grub_module_header *header)
   if (err != GRUB_ERR_NONE)
     return err;
 
-  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
+  if (mode)
+    {
+      err = grub_is_distrusted_cert_hash (cert_data, cert_data_size);
+      if (err != GRUB_ERR_NONE)
+        return err;
+    }
+
+  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, mode);
   if (cert_data != NULL)
     grub_free (cert_data);
 
@@ -1154,6 +1161,20 @@ grub_release_distrusted_list (void)
   grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
 }
 
+static grub_err_t
+grub_load_static_keys (const struct grub_module_header *header, const grub_bool_t mode)
+{
+  int rc = GRUB_ERR_NONE;
+  FOR_MODULES (header)
+    {
+      /* Not an ELF module, skip.  */
+      if (header->type != OBJ_TYPE_X509_PUBKEY)
+        continue;
+      rc = grub_build_static_trusted_list (header, mode);
+    }
+  return rc;
+}
+
 GRUB_MOD_INIT (appendedsig)
 {
   int rc;
@@ -1172,26 +1193,29 @@ GRUB_MOD_INIT (appendedsig)
 
   if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
     {
-      FOR_MODULES (header)
+      rc = grub_load_static_keys (header, 0);
+      if (rc != GRUB_ERR_NONE)
         {
-          /* Not an ELF module, skip.  */
-          if (header->type != OBJ_TYPE_X509_PUBKEY)
-            continue;
-
-          rc = grub_build_static_trusted_list (header);
-          if (rc != GRUB_ERR_NONE)
-            {
-              grub_release_trusted_list ();
-              grub_error (rc, "static trusted list creation failed");
-            }
-          else
-            grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
-                         grub_db.key_entries);
+          grub_release_trusted_list ();
+          grub_error (rc, "static trusted list creation failed");
         }
+      else
+        grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
+                     grub_db.key_entries);
+
     }
   else if (grub_use_platform_keystore && check_sigs == check_sigs_forced)
     {
-      rc = grub_create_trusted_list ();
+
+      if (grub_platform_keystore.use_static_keys == 1)
+        {
+          grub_printf ("Warning: db variable is not available at PKS and using a static keys "
+                       "as a default key in trusted list\n");
+          rc = grub_load_static_keys (header, 1);
+        }
+      else
+        rc = grub_create_trusted_list ();
+
       if (rc != GRUB_ERR_NONE)
         {
           grub_release_trusted_list ();
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 20/21] appendedsig: The grub command's trusted and distrusted support
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (18 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2025-02-07 10:16   ` Avnish Chouhan
  2024-12-18 14:56 ` [PATCH v1 21/21] appendedsig: documentation Sudhakar Kuppusamy
  20 siblings, 1 reply; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

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>
---
 grub-core/commands/appendedsig/appendedsig.c | 517 +++++++++++++------
 1 file changed, 351 insertions(+), 166 deletions(-)

diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 9a9f4ef1c..bb70e00b5 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -116,6 +116,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
+grub_printhex (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.
@@ -387,72 +417,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)
@@ -666,145 +630,347 @@ 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)
-    {
-      err = grub_errno;
-      goto cleanup;
-    }
+  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 = file_read_all (f, &data, &file_size);
+  err = grub_read_file (signed_file, &signed_data, &signed_data_size);
   if (err != GRUB_ERR_NONE)
-    goto cleanup;
-
-  err = grub_verify_appended_signature (data, file_size);
+    {
+      grub_file_close (signed_file);
+      return err;
+    }
 
-  grub_free (data);
+  grub_file_close (signed_file);
+  err = grub_verify_appended_signature (signed_data, signed_data_size);
+  grub_free (signed_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_list (grub_command_t cmd __attribute__((unused)),
+                       int argc __attribute__((unused)), char **args __attribute__((unused)))
 {
-  unsigned long cert_num, i;
-  struct x509_certificate *cert, *prev;
+  struct x509_certificate *cert = NULL;
+  grub_size_t i = 0, cert_num = 1;
 
-  if (argc != 1)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
+  for (cert = grub_db.keys; cert; cert = cert->next)
+    {
+      grub_printf (N_("trusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num);
+      grub_printf (N_("\tserial: "));
 
-  grub_errno = GRUB_ERR_NONE;
-  cert_num = grub_strtoul (args[0], NULL, 10);
-  if (grub_errno != GRUB_ERR_NONE)
-    return grub_errno;
+      for (i = 0; i < cert->serial_len - 1; i++)
+        grub_printf ("%02x:", cert->serial[i]);
 
-  if (cert_num < 1)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-                       N_("Certificate number too small - numbers start at 1"));
+      grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+      grub_printf ("\tCN: %s\n\n", cert->subject);
+      cert_num++;
+    }
 
-  if (cert_num == 1)
+  for (i = 0; i < grub_db.signature_entries; i++)
     {
-      cert = grub_db.keys;
-      grub_db.keys = cert->next;
+      grub_printf (N_("trusted binary hash %" PRIuGRUB_SIZE ":\n"), i+1);
+      grub_printf (N_("\thash: "));
+      grub_printhex (grub_db.signatures[i], grub_db.signature_size[i]);
+    }
 
-      certificate_release (cert);
-      grub_free (cert);
-      return GRUB_ERR_NONE;
+  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 = grub_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++;
     }
-  i = 2;
-  prev = grub_db.keys;
-  cert = grub_db.keys->next;
-  while (cert)
+
+  for (i = 0; i < grub_dbx.signature_entries; i++)
     {
-      if (i == cert_num)
-        {
-          prev->next = cert->next;
-          certificate_release (cert);
-          grub_free (cert);
-          return GRUB_ERR_NONE;
-        }
-      i++;
-      prev = cert;
-      cert = cert->next;
+      grub_printf (N_("distrusted certificate/binary hash %" PRIuGRUB_SIZE ":\n"), i+1);
+      grub_printf (N_("\thash: "));
+      grub_printhex (grub_dbx.signatures[i], grub_dbx.signature_size[i]);
     }
 
-  return grub_error (GRUB_ERR_BAD_ARGUMENT,
-                     N_("No certificate number %lu found - only %lu certificates in the store"),
-                     cert_num, i - 1);
+  return GRUB_ERR_NONE;
 }
 
 static grub_err_t
-grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+grub_cmd_trusted_cert (grub_command_t cmd __attribute__((unused)),
+                       int argc, char **args)
 {
-  grub_file_t certf;
-  struct x509_certificate *cert = NULL;
-  grub_err_t err;
+  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)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+    {
+      grub_printf (N_("a trusted X.509 certificate file is expected\n"
+                      "Example:\n\ttrusted_certificate <CERT FILE>\n"));
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
 
-  certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
-  if (!certf)
-    return grub_errno;
+  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;
+    }
 
-  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 (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 = read_cert_from_file (certf, cert);
-  grub_file_close (certf);
+  err = grub_read_file (cert_file, &cert_data, &cert_data_size);
   if (err != GRUB_ERR_NONE)
     {
-      grub_free (cert);
+      grub_file_close (cert_file);
       return err;
     }
-  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject);
 
-  cert->next = grub_db.keys;
-  grub_db.keys = cert;
+  grub_file_close (cert_file);
+  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
+  if (err != GRUB_ERR_NONE)
+    {
+      grub_release_trusted_list ();
+      grub_release_distrusted_list ();
+      grub_error (err, "adding of trusted certificate failed");
+    }
 
-  return GRUB_ERR_NONE;
+  grub_free (cert_data);
+
+  return err;
 }
 
 static grub_err_t
-grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)),
-               char **args __attribute__ ((unused)))
+grub_cmd_trusted_hash (grub_command_t cmd __attribute__((unused)), int argc, char**args)
 {
-  struct x509_certificate *cert;
-  int cert_num = 1;
-  grub_size_t i;
+  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;
 
-  for (cert = grub_db.keys; cert; cert = cert->next)
+  if (argc != 1)
     {
-      grub_printf (N_("Certificate %d:\n"), cert_num);
+      grub_printf (N_("a trusted binary hash file is expected\n"
+                      "Example:\n\ttrusted_signature <BINARY HASH FILE>\n"));
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
 
-      grub_printf (N_("\tSerial: "));
-      for (i = 0; i < cert->serial_len - 1; i++)
+  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 = grub_add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &grub_db.signatures,
+                      &grub_db.signature_size, &grub_db.signature_entries);
+  if (rc != GRUB_ERR_NONE)
+    {
+      grub_release_trusted_list ();
+      grub_release_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 = grub_db.keys;
+  struct x509_certificate *previous_cert = grub_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;
+    }
+
+  cert_num = grub_strtoul (args[0], NULL, 10);
+  if (cert_num < 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("trusted certificate number should to begin with 1"));
+
+  if (cert_num > grub_db.key_entries)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("trusted certificate number should not exceed %" PRIuGRUB_SIZE ""),
+                       grub_db.key_entries);
+  else if (cert_num < grub_db.key_entries)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("there is no certificate on the trusted list. so, not permitted"));
+
+  for (i = 1; i < grub_db.key_entries; i++)
+    {
+      if (cert_num == 1)
         {
-          grub_printf ("%02x:", cert->serial[i]);
+          previous_cert = current_cert->next;
+          break;
+        }
+      else if (cert_num == i)
+        {
+          previous_cert->next = current_cert->next;
+          break;
         }
-      grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
 
-      grub_printf ("\tCN: %s\n\n", cert->subject);
-      cert_num++;
+      previous_cert = current_cert;
+      current_cert = current_cert->next;
     }
 
+  certificate_release (current_cert);
+  grub_free (current_cert);
+
   return GRUB_ERR_NONE;
 }
 
+static grub_err_t
+grub_cmd_distrusted_hash (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+  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 != 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;
+    }
+
+  if (check_sigs == check_sigs_forced)
+    {
+      grub_printf ("Warning: since secure boot is enabled, "
+                   "adding of distrusted certificate/binary hash is not permitted!\n");
+      return grub_errno;
+    }
+
+  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"));
+
+  if (grub_strlen (args[1]) == 0)
+    return grub_error (GRUB_ERR_BAD_FILENAME,
+                       N_("missing distrusted certificate/binary hash file"));
+
+  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"));
+
+  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 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"));
+    }
+
+  rc = grub_add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &grub_dbx.signatures,
+                      &grub_dbx.signature_size, &grub_dbx.signature_entries);
+  if (rc != GRUB_ERR_NONE)
+    {
+      grub_release_trusted_list ();
+      grub_release_distrusted_list ();
+      grub_error (rc, "adding of distrusted binary/certificate hash failed");
+    }
+
+  grub_free (hash_data);
+
+  return rc;
+}
+
 static grub_err_t
 appendedsig_init (grub_file_t io __attribute__ ((unused)), enum grub_file_type type,
                   void **context __attribute__ ((unused)), enum grub_verify_flags *flags)
@@ -878,8 +1044,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, if it is present, return a bad signature.
@@ -1175,6 +1339,10 @@ grub_load_static_keys (const struct grub_module_header *header, const grub_bool_
   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;
@@ -1240,16 +1408,31 @@ GRUB_MOD_INIT (appendedsig)
       grub_release_platform_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);
@@ -1261,10 +1444,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);
 }
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v1 21/21] appendedsig: documentation
  2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
                   ` (19 preceding siblings ...)
  2024-12-18 14:56 ` [PATCH v1 20/21] appendedsig: The grub command's trusted and distrusted support Sudhakar Kuppusamy
@ 2024-12-18 14:56 ` Sudhakar Kuppusamy
  2025-02-07 10:00   ` Avnish Chouhan
  20 siblings, 1 reply; 83+ messages in thread
From: Sudhakar Kuppusamy @ 2024-12-18 14:56 UTC (permalink / raw)
  To: grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

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>
---
 docs/grub.texi | 110 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 78 insertions(+), 32 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 6b634f111..477e25376 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6382,7 +6382,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
 * efitextmode::                 Set/Get text output mode resolution
@@ -6401,7 +6403,6 @@ you forget a command, you can run the command @command{help}
 * hexdump::                     Show raw contents of a file or memory
 * insmod::                      Insert a module
 * keystatus::                   Check key modifier status
-* 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
@@ -6442,7 +6443,9 @@ you forget a command, you can run the command @command{help}
 * tpm2_key_protector_clear::    Clear the TPM2 key protector
 * 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
@@ -6790,15 +6793,15 @@ These keys are used to validate signatures when environment variable
 GPG-style digital signatures}, for more information.
 @end deffn
 
-@node distrust_certificate
-@subsection distrust_certificate
+@node distrusted_certificate
+@subsection distrusted_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}
@@ -6807,6 +6810,28 @@ variable @code{check_appended_signatures} is set to @code{enforce}
 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
 
@@ -7195,20 +7220,6 @@ without any options, the @command{keystatus} command returns true if and
 only if checking key modifier status is supported.
 @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
 
@@ -8111,17 +8122,17 @@ 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 a 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
 variable @code{check_appended_signatures} is set to @code{enforce}.
 
 Note that if @code{check_appended_signatures} is set to @code{enforce}
-when @command{trust_certificate} is executed, then @var{x509_certificate}
+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 signatures within x509
@@ -8130,6 +8141,33 @@ 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
 
@@ -8153,8 +8191,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.
 
@@ -8824,13 +8862,21 @@ To enable appended signature verification, load the appendedsig module and an
 x509 certificate for verification. Building the appendedsig module into the
 core grub image is recommended.
 
-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.
 
-Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported,
+Only signatures made with the SHA-256, SHA-384 and SHA-512 hash algorithm are supported,
 and only RSA signatures are supported.
 
 A file can be signed with the @command{sign-file} utility supplied with the
-- 
2.43.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature
  2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
@ 2024-12-27 14:58   ` Stefan Berger
  2025-02-26  4:24     ` sudhakar
  2025-01-04 18:30   ` Vladimir 'phcoder' Serbinenko
  2025-01-06  6:25   ` Avnish Chouhan
  2 siblings, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 14:58 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish, Rashmica Gupta



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Rashmica Gupta <rashmica.g@gmail.com>
> 
> Add infrastructure to allow firmware to verify the integrity of grub
> by use of a Linux-kernel-module-style appended signature. We initially
> target powerpc-ieee1275, but the code should be extensible to other
> platforms.
> 
> Usually these signatures are appended to a file without modifying the
> ELF file itself. (This is what the 'sign-file' tool does, for example.)
> The verifier loads the signed file from the file system and looks at the
> end of the file for the appended signature. However, on powerpc-ieee1275
> platforms, the bootloader is often stored directly in the PReP partition
> as raw bytes without a file-system. This makes determining the location
> of an appended signature more difficult.
> 
> To address this, we add a new ELF note.
> 
> The name field of shall be the string "Appended-Signature", zero-padded
> to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
> for the string "ASig"). It must be the final section in the ELF binary.
> 
> The description shall contain the appended signature structure as defined
> by the Linux kernel. The description will also be padded to be a multiple
> of 4 bytes. The padding shall be added before the appended signature
> structure (not at the end) so that the final bytes of a signed ELF file
> are the appended signature magic.
> 
> A subsequent patch documents how to create a grub core.img validly signed
> under this scheme.
> 
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   include/grub/util/install.h |  7 +++++--
>   include/grub/util/mkimage.h |  4 ++--
>   util/grub-install-common.c  | 15 ++++++++++++---
>   util/grub-mkimage.c         | 11 +++++++++++
>   util/grub-mkimagexx.c       | 38 ++++++++++++++++++++++++++++++++++++-
>   util/mkimage.c              |  6 +++---
>   6 files changed, 70 insertions(+), 11 deletions(-)
> 
> diff --git a/include/grub/util/install.h b/include/grub/util/install.h
> index 5c0a52ca2..3aabc4285 100644
> --- a/include/grub/util/install.h
> +++ b/include/grub/util/install.h
> @@ -69,6 +69,8 @@
>         N_("disable shim_lock verifier"), 0 },				\
>     { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
>       N_("disabled command line interface access"), 0 },			\
> +  { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
> +    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
>     { "verbose", 'v', 0, 0,						\
>       N_("print verbose messages."), 1 }
>   
> @@ -132,7 +134,8 @@ enum grub_install_options {
>     GRUB_INSTALL_OPTIONS_DTB,
>     GRUB_INSTALL_OPTIONS_SBAT,
>     GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
> -  GRUB_INSTALL_OPTIONS_DISABLE_CLI
> +  GRUB_INSTALL_OPTIONS_DISABLE_CLI,
> +  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
>   };
>   
>   extern char *grub_install_source_directory;
> @@ -192,7 +195,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
>   			     size_t npubkeys,
>   			     char *config_path,
>   			     const struct grub_install_image_target_desc *image_target,
> -			     int note,
> +			     int note, size_t appsig_size,
>   			     grub_compression_t comp, const char *dtb_file,
>   			     const char *sbat_path, const int disable_shim_lock,
>   			     const int disable_cli);
> diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
> index 9d74f82c5..0d40383eb 100644
> --- a/include/grub/util/mkimage.h
> +++ b/include/grub/util/mkimage.h
> @@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
>   			   const struct grub_install_image_target_desc *image_target);
>   void
>   grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
> -			     int note, char *sbat, char **core_img, size_t *core_size,
> +			     int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
>   			     Elf32_Addr target_addr,
>   			     struct grub_mkimage_layout *layout);
>   void
>   grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
> -			     int note, char *sbat, char **core_img, size_t *core_size,
> +			     int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
>   			     Elf64_Addr target_addr,
>   			     struct grub_mkimage_layout *layout);
>   
> diff --git a/util/grub-install-common.c b/util/grub-install-common.c
> index 22bccb6a3..22f0e56cb 100644
> --- a/util/grub-install-common.c
> +++ b/util/grub-install-common.c
> @@ -467,10 +467,12 @@ static char *sbat;
>   static int disable_shim_lock;
>   static grub_compression_t compression;
>   static int disable_cli;
> +static size_t appsig_size;
>   
>   int
>   grub_install_parse (int key, char *arg)
>   {
> +  const char *end;
>     switch (key)
>       {
>       case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
> @@ -571,6 +573,12 @@ grub_install_parse (int key, char *arg)
>         grub_util_error (_("Unrecognized compression `%s'"), arg);
>       case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
>         return 1;
> +    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
> +      grub_errno = 0;
> +      appsig_size = grub_strtol (arg, &end, 10);
> +      if (grub_errno)
> +        return 0;
> +      return 1;
>       default:
>         return 0;
>       }
> @@ -683,9 +691,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>     *p = '\0';
>   
>     grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
> -		  " --format '%s' --compression '%s'%s%s%s%s\n",
> +		  " --format '%s' --compression '%s'"
> +		  " --appended-signature-size %zu %s %s %s %s\n",
>   		  dir, prefix, outname,
> -		  mkimage_target, compnames[compression],
> +		  mkimage_target, compnames[compression], appsig_size,
>   		  note ? " --note" : "",
>   		  disable_shim_lock ? " --disable-shim-lock" : "",
>   		  disable_cli ? " --disable-cli" : "", s);
> @@ -698,7 +707,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>     grub_install_generate_image (dir, prefix, fp, outname,
>   			       modules.entries, memdisk_path,
>   			       pubkeys, npubkeys, config_path, tgt,
> -			       note, compression, dtb, sbat,
> +			       note, appsig_size, compression, dtb, sbat,
>   			       disable_shim_lock, disable_cli);
>     while (dc--)
>       grub_install_pop_module ();
> diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
> index 547f7310f..6c5063ac2 100644
> --- a/util/grub-mkimage.c
> +++ b/util/grub-mkimage.c
> @@ -84,6 +84,7 @@ static struct argp_option options[] = {
>     {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
>     {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
>     {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
> +  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
>     {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
>     { 0, 0, 0, 0, 0, 0 }
>   };
> @@ -130,6 +131,7 @@ struct arguments
>     int note;
>     int disable_shim_lock;
>     int disable_cli;
> +  size_t appsig_size;
>     const struct grub_install_image_target_desc *image_target;
>     grub_compression_t comp;
>   };
> @@ -140,6 +142,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
>     /* Get the input argument from argp_parse, which we
>        know is a pointer to our arguments structure. */
>     struct arguments *arguments = state->input;
> +  const char* end;

const char *end;


>   
>     switch (key)
>       {
> @@ -172,6 +175,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
>         arguments->note = 1;
>         break;
>   
> +    case 'S':
> +      grub_errno = 0;
> +      arguments->appsig_size = grub_strtol (arg, &end, 10);
> +      if (grub_errno)
> +        return 0;
> +      break;
> +
>       case 'm':
>         if (arguments->memdisk)
>   	free (arguments->memdisk);
> @@ -330,6 +340,7 @@ main (int argc, char *argv[])
>   			       arguments.memdisk, arguments.pubkeys,
>   			       arguments.npubkeys, arguments.config,
>   			       arguments.image_target, arguments.note,
> +			       arguments.appsig_size,
>   			       arguments.comp, arguments.dtb,
>   			       arguments.sbat, arguments.disable_shim_lock,
>   			       arguments.disable_cli);
> diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
> index 448862b2e..6fe348e5b 100644
> --- a/util/grub-mkimagexx.c
> +++ b/util/grub-mkimagexx.c
> @@ -115,6 +115,14 @@ struct grub_sbat_note {
>     char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
>   };
>   
> +#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
> +#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
> +struct grub_appended_signature_note
> +{
> +  Elf32_Nhdr header;
> +  char name[ALIGN_UP (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
> +};
> +
>   static int
>   is_relocatable (const struct grub_install_image_target_desc *image_target)
>   {
> @@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
>   
>   void
>   SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
> -				    int note, char *sbat, char **core_img, size_t *core_size,
> +				    int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
>   				    Elf_Addr target_addr,
>   				    struct grub_mkimage_layout *layout)
>   {
> @@ -237,6 +245,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
>         footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
>       }
>   
> +  if (appsig_size)
> +    {
> +      phnum++;
> +      footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
> +    }
> +
>     if (image_target->id != IMAGE_LOONGSON_ELF)
>       phnum += 2;
>   
> @@ -527,6 +541,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
>         phdr->p_filesz = grub_host_to_target32 (note_size);
>         phdr->p_memsz = 0;
>         phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
> +      footer += note_size;
> +      footer_offset += note_size;
> +    }
> +
> +  if (appsig_size)
> +    {
> +      int note_size = ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
> +      struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) footer;
> +      note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
> +      /* needs to sit at the end, so we round this up and sign some zero padding */
> +      note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP (appsig_size, 4));
> +      note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
> +      strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
> +      phdr++;
> +      phdr->p_type = grub_host_to_target32 (PT_NOTE);
> +      phdr->p_flags = grub_host_to_target32 (PF_R);
> +      phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
> +      phdr->p_vaddr = 0;
> +      phdr->p_paddr = 0;
> +      phdr->p_filesz = grub_host_to_target32 (note_size);
> +      phdr->p_memsz = 0;
> +      phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
>       }
>   
>     {
> diff --git a/util/mkimage.c b/util/mkimage.c
> index b46df2909..f5c59f563 100644
> --- a/util/mkimage.c
> +++ b/util/mkimage.c
> @@ -885,7 +885,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
>   			     char *memdisk_path, char **pubkey_paths,
>   			     size_t npubkeys, char *config_path,
>   			     const struct grub_install_image_target_desc *image_target,
> -			     int note, grub_compression_t comp, const char *dtb_path,
> +			     int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path,
>   			     const char *sbat_path, int disable_shim_lock,
>   			     int disable_cli)
>   {
> @@ -1833,10 +1833,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
>   	else
>   	  target_addr = image_target->link_addr;
>   	if (image_target->voidp_sizeof == 4)
> -	  grub_mkimage_generate_elf32 (image_target, note, sbat, &core_img, &core_size,
> +	  grub_mkimage_generate_elf32 (image_target, note, sbat, appsig_size, &core_img, &core_size,
>   				       target_addr, &layout);
>   	else
> -	  grub_mkimage_generate_elf64 (image_target, note, sbat, &core_img, &core_size,
> +	  grub_mkimage_generate_elf64 (image_target, note, sbat, appsig_size, &core_img, &core_size,
>   				       target_addr, &layout);
>         }
>         break;

With nit fixed:
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 02/21] docs/grub: Document signing grub under UEFI
  2024-12-18 14:56 ` [PATCH v1 02/21] docs/grub: Document signing grub under UEFI Sudhakar Kuppusamy
@ 2024-12-27 15:00   ` Stefan Berger
  0 siblings, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 15:00 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Before adding information about how grub is signed with an appended
> signature scheme, it's worth adding some information about how it
> can currently be signed for UEFI.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   docs/grub.texi | 18 +++++++++++++++++-
>   1 file changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 200e747af..c07d5d0dc 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -8572,6 +8572,7 @@ environment variables and commands are listed in the same order.
>   * Measured Boot::                    Measuring boot components
>   * Lockdown::                         Lockdown when booting on a secure setup
>   * TPM2 key protector::               Managing disk key with TPM2 key protector
> +* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
>   @end menu
>   
>   @node Authentication and authorisation
> @@ -8652,7 +8653,7 @@ commands.
>   
>   GRUB's @file{core.img} can optionally provide enforcement that all files
>   subsequently read from disk are covered by a valid digital signature.
> -This document does @strong{not} cover how to ensure that your
> +This section does @strong{not} cover how to ensure that your
>   platform's firmware (e.g., Coreboot) validates @file{core.img}.
>   
>   If environment variable @code{check_signatures}
> @@ -9119,6 +9120,21 @@ command through the swtpm control channel.
>   # @kbd{swtpm_ioctl -s --unix swtpm-state/ctrl}
>   @end example
>   
> +@node Signing GRUB itself
> +@section Signing GRUB itself
> +To ensure a complete secure-boot chain, there must be a way for the code that
> +loads GRUB to verify the integrity of the core image.
> +This is ultimately platform-specific and individual platforms can define their
> +own mechanisms. However, there are general-purpose mechanisms that can be used
> +with GRUB.
> +@section Signing GRUB for UEFI secure boot
> +On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
> +with a tool such as @command{pesign} or @command{sbsign}. Refer to the
> +suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
> +image works under UEFI secure boot and can maintain the secure-boot chain. It
> +will also be necessary to enrol the public key used into a relevant firmware

s/enrol/enroll

> +key database.
> +
>   @node Platform limitations
>   @chapter Platform limitations
>   

With nit fixed:
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature
  2024-12-18 14:56 ` [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature Sudhakar Kuppusamy
@ 2024-12-27 15:04   ` Stefan Berger
  2025-01-04 18:32   ` Vladimir 'phcoder' Serbinenko
  2025-01-24  9:44   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 15:04 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Signing grub for firmware that verifies an appended signature is a
> bit fiddly. I don't want people to have to figure it out from scratch
> so document it here.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 42 insertions(+)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index c07d5d0dc..6e483298d 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -9135,6 +9135,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It
>   will also be necessary to enrol the public key used into a relevant firmware
>   key database.
>   
> +@section Signing GRUB with an appended signature
> +
> +The @file{core.img} itself can be signed with a Linux kernel module-style
> +appended signature.
> +
> +To support IEEE1275 platforms where the boot image is often loaded directly
> +from a disk partition rather than from a file system, the @file{core.img}
> +can specify the size and location of the appended signature with an ELF
> +note added by @command{grub-install}.
> +
> +An image can be signed this way using the @command{sign-file} command from
> +the Linux kernel:
> +
> +@example
> +@group
> +# grub.key is your private key and certificate.der is your public key
> +
> +# Determine the size of the appended signature. It depends on the signing
> +# certificate and the hash algorithm
> +touch empty
> +sign-file SHA256 grub.key certificate.der empty empty.sig
> +SIG_SIZE=`stat -c '%s' empty.sig`
> +rm empty empty.sig
> +
> +# Build a grub image with $SIG_SIZE reserved for the signature
> +grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
> +
> +# Replace the reserved size with a signature:
> +# cut off the last $SIG_SIZE bytes with truncate's minus modifier
> +truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
> +# sign the trimmed file with an appended signature, restoring the correct size
> +sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
> +
> +# Don't forget to install the signed image as required
> +# (e.g. on powerpc-ieee1275, to the PReP partition)
> +@end group
> +@end example
> +
> +As with UEFI secure boot, it is necessary to build in the required modules,

to build-in (?)

> +or sign them separately.
> +
> +
>   @node Platform limitations
>   @chapter Platform limitations
>   

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target
  2024-12-18 14:56 ` [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target Sudhakar Kuppusamy
@ 2024-12-27 15:06   ` Stefan Berger
  2025-01-04 18:36   ` Vladimir 'phcoder' Serbinenko
  2025-01-24  9:47   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 15:06 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Trying to start grub-emu with a module that calls grub_dl_set_persistent
> will crash because grub-emu fakes modules and passes NULL to the module
> init function.
> 
> Provide an empty function for the emu case.
> 
> Fixes: ee7808e2197c (dl: Add support for persistent modules)
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>


Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   include/grub/dl.h | 11 +++++++++++
>   1 file changed, 11 insertions(+)
> 
> diff --git a/include/grub/dl.h b/include/grub/dl.h
> index 750fc8d3d..fb4476797 100644
> --- a/include/grub/dl.h
> +++ b/include/grub/dl.h
> @@ -242,11 +242,22 @@ grub_dl_get (const char *name)
>     return 0;
>   }
>   
> +#ifdef GRUB_MACHINE_EMU
> +/*
> + * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT.
> + * So we fake this out to avoid a NULL deref.
> + */
> +static inline void
> +grub_dl_set_persistent (grub_dl_t mod __attribute__((unused)))
> +{
> +}
> +#else
>   static inline void
>   grub_dl_set_persistent (grub_dl_t mod)
>   {
>     mod->persistent = 1;
>   }
> +#endif
>   
>   static inline int
>   grub_dl_is_persistent (grub_dl_t mod)


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 05/21] pgp: factor out rsa_pad
  2024-12-18 14:56 ` [PATCH v1 05/21] pgp: factor out rsa_pad Sudhakar Kuppusamy
@ 2024-12-27 15:11   ` Stefan Berger
  2025-01-04 18:40   ` Vladimir 'phcoder' Serbinenko
  2025-01-24 10:40   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 15:11 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
> We want to use it in other RSA signature verification applications.
> 
> I considered and rejected putting it in lib/crypto.c. That file doesn't
> currently require any MPI functions, but rsa_pad does. That's not so
> much of a problem for the grub kernel and modules, but crypto.c also
> gets built into all the grub utilities. So - despite the utils not
> using any asymmetric ciphers -  we would need to built the entire MPI
> infrastructure in to them.
> 
> A better and simpler solution is just to spin rsa_pad out into its own
> PKCS#1 v1.5 module.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   grub-core/Makefile.core.def |  8 +++++
>   grub-core/commands/pgp.c    | 28 ++----------------
>   grub-core/lib/pkcs1_v15.c   | 59 +++++++++++++++++++++++++++++++++++++
>   include/grub/pkcs1_v15.h    | 27 +++++++++++++++++
>   4 files changed, 96 insertions(+), 26 deletions(-)
>   create mode 100644 grub-core/lib/pkcs1_v15.c
>   create mode 100644 include/grub/pkcs1_v15.h
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index f70e02e69..60db2adc5 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2540,6 +2540,14 @@ module = {
>     cppflags = '$(CPPFLAGS_GCRY)';
>   };
>   
> +module = {
> +  name = pkcs1_v15;
> +  common = lib/pkcs1_v15.c;
> +
> +  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
> +  cppflags = '$(CPPFLAGS_GCRY)';
> +};
> +
>   module = {
>     name = all_video;
>     common = lib/fake_module.c;
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index c6766f044..b084dc9a2 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -24,6 +24,7 @@
>   #include <grub/file.h>
>   #include <grub/command.h>
>   #include <grub/crypto.h>
> +#include <grub/pkcs1_v15.h>
>   #include <grub/i18n.h>
>   #include <grub/gcrypt/gcrypt.h>
>   #include <grub/pubkey.h>
> @@ -411,32 +412,7 @@ static int
>   rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>   	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
>   {
> -  grub_size_t tlen, emlen, fflen;
> -  grub_uint8_t *em, *emptr;
> -  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
> -  int ret;
> -  tlen = hash->mdlen + hash->asnlen;
> -  emlen = (nbits + 7) / 8;
> -  if (emlen < tlen + 11)
> -    return 1;
> -
> -  em = grub_malloc (emlen);
> -  if (!em)
> -    return 1;
> -
> -  em[0] = 0x00;
> -  em[1] = 0x01;
> -  fflen = emlen - tlen - 3;
> -  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
> -    *emptr = 0xff;
> -  *emptr++ = 0x00;
> -  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
> -  emptr += hash->asnlen;
> -  grub_memcpy (emptr, hval, hash->mdlen);
> -
> -  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
> -  grub_free (em);
> -  return ret;
> +  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
>   }
>   
>   struct grub_pubkey_context
> diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
> new file mode 100644
> index 000000000..dbacd563d
> --- /dev/null
> +++ b/grub-core/lib/pkcs1_v15.c
> @@ -0,0 +1,59 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2013  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/dl.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +/*
> + * Given a hash value 'hval', of hash specification 'hash', perform
> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
> + * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
> + */
> +gcry_err_code_t
> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
> +		     const gcry_md_spec_t * hash, gcry_mpi_t mod)
> +{
> +  grub_size_t tlen, emlen, fflen;
> +  grub_uint8_t *em, *emptr;
> +  unsigned nbits = gcry_mpi_get_nbits (mod);
> +  int ret;
> +  tlen = hash->mdlen + hash->asnlen;
> +  emlen = (nbits + 7) / 8;
> +  if (emlen < tlen + 11)
> +    return GPG_ERR_TOO_SHORT;
> +
> +  em = grub_malloc (emlen);
> +  if (!em)
> +    return 1;
> +
> +  em[0] = 0x00;
> +  em[1] = 0x01;
> +  fflen = emlen - tlen - 3;
> +  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
> +    *emptr = 0xff;
> +  *emptr++ = 0x00;
> +  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
> +  emptr += hash->asnlen;
> +  grub_memcpy (emptr, hval, hash->mdlen);
> +
> +  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
> +  grub_free (em);
> +  return ret;
> +}
> diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
> new file mode 100644
> index 000000000..5c338c84a
> --- /dev/null
> +++ b/include/grub/pkcs1_v15.h
> @@ -0,0 +1,27 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2013  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/>.
> + */
> +
> +/*
> + * Given a hash value 'hval', of hash specification 'hash', perform
> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
> + * (See RFC 8017 s 9.2)
> + */
> +gcry_err_code_t
> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
> +		     const gcry_md_spec_t * hash, gcry_mpi_t mod);
> +


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c
  2024-12-18 14:56 ` [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
@ 2024-12-27 15:13   ` Stefan Berger
  2025-01-04 18:41   ` Vladimir 'phcoder' Serbinenko
  2025-01-24 10:42   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 15:13 UTC (permalink / raw)
  To: The development of GNU GRUB, Sudhakar Kuppusamy
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the
> pgp module is a bit quirky.
> 
> include/grub/crypto.h contains:
>    extern struct gcry_pk_spec *grub_crypto_pk_rsa;
> 
> commands/pgp.c contains the actual storage:
>    struct gcry_pk_spec *grub_crypto_pk_rsa;
> 
> And the module itself saves to the storage in pgp.c:
>    GRUB_MOD_INIT(gcry_rsa)
>    {
>      grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa;
>    }
> 
> This is annoying: gcry_rsa now has a dependency on pgp!
> 
> We want to be able to bring in gcry_rsa without bringing in PGP,
> so move the storage to crypto.c.
> 
> Previously, gcry_rsa depended on pgp and mpi. Now it depends on
> crypto and mpi. As pgp depends on crypto, this doesn't add any new
> module dependencies using the PGP verfier.
> 
> [FWIW, the story is different for the symmetric ciphers. cryptodisk
> and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name()
> to get a cipher handle. That depends on grub_ciphers being populated
> by people calling grub_cipher_register. import_gcry.py ensures that the
> symmetric ciphers call it.]
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   grub-core/commands/pgp.c | 4 ----
>   grub-core/lib/crypto.c   | 4 ++++
>   2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index b084dc9a2..a45c2213c 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -147,10 +147,6 @@ const char *hashes[] = {
>     [0x0b] = "sha224"
>   };
>   
> -struct gcry_pk_spec *grub_crypto_pk_dsa;
> -struct gcry_pk_spec *grub_crypto_pk_ecdsa;
> -struct gcry_pk_spec *grub_crypto_pk_rsa;
> -
>   static int
>   dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>   	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
> diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
> index 396f76410..d53ddbe2c 100644
> --- a/grub-core/lib/crypto.c
> +++ b/grub-core/lib/crypto.c
> @@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
>         }
>   }
>   
> +struct gcry_pk_spec *grub_crypto_pk_dsa;
> +struct gcry_pk_spec *grub_crypto_pk_ecdsa;
> +struct gcry_pk_spec *grub_crypto_pk_rsa;
> +
>   void
>   grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
>   		  grub_size_t inlen)

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>



_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 07/21] grub-install: support embedding x509 certificates
  2024-12-18 14:56 ` [PATCH v1 07/21] grub-install: support embedding x509 certificates Sudhakar Kuppusamy
@ 2024-12-27 16:08   ` Stefan Berger
  2025-01-24 10:45   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-27 16:08 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish, Alastair D'Silva



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Alastair D'Silva <alastair@d-silva.org>
> 
> To support verification of appended signatures, we need a way to
> embed the necessary public keys. Existing appended signature schemes
> in the Linux kernel use X.509 certificates, so allow certificates to
> be embedded in the grub core image in the same way as PGP keys.
> 
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   grub-core/commands/pgp.c    |  2 +-
>   include/grub/kernel.h       |  2 ++
>   include/grub/util/install.h |  3 +++
>   util/grub-install-common.c  | 19 ++++++++++++++++++-
>   util/grub-mkimage.c         | 14 ++++++++++++--
>   util/mkimage.c              | 33 +++++++++++++++++++++++++++++++--
>   6 files changed, 67 insertions(+), 6 deletions(-)
> 
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index a45c2213c..847a5046a 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
>       grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
>   
>       /* Not an ELF module, skip.  */
> -    if (header->type != OBJ_TYPE_PUBKEY)
> +    if (header->type != OBJ_TYPE_GPG_PUBKEY)
>         continue;
>   
>       pseudo_file.fs = &pseudo_fs;
> diff --git a/include/grub/kernel.h b/include/grub/kernel.h
> index 6121c1e66..5c5ac129d 100644
> --- a/include/grub/kernel.h
> +++ b/include/grub/kernel.h
> @@ -29,6 +29,8 @@ enum
>     OBJ_TYPE_CONFIG,
>     OBJ_TYPE_PREFIX,
>     OBJ_TYPE_PUBKEY,
> +  OBJ_TYPE_GPG_PUBKEY,
> +  OBJ_TYPE_X509_PUBKEY,
>     OBJ_TYPE_DTB,
>     OBJ_TYPE_DISABLE_SHIM_LOCK,
>     OBJ_TYPE_DISABLE_CLI
> diff --git a/include/grub/util/install.h b/include/grub/util/install.h
> index 3aabc4285..52a667c37 100644
> --- a/include/grub/util/install.h
> +++ b/include/grub/util/install.h
> @@ -69,6 +69,8 @@
>         N_("disable shim_lock verifier"), 0 },				\
>     { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
>       N_("disabled command line interface access"), 0 },			\
> +  { "x509key",   'x', N_("FILE"), 0,					\
> +      N_("embed FILE as an x509 certificate for signature checking"), 0}, \
>     { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
>       "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
>     { "verbose", 'v', 0, 0,						\
> @@ -193,6 +195,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
>   			     const char *outname, char *mods[],
>   			     char *memdisk_path, char **pubkey_paths,
>   			     size_t npubkeys,
> +			     char **x509key_paths, size_t nx509keys,
>   			     char *config_path,
>   			     const struct grub_install_image_target_desc *image_target,
>   			     int note, size_t appsig_size,
> diff --git a/util/grub-install-common.c b/util/grub-install-common.c
> index 22f0e56cb..29c45e26e 100644
> --- a/util/grub-install-common.c
> +++ b/util/grub-install-common.c
> @@ -463,6 +463,8 @@ handle_install_list (struct install_list *il, const char *val,
>   
>   static char **pubkeys;
>   static size_t npubkeys;
> +static char **x509keys;
> +static size_t nx509keys;
>   static char *sbat;
>   static int disable_shim_lock;
>   static grub_compression_t compression;
> @@ -510,6 +512,10 @@ grub_install_parse (int key, char *arg)
>       case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
>         disable_cli = 1;
>         return 1;
> +    case 'x':
> +      x509keys = xrealloc (x509keys, sizeof (x509keys[0]) * (nx509keys + 1));
> +      x509keys[nx509keys++] = xstrdup (arg);
> +      return 1;
>   
>       case GRUB_INSTALL_OPTIONS_VERBOSITY:
>         verbosity++;
> @@ -640,6 +646,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>     for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
>       slen += sizeof (" --pubkey ''") + grub_strlen (*pk);
>   
> +  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
> +    slen += sizeof (" --x509key ''") + grub_strlen (*pk);
> +
>     for (md = modules.entries; *md; md++)
>       slen += sizeof (" ''") + grub_strlen (*md);
>   
> @@ -680,6 +689,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>         *p++ = '\'';
>       }
>   
> +  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
> +    {
> +      p = grub_stpcpy (p, "--x509key '");
> +      p = grub_stpcpy (p, *pk);
> +      *p++ = '\'';
> +      *p++ = ' ';
> +    }
> +
>     for (md = modules.entries; *md; md++)
>       {
>         *p++ = ' ';
> @@ -706,7 +723,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>   
>     grub_install_generate_image (dir, prefix, fp, outname,
>   			       modules.entries, memdisk_path,
> -			       pubkeys, npubkeys, config_path, tgt,
> +			       pubkeys, npubkeys,  x509keys, nx509keys, config_path, tgt,
>   			       note, appsig_size, compression, dtb, sbat,
>   			       disable_shim_lock, disable_cli);
>     while (dc--)
> diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
> index 6c5063ac2..1f958e04b 100644
> --- a/util/grub-mkimage.c
> +++ b/util/grub-mkimage.c
> @@ -75,7 +75,8 @@ static struct argp_option options[] = {
>      /* TRANSLATORS: "embed" is a verb (command description).  "*/
>     {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
>      /* TRANSLATORS: "embed" is a verb (command description).  "*/
> -  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0},
> +  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0},
> +  {"x509key",     'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
>     /* TRANSLATORS: NOTE is a name of segment.  */
>     {"note",   'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
>     {"output",  'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
> @@ -125,6 +126,8 @@ struct arguments
>     char *dtb;
>     char **pubkeys;
>     size_t npubkeys;
> +  char **x509keys;
> +  size_t nx509keys;
>     char *font;
>     char *config;
>     char *sbat;
> @@ -208,6 +211,12 @@ argp_parser (int key, char *arg, struct argp_state *state)
>         arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg);
>         break;
>   
> +    case 'x':
> +      arguments->x509keys = xrealloc (arguments->x509keys,
> +                                      sizeof (arguments->x509keys[0]) * (arguments->nx509keys + 1));
> +      arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
> +      break;
> +
>       case 'c':
>         if (arguments->config)
>   	free (arguments->config);
> @@ -338,7 +347,8 @@ main (int argc, char *argv[])
>     grub_install_generate_image (arguments.dir, arguments.prefix, fp,
>   			       arguments.output, arguments.modules,
>   			       arguments.memdisk, arguments.pubkeys,
> -			       arguments.npubkeys, arguments.config,
> +			       arguments.npubkeys, arguments.x509keys,
> +			       arguments.nx509keys, arguments.config,
>   			       arguments.image_target, arguments.note,
>   			       arguments.appsig_size,
>   			       arguments.comp, arguments.dtb,
> diff --git a/util/mkimage.c b/util/mkimage.c
> index f5c59f563..7076d632b 100644
> --- a/util/mkimage.c
> +++ b/util/mkimage.c
> @@ -883,7 +883,7 @@ void
>   grub_install_generate_image (const char *dir, const char *prefix,
>   			     FILE *out, const char *outname, char *mods[],
>   			     char *memdisk_path, char **pubkey_paths,
> -			     size_t npubkeys, char *config_path,
> +			     size_t npubkeys, char **x509key_paths, size_t nx509keys, char *config_path,
>   			     const struct grub_install_image_target_desc *image_target,
>   			     int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path,
>   			     const char *sbat_path, int disable_shim_lock,
> @@ -929,6 +929,18 @@ grub_install_generate_image (const char *dir, const char *prefix,
>         }
>     }
>   
> +  {
> +    size_t i;
> +    for (i = 0; i < nx509keys; i++)
> +      {
> +        size_t curs;
> +        curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
> +        grub_util_info ("the size of x509 public key %u is 0x%" GRUB_HOST_PRIxLONG_LONG,
> +                        (unsigned) i, (unsigned long long) curs);
> +        total_module_size += curs + sizeof (struct grub_module_header);
> +      }
> +  }
> +
>     if (memdisk_path)
>       {
>         memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
> @@ -1053,7 +1065,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
>   	curs = grub_util_get_image_size (pubkey_paths[i]);
>   
>   	header = (struct grub_module_header *) (kernel_img + offset);
> -	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
> +	header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY);
>   	header->size = grub_host_to_target32 (curs + sizeof (*header));
>   	offset += sizeof (*header);
>   
> @@ -1062,6 +1074,23 @@ grub_install_generate_image (const char *dir, const char *prefix,
>         }
>     }
>   
> +  {
> +    size_t i;
> +    for (i = 0; i < nx509keys; i++)
> +      {
> +        size_t curs;
> +        struct grub_module_header *header;
> +
> +        curs = grub_util_get_image_size (x509key_paths[i]);
> +        header = (struct grub_module_header *) (kernel_img + offset);
> +        header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
> +        header->size = grub_host_to_target32 (curs + sizeof (*header));
> +        offset += sizeof (*header);
> +        grub_util_load_image (x509key_paths[i], kernel_img + offset);
> +        offset += ALIGN_ADDR (curs);
> +      }
> +  }
> +
>     if (memdisk_path)
>       {
>         struct grub_module_header *header;


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files
  2024-12-18 14:56 ` [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files Sudhakar Kuppusamy
@ 2024-12-28 19:02   ` Stefan Berger
  2025-01-24 10:47   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-28 19:02 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> In order to parse PKCS#7 messages and X.509 certificates with libtasn1,
> we need some information about how they are encoded.
> 
> We get these from GNUTLS, which has the benefit that they support the
> features we need and are well tested.
> 
> The GNUTLS files are from:
> 
> - https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/gnutls_asn1_tab.c
> - https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/pkix_asn1_tab.c
> 
> The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing
> us to import it without issue.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   .../commands/appendedsig/gnutls_asn1_tab.c    | 121 +++++
>   .../commands/appendedsig/pkix_asn1_tab.c      | 484 ++++++++++++++++++
>   2 files changed, 605 insertions(+)
>   create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
>   create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c
> 
> diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> new file mode 100644
> index 000000000..ddd1314e6
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> @@ -0,0 +1,121 @@
> +#include <grub/mm.h>
> +#include <grub/libtasn1.h>
> +
> +const asn1_static_node gnutls_asn1_tab[] = {
> +  { "GNUTLS", 536872976, NULL },
> +  { NULL, 1073741836, NULL },
> +  { "RSAPublicKey", 1610612741, NULL },
> +  { "modulus", 1073741827, NULL },
> +  { "publicExponent", 3, NULL },
> +  { "RSAPrivateKey", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "modulus", 1073741827, NULL },
> +  { "publicExponent", 1073741827, NULL },
> +  { "privateExponent", 1073741827, NULL },
> +  { "prime1", 1073741827, NULL },
> +  { "prime2", 1073741827, NULL },
> +  { "exponent1", 1073741827, NULL },
> +  { "exponent2", 1073741827, NULL },
> +  { "coefficient", 1073741827, NULL },
> +  { "otherPrimeInfos", 16386, "OtherPrimeInfos"},
> +  { "ProvableSeed", 1610612741, NULL },
> +  { "algorithm", 1073741836, NULL },
> +  { "seed", 7, NULL },
> +  { "OtherPrimeInfos", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "OtherPrimeInfo"},
> +  { "OtherPrimeInfo", 1610612741, NULL },
> +  { "prime", 1073741827, NULL },
> +  { "exponent", 1073741827, NULL },
> +  { "coefficient", 3, NULL },
> +  { "AlgorithmIdentifier", 1610612741, NULL },
> +  { "algorithm", 1073741836, NULL },
> +  { "parameters", 541081613, NULL },
> +  { "algorithm", 1, NULL },
> +  { "DigestInfo", 1610612741, NULL },
> +  { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
> +  { "digest", 7, NULL },
> +  { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
> +  { "DSAPublicKey", 1073741827, NULL },
> +  { "DSAParameters", 1610612741, NULL },
> +  { "p", 1073741827, NULL },
> +  { "q", 1073741827, NULL },
> +  { "g", 3, NULL },
> +  { "DSASignatureValue", 1610612741, NULL },
> +  { "r", 1073741827, NULL },
> +  { "s", 3, NULL },
> +  { "DSAPrivateKey", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "p", 1073741827, NULL },
> +  { "q", 1073741827, NULL },
> +  { "g", 1073741827, NULL },
> +  { "Y", 1073741827, NULL },
> +  { "priv", 3, NULL },
> +  { "DHParameter", 1610612741, NULL },
> +  { "prime", 1073741827, NULL },
> +  { "base", 1073741827, NULL },
> +  { "privateValueLength", 16387, NULL },
> +  { "ECParameters", 1610612754, NULL },
> +  { "namedCurve", 12, NULL },
> +  { "ECPrivateKey", 1610612741, NULL },
> +  { "Version", 1073741827, NULL },
> +  { "privateKey", 1073741831, NULL },
> +  { "parameters", 1610637314, "ECParameters"},
> +  { NULL, 2056, "0"},
> +  { "publicKey", 536895494, NULL },
> +  { NULL, 2056, "1"},
> +  { "PrincipalName", 1610612741, NULL },
> +  { "name-type", 1610620931, NULL },
> +  { NULL, 2056, "0"},
> +  { "name-string", 536879115, NULL },
> +  { NULL, 1073743880, "1"},
> +  { NULL, 27, NULL },
> +  { "KRB5PrincipalName", 1610612741, NULL },
> +  { "realm", 1610620955, NULL },
> +  { NULL, 2056, "0"},
> +  { "principalName", 536879106, "PrincipalName"},
> +  { NULL, 2056, "1"},
> +  { "RSAPSSParameters", 1610612741, NULL },
> +  { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
> +  { NULL, 2056, "0"},
> +  { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
> +  { NULL, 2056, "1"},
> +  { "saltLength", 1610653699, NULL },
> +  { NULL, 1073741833, "20"},
> +  { NULL, 2056, "2"},
> +  { "trailerField", 536911875, NULL },
> +  { NULL, 1073741833, "1"},
> +  { NULL, 2056, "3"},
> +  { "GOSTParameters", 1610612741, NULL },
> +  { "publicKeyParamSet", 1073741836, NULL },
> +  { "digestParamSet", 16396, NULL },
> +  { "GOSTParametersOld", 1610612741, NULL },
> +  { "publicKeyParamSet", 1073741836, NULL },
> +  { "digestParamSet", 1073741836, NULL },
> +  { "encryptionParamSet", 16396, NULL },
> +  { "GOSTPrivateKey", 1073741831, NULL },
> +  { "GOSTPrivateKeyOld", 1073741827, NULL },
> +  { "IssuerSignTool", 1610612741, NULL },
> +  { "signTool", 1073741858, NULL },
> +  { "cATool", 1073741858, NULL },
> +  { "signToolCert", 1073741858, NULL },
> +  { "cAToolCert", 34, NULL },
> +  { "Gost28147-89-EncryptedKey", 1610612741, NULL },
> +  { "encryptedKey", 1073741831, NULL },
> +  { "maskKey", 1610637319, NULL },
> +  { NULL, 4104, "0"},
> +  { "macKey", 7, NULL },
> +  { "SubjectPublicKeyInfo", 1610612741, NULL },
> +  { "algorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "subjectPublicKey", 6, NULL },
> +  { "GostR3410-TransportParameters", 1610612741, NULL },
> +  { "encryptionParamSet", 1073741836, NULL },
> +  { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
> +  { NULL, 4104, "0"},
> +  { "ukm", 7, NULL },
> +  { "GostR3410-KeyTransport", 536870917, NULL },
> +  { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
> +  { "transportParameters", 536895490, "GostR3410-TransportParameters"},
> +  { NULL, 4104, "0"},
> +  { NULL, 0, NULL }
> +};
> diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> new file mode 100644
> index 000000000..adef69d95
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> @@ -0,0 +1,484 @@
> +#include <grub/mm.h>
> +#include <grub/libtasn1.h>
> +
> +const asn1_static_node pkix_asn1_tab[] = {
> +  { "PKIX1", 536875024, NULL },
> +  { NULL, 1073741836, NULL },
> +  { "PrivateKeyUsagePeriod", 1610612741, NULL },
> +  { "notBefore", 1610637349, NULL },
> +  { NULL, 4104, "0"},
> +  { "notAfter", 536895525, NULL },
> +  { NULL, 4104, "1"},
> +  { "AuthorityKeyIdentifier", 1610612741, NULL },
> +  { "keyIdentifier", 1610637319, NULL },
> +  { NULL, 4104, "0"},
> +  { "authorityCertIssuer", 1610637314, "GeneralNames"},
> +  { NULL, 4104, "1"},
> +  { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"},
> +  { NULL, 4104, "2"},
> +  { "SubjectKeyIdentifier", 1073741831, NULL },
> +  { "KeyUsage", 1073741830, NULL },
> +  { "DirectoryString", 1610612754, NULL },
> +  { "teletexString", 1612709918, NULL },
> +  { "MAX", 524298, "1"},
> +  { "printableString", 1612709919, NULL },
> +  { "MAX", 524298, "1"},
> +  { "universalString", 1612709920, NULL },
> +  { "MAX", 524298, "1"},
> +  { "utf8String", 1612709922, NULL },
> +  { "MAX", 524298, "1"},
> +  { "bmpString", 1612709921, NULL },
> +  { "MAX", 524298, "1"},
> +  { "ia5String", 538968093, NULL },
> +  { "MAX", 524298, "1"},
> +  { "SubjectAltName", 1073741826, "GeneralNames"},
> +  { "GeneralNames", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "GeneralName"},
> +  { "GeneralName", 1610612754, NULL },
> +  { "otherName", 1610620930, "AnotherName"},
> +  { NULL, 4104, "0"},
> +  { "rfc822Name", 1610620957, NULL },
> +  { NULL, 4104, "1"},
> +  { "dNSName", 1610620957, NULL },
> +  { NULL, 4104, "2"},
> +  { "x400Address", 1610620941, NULL },
> +  { NULL, 4104, "3"},
> +  { "directoryName", 1610620939, NULL },
> +  { NULL, 1073743880, "4"},
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "ediPartyName", 1610620941, NULL },
> +  { NULL, 4104, "5"},
> +  { "uniformResourceIdentifier", 1610620957, NULL },
> +  { NULL, 4104, "6"},
> +  { "iPAddress", 1610620935, NULL },
> +  { NULL, 4104, "7"},
> +  { "registeredID", 536879116, NULL },
> +  { NULL, 4104, "8"},
> +  { "AnotherName", 1610612741, NULL },
> +  { "type-id", 1073741836, NULL },
> +  { "value", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "type-id", 1, NULL },
> +  { "IssuerAltName", 1073741826, "GeneralNames"},
> +  { "BasicConstraints", 1610612741, NULL },
> +  { "cA", 1610645508, NULL },
> +  { NULL, 131081, NULL },
> +  { "pathLenConstraint", 537411587, NULL },
> +  { "0", 10, "MAX"},
> +  { "CRLDistributionPoints", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "DistributionPoint"},
> +  { "DistributionPoint", 1610612741, NULL },
> +  { "distributionPoint", 1610637314, "DistributionPointName"},
> +  { NULL, 2056, "0"},
> +  { "reasons", 1610637314, "ReasonFlags"},
> +  { NULL, 4104, "1"},
> +  { "cRLIssuer", 536895490, "GeneralNames"},
> +  { NULL, 4104, "2"},
> +  { "DistributionPointName", 1610612754, NULL },
> +  { "fullName", 1610620930, "GeneralNames"},
> +  { NULL, 4104, "0"},
> +  { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"},
> +  { NULL, 4104, "1"},
> +  { "ReasonFlags", 1073741830, NULL },
> +  { "ExtKeyUsageSyntax", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 12, NULL },
> +  { "AuthorityInfoAccessSyntax", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "AccessDescription"},
> +  { "AccessDescription", 1610612741, NULL },
> +  { "accessMethod", 1073741836, NULL },
> +  { "accessLocation", 2, "GeneralName"},
> +  { "Attribute", 1610612741, NULL },
> +  { "type", 1073741836, NULL },
> +  { "values", 536870927, NULL },
> +  { NULL, 13, NULL },
> +  { "AttributeTypeAndValue", 1610612741, NULL },
> +  { "type", 1073741836, NULL },
> +  { "value", 13, NULL },
> +  { "Name", 1610612754, NULL },
> +  { "rdnSequence", 536870923, NULL },
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "DistinguishedName", 1610612747, NULL },
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "RelativeDistinguishedName", 1612709903, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "AttributeTypeAndValue"},
> +  { "Certificate", 1610612741, NULL },
> +  { "tbsCertificate", 1073741826, "TBSCertificate"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 6, NULL },
> +  { "TBSCertificate", 1610612741, NULL },
> +  { "version", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 2056, "0"},
> +  { "serialNumber", 1073741826, "CertificateSerialNumber"},
> +  { "signature", 1073741826, "AlgorithmIdentifier"},
> +  { "issuer", 1073741826, "Name"},
> +  { "validity", 1073741826, "Validity"},
> +  { "subject", 1073741826, "Name"},
> +  { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
> +  { "issuerUniqueID", 1610637314, "UniqueIdentifier"},
> +  { NULL, 4104, "1"},
> +  { "subjectUniqueID", 1610637314, "UniqueIdentifier"},
> +  { NULL, 4104, "2"},
> +  { "extensions", 536895490, "Extensions"},
> +  { NULL, 2056, "3"},
> +  { "CertificateSerialNumber", 1073741827, NULL },
> +  { "Validity", 1610612741, NULL },
> +  { "notBefore", 1073741826, "Time"},
> +  { "notAfter", 2, "Time"},
> +  { "Time", 1610612754, NULL },
> +  { "utcTime", 1073741860, NULL },
> +  { "generalTime", 37, NULL },
> +  { "UniqueIdentifier", 1073741830, NULL },
> +  { "SubjectPublicKeyInfo", 1610612741, NULL },
> +  { "algorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "subjectPublicKey", 6, NULL },
> +  { "Extensions", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "Extension"},
> +  { "Extension", 1610612741, NULL },
> +  { "extnID", 1073741836, NULL },
> +  { "critical", 1610645508, NULL },
> +  { NULL, 131081, NULL },
> +  { "extnValue", 7, NULL },
> +  { "CertificateList", 1610612741, NULL },
> +  { "tbsCertList", 1073741826, "TBSCertList"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 6, NULL },
> +  { "TBSCertList", 1610612741, NULL },
> +  { "version", 1073758211, NULL },
> +  { "signature", 1073741826, "AlgorithmIdentifier"},
> +  { "issuer", 1073741826, "Name"},
> +  { "thisUpdate", 1073741826, "Time"},
> +  { "nextUpdate", 1073758210, "Time"},
> +  { "revokedCertificates", 1610629131, NULL },
> +  { NULL, 536870917, NULL },
> +  { "userCertificate", 1073741826, "CertificateSerialNumber"},
> +  { "revocationDate", 1073741826, "Time"},
> +  { "crlEntryExtensions", 16386, "Extensions"},
> +  { "crlExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "0"},
> +  { "AlgorithmIdentifier", 1610612741, NULL },
> +  { "algorithm", 1073741836, NULL },
> +  { "parameters", 541081613, NULL },
> +  { "algorithm", 1, NULL },
> +  { "Dss-Sig-Value", 1610612741, NULL },
> +  { "r", 1073741827, NULL },
> +  { "s", 3, NULL },
> +  { "Dss-Parms", 1610612741, NULL },
> +  { "p", 1073741827, NULL },
> +  { "q", 1073741827, NULL },
> +  { "g", 3, NULL },
> +  { "pkcs-7-ContentInfo", 1610612741, NULL },
> +  { "contentType", 1073741836, NULL },
> +  { "content", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "contentType", 1, NULL },
> +  { "pkcs-7-DigestInfo", 1610612741, NULL },
> +  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "digest", 7, NULL },
> +  { "pkcs-7-SignedData", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"},
> +  { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
> +  { "certificates", 1610637314, "pkcs-7-CertificateSet"},
> +  { NULL, 4104, "0"},
> +  { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
> +  { NULL, 4104, "1"},
> +  { "signerInfos", 2, "pkcs-7-SignerInfos"},
> +  { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
> +  { NULL, 2, "AlgorithmIdentifier"},
> +  { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
> +  { "eContentType", 1073741836, NULL },
> +  { "eContent", 536895501, NULL },
> +  { NULL, 2056, "0"},
> +  { "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
> +  { NULL, 13, NULL },
> +  { "pkcs-7-CertificateChoices", 1610612754, NULL },
> +  { "certificate", 13, NULL },
> +  { "pkcs-7-CertificateSet", 1610612751, NULL },
> +  { NULL, 2, "pkcs-7-CertificateChoices"},
> +  { "IssuerAndSerialNumber", 1610612741, NULL },
> +  { "issuer", 1073741826, "Name"},
> +  { "serialNumber", 2, "CertificateSerialNumber"},
> +  { "pkcs-7-SignerInfo", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "sid", 1073741826, "SignerIdentifier"},
> +  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signedAttrs", 1610637314, "SignedAttributes"},
> +  { NULL, 4104, "0"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 1073741831, NULL },
> +  { "unsignedAttrs", 536895490, "SignedAttributes"},
> +  { NULL, 4104, "1"},
> +  { "SignedAttributes", 1612709903, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "Attribute"},
> +  { "SignerIdentifier", 1610612754, NULL },
> +  { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
> +  { "subjectKeyIdentifier", 536879111, NULL },
> +  { NULL, 4104, "0"},
> +  { "pkcs-7-SignerInfos", 1610612751, NULL },
> +  { NULL, 2, "pkcs-7-SignerInfo"},
> +  { "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "subject", 1073741826, "Name"},
> +  { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
> +  { "attributes", 536879106, "Attributes"},
> +  { NULL, 4104, "0"},
> +  { "Attributes", 1610612751, NULL },
> +  { NULL, 2, "Attribute"},
> +  { "pkcs-10-CertificationRequest", 1610612741, NULL },
> +  { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 6, NULL },
> +  { "pkcs-9-at-challengePassword", 1879048204, NULL },
> +  { "iso", 1073741825, "1"},
> +  { "member-body", 1073741825, "2"},
> +  { "us", 1073741825, "840"},
> +  { "rsadsi", 1073741825, "113549"},
> +  { "pkcs", 1073741825, "1"},
> +  { NULL, 1073741825, "9"},
> +  { NULL, 1, "7"},
> +  { "pkcs-9-challengePassword", 1610612754, NULL },
> +  { "printableString", 1073741855, NULL },
> +  { "utf8String", 34, NULL },
> +  { "pkcs-9-localKeyId", 1073741831, NULL },
> +  { "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "privateKey", 1073741831, NULL },
> +  { "attributes", 536895490, "Attributes"},
> +  { NULL, 4104, "0"},
> +  { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
> +  { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "encryptedData", 2, "pkcs-8-EncryptedData"},
> +  { "pkcs-8-EncryptedData", 1073741831, NULL },
> +  { "pkcs-5-des-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "8"},
> +  { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "8"},
> +  { "pkcs-5-aes128-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "16"},
> +  { "pkcs-5-aes192-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "16"},
> +  { "pkcs-5-aes256-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "16"},
> +  { "Gost28147-89-Parameters", 1610612741, NULL },
> +  { "iv", 1073741831, NULL },
> +  { "encryptionParamSet", 12, NULL },
> +  { "pkcs-5-PBE-params", 1610612741, NULL },
> +  { "salt", 1073741831, NULL },
> +  { "iterationCount", 3, NULL },
> +  { "pkcs-5-PBES2-params", 1610612741, NULL },
> +  { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
> +  { "encryptionScheme", 2, "AlgorithmIdentifier"},
> +  { "pkcs-5-PBKDF2-params", 1610612741, NULL },
> +  { "salt", 1610612754, NULL },
> +  { "specified", 1073741831, NULL },
> +  { "otherSource", 2, "AlgorithmIdentifier"},
> +  { "iterationCount", 1611137027, NULL },
> +  { "1", 10, "MAX"},
> +  { "keyLength", 1611153411, NULL },
> +  { "1", 10, "MAX"},
> +  { "prf", 16386, "AlgorithmIdentifier"},
> +  { "pkcs-12-PFX", 1610612741, NULL },
> +  { "version", 1610874883, NULL },
> +  { "v3", 1, "3"},
> +  { "authSafe", 1073741826, "pkcs-7-ContentInfo"},
> +  { "macData", 16386, "pkcs-12-MacData"},
> +  { "pkcs-12-PbeParams", 1610612741, NULL },
> +  { "salt", 1073741831, NULL },
> +  { "iterations", 3, NULL },
> +  { "pkcs-12-MacData", 1610612741, NULL },
> +  { "mac", 1073741826, "pkcs-7-DigestInfo"},
> +  { "macSalt", 1073741831, NULL },
> +  { "iterations", 536903683, NULL },
> +  { NULL, 9, "1"},
> +  { "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
> +  { NULL, 2, "pkcs-7-ContentInfo"},
> +  { "pkcs-12-SafeContents", 1610612747, NULL },
> +  { NULL, 2, "pkcs-12-SafeBag"},
> +  { "pkcs-12-SafeBag", 1610612741, NULL },
> +  { "bagId", 1073741836, NULL },
> +  { "bagValue", 1614815245, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "badId", 1, NULL },
> +  { "bagAttributes", 536887311, NULL },
> +  { NULL, 2, "Attribute"},
> +  { "pkcs-12-CertBag", 1610612741, NULL },
> +  { "certId", 1073741836, NULL },
> +  { "certValue", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "certId", 1, NULL },
> +  { "pkcs-12-CRLBag", 1610612741, NULL },
> +  { "crlId", 1073741836, NULL },
> +  { "crlValue", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "crlId", 1, NULL },
> +  { "pkcs-12-SecretBag", 1610612741, NULL },
> +  { "secretTypeId", 1073741836, NULL },
> +  { "secretValue", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "secretTypeId", 1, NULL },
> +  { "pkcs-7-Data", 1073741831, NULL },
> +  { "pkcs-7-EncryptedData", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"},
> +  { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
> +  { NULL, 4104, "1"},
> +  { "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
> +  { "contentType", 1073741836, NULL },
> +  { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
> +  { "encryptedContent", 536895495, NULL },
> +  { NULL, 4104, "0"},
> +  { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
> +  { "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "Attribute"},
> +  { "ProxyCertInfo", 1610612741, NULL },
> +  { "pCPathLenConstraint", 1611153411, NULL },
> +  { "0", 10, "MAX"},
> +  { "proxyPolicy", 2, "ProxyPolicy"},
> +  { "ProxyPolicy", 1610612741, NULL },
> +  { "policyLanguage", 1073741836, NULL },
> +  { "policy", 16391, NULL },
> +  { "certificatePolicies", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "PolicyInformation"},
> +  { "PolicyInformation", 1610612741, NULL },
> +  { "policyIdentifier", 1073741836, NULL },
> +  { "policyQualifiers", 538984459, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "PolicyQualifierInfo"},
> +  { "PolicyQualifierInfo", 1610612741, NULL },
> +  { "policyQualifierId", 1073741836, NULL },
> +  { "qualifier", 541065229, NULL },
> +  { "policyQualifierId", 1, NULL },
> +  { "CPSuri", 1073741853, NULL },
> +  { "UserNotice", 1610612741, NULL },
> +  { "noticeRef", 1073758210, "NoticeReference"},
> +  { "explicitText", 16386, "DisplayText"},
> +  { "NoticeReference", 1610612741, NULL },
> +  { "organization", 1073741826, "DisplayText"},
> +  { "noticeNumbers", 536870923, NULL },
> +  { NULL, 3, NULL },
> +  { "DisplayText", 1610612754, NULL },
> +  { "ia5String", 1612709917, NULL },
> +  { "200", 524298, "1"},
> +  { "visibleString", 1612709923, NULL },
> +  { "200", 524298, "1"},
> +  { "bmpString", 1612709921, NULL },
> +  { "200", 524298, "1"},
> +  { "utf8String", 538968098, NULL },
> +  { "200", 524298, "1"},
> +  { "OCSPRequest", 1610612741, NULL },
> +  { "tbsRequest", 1073741826, "TBSRequest"},
> +  { "optionalSignature", 536895490, "Signature"},
> +  { NULL, 2056, "0"},
> +  { "TBSRequest", 1610612741, NULL },
> +  { "version", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 2056, "0"},
> +  { "requestorName", 1610637314, "GeneralName"},
> +  { NULL, 2056, "1"},
> +  { "requestList", 1610612747, NULL },
> +  { NULL, 2, "Request"},
> +  { "requestExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "2"},
> +  { "Signature", 1610612741, NULL },
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 1073741830, NULL },
> +  { "certs", 536895499, NULL },
> +  { NULL, 1073743880, "0"},
> +  { NULL, 2, "Certificate"},
> +  { "Request", 1610612741, NULL },
> +  { "reqCert", 1073741826, "CertID"},
> +  { "singleRequestExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "0"},
> +  { "CertID", 1610612741, NULL },
> +  { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "issuerNameHash", 1073741831, NULL },
> +  { "issuerKeyHash", 1073741831, NULL },
> +  { "serialNumber", 2, "CertificateSerialNumber"},
> +  { "OCSPResponse", 1610612741, NULL },
> +  { "responseStatus", 1073741826, "OCSPResponseStatus"},
> +  { "responseBytes", 536895490, "ResponseBytes"},
> +  { NULL, 2056, "0"},
> +  { "OCSPResponseStatus", 1610874901, NULL },
> +  { "successful", 1073741825, "0"},
> +  { "malformedRequest", 1073741825, "1"},
> +  { "internalError", 1073741825, "2"},
> +  { "tryLater", 1073741825, "3"},
> +  { "sigRequired", 1073741825, "5"},
> +  { "unauthorized", 1, "6"},
> +  { "ResponseBytes", 1610612741, NULL },
> +  { "responseType", 1073741836, NULL },
> +  { "response", 7, NULL },
> +  { "BasicOCSPResponse", 1610612741, NULL },
> +  { "tbsResponseData", 1073741826, "ResponseData"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 1073741830, NULL },
> +  { "certs", 536895499, NULL },
> +  { NULL, 1073743880, "0"},
> +  { NULL, 2, "Certificate"},
> +  { "ResponseData", 1610612741, NULL },
> +  { "version", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 2056, "0"},
> +  { "responderID", 1073741826, "ResponderID"},
> +  { "producedAt", 1073741861, NULL },
> +  { "responses", 1610612747, NULL },
> +  { NULL, 2, "SingleResponse"},
> +  { "responseExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "1"},
> +  { "ResponderID", 1610612754, NULL },
> +  { "byName", 1610620939, NULL },
> +  { NULL, 1073743880, "1"},
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "byKey", 536879111, NULL },
> +  { NULL, 2056, "2"},
> +  { "SingleResponse", 1610612741, NULL },
> +  { "certID", 1073741826, "CertID"},
> +  { "certStatus", 1073741826, "CertStatus"},
> +  { "thisUpdate", 1073741861, NULL },
> +  { "nextUpdate", 1610637349, NULL },
> +  { NULL, 2056, "0"},
> +  { "singleExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "1"},
> +  { "CertStatus", 1610612754, NULL },
> +  { "good", 1610620948, NULL },
> +  { NULL, 4104, "0"},
> +  { "revoked", 1610620930, "RevokedInfo"},
> +  { NULL, 4104, "1"},
> +  { "unknown", 536879106, "UnknownInfo"},
> +  { NULL, 4104, "2"},
> +  { "RevokedInfo", 1610612741, NULL },
> +  { "revocationTime", 1073741861, NULL },
> +  { "revocationReason", 537157653, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "unspecified", 1, "0"},
> +  { "UnknownInfo", 1073741844, NULL },
> +  { "NameConstraints", 1610612741, NULL },
> +  { "permittedSubtrees", 1610637314, "GeneralSubtrees"},
> +  { NULL, 4104, "0"},
> +  { "excludedSubtrees", 536895490, "GeneralSubtrees"},
> +  { NULL, 4104, "1"},
> +  { "GeneralSubtrees", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "GeneralSubtree"},
> +  { "GeneralSubtree", 1610612741, NULL },
> +  { "base", 1073741826, "GeneralName"},
> +  { "minimum", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 4104, "0"},
> +  { "maximum", 536895491, NULL },
> +  { NULL, 4104, "1"},
> +  { "TlsFeatures", 536870923, NULL },
> +  { NULL, 3, NULL },
> +  { NULL, 0, NULL }
> +};


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates
  2024-12-18 14:56 ` [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates Sudhakar Kuppusamy
@ 2024-12-28 19:46   ` Stefan Berger
  2025-02-26  4:26     ` sudhakar
  2025-01-24 11:10   ` Avnish Chouhan
  2025-01-24 11:23   ` Michal Suchánek
  2 siblings, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-28 19:46 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish, Javier Martinez Canillas, Michal Suchanek



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> This code allows us to parse:
> 
>   - PKCS#7 signedData messages. Only a single signerInfo is supported,
>     which is all that the Linux sign-file utility supports creating
>     out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
>     Any certificate embedded in the PKCS#7 message will be ignored.
> 
>   - X.509 certificates: at least enough to verify the signatures on the
>     PKCS#7 messages. We expect that the certificates embedded in grub will
>     be leaf certificates, not CA certificates. The parser enforces this.
> 
>   - X.509 certificates support the Extended Key Usage extension and handle
>     it by verifying that the certificate has a single purpose, that is code
>     signing. This is required because Red Hat certificates have both Key
>     Usage and Extended Key Usage extensions present.
> 
> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> # EKU support
> Reported-by: Michal Suchanek <msuchanek@suse.com> # key usage issue
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   grub-core/commands/appendedsig/appendedsig.h | 110 +++
>   grub-core/commands/appendedsig/asn1util.c    |  99 ++
>   grub-core/commands/appendedsig/pkcs7.c       | 473 +++++++++
>   grub-core/commands/appendedsig/x509.c        | 981 +++++++++++++++++++
>   4 files changed, 1663 insertions(+)
>   create mode 100644 grub-core/commands/appendedsig/appendedsig.h
>   create mode 100644 grub-core/commands/appendedsig/asn1util.c
>   create mode 100644 grub-core/commands/appendedsig/pkcs7.c
>   create mode 100644 grub-core/commands/appendedsig/x509.c
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
> new file mode 100644
> index 000000000..fa59302c8
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/appendedsig.h
> @@ -0,0 +1,110 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/crypto.h>
> +#include <grub/libtasn1.h>
> +
> +extern asn1_node _gnutls_gnutls_asn;
> +extern asn1_node _gnutls_pkix_asn;
> +
> +#define MAX_OID_LEN 32
> +
> +/*
> + * One or more x509 certificates.
> + * We do limited parsing: extracting only the serial, CN and RSA public key.
> + */
> +struct x509_certificate
> +{
> +  struct x509_certificate *next;
> +  grub_uint8_t *serial;
> +  grub_size_t serial_len;
> +  char *subject;
> +  grub_size_t subject_len;
> +  /* We only support RSA public keys. This encodes [modulus, publicExponent] */
> +  gcry_mpi_t mpis[2];
> +};
> +
> +/*
> + * A PKCS#7 signedData signerInfo.
> + */
> +struct pkcs7_signerInfo
> +{
> +  const gcry_md_spec_t *hash;
> +  gcry_mpi_t sig_mpi;
> +};
> +
> +/*
> + * A PKCS#7 signedData message.
> + * We make no attempt to match intelligently, so we don't save any info about
> + * the signer.
> + */
> +struct pkcs7_signedData
> +{
> +  int signerInfo_count;
> +  struct pkcs7_signerInfo *signerInfos;
> +};
> +
> +/* Do libtasn1 init */
> +int
> +asn1_init (void);
> +
> +/*
> + * Import a DER-encoded certificate at 'data', of size 'size'.
> + * Place the results into 'results', which must be already allocated.
> + */
> +grub_err_t
> +parse_x509_certificate (const void *data, grub_size_t size, struct x509_certificate *results);
> +
> +/*
> + * Release all the storage associated with the x509 certificate.
> + * If the caller dynamically allocated the certificate, it must free it.
> + * The caller is also responsible for maintenance of the linked list.
> + */
> +void
> +certificate_release (struct x509_certificate *cert);
> +
> +/*
> + * Parse a PKCS#7 message, which must be a signedData message.
> + * The message must be in 'sigbuf' and of size 'data_size'. The result is
> + * placed in 'msg', which must already be allocated.
> + */
> +grub_err_t
> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg);
> +
> +/*
> + * Release all the storage associated with the PKCS#7 message.
> + * If the caller dynamically allocated the message, it must free it.
> + */
> +void
> +pkcs7_signedData_release (struct pkcs7_signedData *msg);
> +
> +/*
> + * Read a value from an ASN1 node, allocating memory to store it.
> + * It will work for anything where the size libtasn1 returns is right:
> + *  - Integers
> + *  - Octet strings
> + *  - DER encoding of other structures
> + * It will _not_ work for things where libtasn1 size requires adjustment:
> + *  - Strings that require an extra NULL byte at the end

NUL byte.

> + *  - Bit strings because libtasn1 returns the length in bits, not bytes.
> + *
> + * If the function returns a non-NULL value, the caller must free it.
> + */
> +void *
> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size);
> diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
> new file mode 100644
> index 000000000..609d0ecf2
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/asn1util.c
> @@ -0,0 +1,99 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
> +#include <grub/types.h>
> +#include <grub/err.h>
> +#include <grub/mm.h>
> +#include <grub/crypto.h>
> +#include <grub/misc.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +#include "appendedsig.h"
> +
> +asn1_node _gnutls_gnutls_asn = NULL;
> +asn1_node _gnutls_pkix_asn = NULL;
> +
> +extern const asn1_static_node gnutls_asn1_tab[];
> +extern const asn1_static_node pkix_asn1_tab[];
> +
> +/*
> + * Read a value from an ASN1 node, allocating memory to store it.
> + * It will work for anything where the size libtasn1 returns is right:
> + *  - Integers
> + *  - Octet strings
> + *  - DER encoding of other structures
> + * It will _not_ work for things where libtasn1 size requires adjustment:
> + *  - Strings that require an extra NULL byte at the end
> + *  - Bit strings because libtasn1 returns the length in bits, not bytes.
> + * If the function returns a non-NULL value, the caller must free it.
> + */
> +void *
> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size)
> +{
> +  int result;
> +  grub_uint8_t *tmpstr = NULL;
> +  int tmpstr_size = 0;
> +
> +  result = asn1_read_value (node, name, NULL, &tmpstr_size);
> +  if (result != ASN1_MEM_ERROR)
> +    {
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
> +                     _("Reading size of %s did not return expected status: %s"),
> +                     friendly_name, asn1_strerror (result));
> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
> +      return NULL;
> +    }
> +
> +  tmpstr = grub_malloc (tmpstr_size);
> +  if (tmpstr == NULL)
> +    {
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
> +                     "Could not allocate memory to store %s", friendly_name);
> +      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
> +      return NULL;
> +    }
> +
> +  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      grub_free (tmpstr);
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error reading %s: %s",
> +                     friendly_name, asn1_strerror (result));
> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
> +      return NULL;
> +    }
> +
> +  *content_size = tmpstr_size;
> +
> +  return tmpstr;
> +}
> +
> +int
> +asn1_init (void)
> +{
> +  int res;
> +  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return res;
> +    }
> +  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
> +  return res;
> +}
> diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c
> new file mode 100644
> index 000000000..61e560854
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/pkcs7.c
> @@ -0,0 +1,473 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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 "appendedsig.h"
> +#include <grub/misc.h>
> +#include <grub/crypto.h>
> +#include <grub/gcrypt/gcrypt.h>
> +#include <sys/types.h>
> +
> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
> +
> +/*
> + * RFC 5652 s 5.1
> + */
> +static const char *signedData_oid = "1.2.840.113549.1.7.2";
> +
> +/*
> + * RFC 4055 s 2.1
> + */
> +static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
> +static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
> +
> +static grub_err_t
> +process_content (grub_uint8_t *content, int size, struct pkcs7_signedData *msg)
> +{
> +  int res;
> +  asn1_node signed_part;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char algo_oid[MAX_OID_LEN];
> +  int algo_oid_size = sizeof (algo_oid);
> +  int algo_count;
> +  int signer_count;
> +  int i;
> +  char version;
> +  int version_size = sizeof (version);
> +  grub_uint8_t *result_buf;
> +  int result_size = 0;
> +  int crls_size = 0;
> +  gcry_error_t gcry_err;
> +  bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
> +  char *da_path;
> +  char *si_sig_path;
> +  char *si_da_path;
> +
> +  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for PKCS#7 signed "
> +                         "part.");
> +    }
> +
> +  res = asn1_der_decoding2 (&signed_part, content, &size,
> +                            ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Error reading PKCS#7 signed data: %s", asn1_error);
> +      goto cleanup_signed_part;
> +    }
> +
> +  /*
> +   * SignedData ::= SEQUENCE {
> +   *     version CMSVersion,
> +   *     digestAlgorithms DigestAlgorithmIdentifiers,
> +   *     encapContentInfo EncapsulatedContentInfo,
> +   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
> +   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
> +   *     signerInfos SignerInfos }
> +   */
> +
> +  /* version per the algo in 5.1, must be 1 */
> +  res = asn1_read_value (signed_part, "version", &version, &version_size);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading signedData version: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (version != 1)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Unexpected signature version v%d, only v1 supported", version);
> +      goto cleanup_signed_part;
> +    }
> +
> +  /*
> +   * digestAlgorithms DigestAlgorithmIdentifiers
> +   *
> +   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
> +   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
> +   *
> +   * RFC 4055 s 2.1:
> +   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
> +   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
> +   *
> +   * We only support 1 element in the set, and we do not check parameters atm.
> +   */
> +  res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of digest algorithms: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (algo_count <= 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "A minimum of 1 digest algorithm is required");
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (algo_count > 2)
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                        "A maximum of 2 digest algorithms are supported");

s/are/is - it's the maximum that 'is' supported

> +      goto cleanup_signed_part;
> +    }
> +
> +  sha256_in_da = false;
> +  sha512_in_da = false;
> +
> +  for (i = 0; i < algo_count; i++)
> +    {
> +      da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1);
> +      if (!da_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                            "Could not allocate path for digest algorithm "
> +                            "parsing path");
> +          goto cleanup_signed_part;
> +        }
> +
> +      algo_oid_size = sizeof (algo_oid);
> +      res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size);
> +      if (res != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading digest algorithm: %s",
> +                            asn1_strerror (res));
> +          grub_free (da_path);
> +          goto cleanup_signed_part;
> +        }
> +
> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha512_in_da)
> +            {
> +              sha512_in_da = true;
> +            }
> +          else
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                                "SHA-512 specified twice in digest algorithm "
> +                                "list");

Move "list" to line above

> +              grub_free (da_path);
> +              goto cleanup_signed_part;
> +            }
> +        }
> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha256_in_da)
> +            {
> +              sha256_in_da = true;
> +            }
> +          else
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                                "SHA-256 specified twice in digest algorithm "
> +                                "list");

Same here

> +              grub_free (da_path);
> +              goto cleanup_signed_part;
> +            }
> +        }
> +      else
> +        {
> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
> +                            algo_oid);
> +          grub_free (da_path);
> +          goto cleanup_signed_part;
> +        }
> +
> +      grub_free (da_path);
> +    }
> +
> +  /* at this point, at least one of sha{256,512}_in_da must be true */
> +
> +  /*
> +   * We ignore the certificates, but we don't permit CRLs.
> +   * A CRL entry might be revoking the certificate we're using, and we have
> +   * no way of dealing with that at the moment.
> +   */
> +  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
> +  if (res != ASN1_ELEMENT_NOT_FOUND)
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                        "PKCS#7 messages with embedded CRLs are not supported");
> +      goto cleanup_signed_part;
> +    }
> +
> +  /* read the signatures */
> +
> +  res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of signers: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (signer_count <= 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "A minimum of 1 signer is required");
> +      goto cleanup_signed_part;
> +    }
> +
> +  msg->signerInfos = grub_calloc (signer_count, sizeof (struct pkcs7_signerInfo));
> +  if (!msg->signerInfos)
> +    {
> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                        "Could not allocate space for %d signers", signer_count);
> +      goto cleanup_signed_part;
> +    }
> +
> +  msg->signerInfo_count = 0;
> +  for (i = 0; i < signer_count; i++)
> +    {
> +      si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
> +      if (!si_da_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate path for signer %d's digest algorithm parsing path",
> +                            i);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      algo_oid_size = sizeof (algo_oid);
> +      res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size);
> +      if (res != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Error reading signer %d's digest algorithm: %s", i,
> +                            asn1_strerror (res));
> +          grub_free (si_da_path);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      grub_free (si_da_path);
> +
> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha512_in_da)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d claims a SHA-512 signature "
> +                                "which was not specified in the outer DigestAlgorithms", i);

Merge into one string.

> +              goto cleanup_signerInfos;
> +            }
> +          else
> +            {
> +              sha512_in_si = true;
> +              msg->signerInfos[i].hash =
> +                      grub_crypto_lookup_md_by_name ("sha512");

Not sure what the char-per-line limit is, but I have seen 87 chars, so 
probably can move this one up.

> +            }
> +        }
> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha256_in_da)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d claims a SHA-256 signature "
> +                                "which was not specified in the outer DigestAlgorithms", i);

Merge the string?

> +              goto cleanup_signerInfos;
> +            }
> +          else
> +            {
> +              sha256_in_si = true;
> +              msg->signerInfos[i].hash =
> +                      grub_crypto_lookup_md_by_name ("sha256");

also this one up

> +            }
> +        }
> +      else
> +        {
> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                            "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
> +                            algo_oid);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      if (!msg->signerInfos[i].hash)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1);
> +      if (!si_sig_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                            "Could not allocate path for signer %d's signature parsing path", i);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path,
> +                                                "signature data", &result_size);
> +      grub_free (si_sig_path);
> +
> +      if (!result_buf)
> +        {
> +          err = grub_errno;
> +          goto cleanup_signerInfos;
> +        }
> +
> +      gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi), GCRYMPI_FMT_USG,
> +                                result_buf, result_size, NULL);
> +
> +      grub_free (result_buf);
> +
> +      if (gcry_err != GPG_ERR_NO_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Error loading signature %d into MPI structure: %d",
> +                            i, gcry_err);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      /*
> +       * use msg->signerInfo_count to track fully populated signerInfos so we
> +       * know how many we need to clean up
> +       */
> +      msg->signerInfo_count++;
> +    }
> +
> +  /*
> +   * Final consistency check of signerInfo.*.digestAlgorithm vs
> +   * digestAlgorithms.*.algorithm. An algorithm must be present in both
> +   * digestAlgorithms and signerInfo or in neither. We have already checked
> +   * for an algorithm in signerInfo that is not in digestAlgorithms, here we
> +   * check for algorithms in digestAlgorithms but not in signerInfos.
> +   */
> +  if (sha512_in_da && !sha512_in_si)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "SHA-512 specified in DigestAlgorithms but did not "
> +                        "appear in SignerInfos");
> +      goto cleanup_signerInfos;
> +    }
> +
> +  if (sha256_in_da && !sha256_in_si)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "SHA-256 specified in DigestAlgorithms but did not "
> +                        "appear in SignerInfos");
> +      goto cleanup_signerInfos;
> +    }
> +
> +  asn1_delete_structure (&signed_part);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_signerInfos:
> +  for (i = 0; i < msg->signerInfo_count; i++)
> +    gcry_mpi_release (msg->signerInfos[i].sig_mpi);
> +  grub_free (msg->signerInfos);
> +cleanup_signed_part:
> +  asn1_delete_structure (&signed_part);
> +  return err;
> +}
> +
> +grub_err_t
> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg)
> +{
> +  int res;
> +  asn1_node content_info;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char content_oid[MAX_OID_LEN];
> +  grub_uint8_t *content;
> +  int content_size;
> +  int content_oid_size = sizeof (content_oid);
> +  int size;
> +
> +  if (data_size > GRUB_INT_MAX)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 message "
> +                                              "where data size > INT_MAX");
> +  size = (int) data_size;
> +
> +  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for PKCS#7 data: %s",
> +                         asn1_strerror (res));
> +    }
> +
> +  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
> +                            ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING,
> +                            asn1_error);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Error decoding PKCS#7 message DER: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * ContentInfo ::= SEQUENCE {
> +   *     contentType ContentType,
> +   *     content [0] EXPLICIT ANY DEFINED BY contentType }
> +   *
> +   * ContentType ::= OBJECT IDENTIFIER
> +   */
> +  res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7 content type: %s",
> +                        asn1_strerror (res));
> +      goto cleanup;
> +    }
> +
> +  /* OID for SignedData defined in 5.1 */
> +  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Unexpected content type in PKCS#7 message: OID %s", content_oid);
> +      goto cleanup;
> +    }
> +
> +  content = grub_asn1_allocate_and_read (content_info, "content",
> +                                         "PKCS#7 message content", &content_size);
> +  if (!content)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  err = process_content (content, content_size, msg);
> +  grub_free (content);
> +
> +cleanup:
> +  asn1_delete_structure (&content_info);
> +  return err;
> +}
> +
> +/*
> + * Release all the storage associated with the PKCS#7 message.
> + * If the caller dynamically allocated the message, it must free it.
> + */
> +void
> +pkcs7_signedData_release (struct pkcs7_signedData *msg)
> +{
> +  grub_ssize_t i;
> +
> +  for (i = 0; i < msg->signerInfo_count; i++)
> +    {
> +      gcry_mpi_release (msg->signerInfos[i].sig_mpi);
> +    }
> +  grub_free (msg->signerInfos);
> +}
> diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
> new file mode 100644
> index 000000000..eb9a1ca0f
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/x509.c
> @@ -0,0 +1,981 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
> +#include <grub/types.h>
> +#include <grub/err.h>
> +#include <grub/mm.h>
> +#include <grub/crypto.h>
> +#include <grub/misc.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +#include "appendedsig.h"
> +
> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
> +
> +/*
> + * RFC 3279 2.3.1  RSA Keys
> + */
> +static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
> +
> +/*
> + * RFC 5280 Appendix A
> + */
> +static const char *commonName_oid = "2.5.4.3";
> +
> +/*
> + * RFC 5280 4.2.1.3 Key Usage
> + */
> +static const char *keyUsage_oid = "2.5.29.15";
> +
> +static const grub_uint8_t digitalSignatureUsage = 0x80;
> +
> +/*
> + * RFC 5280 4.2.1.9 Basic Constraints
> + */
> +static const char *basicConstraints_oid = "2.5.29.19";
> +
> +/*
> + * RFC 5280 4.2.1.12 Extended Key Usage
> + */
> +static const char *extendedKeyUsage_oid = "2.5.29.37";
> +static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
> +
> +/*
> + * RFC 3279 2.3.1
> + *
> + *  The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
> + *
> + *     RSAPublicKey ::= SEQUENCE {
> + *        modulus            INTEGER,    -- n
> + *        publicExponent     INTEGER  }  -- e
> + *
> + *  where modulus is the modulus n, and publicExponent is the public
> + *  exponent e.
> + */
> +static grub_err_t
> +grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct x509_certificate *certificate)
> +{
> +  int result;
> +  asn1_node spk = NULL;
> +  grub_uint8_t *m_data, *e_data;
> +  int m_size, e_size;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  gcry_error_t gcry_err;
> +
> +  result = asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Cannot create storage for public key ASN.1 data");
> +    }
> +
> +  result = asn1_der_decoding2 (&spk, der, &dersize, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Cannot decode certificate public key DER: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
> +  if (!m_data)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  e_data = grub_asn1_allocate_and_read (spk, "publicExponent",
> +                                        "RSA public exponent", &e_size);
> +  if (!e_data)
> +    {
> +      err = grub_errno;
> +      goto cleanup_m_data;
> +    }
> +
> +  /*
> +   * convert m, e to mpi
> +   *
> +   * nscanned is not set for FMT_USG, it's only set for FMT_PGP,
> +   * so we can't verify it
> +   */
> +  gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, NULL);
> +  if (gcry_err != GPG_ERR_NO_ERROR)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error loading RSA modulus into MPI structure: %d", gcry_err);
> +      goto cleanup_e_data;
> +    }
> +
> +  gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, NULL);
> +  if (gcry_err != GPG_ERR_NO_ERROR)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error loading RSA exponent into MPI structure: %d", gcry_err);
> +      goto cleanup_m_mpi;
> +    }
> +
> +  grub_free (e_data);
> +  grub_free (m_data);
> +  asn1_delete_structure (&spk);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_m_mpi:
> +  gcry_mpi_release (certificate->mpis[0]);
> +cleanup_e_data:
> +  grub_free (e_data);
> +cleanup_m_data:
> +  grub_free (m_data);
> +cleanup:
> +  asn1_delete_structure (&spk);
> +  return err;
> +}
> +
> +/*
> + * RFC 5280:
> + *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
> + *       algorithm            AlgorithmIdentifier,
> + *       subjectPublicKey     BIT STRING  }
> + *
> + * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
> + * only support RSA Encryption.
> + */
> +
> +static grub_err_t
> +grub_x509_read_subject_public_key (asn1_node asn, struct x509_certificate *results)
> +{
> +  int result;
> +  grub_err_t err;
> +  const char *algo_name =
> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
> +  const char *params_name =
> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
> +  const char *pk_name = "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
> +  char algo_oid[MAX_OID_LEN];
> +  int algo_size = sizeof (algo_oid);
> +  char params_value[2];
> +  int params_size = sizeof (params_value);
> +  grub_uint8_t *key_data = NULL;
> +  int key_size = 0;
> +  unsigned int key_type;
> +
> +  /* algorithm: see notes for rsaEncryption_oid */
> +  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key algorithm: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) != 0)
> +    {
> +      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                         "Unsupported x509 public key algorithm: %s", algo_oid);
> +    }
> +
> +  /*
> +   * RFC 3279 2.3.1
> +   * The rsaEncryption OID is intended to be used in the algorithm field
> +   * of a value of type AlgorithmIdentifier.  The parameters field MUST
> +   * have ASN.1 type NULL for this algorithm identifier.
> +   */
> +  result = asn1_read_value (asn, params_name, params_value, &params_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key parameters: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (params_value[0] != ASN1_TAG_NULL)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                         "Invalid x509 public key parameters: expected NULL");
> +    }
> +
> +  /*
> +   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of the BIT
> +   * STRING subjectPublicKey.
> +   */
> +  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
> +  if (result != ASN1_MEM_ERROR)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of x509 public key: %s",
> +                         asn1_strerror (result));
> +    }
> +  if (key_type != ASN1_ETYPE_BIT_STRING)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1 type when reading x509 public key: %x",
> +                         key_type);
> +    }
> +
> +  /* length is in bits */
> +  key_size = (key_size + 7) / 8;
> +
> +  key_data = grub_malloc (key_size);
> +  if (!key_data)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Out of memory for x509 public key");
> +    }
> +
> +  result = asn1_read_value (asn, pk_name, key_data, &key_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      grub_free (key_data);
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                         "Error reading public key data");
> +    }
> +  key_size = (key_size + 7) / 8;
> +
> +  err = grub_parse_rsa_pubkey (key_data, key_size, results);
> +  grub_free (key_data);
> +
> +  return err;
> +}
> +
> +/* Decode a string as defined in Appendix A */
> +static grub_err_t
> +decode_string (char *der, int der_size, char **string, grub_size_t *string_size)
> +{
> +  asn1_node strasn;
> +  int result;
> +  char *choice;
> +  int choice_size = 0;
> +  int tmp_size = 0;
> +  grub_err_t err = GRUB_ERR_NONE;
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for certificate: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  result = asn1_der_decoding2 (&strasn, der, &der_size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Could not parse DER for DirectoryString: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", &choice_size);
> +  if (!choice)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  if (grub_strncmp ("utf8String", choice, choice_size) == 0)
> +    {
> +      result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
> +      if (result != ASN1_MEM_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_choice;
> +        }
> +    }
> +  else if (grub_strncmp ("printableString", choice, choice_size) == 0)
> +    {
> +      result = asn1_read_value (strasn, "printableString", NULL, &tmp_size);
> +      if (result != ASN1_MEM_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_choice;
> +        }
> +    }
> +  else
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and printable DirectoryStrings are supported, got %s",
> +                        choice);
> +      goto cleanup_choice;
> +    }
> +
> +  /* read size does not include trailing null */
> +  tmp_size++;
> +
> +  *string = grub_malloc (tmp_size);
> +  if (!*string)
> +    {
> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                        "Cannot allocate memory for DirectoryString contents");
> +      goto cleanup_choice;
> +    }
> +
> +  result = asn1_read_value (strasn, choice, *string, &tmp_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s in DirectoryString: %s",
> +                        choice, asn1_strerror (result));
> +      grub_free (*string);

*string = NULL;

> +      goto cleanup_choice;
> +    }
> +  *string_size = tmp_size + 1;
> +  (*string)[tmp_size] = '\0';
> +
> +cleanup_choice:
> +  grub_free (choice);
> +cleanup:
> +  asn1_delete_structure (&strasn);
> +  return err;
> +}
> +
> +/*
> + * TBSCertificate  ::=  SEQUENCE  {
> + *       version         [0]  EXPLICIT Version DEFAULT v1,
> + * ...
> + *
> + * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
> + */
> +static grub_err_t
> +check_version (asn1_node certificate)
> +{
> +  int rc;
> +  const char *name = "tbsCertificate.version";
> +  grub_uint8_t version;
> +  int len = sizeof (version);
> +
> +  rc = asn1_read_value (certificate, name, &version, &len);
> +
> +  /* require version 3 */
> +  if (rc != ASN1_SUCCESS || len != 1)
> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                       "Error reading certificate version");
> +
> +  if (version != 0x02)
> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x",
> +                       version);
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * This is an X.501 Name, which is complex.
> + *
> + * For simplicity, we extract only the CN.
> + */
> +static grub_err_t
> +read_name (asn1_node asn, const char *name_path, char **name, grub_size_t *name_size)
> +{
> +  int seq_components, set_components;
> +  int result;
> +  int i, j;
> +  char *top_path, *set_path, *type_path, *val_path;
> +  char type[MAX_OID_LEN];
> +  int type_len = sizeof (type);
> +  int string_size = 0;
> +  char *string_der;
> +  grub_err_t err;
> +
> +  *name = NULL;
> +
> +  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
> +  if (!top_path)
> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                       "Could not allocate memory for %s name parsing path", name_path);
> +
> +  result = asn1_number_of_elements (asn, top_path, &seq_components);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name components: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  for (i = 1; i <= seq_components; i++)
> +    {
> +      set_path = grub_xasprintf ("%s.?%d", top_path, i);
> +      if (!set_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name set parsing path",
> +                            name_path);
> +          goto cleanup_set;
> +        }
> +      /* this brings us, hopefully, to a set */
> +      result = asn1_number_of_elements (asn, set_path, &set_components);
> +      if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name sub-components components (element %d): %s",
> +                            i, asn1_strerror (result));
> +          goto cleanup_set;
> +        }
> +      for (j = 1; j <= set_components; j++)
> +        {
> +          type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
> +          if (!type_path)
> +            {
> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component type path",
> +                                name_path);
> +              goto cleanup_set;
> +            }
> +          type_len = sizeof (type);
> +          result = asn1_read_value (asn, type_path, type, &type_len);
> +          if (result != ASN1_SUCCESS)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading %s name component type: %s",
> +                                name_path, asn1_strerror (result));
> +              goto cleanup_type;
> +            }
> +
> +          if (grub_strncmp (type, commonName_oid, type_len) != 0)
> +            {
> +              grub_free (type_path);
> +              continue;
> +            }
> +
> +          val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
> +          if (!val_path)
> +            {
> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component value path",
> +                                name_path);
 > +              goto cleanup_set;

goto cleanup_type;


> +            }
> +
> +          string_der = grub_asn1_allocate_and_read (asn, val_path, name_path, &string_size);
> +          if (!string_der)
> +            {
> +              err = grub_errno;
> +              goto cleanup_val_path;
> +            }
> +
> +          err = decode_string (string_der, string_size, name, name_size);
> +          if (err)
> +            goto cleanup_string;
> +
> +          grub_free (string_der);
> +          grub_free (type_path);
> +          grub_free (val_path);
> +          break;
> +        }
> +      grub_free (set_path);
> +
> +      if (*name)
> +        break;
> +    }
> +
> +  grub_free (top_path);
> +
> +  return GRUB_ERR_NONE;
> +
> +cleanup_string:
> +  grub_free (string_der);
> +cleanup_val_path:
> +  grub_free (val_path);
> +cleanup_type:
> +  grub_free (type_path);
> +cleanup_set:
> +  grub_free (set_path);
> +cleanup:
> +  grub_free (top_path);
> +  return err;
> +}
> +
> +/*
> + * Verify the Key Usage extension.
> + * We require the Digital signature usage.
> + */
> +static grub_err_t
> +verify_key_usage (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node usageasn;
> +  int result;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  grub_uint8_t usage = 0xff;
> +  int usage_size = sizeof (usage_size);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for key usage");
> +    }
> +
> +  result = asn1_der_decoding2 (&usageasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Key Usage: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (usageasn, "", &usage, &usage_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key Usage value: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (!(usage & digitalSignatureUsage))
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Key Usage (0x%x) missing Digital Signature usage", usage);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&usageasn);
> +  return err;
> +}
> +
> +/*
> + * BasicConstraints ::= SEQUENCE {
> + *       cA                      BOOLEAN DEFAULT FALSE,
> + *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
> + */
> +static grub_err_t
> +verify_basic_constraints (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node basicasn;
> +  int result;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char cA[6]; /* FALSE or TRUE */
> +  int cA_size = sizeof (cA);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", &basicasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for Basic "
> +                         "Constraints");
> +    }
> +
> +  result = asn1_der_decoding2 (&basicasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Basic Constraints: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
> +  if (result == ASN1_ELEMENT_NOT_FOUND)
> +    {
> +      /* Not present, default is False, so this is OK */
> +      err = GRUB_ERR_NONE;
> +      goto cleanup;
> +    }
> +  else if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic Constraints cA value: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  /* The certificate must not be a CA certificate */
> +  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", cA);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&basicasn);
> +  return err;
> +}
> +
> +/*
> + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
> + *
> + * KeyPurposeId ::= OBJECT IDENTIFIER
> + */
> +static grub_err_t
> +verify_extended_key_usage (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node extendedasn;
> +  int result, count;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char usage[MAX_OID_LEN];
> +  int usage_size = sizeof (usage);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", &extendedasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for Extended Key "
> +                         "Usage");
> +    }
> +
> +  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Extended Key Usage: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * If EKUs are present, there must be exactly 1 usage and it must be a
> +   * codeSigning usage. (If we get to this point, we are parsing an EKU
> +   * extension and therefore must have a usage. The code that makes having an
> +   * EKU extension optional is in verify_extensions.)
> +   */
> +  result = asn1_number_of_elements (extendedasn, "", &count);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of Extended Key Usages: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (count != 1)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usages: %d, 1 expected",
> +                        count);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Extended Key Usage: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Unexpected Extended Key Usage OID, got: %s", usage);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&extendedasn);
> +  return err;
> +}
> +
> +/*
> + * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
> + *
> + * Extension  ::=  SEQUENCE  {
> + *      extnID      OBJECT IDENTIFIER,
> + *      critical    BOOLEAN DEFAULT FALSE,
> + *      extnValue   OCTET STRING
> + *                  -- contains the DER encoding of an ASN.1 value
> + *                  -- corresponding to the extension type identified
> + *                  -- by extnID
> + * }
> + *
> + * A certificate must:
> + *  - contain the Digital Signature usage only
> + *  - not be a CA
> + *  - contain no extended usages, or only a code signing extended usage
> + *  - not contain any other critical extensions (RFC 5280 s 4.2)
> + */
> +static grub_err_t
> +verify_extensions (asn1_node cert)
> +{
> +  int result;
> +  int ext, num_extensions = 0;
> +  int usage_present = 0, constraints_present = 0, extended_usage_present = 0;
> +  char *oid_path, *critical_path, *value_path;
> +  char extnID[MAX_OID_LEN];
> +  int extnID_size;
> +  grub_err_t err;
> +  char critical[6]; /* we get either "TRUE" or "FALSE" */
> +  int critical_size;
> +  grub_uint8_t *value;
> +  int value_size;
> +
> +  result = asn1_number_of_elements (cert, "tbsCertificate.extensions", &num_extensions);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of extensions: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (num_extensions < 2)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Insufficient number of extensions for "
> +                         "certificate, need at least 2, got %d",
> +                         num_extensions);
> +    }
> +
> +  for (ext = 1; ext <= num_extensions; ext++)
> +    {
> +      oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);

if (!oid_path) ...
    err = ...
    return err;

> +
> +      extnID_size = sizeof (extnID);
> +      result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
> +      if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension OID: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_oid_path;
> +        }
> +
> +      critical_path = grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);

if (!critical_path) ...
    err =
    goto cleanup_oid_path

> +      critical_size = sizeof (critical);
> +      result = asn1_read_value (cert, critical_path, critical, &critical_size);
> +      if (result == ASN1_ELEMENT_NOT_FOUND)
> +        {
> +          critical[0] = '\0';
> +        }
> +      else if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension criticality: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_critical_path;
> +        }
> +
> +      value_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);

if (!value_path) ...
    err = ...
    goto cleanup_critical_path

> +      value = grub_asn1_allocate_and_read (cert, value_path,
> +                                           "certificate extension value", &value_size);
> +      if (!value)
> +        {
> +          err = grub_errno;
> +          goto cleanup_value_path;
> +        }
> +
> +      /*
> +       * Now we must see if we recognise the OID.
> +       * If we have an unrecognised critical extension we MUST bail.
> +       */
> +      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_key_usage (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          usage_present++;
> +        }
> +      else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_basic_constraints (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          constraints_present++;
> +        }
> +      else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_extended_key_usage (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          extended_usage_present++;
> +        }
> +      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
> +        {
> +          /*
> +           * per the RFC, we must not process a certificate with
> +           * a critical extension we do not understand.
> +           */
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                            "Unhandled critical x509 extension with OID %s", extnID);
> +          goto cleanup_value;
> +        }
> +
> +      grub_free (value);
> +      grub_free (value_path);
> +      grub_free (critical_path);
> +      grub_free (oid_path);
> +    }
> +
> +  if (usage_present != 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Key Usage extensions "
> +                         "- expected 1, got %d", usage_present);
> +    }
> +  if (constraints_present != 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of basic constraints extensions "
> +                         "- expected 1, got %d", constraints_present);
> +    }
> +  if (extended_usage_present > 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usage extensions "
> +                         "- expected 0 or 1, got %d", extended_usage_present);
> +    }
> +  return GRUB_ERR_NONE;
> +
> +cleanup_value:
> +  grub_free (value);
> +cleanup_value_path:
> +  grub_free (value_path);
> +cleanup_critical_path:
> +  grub_free (critical_path);
> +cleanup_oid_path:
> +  grub_free (oid_path);
> +  return err;
> +}
> +
> +/*
> + * Parse a certificate whose DER-encoded form is in @data, of size @data_size.
> + * Return the results in @results, which must point to an allocated x509 certificate.
> + */
> +grub_err_t
> +parse_x509_certificate (const void *data, grub_size_t data_size, struct x509_certificate *results)
> +{
> +  int result = 0;
> +  asn1_node cert;
> +  grub_err_t err;
> +  int size;
> +  int tmp_size;
> +
> +  if (data_size > GRUB_INT_MAX)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE,
> +                       "Cannot parse a certificate where data size > INT_MAX");
> +  size = (int) data_size;
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for certificate: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  result = asn1_der_decoding2 (&cert, data, &size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Could not parse DER for certificate: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE {
> +   *     version         [0]  EXPLICIT Version DEFAULT v1
> +   */
> +  err = check_version (cert);
> +  if (err != GRUB_ERR_NONE)
> +    {
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * serialNumber         CertificateSerialNumber,
> +   *
> +   * CertificateSerialNumber  ::=  INTEGER
> +   */
> +  results->serial = grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
> +                                                 "certificate serial number", &tmp_size);
> +  if (!results->serial)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +  /*
> +   * It's safe to cast the signed int to an unsigned here, we know
> +   * length is non-negative
> +   */
> +  results->serial_len = tmp_size;
> +
> +  /*
> +   * signature            AlgorithmIdentifier,
> +   *
> +   * We don't load the signature or issuer at the moment,
> +   * as we don't attempt x509 verification.
> +   */
> +
> +  /*
> +   * issuer               Name,
> +   *
> +   * The RFC only requires the serial number to be unique within
> +   * issuers, so to avoid ambiguity we _technically_ ought to make
> +   * this available.
> +   */
> +
> +  /*
> +   * validity             Validity,
> +   *
> +   * Validity ::= SEQUENCE {
> +   *     notBefore      Time,
> +   *     notAfter       Time }
> +   *
> +   * We can't validate this reasonably, we have no true time source on several
> +   * platforms. For now we do not parse them.
> +   */
> +
> +  /*
> +   * subject              Name,
> +   *
> +   * This is an X501 name, we parse out just the CN.
> +   */
> +  err = read_name (cert, "tbsCertificate.subject", &results->subject, &results->subject_len);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_serial;
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE  {
> +   *    ...
> +   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
> +   *    ...
> +   */
> +  err = grub_x509_read_subject_public_key (cert, results);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_name;
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE  {
> +   *    ...
> +   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
> +   *                         -- If present, version MUST be v3
> +   * }
> +   */
> +
> +  err = verify_extensions (cert);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_mpis;
> +
> +  /*
> +   * We do not read or check the signature on the certificate:
> +   * as discussed we do not try to validate the certificate but trust
> +   * it implictly.
> +   */
> +
> +  asn1_delete_structure (&cert);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_mpis:
> +  gcry_mpi_release (results->mpis[0]);
> +  gcry_mpi_release (results->mpis[1]);
> +cleanup_name:
> +  grub_free (results->subject);
> +cleanup_serial:
> +  grub_free (results->serial);
> +cleanup:
> +  asn1_delete_structure (&cert);
> +  return err;
> +}
> +
> +/*
> + * Release all the storage associated with the x509 certificate.
> + * If the caller dynamically allocated the certificate, it must free it.
> + * The caller is also responsible for maintenance of the linked list.
> + */
> +void
> +certificate_release (struct x509_certificate *cert)
> +{
> +  grub_free (cert->subject);
> +  grub_free (cert->serial);
> +  gcry_mpi_release (cert->mpis[0]);
> +  gcry_mpi_release (cert->mpis[1]);
> +}



_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 10/21] appended signatures: support verifying appended signatures
  2024-12-18 14:56 ` [PATCH v1 10/21] appended signatures: support verifying appended signatures Sudhakar Kuppusamy
@ 2024-12-29 16:37   ` Stefan Berger
  2025-02-06  6:10   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-29 16:37 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Building on the parsers and the ability to embed x509 certificates, as
> well as the existing gcrypt functionality, add a module for verifying
> appended signatures.
> 
> This includes a verifier that requires that Linux kernels and grub modules
> have appended signatures, and commands to manage the list of trusted
> certificates for verification.
> 
> Verification must be enabled by setting check_appended_signatures. If
> GRUB is locked down when the module is loaded, verification will be
> enabled and locked automatically.
> 
> As with the PGP verifier, it is not a complete secure-boot solution:
> other mechanisms, such as a password or lockdown, must be used to ensure
> that a user cannot drop to the grub shell and disable verification.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   grub-core/Makefile.core.def                   |  14 +
>   grub-core/commands/appendedsig/appendedsig.c  | 620 ++++++++++++++++++
>   grub-core/commands/appendedsig/appendedsig.h  |   2 +-
>   grub-core/commands/appendedsig/asn1util.c     |   2 +-
>   .../commands/appendedsig/gnutls_asn1_tab.c    |   2 +-
>   .../commands/appendedsig/pkix_asn1_tab.c      |   2 +-
>   grub-core/commands/appendedsig/x509.c         |   2 +-
>   include/grub/file.h                           |   2 +
>   8 files changed, 641 insertions(+), 5 deletions(-)
>   create mode 100644 grub-core/commands/appendedsig/appendedsig.c
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 60db2adc5..d693986c6 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -979,6 +979,20 @@ module = {
>     cppflags = '-I$(srcdir)/lib/posix_wrap';
>   };
>   
> +module = {
> +  name = appendedsig;
> +  common = commands/appendedsig/appendedsig.c;
> +  common = commands/appendedsig/x509.c;
> +  common = commands/appendedsig/pkcs7.c;
> +  common = commands/appendedsig/asn1util.c;
> +  common = commands/appendedsig/gnutls_asn1_tab.c;
> +  common = commands/appendedsig/pkix_asn1_tab.c;
> +
> +  // posix wrapper required for gcry to get sys/types.h
> +  cflags = '$(CFLAGS_POSIX)';
> +  cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/libtasn1-grub';
> +};
> +
>   module = {
>     name = hdparm;
>     common = commands/hdparm.c;
> diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
> new file mode 100644
> index 000000000..5c82b96a4
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -0,0 +1,620 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2021, 2022 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/types.h>
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +#include <grub/err.h>
> +#include <grub/dl.h>
> +#include <grub/file.h>
> +#include <grub/command.h>
> +#include <grub/crypto.h>
> +#include <grub/pkcs1_v15.h>
> +#include <grub/i18n.h>
> +#include <grub/gcrypt/gcrypt.h>
> +#include <grub/kernel.h>
> +#include <grub/extcmd.h>
> +#include <grub/verify.h>
> +#include <libtasn1.h>
> +#include <grub/env.h>
> +#include <grub/lockdown.h>
> +
> +#include "appendedsig.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +const char magic[] = "~Module signature appended~\n";
> +
> +/*
> + * This structure is extracted from scripts/sign-file.c in the linux kernel
> + * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
> + */
> +struct module_signature
> +{
> +  grub_uint8_t algo;       /* Public-key crypto algorithm [0] */
> +  grub_uint8_t hash;       /* Digest algorithm [0] */
> +  grub_uint8_t id_type;    /* Key identifier type [PKEY_ID_PKCS7] */
> +  grub_uint8_t signer_len; /* Length of signer's name [0] */
> +  grub_uint8_t key_id_len; /* Length of key identifier [0] */
> +  grub_uint8_t __pad[3];
> +  grub_uint32_t sig_len;   /* Length of signature data */
> +} GRUB_PACKED;
> +
> +/* This represents an entire, parsed, appended signature */
> +struct grub_appended_signature
> +{
> +  grub_size_t signature_len;            /* Length of PKCS#7 data + metadata + magic */
> +  struct module_signature sig_metadata; /* Module signature metadata */
> +  struct pkcs7_signedData pkcs7;        /* Parsed PKCS#7 data */
> +};
> +
> +/* Trusted certificates for verifying appended signatures */
> +struct x509_certificate *grub_trusted_key;
> +
> +/*
> + * Force gcry_rsa to be a module dependency.
> + *
> + * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built
> + * in if you add 'appendedsig' to grub-install --modules. You would need to
> + * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when
> + * we only support RSA.
> + *
> + * Dynamic loading also causes some concerns. We can't load gcry_rsa from the
> + * the filesystem after we install the verifier - we won't be able to verify
> + * it without having it already present. We also shouldn't load it before we
> + * install the verifier, because that would mean it wouldn't be verified - an
> + * attacker could insert any code they wanted into the module.
> + *
> + * So instead, reference the internal symbol from gcry_rsa. That creates a
> + * direct dependency on gcry_rsa, so it will be built in when this module
> + * is built in. Being built in (assuming the core image is itself signed!)
> + * also resolves our concerns about loading from the filesystem.
> + */
> +extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
> +
> +static enum
> +{
> +  check_sigs_no = 0,
> +  check_sigs_enforce = 1,
> +  check_sigs_forced = 2
> +} check_sigs = check_sigs_no;
> +
> +static const char *
> +grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
> +                   const char *val __attribute__ ((unused)))
> +{
> +  if (check_sigs == check_sigs_forced)
> +    return "forced";
> +  else if (check_sigs == check_sigs_enforce)
> +    return "enforce";
> +  else
> +    return "no";
> +}
> +
> +static char *
> +grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const char *val)
> +{
> +  /* Do not allow the value to be changed if set to forced */
> +  if (check_sigs == check_sigs_forced)
> +    return grub_strdup ("forced");
> +
> +  if ((*val == '2') || (*val == 'f'))
> +    check_sigs = check_sigs_forced;
> +  else if ((*val == '1') || (*val == 'e'))
> +    check_sigs = check_sigs_enforce;
> +  else if ((*val == '0') || (*val == 'n'))
> +    check_sigs = check_sigs_no;
> +
> +  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)
> +{
> +  grub_size_t pkcs7_size;
> +  grub_size_t remaining_len;
> +  const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic);
> +
> +  if (bufsize < grub_strlen (magic))
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for signature magic"));
> +
> +  if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic)))
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Missing or invalid signature magic"));
> +
> +  remaining_len = bufsize - grub_strlen (magic);
> +
> +  if (remaining_len < sizeof (struct module_signature))
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for signature metadata"));
> +
> +  appsigdata -= sizeof (struct module_signature);
> +
> +  /* extract the metadata */
> +  grub_memcpy (&(sig->sig_metadata), appsigdata, sizeof (struct module_signature));
> +
> +  remaining_len -= sizeof (struct module_signature);
> +
> +  if (sig->sig_metadata.id_type != 2)
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type"));
> +
> +  pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len);
> +
> +  if (pkcs7_size > remaining_len)
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for PKCS#7 message"));
> +
> +  grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size);
> +
> +  sig->signature_len = grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size;
> +
> +  /* rewind pointer and parse pkcs7 data */
> +  appsigdata -= pkcs7_size;
> +
> +  return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
> +}
> +
> +static grub_err_t
> +grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
> +{
> +  grub_err_t err = GRUB_ERR_NONE;
> +  grub_size_t datasize;
> +  void *context;
> +  unsigned char *hash;
> +  gcry_mpi_t hashmpi;
> +  gcry_err_code_t rc;
> +  struct x509_certificate *pk;
> +  struct grub_appended_signature sig;
> +  struct pkcs7_signerInfo *si;
> +  int i;
> +
> +  if (!grub_trusted_key)
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
> +
> +  err = extract_appended_signature (buf, bufsize, &sig);
> +  if (err != GRUB_ERR_NONE)
> +    return err;
> +
> +  datasize = bufsize - sig.signature_len;
> +
> +  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
> +    {
> +      /*
> +       * 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 = grub_trusted_key; pk; pk = pk->next)
> +        {
> +          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;
> +            }
> +
> +          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
> +          gcry_mpi_release (hashmpi);
> +
> +          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", "verify signer %d with key '%s' failed with %d\n",
> +                        i, pk->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);
> +
> +  return err;
> +}
> +
> +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;
> +
> +  if (argc < 1)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
> +
> +  grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
> +
> +  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
> +  if (!f)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  err = file_read_all (f, &data, &file_size);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup;
> +
> +  err = grub_verify_appended_signature (data, file_size);
> +
> +  grub_free (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)
> +{
> +  unsigned long cert_num, i;
> +  struct x509_certificate *cert, *prev;
> +
> +  if (argc != 1)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
> +
> +  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"));
> +
> +  if (cert_num == 1)
> +    {
> +      cert = grub_trusted_key;
> +      grub_trusted_key = cert->next;
> +
> +      certificate_release (cert);
> +      grub_free (cert);
> +      return GRUB_ERR_NONE;
> +    }
> +  i = 2;
> +  prev = grub_trusted_key;
> +  cert = grub_trusted_key->next;
> +  while (cert)
> +    {
> +      if (i == cert_num)
> +        {
> +          prev->next = cert->next;
> +          certificate_release (cert);
> +          grub_free (cert);
> +          return GRUB_ERR_NONE;
> +        }
> +      i++;
> +      prev = cert;
> +      cert = 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);
> +}
> +
> +static grub_err_t
> +grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
> +{
> +  grub_file_t certf;
> +  struct x509_certificate *cert = NULL;
> +  grub_err_t err;
> +
> +  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"));
> +
> +  err = read_cert_from_file (certf, cert);
> +  grub_file_close (certf);
> +  if (err != GRUB_ERR_NONE)
> +    {
> +      grub_free (cert);
> +      return err;
> +    }
> +  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject);
> +
> +  cert->next = grub_trusted_key;
> +  grub_trusted_key = cert;
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +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;
> +
> +  for (cert = grub_trusted_key; cert; cert = cert->next)
> +    {
> +      grub_printf (N_("Certificate %d:\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++;
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +appendedsig_init (grub_file_t io __attribute__ ((unused)), enum grub_file_type type,
> +                  void **context __attribute__ ((unused)), enum grub_verify_flags *flags)
> +{
> +  if (check_sigs == check_sigs_no)
> +    {
> +      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
> +      return GRUB_ERR_NONE;
> +    }
> +
> +  switch (type & GRUB_FILE_TYPE_MASK)
> +    {
> +      case GRUB_FILE_TYPE_CERTIFICATE_TRUST:
> +        /*
> +         * This is a certificate to add to trusted keychain.
> +         *
> +         * This needs to be verified or blocked. Ideally we'd write an x509
> +         * verifier, but we lack the hubris required to take this on. Instead,
> +         * require that it have an appended signature.
> +         */
> +
> +        /* Fall through */
> +
> +      case GRUB_FILE_TYPE_LINUX_KERNEL:
> +      case GRUB_FILE_TYPE_GRUB_MODULE:
> +        /*
> +         * Appended signatures are only defined for ELF binaries.
> +         * Out of an abundance of caution, we only verify Linux kernels and
> +         * GRUB modules at this point.
> +         */
> +        *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
> +        return GRUB_ERR_NONE;
> +
> +      case GRUB_FILE_TYPE_ACPI_TABLE:
> +      case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
> +        /*
> +         * It is possible to use appended signature verification without
> +         * lockdown - like the PGP verifier. When combined with an embedded
> +         * config file in a signed grub binary, this could still be a meaningful
> +         * secure-boot chain - so long as it isn't subverted by something like a
> +         * rouge ACPI table or DT image. Defer them explicitly.
> +         */
> +        *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
> +        return GRUB_ERR_NONE;
> +
> +      default:
> +        *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
> +        return GRUB_ERR_NONE;
> +    }
> +}
> +
> +static grub_err_t
> +appendedsig_write (void *ctxt __attribute__ ((unused)), void *buf, grub_size_t size)
> +{
> +  return grub_verify_appended_signature (buf, size);
> +}
> +
> +struct grub_file_verifier grub_appendedsig_verifier = {
> +  .name = "appendedsig",
> +  .init = appendedsig_init,
> +  .write = appendedsig_write,
> +};
> +
> +static grub_ssize_t
> +pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
> +{
> +  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
> +  return 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;
> +
> +GRUB_MOD_INIT (appendedsig)
> +{
> +  int rc;
> +  struct grub_module_header *header;
> +
> +  /* If in lockdown, immediately enter forced mode */
> +  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");
> +
> +  rc = asn1_init ();
> +  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;
> +
> +    /* Not an X.509 certificate, skip. */
> +    if (header->type != OBJ_TYPE_X509_PUBKEY)
> +      continue;
> +
> +    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;
> +  }
> +
> +  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_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."));
> +
> +  grub_verifier_register (&grub_appendedsig_verifier);
> +  grub_dl_set_persistent (mod);
> +}
> +
> +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);
> +}
> diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
> index fa59302c8..60ee0f2fa 100644
> --- a/grub-core/commands/appendedsig/appendedsig.h
> +++ b/grub-core/commands/appendedsig/appendedsig.h
> @@ -18,7 +18,7 @@
>    */
>   
>   #include <grub/crypto.h>
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>   
>   extern asn1_node _gnutls_gnutls_asn;
>   extern asn1_node _gnutls_pkix_asn;
> diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
> index 609d0ecf2..a2c46724a 100644
> --- a/grub-core/commands/appendedsig/asn1util.c
> +++ b/grub-core/commands/appendedsig/asn1util.c
> @@ -17,7 +17,7 @@
>    *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
>    */
>   
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>   #include <grub/types.h>
>   #include <grub/err.h>
>   #include <grub/mm.h>
> diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> index ddd1314e6..8c4eb81d7 100644
> --- a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> +++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> @@ -1,5 +1,5 @@
>   #include <grub/mm.h>
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>   
>   const asn1_static_node gnutls_asn1_tab[] = {
>     { "GNUTLS", 536872976, NULL },
> diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> index adef69d95..8eeeac047 100644
> --- a/grub-core/commands/appendedsig/pkix_asn1_tab.c
> +++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> @@ -1,5 +1,5 @@
>   #include <grub/mm.h>
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>   
>   const asn1_static_node pkix_asn1_tab[] = {
>     { "PKIX1", 536875024, NULL },
> diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
> index eb9a1ca0f..b113ac38b 100644
> --- a/grub-core/commands/appendedsig/x509.c
> +++ b/grub-core/commands/appendedsig/x509.c
> @@ -17,7 +17,7 @@
>    *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
>    */
>   
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>   #include <grub/types.h>
>   #include <grub/err.h>
>   #include <grub/mm.h>
> diff --git a/include/grub/file.h b/include/grub/file.h
> index a5bf3a792..d678de063 100644
> --- a/include/grub/file.h
> +++ b/include/grub/file.h
> @@ -80,6 +80,8 @@ enum grub_file_type
>       GRUB_FILE_TYPE_PUBLIC_KEY,
>       /* File holding public key to add to trused keys.  */
>       GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
> +    /* File holding x509 certificiate to add to trusted keys.  */
> +    GRUB_FILE_TYPE_CERTIFICATE_TRUST,
>       /* File of which we intend to print a blocklist to the user.  */
>       GRUB_FILE_TYPE_PRINT_BLOCKLIST,
>       /* File we intend to use for test loading or testing speed.  */


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 11/21] appended signatures: verification tests
  2024-12-18 14:56 ` [PATCH v1 11/21] appended signatures: verification tests Sudhakar Kuppusamy
@ 2024-12-30 15:39   ` Stefan Berger
  2025-02-14 10:27   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-30 15:39 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> These tests are run through all_functional_test and test a range
> of commands and behaviours.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   grub-core/Makefile.core.def               |   6 +
>   grub-core/tests/appended_signature_test.c | 258 ++++++
>   grub-core/tests/appended_signatures.h     | 975 ++++++++++++++++++++++
>   grub-core/tests/lib/functional_test.c     |   1 +
>   4 files changed, 1240 insertions(+)
>   create mode 100644 grub-core/tests/appended_signature_test.c
>   create mode 100644 grub-core/tests/appended_signatures.h
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index d693986c6..9cf4a6009 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2194,6 +2194,12 @@ module = {
>     common = tests/setjmp_test.c;
>   };
>   
> +module = {
> +  name = appended_signature_test;
> +  common = tests/appended_signature_test.c;
> +  common = tests/appended_signatures.h;
> +};
> +
>   module = {
>     name = signature_test;
>     common = tests/signature_test.c;
> diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c
> new file mode 100644
> index 000000000..3d5b97391
> --- /dev/null
> +++ b/grub-core/tests/appended_signature_test.c
> @@ -0,0 +1,258 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/time.h>
> +#include <grub/misc.h>
> +#include <grub/dl.h>
> +#include <grub/command.h>
> +#include <grub/env.h>
> +#include <grub/test.h>
> +#include <grub/mm.h>
> +#include <grub/procfs.h>
> +#include <grub/file.h>
> +
> +#include "appended_signatures.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +#define PROC_FILE(identifier, file_name)                                    \
> +  static char *get_##identifier (grub_size_t *sz)                           \
> +  {                                                                         \
> +    char *ret;                                                              \
> +                                                                            \
> +    *sz = identifier##_len;                                                 \
> +    ret = grub_malloc (*sz);                                                \
> +    if (ret)                                                                \
> +      grub_memcpy (ret, identifier, *sz);                                   \
> +    return ret;                                                             \
> +  }                                                                         \
> +                                                                            \
> +  static struct grub_procfs_entry identifier##_entry = { .name = file_name, \
> +                                                         .get_contents = get_##identifier };
> +
> +#define DEFINE_TEST_CASE(case_name) PROC_FILE (case_name, #case_name)
> +
> +#define DO_TEST(case_name, is_valid)                       \
> +  {                                                        \
> +    grub_procfs_register (#case_name, &case_name##_entry); \
> +    do_verify ("(proc)/" #case_name, is_valid);            \
> +    grub_procfs_unregister (&case_name##_entry);           \
> +  }
> +
> +DEFINE_TEST_CASE (hi_signed);
> +DEFINE_TEST_CASE (hi_signed_sha256);
> +DEFINE_TEST_CASE (hj_signed);
> +DEFINE_TEST_CASE (short_msg);
> +DEFINE_TEST_CASE (unsigned_msg);
> +DEFINE_TEST_CASE (hi_signed_2nd);
> +DEFINE_TEST_CASE (hi_double);
> +DEFINE_TEST_CASE (hi_double_extended);
> +
> +PROC_FILE (certificate_der, "certificate.der")
> +PROC_FILE (certificate2_der, "certificate2.der")
> +PROC_FILE (certificate_printable_der, "certificate_printable.der")
> +PROC_FILE (certificate_eku_der, "certificate_eku.der")
> +
> +static void
> +do_verify (const char *f, int is_valid)
> +{
> +  grub_command_t cmd;
> +  char *args[] = { (char *) f, NULL };
> +  grub_err_t err;
> +
> +  cmd = grub_command_find ("verify_appended");
> +  if (!cmd)
> +    {
> +      grub_test_assert (0, "can't find command `%s'", "verify_appended");
> +      return;
> +    }
> +  err = (cmd->func) (cmd, 1, args);
> +  if (is_valid)
> +    {
> +      grub_test_assert (err == GRUB_ERR_NONE, "verification of %s failed: %d: %s",
> +                        f, grub_errno, grub_errmsg);
> +    }
> +  else
> +    {
> +      grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE,
> +                        "verification of %s unexpectedly succeeded", f);
> +    }
> +  grub_errno = GRUB_ERR_NONE;
> +}
> +
> +static void
> +appended_signature_test (void)
> +{
> +  grub_command_t cmd_trust, cmd_distrust;
> +  char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
> +  char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
> +  char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", NULL };
> +  char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL };
> +  char *distrust_args[] = { (char *) "1", NULL };
> +  char *distrust2_args[] = { (char *) "2", NULL };
> +  grub_err_t err;
> +
> +  grub_procfs_register ("certificate.der", &certificate_der_entry);
> +  grub_procfs_register ("certificate2.der", &certificate2_der_entry);
> +  grub_procfs_register ("certificate_printable.der", &certificate_printable_der_entry);
> +  grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry);
> +
> +  cmd_trust = grub_command_find ("trust_certificate");
> +  if (!cmd_trust)
> +    {
> +      grub_test_assert (0, "can't find command `%s'", "trust_certificate");
> +      return;
> +    }
> +  grub_errno = GRUB_ERR_NONE;
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
> +
> +  grub_test_assert (err == GRUB_ERR_NONE, "loading certificate failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  /* If we have no certificate the remainder of the tests are meaningless */
> +  if (err != GRUB_ERR_NONE)
> +    return;
> +
> +  /*
> +   * Reload the command: this works around some 'interesting' behaviour in the
> +   * dynamic command dispatcher. The first time you call cmd->func you get a
> +   * dispatcher that loads the module, finds the real cmd, calls it, and then
> +   * releases some internal storage. This means it's not safe to call a second
> +   * time and we need to reload it.
> +   */
> +  cmd_trust = grub_command_find ("trust_certificate");
> +
> +  /* hi, signed with key 1, SHA-512 */
> +  DO_TEST (hi_signed, 1);
> +
> +  /* hi, signed with key 1, SHA-256 */
> +  DO_TEST (hi_signed_sha256, 1);
> +
> +  /* hi, key 1, SHA-512, second byte corrupted */
> +  DO_TEST (hj_signed, 0);
> +
> +  /* message too short for a signature */
> +  DO_TEST (short_msg, 0);
> +
> +  /* lorem ipsum */
> +  DO_TEST (unsigned_msg, 0);
> +
> +  /* hi, signed with both keys, SHA-512 */
> +  DO_TEST (hi_double, 1);
> +
> +  /*
> +   * hi, signed with both keys and with empty space to test we haven't broken
> +   * support for adding more signatures after the fact
> +   */
> +  DO_TEST (hi_double_extended, 1);
> +
> +  /*
> +   * in enforcing mode, we shouldn't be able to load a certificate that isn't
> +   * signed by an existing trusted key.
> +   *
> +   * However, procfs files automatically skip the verification test, so we can't
> +   * easily test this.
> +   */
> +
> +  /*
> +   * verify that testing with 2 trusted certs works
> +   */
> +  DO_TEST (hi_signed_2nd, 0);
> +
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
> +
> +  grub_test_assert (err == GRUB_ERR_NONE, "loading certificate 2 failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  if (err != GRUB_ERR_NONE)
> +    return;
> +
> +  DO_TEST (hi_signed_2nd, 1);
> +  DO_TEST (hi_signed, 1);
> +  DO_TEST (hi_double, 1);
> +  DO_TEST (hi_double_extended, 1);
> +
> +  /*
> +   * Check certificate removal. They're added to the _top_ of the list and
> +   * removed by position in the list. Current the list looks like [#2, #1].
> +   *
> +   * First test removing the second certificate in the list, which is
> +   * certificate #1, giving us just [#2].
> +   */
> +  cmd_distrust = grub_command_find ("distrust_certificate");
> +  if (!cmd_distrust)
> +    {
> +      grub_test_assert (0, "can't find command `%s'", "distrust_certificate");
> +      return;
> +    }
> +
> +  err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args);
> +  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed_2nd, 1);
> +  DO_TEST (hi_signed, 0);
> +  DO_TEST (hi_double, 1);
> +
> +  /*
> +   * Now reload certificate #1. This will make the list look like [#1, #2]
> +   */
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
> +
> +  grub_test_assert (err == GRUB_ERR_NONE, "reloading certificate 1 failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed, 1);
> +
> +  /* Remove the first certificate in the list, giving us just [#2] */
> +  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
> +  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 (first time) failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed_2nd, 1);
> +  DO_TEST (hi_signed, 0);
> +
> +  /*
> +   * Remove the first certificate again, giving an empty list.
> +   *
> +   * verify_appended should fail if there are no certificates to verify against.
> +   */
> +  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
> +  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 (second time) failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed_2nd, 0);
> +  DO_TEST (hi_double, 0);
> +
> +  /*
> +   * Lastly, check a certificate that uses printableString rather than
> +   * utf8String loads properly, and that a certificate with an appropriate
> +   * extended key usage loads.
> +   */
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
> +  grub_test_assert (err == GRUB_ERR_NONE, "trusting printable certificate failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku);
> +  grub_test_assert (err == GRUB_ERR_NONE, "trusting certificate with extended key usage failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  grub_procfs_unregister (&certificate_der_entry);
> +  grub_procfs_unregister (&certificate2_der_entry);
> +  grub_procfs_unregister (&certificate_printable_der_entry);
> +  grub_procfs_unregister (&certificate_eku_der_entry);
> +}
> +
> +GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
> diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
> new file mode 100644
> index 000000000..c6aa12d86
> --- /dev/null
> +++ b/grub-core/tests/appended_signatures.h
> @@ -0,0 +1,975 @@
> +unsigned char certificate_der[] = {
> +  0x30, 0x82, 0x05, 0x5d, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01,
> +  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
> +  0x05, 0x00, 0x30, 0x3d, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04,
> +  0x03, 0x0c, 0x32, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65,
> +  0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
> +  0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
> +  0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 0x30,
> +  0x36, 0x32, 0x39, 0x30, 0x38, 0x33, 0x36, 0x31, 0x33, 0x5a, 0x18, 0x0f,
> +  0x32, 0x31, 0x32, 0x31, 0x30, 0x36, 0x30, 0x35, 0x30, 0x38, 0x33, 0x36,
> +  0x31, 0x33, 0x5a, 0x30, 0x33, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55,
> +  0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
> +  0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67,
> +  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, 0x22,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
> +  0x02, 0x82, 0x02, 0x01, 0x00, 0xb9, 0x09, 0xb2, 0xf6, 0x24, 0x34, 0xdc,
> +  0x62, 0xe6, 0x4e, 0xee, 0x04, 0xdb, 0x29, 0xdc, 0x94, 0xcc, 0xee, 0x8a,
> +  0x5b, 0xc3, 0x9e, 0x06, 0xba, 0xa7, 0x9b, 0xa4, 0x5f, 0x15, 0x59, 0x8e,
> +  0xb8, 0x6e, 0x3c, 0xeb, 0x2e, 0xf2, 0xac, 0x21, 0x42, 0xbd, 0x30, 0xa1,
> +  0x39, 0xe5, 0xb9, 0x4f, 0xa0, 0x53, 0xd5, 0x42, 0xdc, 0x8a, 0x87, 0x30,
> +  0x38, 0x93, 0x44, 0x80, 0x3b, 0x1a, 0x7e, 0x9e, 0x8e, 0x3e, 0xea, 0x45,
> +  0xa0, 0x11, 0x8b, 0xfb, 0x78, 0xe4, 0xbc, 0x65, 0x6b, 0x73, 0xea, 0x6e,
> +  0xdf, 0x7c, 0x5b, 0x63, 0x7e, 0x5b, 0x0a, 0x1c, 0xe6, 0x76, 0x19, 0xb5,
> +  0x01, 0xde, 0xf6, 0x65, 0x51, 0x30, 0x0a, 0x56, 0x69, 0x69, 0xe8, 0x20,
> +  0xf9, 0x13, 0xf1, 0xbf, 0x6f, 0xdd, 0xce, 0x94, 0x96, 0x6e, 0x63, 0xd6,
> +  0xfa, 0xa4, 0x91, 0x5f, 0xb3, 0x9c, 0xc7, 0xfa, 0xa9, 0xff, 0x66, 0x5f,
> +  0xf3, 0xab, 0x5e, 0xdf, 0x4e, 0xca, 0x11, 0xcf, 0xbf, 0xf8, 0xad, 0x65,
> +  0xb1, 0x49, 0x8b, 0xe9, 0x2a, 0xad, 0x7d, 0xf3, 0x0b, 0xfa, 0x5b, 0x6a,
> +  0x6a, 0x20, 0x12, 0x77, 0xef, 0x4b, 0xb6, 0xbe, 0x92, 0xba, 0x14, 0x9c,
> +  0x5e, 0xea, 0xdc, 0x56, 0x6d, 0x92, 0xd3, 0x64, 0x22, 0xf6, 0x12, 0xe8,
> +  0x7d, 0x5e, 0x9c, 0xd6, 0xf9, 0x75, 0x68, 0x7f, 0x8f, 0xd3, 0x6e, 0x05,
> +  0x94, 0x91, 0x4f, 0xa1, 0xd6, 0x50, 0x72, 0x3b, 0x11, 0x1f, 0x28, 0x13,
> +  0xe8, 0x25, 0x6b, 0xdf, 0xff, 0x72, 0x46, 0x25, 0xe9, 0x05, 0x6f, 0x02,
> +  0xc7, 0x1e, 0xc9, 0xcf, 0x99, 0xe9, 0xa7, 0xe2, 0xae, 0xbc, 0xc1, 0x22,
> +  0x32, 0x73, 0x2d, 0xa3, 0x70, 0x8f, 0xa7, 0x8d, 0xbf, 0x5f, 0x74, 0x05,
> +  0x1b, 0x5e, 0xfe, 0x97, 0x3c, 0xe7, 0x3b, 0x86, 0x0d, 0xf6, 0x38, 0xdb,
> +  0xd2, 0x39, 0x47, 0x82, 0x00, 0x44, 0x6c, 0x7b, 0x40, 0x24, 0x0b, 0x3a,
> +  0xd4, 0x19, 0x31, 0xba, 0x4e, 0x8e, 0xa3, 0x33, 0xa6, 0x78, 0xef, 0x72,
> +  0x9f, 0x06, 0x37, 0x01, 0x9b, 0x79, 0x0d, 0x04, 0xbf, 0xba, 0xd5, 0x1f,
> +  0x27, 0xdc, 0x85, 0xbb, 0xef, 0xd2, 0x60, 0xda, 0xa0, 0x3f, 0x66, 0xce,
> +  0x9f, 0xa2, 0x7e, 0xa8, 0x8d, 0xee, 0x14, 0x4b, 0xcb, 0x93, 0xf1, 0x38,
> +  0xac, 0x4f, 0xd8, 0x29, 0xf3, 0x6f, 0xd4, 0xfd, 0x4d, 0x34, 0x77, 0x58,
> +  0x99, 0xdb, 0x16, 0xc1, 0xd0, 0xc7, 0x43, 0x41, 0x70, 0xc4, 0xad, 0x01,
> +  0x29, 0x65, 0x22, 0x43, 0x00, 0x6f, 0xb3, 0x00, 0x27, 0x38, 0xc1, 0x4f,
> +  0xda, 0x28, 0x96, 0x42, 0xdc, 0xbc, 0x3e, 0x34, 0x8e, 0x14, 0xb8, 0xf3,
> +  0x86, 0x4a, 0xea, 0x16, 0x90, 0xf9, 0x0e, 0x9e, 0x8f, 0x66, 0x0c, 0xbf,
> +  0x29, 0xd3, 0x8f, 0xfc, 0x4d, 0x38, 0x68, 0xe2, 0xe7, 0x64, 0x32, 0x47,
> +  0xdd, 0x56, 0xc9, 0xe4, 0x47, 0x9f, 0x18, 0x89, 0xfc, 0x30, 0x7a, 0xae,
> +  0x63, 0xe4, 0xec, 0x93, 0x04, 0xd4, 0x61, 0xe7, 0xbf, 0x0a, 0x06, 0x29,
> +  0xc2, 0xa6, 0xd5, 0x53, 0x5d, 0x65, 0x6d, 0x4a, 0xd0, 0xb7, 0x68, 0x4d,
> +  0x46, 0x0a, 0xb5, 0xff, 0x52, 0x5e, 0x92, 0x7e, 0x75, 0x08, 0xa4, 0x63,
> +  0x0a, 0x6c, 0x31, 0x7a, 0xaa, 0x0c, 0x52, 0xf4, 0x2e, 0xcd, 0x08, 0xeb,
> +  0xb3, 0xbd, 0xad, 0x8b, 0x8b, 0x9b, 0x8d, 0x71, 0x42, 0x30, 0x8e, 0xc7,
> +  0xfd, 0xec, 0xb7, 0xe6, 0x26, 0x96, 0xf2, 0x74, 0x1b, 0x78, 0x95, 0x22,
> +  0x14, 0xf3, 0xc9, 0xd3, 0x79, 0x11, 0xd9, 0xb7, 0x4d, 0x0d, 0x61, 0x60,
> +  0x5c, 0x47, 0x50, 0xf3, 0xca, 0x84, 0x4c, 0x5c, 0x30, 0x2c, 0x6a, 0x18,
> +  0x26, 0xb0, 0xf3, 0xd1, 0x15, 0x19, 0x39, 0xc3, 0x23, 0x13, 0x0f, 0x9c,
> +  0x97, 0x2b, 0x97, 0x93, 0xf9, 0xf8, 0x18, 0x9b, 0x4a, 0x4d, 0xd6, 0xd3,
> +  0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c,
> +  0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
> +  0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07,
> +  0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
> +  0x8f, 0xba, 0x8b, 0xf5, 0xf4, 0x77, 0xb2, 0xa4, 0x19, 0xef, 0x43, 0xb1,
> +  0x8b, 0x03, 0x4b, 0x45, 0x47, 0xb5, 0x2a, 0x48, 0x30, 0x1f, 0x06, 0x03,
> +  0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x59, 0x1c, 0xb5,
> +  0x52, 0x62, 0x83, 0x05, 0x3b, 0x41, 0x4c, 0x63, 0x4d, 0x5b, 0xf4, 0x8c,
> +  0xe6, 0xd7, 0xda, 0x87, 0x54, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
> +  0x00, 0x36, 0x2d, 0x0a, 0xcb, 0x49, 0x54, 0x75, 0xd7, 0xca, 0x21, 0x86,
> +  0xae, 0x40, 0x0f, 0x63, 0x10, 0x35, 0xfd, 0xbc, 0xba, 0x28, 0x31, 0x33,
> +  0x07, 0x08, 0x64, 0x03, 0x6c, 0xd3, 0xd5, 0xf7, 0xb7, 0x79, 0x11, 0x0c,
> +  0xa8, 0x9e, 0xfd, 0x34, 0xa2, 0xba, 0x77, 0x15, 0x15, 0x2d, 0x2c, 0x96,
> +  0xae, 0x47, 0xbb, 0x82, 0x89, 0x09, 0x7f, 0xd1, 0x95, 0x69, 0x9b, 0xfe,
> +  0xd7, 0x6f, 0x4e, 0x68, 0xf6, 0xe7, 0x5f, 0x54, 0xa1, 0x3a, 0xeb, 0xa4,
> +  0xbf, 0x7a, 0xb6, 0x7f, 0xaa, 0xd8, 0xd7, 0x99, 0xcb, 0xae, 0x88, 0x6d,
> +  0x7a, 0xf3, 0xfa, 0x9e, 0x44, 0x2f, 0x30, 0xa8, 0xe6, 0xb9, 0x75, 0xa0,
> +  0x82, 0xd6, 0xb0, 0xe3, 0x03, 0xb3, 0x12, 0xa3, 0xdc, 0xb9, 0x4d, 0x93,
> +  0xd4, 0x30, 0xea, 0xce, 0x96, 0x92, 0x07, 0xf8, 0xba, 0xe4, 0x0f, 0x41,
> +  0xe3, 0x04, 0xaa, 0x8c, 0x07, 0x1a, 0x34, 0x60, 0xfc, 0xc0, 0x05, 0xd2,
> +  0x5a, 0xa8, 0x66, 0xef, 0xe0, 0x94, 0xc5, 0x2f, 0x0f, 0xff, 0xdc, 0x70,
> +  0xfb, 0xe2, 0x9d, 0x61, 0x51, 0x25, 0x02, 0xff, 0x4b, 0x69, 0xfd, 0x66,
> +  0xb9, 0xeb, 0x0c, 0xc8, 0x50, 0xd3, 0xb1, 0x08, 0x1e, 0x09, 0x54, 0x87,
> +  0xe8, 0xa3, 0x4b, 0xef, 0x0c, 0x32, 0x0a, 0x6c, 0xec, 0x27, 0x22, 0xba,
> +  0x7f, 0xdc, 0x52, 0x27, 0x31, 0x14, 0x9a, 0xa8, 0xf7, 0xf9, 0xeb, 0xc8,
> +  0xb5, 0x8d, 0x12, 0xed, 0x94, 0xab, 0x3d, 0x9a, 0xfb, 0x4e, 0x04, 0x05,
> +  0xd2, 0x3c, 0x7c, 0x8a, 0xed, 0x46, 0x1b, 0x7c, 0xb5, 0x6c, 0x40, 0xb8,
> +  0xc1, 0xbf, 0xb0, 0xd2, 0x93, 0x8e, 0xa8, 0x0f, 0xde, 0x78, 0xf3, 0x8c,
> +  0xd8, 0x9f, 0xf8, 0xdc, 0xa1, 0x23, 0x20, 0x40, 0x17, 0xb4, 0xdb, 0xb7,
> +  0x09, 0x74, 0xa7, 0x80, 0xc2, 0x12, 0xd9, 0x76, 0x79, 0x5b, 0x71, 0xa9,
> +  0x6c, 0xd4, 0x57, 0x48, 0xe8, 0xfe, 0xc5, 0xc2, 0x6e, 0xe7, 0x83, 0x5a,
> +  0x07, 0xf0, 0x33, 0xc1, 0xc1, 0x1d, 0x34, 0xd4, 0xc8, 0xb0, 0xb7, 0xdb,
> +  0xeb, 0xe9, 0xe3, 0x59, 0xdc, 0x7f, 0x36, 0x58, 0xa9, 0xb8, 0x52, 0xdd,
> +  0xf9, 0xfd, 0x1c, 0x22, 0x2f, 0x93, 0x3d, 0x53, 0x89, 0x80, 0xde, 0xa2,
> +  0xb5, 0xa5, 0x36, 0xbd, 0xc3, 0x92, 0x03, 0xf3, 0x93, 0xc8, 0xc7, 0x4a,
> +  0x0b, 0x8b, 0x62, 0xfe, 0xd0, 0xf8, 0x0d, 0x7a, 0x32, 0xb4, 0x39, 0x1a,
> +  0xb7, 0x4e, 0xaa, 0xc4, 0x33, 0x32, 0x90, 0x8c, 0xab, 0xd4, 0xae, 0xa5,
> +  0xa4, 0x85, 0xcf, 0xba, 0xe1, 0x1b, 0x26, 0x7f, 0x74, 0x02, 0x12, 0x09,
> +  0x89, 0x56, 0xe4, 0xe7, 0x9d, 0x91, 0xde, 0x88, 0xe7, 0x1c, 0xed, 0x80,
> +  0x05, 0xa8, 0x58, 0x9a, 0x3e, 0x16, 0x97, 0xd5, 0xbc, 0x54, 0xcc, 0xf0,
> +  0x32, 0xf2, 0x93, 0x09, 0x94, 0x9f, 0x3c, 0xd9, 0x58, 0xca, 0x68, 0x0b,
> +  0xde, 0x3f, 0x73, 0x64, 0xb7, 0xf4, 0xd7, 0x5f, 0x2b, 0xe7, 0x7b, 0x06,
> +  0xca, 0xb1, 0x3e, 0xed, 0xd2, 0xb9, 0x29, 0xc1, 0x95, 0x87, 0xad, 0xd6,
> +  0x63, 0x69, 0xb8, 0x1f, 0x70, 0xdb, 0xeb, 0xc7, 0x11, 0x7d, 0xe2, 0x99,
> +  0x64, 0x6a, 0xf5, 0x3f, 0x30, 0x74, 0x5f, 0x2a, 0x21, 0xda, 0xef, 0x44,
> +  0x1d, 0xad, 0x97, 0xa1, 0xfe, 0x14, 0xa7, 0x88, 0x99, 0xd0, 0x1e, 0xb0,
> +  0x61, 0x88, 0x09, 0xc9, 0xfa, 0xd1, 0xb3, 0xcb, 0x1d, 0x76, 0x04, 0xbe,
> +  0x06, 0x44, 0xd2, 0x30, 0x5e, 0x95, 0x4b, 0x96, 0xc0, 0xd6, 0xbe, 0xd0,
> +  0x4d, 0xf2, 0xf4, 0x71, 0x72, 0xa9, 0xbd, 0x07, 0x4f, 0xbc, 0xb3, 0x78,
> +  0xb4, 0x8a, 0x44, 0xbd, 0x58, 0xd5, 0x21, 0xb6, 0x47, 0x9c, 0x88, 0x1f,
> +  0xbc, 0xbd, 0x54, 0xfa, 0x1d, 0x49, 0xec, 0x51, 0xd9, 0x43, 0x49, 0x9c,
> +  0x0c, 0xfa, 0x18, 0xdb, 0xeb, 0x05, 0x77, 0xa2, 0x9a
> +};
> +unsigned int certificate_der_len = 1377;
> +
> +unsigned char hi_signed[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82,
> +  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
> +  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d,
> +  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
> +  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
> +  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
> +  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
> +  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
> +  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77,
> +  0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03,
> +  0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e,
> +  0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52,
> +  0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01,
> +  0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75,
> +  0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1,
> +  0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d,
> +  0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e,
> +  0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f,
> +  0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae,
> +  0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5,
> +  0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a,
> +  0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33,
> +  0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2,
> +  0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9,
> +  0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70,
> +  0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67,
> +  0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a,
> +  0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3,
> +  0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33,
> +  0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4,
> +  0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1,
> +  0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26,
> +  0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41,
> +  0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda,
> +  0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3,
> +  0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98,
> +  0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5,
> +  0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e,
> +  0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe,
> +  0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c,
> +  0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6,
> +  0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5,
> +  0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f,
> +  0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb,
> +  0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0,
> +  0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4,
> +  0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b,
> +  0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52,
> +  0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f,
> +  0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c,
> +  0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17,
> +  0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_signed_len = 739;
> +
> +unsigned char hj_signed[] = {
> +  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82,
> +  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
> +  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d,
> +  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
> +  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
> +  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
> +  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
> +  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
> +  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77,
> +  0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03,
> +  0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e,
> +  0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52,
> +  0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01,
> +  0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75,
> +  0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1,
> +  0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d,
> +  0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e,
> +  0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f,
> +  0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae,
> +  0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5,
> +  0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a,
> +  0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33,
> +  0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2,
> +  0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9,
> +  0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70,
> +  0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67,
> +  0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a,
> +  0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3,
> +  0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33,
> +  0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4,
> +  0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1,
> +  0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26,
> +  0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41,
> +  0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda,
> +  0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3,
> +  0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98,
> +  0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5,
> +  0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e,
> +  0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe,
> +  0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c,
> +  0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6,
> +  0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5,
> +  0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f,
> +  0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb,
> +  0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0,
> +  0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4,
> +  0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b,
> +  0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52,
> +  0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f,
> +  0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c,
> +  0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17,
> +  0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hj_signed_len = 739;
> +
> +unsigned char hi_signed_sha256[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82,
> +  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
> +  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d,
> +  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
> +  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
> +  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
> +  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
> +  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30,
> +  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0x96, 0x02, 0x7b, 0xa4, 0x07,
> +  0xa7, 0x39, 0x8d, 0xa6, 0x0b, 0xde, 0x33, 0xdd, 0xf8, 0xec, 0x24, 0x5d,
> +  0x06, 0x81, 0xe7, 0x3c, 0x2d, 0x0c, 0x53, 0xfb, 0x7e, 0x5a, 0xf3, 0xee,
> +  0xe5, 0x4c, 0x7c, 0xf7, 0xe7, 0x8f, 0x36, 0x62, 0x35, 0xb8, 0x99, 0xc3,
> +  0xeb, 0x85, 0x1d, 0x2e, 0x40, 0x6e, 0x2a, 0xb4, 0x3a, 0x76, 0x48, 0x4f,
> +  0x8b, 0x29, 0xd4, 0x9e, 0x5c, 0xd2, 0x41, 0x4d, 0xc1, 0x72, 0x0f, 0x97,
> +  0xe0, 0x7d, 0x88, 0xed, 0x1a, 0xb0, 0xde, 0x1b, 0x21, 0xa6, 0x0c, 0x19,
> +  0xd8, 0xb0, 0x12, 0x54, 0x7b, 0xd8, 0x19, 0x03, 0xbd, 0x77, 0x83, 0x23,
> +  0xeb, 0xeb, 0x68, 0x0a, 0x7b, 0x3a, 0x4d, 0x25, 0x44, 0xe1, 0x64, 0x8d,
> +  0x43, 0x5a, 0x1c, 0x9f, 0x74, 0x79, 0x31, 0x3f, 0xc7, 0x8e, 0xae, 0xe1,
> +  0xf9, 0x1e, 0x54, 0x12, 0x36, 0x85, 0xf2, 0x55, 0xba, 0x42, 0x60, 0x64,
> +  0x25, 0x9f, 0x73, 0x62, 0x42, 0xd2, 0x1c, 0x5e, 0x39, 0x4f, 0x7d, 0x91,
> +  0xb8, 0xf9, 0x59, 0x3c, 0x13, 0x6b, 0x84, 0x76, 0x6d, 0x8a, 0xc3, 0xcb,
> +  0x2d, 0x14, 0x27, 0x16, 0xdc, 0x20, 0x2c, 0xbc, 0x6b, 0xc9, 0xda, 0x9f,
> +  0xef, 0xe2, 0x2d, 0xc3, 0x83, 0xd8, 0xf9, 0x94, 0x18, 0xbc, 0xfe, 0x8f,
> +  0xa9, 0x44, 0xad, 0xff, 0x1b, 0xcb, 0x86, 0x30, 0x96, 0xa8, 0x3c, 0x7a,
> +  0x4b, 0x73, 0x1b, 0xa9, 0xc3, 0x3b, 0xaa, 0xd7, 0x44, 0xa8, 0x4d, 0xd6,
> +  0x92, 0xb6, 0x00, 0x04, 0x09, 0x05, 0x4a, 0x95, 0x02, 0x90, 0x19, 0x8c,
> +  0x9a, 0xa5, 0xee, 0x58, 0x24, 0xb0, 0xca, 0x5e, 0x6f, 0x73, 0xdb, 0xf5,
> +  0xa1, 0xf4, 0xf0, 0xa9, 0xeb, 0xe4, 0xdc, 0x55, 0x9f, 0x8f, 0x7a, 0xd0,
> +  0xf7, 0xb6, 0xaa, 0xa6, 0xb5, 0xb4, 0xab, 0xb8, 0x65, 0xad, 0x12, 0x32,
> +  0x1c, 0xe6, 0x99, 0x71, 0x93, 0xe8, 0xb4, 0x1e, 0x21, 0x27, 0x52, 0xea,
> +  0x8c, 0xc8, 0x79, 0x96, 0x2e, 0x48, 0x60, 0x57, 0x1c, 0x7d, 0x8c, 0x0d,
> +  0x07, 0xa7, 0x12, 0x83, 0x0a, 0x76, 0x6a, 0x64, 0xed, 0xbe, 0x8d, 0xaf,
> +  0xdf, 0x51, 0x05, 0xdd, 0xf2, 0xd3, 0xb8, 0x93, 0xa9, 0x13, 0xa5, 0x96,
> +  0xe8, 0xfa, 0x82, 0x02, 0x18, 0x71, 0x7a, 0x71, 0xbb, 0x39, 0x6f, 0x85,
> +  0xee, 0x16, 0x82, 0x27, 0x42, 0x9f, 0x83, 0xc8, 0xab, 0x6a, 0x3b, 0x99,
> +  0xba, 0x38, 0x92, 0x38, 0xae, 0x59, 0xfa, 0xaa, 0x40, 0x2b, 0x52, 0x95,
> +  0xca, 0x5e, 0xe1, 0x9b, 0x00, 0xbd, 0xb9, 0x63, 0x25, 0x8d, 0xc7, 0x22,
> +  0xaf, 0xe5, 0x67, 0x76, 0x91, 0xf4, 0xda, 0xc9, 0x7e, 0x9e, 0xec, 0x9b,
> +  0x1f, 0x7d, 0x3b, 0xfe, 0xa1, 0x20, 0x52, 0xac, 0xd0, 0xe5, 0xa6, 0xf1,
> +  0xfd, 0x4c, 0x08, 0x59, 0x7d, 0x50, 0xbb, 0x0c, 0xcf, 0xd8, 0xb6, 0x0f,
> +  0xc7, 0x19, 0xcb, 0x7a, 0x96, 0x6f, 0x0f, 0x6c, 0x71, 0x56, 0x72, 0xd1,
> +  0x06, 0x29, 0x0f, 0x08, 0xa2, 0x46, 0x3e, 0x58, 0x42, 0xc4, 0x8c, 0xe0,
> +  0x6e, 0xe9, 0x37, 0xd5, 0x2f, 0x74, 0x36, 0x1d, 0x14, 0xcb, 0x10, 0x0e,
> +  0x7d, 0x67, 0xbd, 0x38, 0x0e, 0xa4, 0x27, 0x1d, 0x3c, 0x78, 0x4d, 0x0d,
> +  0x15, 0x42, 0x70, 0x20, 0xe0, 0x1d, 0x83, 0x6c, 0x4d, 0xf1, 0x02, 0xa1,
> +  0x51, 0xc4, 0xc5, 0x5d, 0x69, 0x90, 0x58, 0x82, 0x94, 0x50, 0x36, 0x22,
> +  0xb3, 0xa4, 0x15, 0x77, 0xdc, 0x44, 0xb0, 0x50, 0xa2, 0x3f, 0xd0, 0x0e,
> +  0x1b, 0xfc, 0xf4, 0x5b, 0x3b, 0x7d, 0x63, 0x94, 0x22, 0xf3, 0x87, 0x0a,
> +  0x41, 0x8a, 0x27, 0x48, 0xcb, 0x6c, 0xfd, 0x70, 0x66, 0x5f, 0x11, 0x6f,
> +  0x74, 0x2c, 0x42, 0xaf, 0x74, 0x45, 0x3f, 0x0c, 0x03, 0xc8, 0x80, 0xe2,
> +  0x71, 0x08, 0x93, 0xbd, 0x4d, 0x18, 0x78, 0x1e, 0x8e, 0xb9, 0x3a, 0xd6,
> +  0x1a, 0xde, 0xf9, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_signed_sha256_len = 739;
> +
> +unsigned char short_msg[] = {
> +  0x68, 0x69, 0x0a
> +};
> +unsigned int short_msg_len = 3;
> +
> +unsigned char unsigned_msg[] = {
> +  0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70,
> +  0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65,
> +  0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20,
> +  0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20,
> +  0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
> +  0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69,
> +  0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75,
> +  0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d,
> +  0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20,
> +  0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71,
> +  0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65,
> +  0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76,
> +  0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74,
> +  0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73,
> +  0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f,
> +  0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61,
> +  0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74,
> +  0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20,
> +  0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70,
> +  0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
> +  0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75,
> +  0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70,
> +  0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20,
> +  0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67,
> +  0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61,
> +  0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75,
> +  0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f,
> +  0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20,
> +  0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75,
> +  0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69,
> +  0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e,
> +  0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71,
> +  0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c,
> +  0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d,
> +  0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20,
> +  0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d,
> +  0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65,
> +  0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63,
> +  0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64,
> +  0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75,
> +  0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d,
> +  0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20,
> +  0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20,
> +  0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f,
> +  0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20,
> +  0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65,
> +  0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
> +  0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20,
> +  0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65,
> +  0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e,
> +  0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63,
> +  0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c,
> +  0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73,
> +  0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61,
> +  0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69,
> +  0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69,
> +  0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
> +  0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61,
> +  0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75,
> +  0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20,
> +  0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65,
> +  0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69,
> +  0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61,
> +  0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73,
> +  0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c,
> +  0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63,
> +  0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20,
> +  0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75,
> +  0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75,
> +  0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f,
> +  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75,
> +  0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72,
> +  0x3f, 0x0a
> +};
> +unsigned int unsigned_msg_len = 866;
> +
> +unsigned char certificate2_der[] = {
> +  0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01,
> +  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
> +  0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04,
> +  0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20,
> +  0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
> +  0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
> +  0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
> +  0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38,
> +  0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32,
> +  0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a,
> +  0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
> +  0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65,
> +  0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
> +  0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02,
> +  0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
> +  0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
> +  0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e,
> +  0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3,
> +  0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93,
> +  0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca,
> +  0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19,
> +  0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a,
> +  0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14,
> +  0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29,
> +  0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55,
> +  0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37,
> +  0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb,
> +  0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70,
> +  0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34,
> +  0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24,
> +  0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6,
> +  0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f,
> +  0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89,
> +  0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca,
> +  0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc,
> +  0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26,
> +  0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0,
> +  0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a,
> +  0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63,
> +  0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4,
> +  0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb,
> +  0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7,
> +  0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8,
> +  0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04,
> +  0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c,
> +  0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2,
> +  0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24,
> +  0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66,
> +  0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51,
> +  0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b,
> +  0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2,
> +  0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1,
> +  0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c,
> +  0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73,
> +  0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41,
> +  0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98,
> +  0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe,
> +  0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5,
> +  0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24,
> +  0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30,
> +  0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30,
> +  0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02,
> +  0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
> +  0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1,
> +  0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06,
> +  0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94,
> +  0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb,
> +  0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
> +  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
> +  0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf,
> +  0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64,
> +  0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b,
> +  0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12,
> +  0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d,
> +  0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91,
> +  0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d,
> +  0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60,
> +  0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c,
> +  0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4,
> +  0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1,
> +  0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79,
> +  0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd,
> +  0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a,
> +  0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7,
> +  0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60,
> +  0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70,
> +  0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba,
> +  0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70,
> +  0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75,
> +  0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d,
> +  0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda,
> +  0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86,
> +  0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e,
> +  0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11,
> +  0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9,
> +  0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95,
> +  0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f,
> +  0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20,
> +  0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48,
> +  0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac,
> +  0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b,
> +  0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75,
> +  0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71,
> +  0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e,
> +  0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a,
> +  0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6,
> +  0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59,
> +  0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91,
> +  0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88,
> +  0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87,
> +  0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19,
> +  0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48
> +};
> +unsigned int certificate2_der_len = 1366;
> +
> +unsigned char hi_signed_2nd[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82,
> +  0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
> +  0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
> +  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
> +  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
> +  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
> +  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
> +  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
> +  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
> +  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
> +  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
> +  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
> +  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
> +  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
> +  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
> +  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
> +  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
> +  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
> +  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
> +  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
> +  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
> +  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
> +  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
> +  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
> +  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
> +  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
> +  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
> +  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
> +  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
> +  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
> +  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
> +  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
> +  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
> +  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
> +  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
> +  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
> +  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
> +  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
> +  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
> +  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
> +  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
> +  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
> +  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
> +  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
> +  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
> +  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
> +  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
> +  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
> +  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
> +  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
> +  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
> +  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
> +  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
> +  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5,
> +  0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e,
> +  0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64,
> +  0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_signed_2nd_len = 736;
> +
> +unsigned char hi_double[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 0x82,
> +  0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x04,
> +  0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
> +  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
> +  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
> +  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
> +  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
> +  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
> +  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
> +  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
> +  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
> +  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
> +  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
> +  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
> +  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
> +  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
> +  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
> +  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
> +  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
> +  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
> +  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
> +  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
> +  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
> +  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
> +  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
> +  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
> +  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
> +  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
> +  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
> +  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
> +  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
> +  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
> +  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
> +  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
> +  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
> +  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
> +  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
> +  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
> +  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
> +  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
> +  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
> +  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
> +  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
> +  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
> +  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
> +  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
> +  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
> +  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
> +  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
> +  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
> +  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
> +  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
> +  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
> +  0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 0x31,
> +  0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 0x72,
> +  0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
> +  0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x65,
> +  0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
> +  0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
> +  0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a,
> +  0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 0x0b,
> +  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
> +  0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 0x97,
> +  0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 0xdf,
> +  0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 0x77,
> +  0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 0x55,
> +  0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 0xc2,
> +  0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 0x88,
> +  0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 0xd1,
> +  0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 0xe3,
> +  0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 0x45,
> +  0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 0x86,
> +  0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 0xcd,
> +  0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 0x27,
> +  0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 0xf1,
> +  0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 0x1a,
> +  0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 0x8d,
> +  0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 0xc5,
> +  0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 0xa1,
> +  0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 0x04,
> +  0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 0x9a,
> +  0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 0x1c,
> +  0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 0xd6,
> +  0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 0xe9,
> +  0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 0x60,
> +  0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 0x83,
> +  0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 0xd7,
> +  0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 0x35,
> +  0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 0x0f,
> +  0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 0xa0,
> +  0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 0xaa,
> +  0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 0xe2,
> +  0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 0xc3,
> +  0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 0x24,
> +  0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 0xe6,
> +  0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 0x5e,
> +  0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 0x74,
> +  0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 0x3b,
> +  0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 0x8a,
> +  0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 0xdc,
> +  0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 0x83,
> +  0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 0x21,
> +  0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 0x51,
> +  0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 0x19,
> +  0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 0x35,
> +  0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x05, 0x33, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69,
> +  0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65,
> +  0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_double_len = 1374;
> +
> +unsigned char hi_double_extended[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 0x82,
> +  0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x04,
> +  0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
> +  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
> +  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
> +  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
> +  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
> +  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
> +  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
> +  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
> +  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
> +  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
> +  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
> +  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
> +  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
> +  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
> +  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
> +  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
> +  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
> +  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
> +  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
> +  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
> +  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
> +  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
> +  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
> +  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
> +  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
> +  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
> +  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
> +  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
> +  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
> +  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
> +  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
> +  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
> +  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
> +  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
> +  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
> +  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
> +  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
> +  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
> +  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
> +  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
> +  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
> +  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
> +  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
> +  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
> +  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
> +  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
> +  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
> +  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
> +  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
> +  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
> +  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
> +  0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 0x31,
> +  0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 0x72,
> +  0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
> +  0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x65,
> +  0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
> +  0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
> +  0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a,
> +  0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 0x0b,
> +  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
> +  0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 0x97,
> +  0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 0xdf,
> +  0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 0x77,
> +  0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 0x55,
> +  0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 0xc2,
> +  0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 0x88,
> +  0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 0xd1,
> +  0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 0xe3,
> +  0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 0x45,
> +  0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 0x86,
> +  0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 0xcd,
> +  0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 0x27,
> +  0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 0xf1,
> +  0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 0x1a,
> +  0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 0x8d,
> +  0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 0xc5,
> +  0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 0xa1,
> +  0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 0x04,
> +  0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 0x9a,
> +  0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 0x1c,
> +  0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 0xd6,
> +  0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 0xe9,
> +  0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 0x60,
> +  0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 0x83,
> +  0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 0xd7,
> +  0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 0x35,
> +  0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 0x0f,
> +  0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 0xa0,
> +  0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 0xaa,
> +  0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 0xe2,
> +  0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 0xc3,
> +  0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 0x24,
> +  0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 0xe6,
> +  0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 0x5e,
> +  0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 0x74,
> +  0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 0x3b,
> +  0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 0x8a,
> +  0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 0xdc,
> +  0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 0x83,
> +  0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 0x21,
> +  0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 0x51,
> +  0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 0x19,
> +  0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 0x35,
> +  0x23, 0x2d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x05, 0x34, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_double_extended_len = 1375;
> +
> +unsigned char certificate_printable_der[] = {
> +  0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01,
> +  0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55,
> +  0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
> +  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
> +  0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30,
> +  0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31,
> +  0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35,
> +  0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30,
> +  0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20,
> +  0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42,
> +  0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20,
> +  0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
> +  0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15,
> +  0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2,
> +  0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b,
> +  0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b,
> +  0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11,
> +  0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d,
> +  0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74,
> +  0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d,
> +  0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39,
> +  0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4,
> +  0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b,
> +  0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b,
> +  0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20,
> +  0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf,
> +  0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c,
> +  0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b,
> +  0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e,
> +  0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf,
> +  0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5,
> +  0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f,
> +  0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34,
> +  0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01,
> +  0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
> +  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03,
> +  0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06,
> +  0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca,
> +  0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d,
> +  0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
> +  0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed,
> +  0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3,
> +  0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
> +  0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d,
> +  0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19,
> +  0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6,
> +  0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd,
> +  0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47,
> +  0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03,
> +  0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d,
> +  0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93,
> +  0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9,
> +  0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c,
> +  0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1,
> +  0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d,
> +  0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf,
> +  0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93,
> +  0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1,
> +  0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae,
> +  0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5,
> +  0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25,
> +  0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49,
> +  0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64,
> +  0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67,
> +  0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56,
> +  0xd2
> +};
> +unsigned int certificate_printable_der_len = 829;
> +
> +unsigned char certificate_eku_der[] = {
> +  0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01,
> +  0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
> +  0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
> +  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
> +  0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86,
> +  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63,
> +  0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74,
> +  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32,
> +  0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33,
> +  0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a,
> +  0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
> +  0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63,
> +  0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67,
> +  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20,
> +  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
> +  0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65,
> +  0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
> +  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
> +  0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15,
> +  0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85,
> +  0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06,
> +  0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5,
> +  0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76,
> +  0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd,
> +  0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c,
> +  0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9,
> +  0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78,
> +  0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29,
> +  0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb,
> +  0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09,
> +  0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6,
> +  0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27,
> +  0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7,
> +  0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55,
> +  0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68,
> +  0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90,
> +  0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62,
> +  0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16,
> +  0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b,
> +  0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01,
> +  0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
> +  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03,
> +  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
> +  0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c,
> +  0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
> +  0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c,
> +  0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f,
> +  0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55,
> +  0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab,
> +  0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4,
> +  0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
> +  0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
> +  0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9,
> +  0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef,
> +  0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29,
> +  0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b,
> +  0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf,
> +  0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32,
> +  0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9,
> +  0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74,
> +  0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb,
> +  0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0,
> +  0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24,
> +  0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06,
> +  0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57,
> +  0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61,
> +  0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21,
> +  0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1,
> +  0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81,
> +  0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3,
> +  0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e,
> +  0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd,
> +  0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21,
> +  0x89, 0xa0, 0x55, 0xf7
> +};
> +unsigned int certificate_eku_der_len = 916;
> diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
> index 38e981f2c..23048919d 100644
> --- a/grub-core/tests/lib/functional_test.c
> +++ b/grub-core/tests/lib/functional_test.c
> @@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)),
>     grub_dl_load ("xnu_uuid_test");
>     grub_dl_load ("pbkdf2_test");
>     grub_dl_load ("signature_test");
> +  grub_dl_load ("appended_signature_test");
>     grub_dl_load ("sleep_test");
>     grub_dl_load ("bswap_test");
>     grub_dl_load ("ctz_test");


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 12/21] appended signatures: documentation
  2024-12-18 14:56 ` [PATCH v1 12/21] appended signatures: documentation Sudhakar Kuppusamy
@ 2024-12-30 15:50   ` Stefan Berger
  2025-02-26  4:28     ` sudhakar
  2025-02-14 10:39   ` Avnish Chouhan
  1 sibling, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-30 15:50 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> This explains how appended signatures can be used to form part of
> a secure boot chain, and documents the commands and variables
> introduced.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   docs/grub.texi | 185 ++++++++++++++++++++++++++++++++++++++++++++-----
>   1 file changed, 167 insertions(+), 18 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 6e483298d..f71ce9ffc 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -3274,6 +3274,7 @@ These variables have special meaning to GRUB.
>   
>   @menu
>   * biosnum::
> +* check_appended_signatures::
>   * check_signatures::
>   * chosen::
>   * cmdpath::
> @@ -3336,12 +3337,16 @@ this.
>   For an alternative approach which also changes BIOS drive mappings for the
>   chain-loaded system, @pxref{drivemap}.
>   
> +@node check_appended_signatures
> +@subsection check_appended_signatures
> +This variable controls whether GRUB enforces appended signature validation on
> +certain loaded files. @xref{Using appended signatures}.
>   
>   @node check_signatures
>   @subsection check_signatures
>   
> -This variable controls whether GRUB enforces digital signature
> -validation on loaded files. @xref{Using digital signatures}.
> +This variable controls whether GRUB enforces GPG-style digital signature
> +validation on loaded files. @xref{Using GPG-style digital signatures}.

I am not sure whether everybody knows what GPG-style digitiabl 
signatures are. Maybe mention here once that those are in a separate file.

>   
>   @node chosen
>   @subsection chosen
> @@ -6377,6 +6382,7 @@ 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
>   * drivemap::                    Map a drive to another
>   * echo::                        Display a line of text
>   * efitextmode::                 Set/Get text output mode resolution
> @@ -6395,6 +6401,7 @@ you forget a command, you can run the command @command{help}
>   * hexdump::                     Show raw contents of a file or memory
>   * insmod::                      Insert a module
>   * keystatus::                   Check key modifier status
> +* 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
> @@ -6435,8 +6442,10 @@ you forget a command, you can run the command @command{help}
>   * tpm2_key_protector_clear::    Clear the TPM2 key protector
>   * 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
>   * unset::                       Unset an environment variable
>   @comment * vbeinfo::                     List available video modes
> +* verify_appended::             Verify appended digital signature
>   * verify_detached::             Verify detached digital signature
>   * videoinfo::                   List available video modes
>   * wrmsr::                       Write values to model-specific registers
> @@ -6778,7 +6787,24 @@ These keys are used to validate signatures when environment variable
>   @code{check_signatures} is set to @code{enforce}
>   (@pxref{check_signatures}), and by some invocations of
>   @command{verify_detached} (@pxref{verify_detached}).  @xref{Using
> -digital signatures}, for more information.
> +GPG-style digital signatures}, for more information.
> +@end deffn
> +
> +@node distrust_certificate
> +@subsection distrust_certificate
> +
> +@deffn Command distrust_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}).
> +
> +These certificates are used to validate appended signatures when environment
> +variable @code{check_appended_signatures} is set to @code{enforce}
> +(@pxref{check_appended_signatures}), and by @command{verify_appended}
> +(@pxref{verify_appended}). See @xref{Using appended signatures} for more
> +information.
>   @end deffn
>   
>   @node drivemap
> @@ -7169,6 +7195,19 @@ without any options, the @command{keystatus} command returns true if and
>   only if checking key modifier status is supported.
>   @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
> @@ -7189,7 +7228,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of
>   @code{gpg --fingerprint}).  The least significant four bytes (last
>   eight hexadecimal digits) can be used as an argument to
>   @command{distrust} (@pxref{distrust}).
> -@xref{Using digital signatures}, for more information about uses for
> +@xref{Using GPG-style digital signatures}, for more information about uses for
>   these keys.
>   @end deffn
>   
> @@ -7224,8 +7263,11 @@ When used with care, @option{--skip-sig} and the whitelist enable an
>   administrator to configure a system to boot only signed
>   configurations, but to allow the user to select from among multiple
>   configurations, and to enable ``one-shot'' boot attempts and
> -``savedefault'' behavior.  @xref{Using digital signatures}, for more
> +``savedefault'' behavior.  @xref{Using GPG-style digital signatures}, for more
>   information.
> +Extra care should be taken when combining this command with appended signatures
> +(@pxref{Using appended signatures}), as this file is not validated by an
> +appended signature and could set @code{check_appended_signatures=no}.
>   @end deffn
>   
>   
> @@ -7596,7 +7638,7 @@ read.  It is possible to modify a digitally signed environment block
>   file from within GRUB using this command, such that its signature will
>   no longer be valid on subsequent boots.  Care should be taken in such
>   advanced configurations to avoid rendering the system
> -unbootable. @xref{Using digital signatures}, for more information.
> +unbootable. @xref{Using GPG-style digital signatures}, for more information.
>   @end deffn
>   
>   
> @@ -8064,11 +8106,30 @@ signatures when environment variable @code{check_signatures} is set to
>   must itself be properly signed.  The @option{--skip-sig} option can be
>   used to disable signature-checking when reading @var{pubkey_file}
>   itself. It is expected that @option{--skip-sig} is useful for testing
> -and manual booting. @xref{Using digital signatures}, for more
> +and manual booting. @xref{Using GPG-style digital signatures}, for more
>   information.
>   @end deffn
>   
>   
> +@node trust_certificate
> +@subsection trust_certificate
> +
> +@deffn Command trust_certificate x509_certificate
> +Read a 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
> +variable @code{check_appended_signatures} is set to @code{enforce}.
> +
> +Note that if @code{check_appended_signatures} is set to @code{enforce}
> +when @command{trust_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 signatures within x509

s/grub/GRUB

> +certificates themselves.)
> +
> +See @xref{Using appended signatures} for more information.
> +@end deffn
> +
>   @node unset
>   @subsection unset
>   
> @@ -8087,6 +8148,18 @@ only on PC BIOS platforms.
>   @end deffn
>   @end ignore
>   
> +@node verify_appended
> +@subsection verify_appended
> +
> +@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}).
> +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.
> +@end deffn
>   
>   @node verify_detached
>   @subsection verify_detached
> @@ -8105,7 +8178,7 @@ tried.
>   
>   Exit code @code{$?} is set to 0 if the signature validates
>   successfully.  If validation fails, it is set to a non-zero value.
> -@xref{Using digital signatures}, for more information.
> +@xref{Using GPG-style digital signatures}, for more information.
>   @end deffn
>   
>   @node videoinfo
> @@ -8565,14 +8638,15 @@ environment variables and commands are listed in the same order.
>   @chapter Security
>   
>   @menu
> -* Authentication and authorisation:: Users and access control
> -* Using digital signatures::         Booting digitally signed code
> -* UEFI secure boot and shim::        Booting digitally signed PE files
> -* Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
> -* Measured Boot::                    Measuring boot components
> -* Lockdown::                         Lockdown when booting on a secure setup
> -* TPM2 key protector::               Managing disk key with TPM2 key protector
> -* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
> +* Authentication and authorisation::   Users and access control
> +* Using GPG-style digital signatures:: Booting digitally signed code
> +* Using appended signatures::          An alternative approach to booting digitally signed code
> +* UEFI secure boot and shim::          Booting digitally signed PE files
> +* Secure Boot Advanced Targeting::     Embedded information for generation number based revocation
> +* Measured Boot::                      Measuring boot components
> +* Lockdown::                           Lockdown when booting on a secure setup
> +* TPM2 key protector::                 Managing disk key with TPM2 key protector
> +* Signing GRUB itself::                Ensuring the integrity of the GRUB core image
>   @end menu
>   
>   @node Authentication and authorisation
> @@ -8648,8 +8722,8 @@ generating configuration files with authentication.  You can use
>   adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
>   commands.
>   
> -@node Using digital signatures
> -@section Using digital signatures in GRUB
> +@node Using GPG-style digital signatures
> +@section Using GPG-style digital signatures in GRUB
>   
>   GRUB's @file{core.img} can optionally provide enforcement that all files
>   subsequently read from disk are covered by a valid digital signature.
> @@ -8732,6 +8806,81 @@ or BIOS) configuration to cause the machine to boot from a different
>   (attacker-controlled) device.  GRUB is at best only one link in a
>   secure boot chain.
>   
> +@node Using appended signatures
> +@section Using appended signatures in GRUB
> +
> +GRUB supports verifying Linux-style 'appended signatures' for secure boot.
> +Appended signatures are PKCS#7 messages containing a signature over the
> +contents of a file, plus some metadata, appended to the end of a file. A file
> +with an appended signature ends with the magic string:
> +
> +@example
> +~Module signature appended~\n
> +@end example
> +
> +where @code{\n} represents the carriage-return character, @code{0x0a}.

\n is the newline parameter, \r is carriage-return

> +
> +To enable appended signature verification, load the appendedsig module and an
> +x509 certificate for verification. Building the appendedsig module into the
> +core grub image is recommended.
> +
> +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}.
> +A file can be explictly verified using the @pxref{verify_appended} command.

explicitly

> +
> +Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported,
> +and only RSA signatures are supported.
> +
> +A file can be signed with the @command{sign-file} utility supplied with the
> +Linux kernel source. For example, if you have @code{signing.key} as the private
> +key and @code{certificate.der} as the x509 certificate containing the public key:
> +
> +@example
> +sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
> +@end example
> +
> +Enforcement of signature verification is controlled by the
> +@code{check_appended_signatures} variable. Verification will only take place
> +when files are loaded if the variable is set to @code{enforce}. If a
> +certificate is built into the grub core image with the @code{--x509} parameter,
> +the variable will be automatically set to @code{enforce} when the appendedsig
> +module is loaded.
> +
> +Unlike GPG-style signatures, not all files loaded by GRUB are required to be
> +signed. Once verification is turned on, the following file types must carry
> +appended signatures:
> +
> +@enumerate
> +@item Linux, Multiboot, BSD, XNU and Plan9 kernels
> +@item Grub modules, except those built in to the core image
> +@item Any new certificate files to be trusted
> +@end enumerate
> +
> +ACPI tables and Device Tree images will not be checked for appended signatures
> +but must be verified by another mechanism such as GPG-style signatures before
> +they will be loaded.
> +
> +No attempt is made to validate any other file type. In particular,
> +chain-loaded binaries are not verified - if your platform supports
> +chain-loading and this cannot be disabled, consider an alternative secure
> +boot mechanism.
> +
> +As with GPG-style appended signatures, signature checking does @strong{not}
> +stop an attacker with console access from dropping manually to the GRUB
> +console and executing:
> +
> +@example
> +set check_appended_signatures=no
> +@end example
> +
> +Refer to the section on password-protecting GRUB (@pxref{Authentication
> +and authorisation}) for more information on preventing this.
> +
> +Additionally, special care must be taken around the @command{loadenv} command,
> +which can be used to turn off @code{check_appended_signature}.
> +
>   @node UEFI secure boot and shim
>   @section UEFI secure boot and shim support
>   

With nits fixed:

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot
  2024-12-18 14:56 ` [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot Sudhakar Kuppusamy
@ 2024-12-30 22:02   ` Stefan Berger
  2025-02-06  6:23   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Stefan Berger @ 2024-12-30 22:02 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> If the 'ibm,secure-boot' property of the root node is 2 or greater,
> enter lockdown.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>


Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

> ---
>   docs/grub.texi                 |  4 ++--
>   grub-core/Makefile.core.def    |  1 +
>   grub-core/kern/ieee1275/init.c | 28 ++++++++++++++++++++++++++++
>   include/grub/lockdown.h        |  3 ++-
>   4 files changed, 33 insertions(+), 3 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index f71ce9ffc..6b634f111 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -8959,8 +8959,8 @@ platforms.
>   @section Lockdown when booting on a secure setup
>   
>   The GRUB can be locked down when booted on a secure boot environment, for example
> -if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will
> -be restricted and some operations/commands cannot be executed.
> +if UEFI or Power secure boot is enabled. On a locked down configuration, the
> +GRUB will be restricted and some operations/commands cannot be executed.
>   
>   The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
>   Otherwise it does not exit.
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 9cf4a6009..1ed55b0e3 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -331,6 +331,7 @@ kernel = {
>     powerpc_ieee1275 = kern/powerpc/cache.S;
>     powerpc_ieee1275 = kern/powerpc/dl.c;
>     powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
> +  powerpc_ieee1275 = kern/lockdown.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 dfbd0b899..59984b605 100644
> --- a/grub-core/kern/ieee1275/init.c
> +++ b/grub-core/kern/ieee1275/init.c
> @@ -49,6 +49,7 @@
>   #if defined(__powerpc__) || defined(__i386__)
>   #include <grub/ieee1275/alloc.h>
>   #endif
> +#include <grub/lockdown.h>
>   
>   /* The maximum heap size we're going to claim at boot. Not used by sparc. */
>   #ifdef __i386__
> @@ -953,6 +954,31 @@ grub_parse_cmdline (void)
>       }
>   }
>   
> +static void
> +grub_get_ieee1275_secure_boot (void)
> +{
> +  grub_ieee1275_phandle_t root;
> +  int rc;
> +  grub_uint32_t is_sb;
> +
> +  grub_ieee1275_finddevice ("/", &root);
> +
> +  rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb,
> +                                           sizeof (is_sb), 0);
> +
> +  /*
> +   * ibm,secure-boot:
> +   * 0 - disabled
> +   * 1 - audit
> +   * 2 - enforce
> +   * 3 - enforce + OS-specific behaviour
> +   *
> +   * We only support enforce.
> +   */
> +  if (rc >= 0 && is_sb >= 2)
> +    grub_lockdown ();
> +}
> +
>   grub_addr_t grub_modbase;
>   
>   void
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> @@ -978,6 +1004,8 @@ grub_machine_init (void)
>   #else
>     grub_install_get_time_ms (grub_rtc_get_time_ms);
>   #endif
> +
> +  grub_get_ieee1275_secure_boot ();
>   }
>   
>   void
> diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
> index 40531fa82..ebfee4bf0 100644
> --- a/include/grub/lockdown.h
> +++ b/include/grub/lockdown.h
> @@ -24,7 +24,8 @@
>   #define GRUB_LOCKDOWN_DISABLED       0
>   #define GRUB_LOCKDOWN_ENABLED        1
>   
> -#ifdef GRUB_MACHINE_EFI
> +#if defined(GRUB_MACHINE_EFI) || \
> +    (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
>   extern void
>   EXPORT_FUNC (grub_lockdown) (void);
>   extern int


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support
  2024-12-18 14:56 ` [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support Sudhakar Kuppusamy
@ 2024-12-30 22:14   ` Stefan Berger
  2025-02-26  4:33     ` sudhakar
  2025-02-06  9:09   ` Avnish Chouhan
  1 sibling, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-30 22:14 UTC (permalink / raw)
  To: The development of GNU GRUB, Sudhakar Kuppusamy
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> 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>
> ---
>   grub-core/kern/ieee1275/ieee1275.c | 117 +++++++++++++++++++++++++++++

Since this is pSeries-specific stuff I wonder whether this should not 
rather go into include/grub/powerpc/ieee1275/ieee1275.h and 
grub-core/kern/powerpc/ieee1275/ieee1275.c ?

>   include/grub/ieee1275/ieee1275.h   |  14 ++++
>   2 files changed, 131 insertions(+)
> 
> diff --git a/grub-core/kern/ieee1275/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c
> index 36ca2dbfc..8d0048844 100644
> --- a/grub-core/kern/ieee1275/ieee1275.c
> +++ b/grub-core/kern/ieee1275/ieee1275.c
> @@ -807,3 +807,120 @@ grub_ieee1275_get_block_size (grub_ieee1275_ihandle_t ihandle)
>   
>     return args.size;
>   }
> +
> +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/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
> index c445d0499..edd8cd0eb 100644
> --- a/include/grub/ieee1275/ieee1275.h
> +++ b/include/grub/ieee1275/ieee1275.h
> @@ -230,6 +230,20 @@ char *EXPORT_FUNC(grub_ieee1275_encode_uint4) (grub_ieee1275_ihandle_t ihandle,
>                                                grub_size_t *size);
>   int EXPORT_FUNC(grub_ieee1275_get_block_size) (grub_ieee1275_ihandle_t ihandle);
>   
> +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);
> +
>   grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size);
>   
>   int


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables
  2024-12-18 14:56 ` [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables Sudhakar Kuppusamy
@ 2024-12-30 23:01   ` Stefan Berger
  2025-02-26  4:43     ` sudhakar
  2024-12-30 23:04   ` Stefan Berger
  2025-02-07  5:57   ` Avnish Chouhan
  2 siblings, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-30 23:01 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> 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>
> ---
>   grub-core/Makefile.am                       |   1 +
>   grub-core/Makefile.core.def                 |   1 +
>   grub-core/kern/ieee1275/init.c              |  14 +-
>   grub-core/kern/ieee1275/platform_keystore.c | 337 ++++++++++++++++++++
>   include/grub/platform_keystore.h            | 233 ++++++++++++++
>   5 files changed, 584 insertions(+), 2 deletions(-)
>   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 e50db8106..afb25dc4f 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 1ed55b0e3..2fd060123 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;

This now becomes a file shared with other ieee1275 platforms, such as 
sparc64, as well. Also here maybe it should be

  powerpc_ieee1275 = kern/ieee1275/platform_keystore.c

or

  powerpc_ieee1275 = kern/powerpc/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 59984b605..7d96c38f3 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__
> @@ -959,7 +960,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);
>   
> @@ -976,7 +977,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..1c564d5da
> --- /dev/null
> +++ b/grub-core/kern/ieee1275/platform_keystore.c
> @@ -0,0 +1,337 @@
> +/*
> + *  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/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 ((grub_err_t) -7)
> +
> +/* Platform Keystore */
> +static grub_size_t pks_max_object_size;
> +grub_uint8_t grub_use_platform_keystore = 0;
> +grub_pks_t grub_platform_keystore = { .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));

grub_realloc knows how to handle the case when first parameter is NULL.

> +
> +      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;
> +}
> +
> +/*
> + * reads the secure boot version from PKS as an object.
> + * caller must free result
> + */
> +static grub_err_t
> +grub_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
> +grub_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
> +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");

Firmware doesn't have ...  ?

> +  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_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 = grub_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 = grub_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) */
> +static grub_err_t
> +grub_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 = grub_read_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))

same as (*data >= 2) ?

> +    {
> +      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));

s/0x00/0

> +}
> +
> +/* 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_get_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));

s/0x00/0

> +      /* DB */
> +      rc = grub_read_secure_boot_variables (0, DB, &grub_platform_keystore.db,
> +                                            &grub_platform_keystore.db_entries);
> +      if (rc == GRUB_ERR_NONE)
> +        {
> +          /* DBX */
> +          rc = grub_read_secure_boot_variables (0, DBX, &grub_platform_keystore.dbx,
> +                                                &grub_platform_keystore.dbx_entries);
> +          if (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..7a7378926
> --- /dev/null
> +++ b/include/grub/platform_keystore.h
> @@ -0,0 +1,233 @@
> +/*
> + * 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_UUID_SIZE 16

grub/types.h ?

> +#define GRUB_MAX_HASH_SIZE 64
> +
> +typedef struct grub_uuid grub_uuid_t;

grub/types.h ?

> +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];
> +};

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_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_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 = {NULL, NULL, 0, 0};
> +void grub_release_platform_keystore (void);
> +
> +#endif
> +
> +#endif


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables
  2024-12-18 14:56 ` [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables Sudhakar Kuppusamy
  2024-12-30 23:01   ` Stefan Berger
@ 2024-12-30 23:04   ` Stefan Berger
  2025-02-26  4:44     ` sudhakar
  2025-02-07  5:57   ` Avnish Chouhan
  2 siblings, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-30 23:04 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> 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

What is 'it'. The certificates would be saved ... ?

> the appendedsig (module) would read it later to extract
> the certificate's details.

certifcates' ?

> 
> In the following scenarios, static key mode will be activated:
>   1. When secure boot is enabled with static

static keys ?

>   2. When SB Version is unavailable but Secure Boot is enabled
>   3. When PKS support is unavailable but secure boot is enabled

Secure Boot

> 
> Note:-
> 
> SB Version - secure boot mode

Secure Boot

> 1 - PKS
> 0 - static key (embeded key)

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists
  2024-12-18 14:56 ` [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists Sudhakar Kuppusamy
@ 2024-12-31 17:21   ` Stefan Berger
  2025-02-27 15:21     ` sudhakar
  2025-02-07  6:39   ` Avnish Chouhan
  1 sibling, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-31 17:21 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> 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 integerity of the kernel, the extracted data

integrity

> would be stored in the buffer db and dbx.

needs to be stored?

> 
> 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,

integrity

> the extracted data would be stored in the buffer db.

needs to be stored?

> 
> Note:-
> 
> if the trusted certificate nor binary hash exists in the distrusted list (DBX),

If neither the ... nor ...

> rejected it while extracting it from the platform keystore buffer.

what is 'it' in this context

> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   grub-core/commands/appendedsig/appendedsig.c | 636 +++++++++++++++++--
>   1 file changed, 592 insertions(+), 44 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
> index 5c82b96a4..31649e800 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -34,7 +34,7 @@
>   #include <libtasn1.h>
>   #include <grub/env.h>
>   #include <grub/lockdown.h>
> -
> +#include <grub/platform_keystore.h>
>   #include "appendedsig.h"
>   
>   GRUB_MOD_LICENSE ("GPLv3+");
> @@ -64,9 +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 grub_db = {.keys = NULL, .key_entries = 0, .signatures = NULL,
> +                                .signature_size = NULL, .signature_entries = 0};
>   
> +/* Distrusted list */
> +struct grub_database grub_dbx = {.signatures = NULL, .signature_size = NULL,
> +                                 .signature_entries = 0};
>   /*
>    * Force gcry_rsa to be a module dependency.
>    *
> @@ -87,6 +101,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;
> +
> +/* releasing trusted list memory */

Typically these functions start with 'free'. Free trusted list memory.

> +static void grub_release_trusted_list (void);
> +/* releasing distrusted list memory */
> +static void grub_release_distrusted_list (void);

I am not sure whether local functions and variables should be prefixed 
with grub_ since typically those prefixed wit grub_ are global 
functions. This comment applies to all functions in this patch and series.

>   
>   static enum
>   {
> @@ -95,6 +116,248 @@ 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
> +grub_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_ERR_UNKNOWN_COMMAND;

return grub_error (GRUB_ERR_OUT_OF_RANGE, "Unsupported GUID for hash")

> +
> +  grub_memset (hash, 0x00, GRUB_MAX_HASH_SIZE);
> +  grub_crypto_hash (hash_func, hash, data, data_size);
> +  *hash_size =  hash_func->mdlen;

grub_memset(hash, 0, *hash_size);

> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/* adding the certificate/binary hash into the trusted/distrusted list */

Add the ...

> +static grub_err_t
> +grub_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");
> +
> +  if (signatures == NULL && signature_size == NULL)
> +    {
> +      signatures = grub_zalloc (sizeof (grub_uint8_t *));
> +      signature_size = grub_zalloc (sizeof (grub_size_t));
> +    }
> +  else
> +    {
> +      signatures = grub_realloc (signatures, sizeof (grub_uint8_t *) * (signature_entries + 1));
> +      signature_size = grub_realloc (signature_size,
> +                                     sizeof (grub_size_t) * (signature_entries + 1));
> +    }

Also in this case grub_realloc can be used for first parameter being 
NULL but may need a 2nd variable to handle allocation failures.

> +
> +  if (signatures == NULL || signature_size == NULL)
> +    {
> +      /*
> +       * allocated memory will be freed by
> +       * grub_release_trusted_list/grub_release_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 grub_err_t
> +grub_is_x509 (const grub_uuid_t *guid)

Return int like many other *_is_xyz functions do ?

> +{
> +  if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_UUID_SIZE) == 0)
> +    return GRUB_ERR_NONE;
> +
> +  return GRUB_ERR_UNKNOWN_COMMAND;
> +}
> +
> +static grub_err_t
> +grub_is_cert_match (const struct x509_certificate *distrusted_cert,
> +                    const struct x509_certificate *db_cert)

Return int ?

> +{
> +
> +  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

Verify -- capitalize everywhere.

> + * distrusted list, if it is present, return a bad signature.

You won't construct a bad signture but you return GRUB_ERR_BAD_SIGNATURE.

> + * else, no errors.

Otherwise no error is returned. -- or omit entirely. Also in other cases.

It looks like it can return GRUB_ERR_OUT_OF_MEMORY as well.


> + */
> +static grub_err_t
> +grub_is_distrusted_cert (const struct x509_certificate *db_cert)

So this one here can have allocation failures and should return 
grub_err_t but calls the other two without propagating their errors.

> +{
> +  grub_err_t rc = GRUB_ERR_NONE;
> +  grub_size_t i = 0;
> +  struct x509_certificate *distrusted_cert = NULL;
> +
> +  for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data == NULL &&


should be a '||' or simply remove data_size == 0 check?

> +          grub_platform_keystore.dbx[i].data_size == 0)
> +        continue;
> +
> +      if (grub_is_x509 (&grub_platform_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_platform_keystore.dbx[i].data,
> +                                       grub_platform_keystore.dbx[i].data_size, distrusted_cert);
> +          if (rc != GRUB_ERR_NONE)
> +            {
> +              grub_free (distrusted_cert);
> +              continue;
> +            }
> +
> +          if (grub_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_platform_keystore.dbx[i].data);
> +              grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof (grub_pks_sd_t));

s/0x00/0

> +              certificate_release (distrusted_cert);
> +              grub_free (distrusted_cert);
> +              return GRUB_ERR_BAD_SIGNATURE;
> +            }
> +
> +          certificate_release (distrusted_cert);
> +          grub_free (distrusted_cert);
> +        }
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/* adding the certificate into the trusted/distrusted list */

Add the ..

> +static grub_err_t
> +grub_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_printf ("Warning: skipping %s certificate (%d)\n",
> +                   (is_db ? "trusted":"distrused"), rc);
> +      grub_free (cert);
> +      return rc;
> +    }
> +
> +  if (is_db)
> +    {
> +      rc = grub_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":"distrused"), cert->subject);

distrusted

> +
> +  key_entries++;
> +  cert->next = database->keys;
> +  database->keys = cert;
> +  database->key_entries = key_entries;
> +
> +  return rc;
> +}
> +
> +static grub_err_t
> +grub_read_file (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size)

This function sounds so generic that it could be used in other places as 
well. It would we goood to move it to the same file as grub_file_read.

> +{
> +  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 parse the unknown size of the file."));

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;
> +}
> +
>   static const char *
>   grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
>                      const char *val __attribute__ ((unused)))
> @@ -248,7 +511,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 (!grub_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 +542,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 = grub_db.keys; pk; pk = pk->next)
>           {
>             rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
>             if (rc)
> @@ -376,16 +639,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 = grub_db.keys;
> +      grub_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 = grub_db.keys;
> +  cert = grub_db.keys->next;
>     while (cert)
>       {
>         if (i == cert_num)
> @@ -432,8 +695,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 = grub_db.keys;
> +  grub_db.keys = cert;
>   
>     return GRUB_ERR_NONE;
>   }
> @@ -446,7 +709,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 = grub_db.keys; cert; cert = cert->next)
>       {
>         grub_printf (N_("Certificate %d:\n"), cert_num);
>   
> @@ -539,6 +802,280 @@ 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

Verify

> + * distrusted list, if it is present, return a bad signature.

Same comments as above.

> + * else, no errors.


> + */
> +static grub_err_t
> +grub_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_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data == NULL &&

'||' ?

> +          grub_platform_keystore.dbx[i].data_size == 0)
> +        continue;
> +
> +      rc = grub_get_hash (&grub_platform_keystore.dbx[i].guid, data, data_size,
> +                          cert_hash, &cert_hash_size);
> +      if (rc != GRUB_ERR_NONE)
> +        continue;
> +
> +      if (cert_hash_size == grub_platform_keystore.dbx[i].data_size &&
> +          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
> +          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof (grub_pks_sd_t));

s/0x00/0

sizeof(grub_platform_keystore.dbx[i]) -- so we don't need to know the 
type of this array

> +          return GRUB_ERR_BAD_SIGNATURE;
> +        }
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * verify the trusted binary hash against the platform keystore buffer's

Verify.

> + * distrusted list, if it is present, return a bad signature.

Same comments as above.

> + * else, no errors.
> + */
> +static grub_err_t
> +grub_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_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data == NULL &&

'||' ?

> +          grub_platform_keystore.dbx[i].data_size == 0)
> +        continue;
> +
> +      if (binary_hash_size == grub_platform_keystore.dbx[i].data_size &&
> +          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
> +          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof (grub_pks_sd_t));

same comments as above

> +          return GRUB_ERR_BAD_SIGNATURE;
> +        }
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * extracts the binary hashes from the platform keystore buffer,

Extract the ...

> + * and adds it to the trusted list if not exists in distrusted list.

and add it .. if it does not exist in the distrusted list.

> + */
> +static grub_err_t
> +grub_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)

Here you have the '||'...

> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted binary hash data/size is null");
> +
> +  rc = grub_is_distrusted_binary_hash (*data, data_size);
> +  if (rc != GRUB_ERR_NONE)
> +    return rc;
> +
> +  rc = grub_add_hash (data, data_size, &grub_db.signatures, &grub_db.signature_size,
> +                      &grub_db.signature_entries);
> +  return rc;
> +}
> +
> +static grub_err_t
> +grub_is_hash (const grub_uuid_t *guid)

Same comments as with other functions as above.

> +{
> +  /* 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;
> +}
> +
 > +/*> + * extracts the x509 certificates/binary hashes from the 
platform keystore buffer,

Extract the x509...

> + * parses it, and adds it to the trusted list.

parse it, and add it to the trusted list.

> + */
> +static grub_err_t
> +grub_create_trusted_list (void)
> +{
> +  grub_err_t rc = GRUB_ERR_NONE;
> +  grub_size_t i = 0;
> +
> +  for (i = 0; i < grub_platform_keystore.db_entries; i++)
> +    {
> +      if (grub_is_hash (&grub_platform_keystore.db[i].guid) == GRUB_ERR_NONE)
> +        {
> +          rc = grub_add_trusted_binary_hash ((const grub_uint8_t **)
> +                                             &grub_platform_keystore.db[i].data,
> +                                             grub_platform_keystore.db[i].data_size);
> +          if (rc == GRUB_ERR_OUT_OF_MEMORY)
> +            return rc;
> +
> +          continue;

'continue' not needed

> +        }
> +      else if (grub_is_x509 (&grub_platform_keystore.db[i].guid) == GRUB_ERR_NONE)
> +        {
> +

stray empty line

> +          rc = grub_is_distrusted_cert_hash (grub_platform_keystore.db[i].data,
> +                                             grub_platform_keystore.db[i].data_size);
 > +          if (rc != GRUB_ERR_NONE)> +            continue;
> +
> +          rc = grub_add_certificate (grub_platform_keystore.db[i].data,
> +                                     grub_platform_keystore.db[i].data_size, &grub_db, 1);
> +          if (rc == GRUB_ERR_OUT_OF_MEMORY)
> +            return rc;
> +          else if (rc != GRUB_ERR_NONE)
> +            continue;
> +        }
> +      else
> +        grub_printf ("Warning: unsupported signature data type and "
> +                     "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * extracts the certificates, certificate/binary hashes out of the platform keystore buffer,
> + * and adds it to the distrusted list.
> + */
> +static grub_err_t
> +grub_create_distrusted_list (void)
> +{
> +  grub_err_t rc = GRUB_ERR_NONE;
> +  grub_size_t i = 0;
> +
> +  for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data != NULL &&

'||'?

> +          grub_platform_keystore.dbx[i].data_size > 0)
> +        {
> +          if (grub_is_x509 (&grub_platform_keystore.dbx[i].guid) == GRUB_ERR_NONE)
> +            {
> +              rc = grub_add_certificate (grub_platform_keystore.dbx[i].data,
> +                                         grub_platform_keystore.dbx[i].data_size, &grub_dbx, 0);
> +              if (rc == GRUB_ERR_OUT_OF_MEMORY)
> +                return rc;
> +            }
> +          else if (grub_is_hash (&grub_platform_keystore.dbx[i].guid) == GRUB_ERR_NONE)
> +            {
> +              rc = grub_add_hash ((const grub_uint8_t **) &grub_platform_keystore.dbx[i].data,
> +                                  grub_platform_keystore.dbx[i].data_size,
> +                                  &grub_dbx.signatures, &grub_dbx.signature_size,
> +                                  &grub_dbx.signature_entries);
> +              if (rc != GRUB_ERR_NONE)
> +                return rc;
> +            }
> +          else
> +            grub_printf ("Warning: unsupported signature data type and "
> +                         "skipping distrusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
> +        }
> +    }
> +
> +  return rc;
> +}
> +
> +/*
> + * extracts the x509 certificates from the ELF note header,
> + * parses it, and adds it to the trusted list.
> + */
> +static grub_err_t
> +grub_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));

ah, '0'

> +  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 = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
> +  if (cert_data != NULL)
> +    grub_free (cert_data);

no need to check for cert_data != NULL
> +
> +  return err;
> +}
> +
> +/* releasing memory */
> +static void
> +grub_release_trusted_list (void)
> +{
> +  struct x509_certificate *cert;
> +  grub_size_t i = 0;
> +
> +  while (grub_db.keys != NULL)
> +    {
> +      cert = grub_db.keys;
> +      grub_db.keys = grub_db.keys->next;
> +      certificate_release (cert);
> +      grub_free (cert);
> +    }
> +
> +  for (i = 0; i < grub_db.signature_entries; i++)
> +    grub_free (grub_db.signatures[i]);
> +
> +  grub_free (grub_db.signatures);
> +  grub_free (grub_db.signature_size);
> +  grub_memset (&grub_db, 0x00, sizeof (grub_db));

s/0x00/0

> +}
> +
> +/* releasing memory */
> +static void
> +grub_release_distrusted_list (void)
> +{
> +  struct x509_certificate *cert;
> +  grub_size_t i = 0;
> +
> +  while (grub_dbx.keys != NULL)
> +    {
> +      cert = grub_dbx.keys;
> +      grub_dbx.keys = grub_dbx.keys->next;
> +      certificate_release (cert);
> +      grub_free (cert);
> +    }
> +
> +  for (i = 0; i < grub_dbx.signature_entries; i++)
> +    grub_free (grub_dbx.signatures[i]);
> +
> +  grub_free (grub_dbx.signatures);
> +  grub_free (grub_dbx.signature_size);
> +  grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));

s/0x00.0

> +}
> +
>   GRUB_MOD_INIT (appendedsig)
>   {
>     int rc;
> @@ -548,7 +1085,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,39 +1092,51 @@ 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;
> -
> -    /* Not an X.509 certificate, skip. */
> -    if (header->type != OBJ_TYPE_X509_PUBKEY)
> -      continue;
> -
> -    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);
> +  if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
> +    {
> +      FOR_MODULES (header)
> +        {
> +          /* Not an ELF module, skip.  */
> +          if (header->type != OBJ_TYPE_X509_PUBKEY)
> +            continue;
>   
> -    grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
> +          rc = grub_build_static_trusted_list (header);
> +          if (rc != GRUB_ERR_NONE)
> +            {
> +              grub_release_trusted_list ();
> +              grub_error (rc, "static trusted list creation failed");
> +            }
> +          else
> +            grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
> +                         grub_db.key_entries);
> +        }
> +    }
> +  else if (grub_use_platform_keystore && check_sigs == check_sigs_forced)
> +    {
> +      rc = grub_create_trusted_list ();
> +      if (rc != GRUB_ERR_NONE)
> +        {
> +          grub_release_trusted_list ();
> +          grub_error (rc, "trusted list creation failed");
> +        }
> +      else
> +        {
> +          rc = grub_create_distrusted_list ();
> +          if (rc != GRUB_ERR_NONE)
> +            {
> +              grub_release_trusted_list ();
> +              grub_release_distrusted_list ();
> +              grub_error (rc, "distrusted list creation failed");
> +            }
> +          else
> +            grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " keys.\n"
> +                         "appendedsig: the distrusted list now has %" PRIuGRUB_SIZE " keys.\n",
> +                         grub_db.signature_entries + grub_db.key_entries,
> +                         grub_dbx.signature_entries);
> +        }
>   
> -    pk->next = grub_trusted_key;
> -    grub_trusted_key = pk;
> -  }
> +      grub_release_platform_keystore ();
> +    }
>   
>     cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
>                                        N_("Add X509_CERTIFICATE to trusted certificates."));


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 17/21] appendedsig: While verifying the kernel, use trusted and distrusted lists
  2024-12-18 14:56 ` [PATCH v1 17/21] appendedsig: While verifying the kernel, use " Sudhakar Kuppusamy
@ 2024-12-31 17:37   ` Stefan Berger
  2025-02-27 15:22     ` sudhakar
  2025-02-07  6:44   ` Avnish Chouhan
  1 sibling, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2024-12-31 17:37 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> To verify the kernel's: verify the kernel binary against list of binary hashes

To verify the kernel's signature?

against lists of binary hashes

> that are distrusted and trusted. If it is not listed in both trusted and distrusted,

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.

> the trusted keys from trusted key list used to verify the signature.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   grub-core/commands/appendedsig/appendedsig.c | 188 +++++++++++++------
>   1 file changed, 133 insertions(+), 55 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
> index 31649e800..8b084087e 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -497,6 +497,81 @@ 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
> +grub_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 grub_get_hash (&guid, data, data_size, hash, hash_size);
> +}
> +
> +/*
> + * verify binary hash against the list of binary hashes that are distrusted
Verify a binary hash
> + * 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
> +grub_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 < grub_dbx.signature_entries; i++)
> +    {
> +      rc = grub_get_binary_hash (grub_dbx.signature_size[i], data, data_size,
> +                                 hash, &hash_size);
> +      if (rc != GRUB_ERR_NONE)
> +        continue;
> +
> +      if (hash_size == grub_dbx.signature_size[i] &&
> +          grub_memcmp (grub_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]);

merge the error string into one

> +          return GRUB_ERR_BAD_SIGNATURE;
> +        }
> +    }
> +
> +  for (i = 0; i < grub_db.signature_entries; i++)
> +    {
> +      rc = grub_get_binary_hash (grub_db.signature_size[i], data, data_size,
> +                                 hash, &hash_size);
> +      if (rc != GRUB_ERR_NONE)
> +        continue;
> +
> +      if (hash_size == grub_db.signature_size[i] &&
> +          grub_memcmp (grub_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)
>   {
> @@ -506,12 +581,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 (!grub_db.key_entries)
> +  if (!grub_db.key_entries && !grub_db.signature_entries)
>       return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
>   
>     err = extract_appended_signature (buf, bufsize, &sig);
> @@ -520,68 +595,71 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
>   
>     datasize = bufsize - sig.signature_len;
>   
> -  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
> +  err = grub_verify_binary_hash (buf, datasize);
> +  if (err == GRUB_ERR_EOF)
>       {
> -      /*
> -       * 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 = grub_db.keys; pk; pk = pk->next)

/* 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)
> +          /*
> +           * 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(grub_db.keys * pkcs7 signers) approach.
> +           */
> +          si = &sig.pkcs7.signerInfos[i];
> +          context = grub_zalloc (si->hash->contextsize);
> +          if (context == NULL)
> +            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 (cert = grub_db.keys; cert; cert = cert->next)
>               {
> -              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> -                                N_("Error padding hash for RSA verification: %d"), rc);
> -              grub_free (context);
> -              goto cleanup;
> +              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;
> +                }
> +
> +              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;
> +                }
> +
> +              grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
> +                            i, cert->subject, rc);
>               }
>   
> -          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
> -          gcry_mpi_release (hashmpi);
> -
> -          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", "verify signer %d with key '%s' failed with %d\n",
> -                        i, pk->subject, rc);
> -        }
> -
> -      grub_free (context);
> -
> -      if (err == GRUB_ERR_NONE)
> -        break;
> +          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"));

You may need a special case to jump to from after the hash list test to 
indicate that the hash was found in the distrusted hashes list.

> +  else
> +    grub_printf ("appendedsig: successfully verified the signature with a trusted key\n");
> +
>     return err;
>   }
>   


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note
  2024-12-18 14:56 ` [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note Sudhakar Kuppusamy
@ 2025-01-02 13:19   ` Stefan Berger
  2025-02-27 15:23     ` sudhakar
  2025-02-07  6:54   ` Avnish Chouhan
  1 sibling, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2025-01-02 13:19 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> if secure boot enabled with PKS and set use_static_keys flag, it

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.

> reads the DB default keys from ELF Note and store it in trusted list buffer.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   grub-core/commands/appendedsig/appendedsig.c | 58 ++++++++++++++------
>   1 file changed, 41 insertions(+), 17 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
> index 8b084087e..9a9f4ef1c 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -1082,7 +1082,7 @@ grub_create_distrusted_list (void)
>    * parses it, and adds it to the trusted list.
>    */
>   static grub_err_t
> -grub_build_static_trusted_list (const struct grub_module_header *header)
> +grub_build_static_trusted_list (const struct grub_module_header *header, const grub_bool_t mode)

A more meaningful variable name than 'mode' would be good. mode = true 
or false doesn't mean much.

>   {
>     grub_err_t err = GRUB_ERR_NONE;
>     struct grub_file pseudo_file;
> @@ -1101,7 +1101,14 @@ grub_build_static_trusted_list (const struct grub_module_header *header)
>     if (err != GRUB_ERR_NONE)
>       return err;
>   
> -  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
> +  if (mode)
> +    {
> +      err = grub_is_distrusted_cert_hash (cert_data, cert_data_size);
> +      if (err != GRUB_ERR_NONE)
> +        return err;
> +    }
> +
> +  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, mode);
>     if (cert_data != NULL)
>       grub_free (cert_data);
>   
> @@ -1154,6 +1161,20 @@ grub_release_distrusted_list (void)
>     grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
>   }
>   
> +static grub_err_t
> +grub_load_static_keys (const struct grub_module_header *header, const grub_bool_t mode)
> +{
> +  int rc = GRUB_ERR_NONE;
> +  FOR_MODULES (header)
> +    {
> +      /* Not an ELF module, skip.  */
> +      if (header->type != OBJ_TYPE_X509_PUBKEY)
> +        continue;
> +      rc = grub_build_static_trusted_list (header, mode);

Do you have to check rc at this point?

> +    }
> +  return rc;
> +}
> +
>   GRUB_MOD_INIT (appendedsig)
>   {
>     int rc;
> @@ -1172,26 +1193,29 @@ GRUB_MOD_INIT (appendedsig)
>   
>     if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
>       {
> -      FOR_MODULES (header)
> +      rc = grub_load_static_keys (header, 0);
> +      if (rc != GRUB_ERR_NONE)
>           {
> -          /* Not an ELF module, skip.  */
> -          if (header->type != OBJ_TYPE_X509_PUBKEY)
> -            continue;
> -
> -          rc = grub_build_static_trusted_list (header);
> -          if (rc != GRUB_ERR_NONE)
> -            {
> -              grub_release_trusted_list ();
> -              grub_error (rc, "static trusted list creation failed");
> -            }
> -          else
> -            grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
> -                         grub_db.key_entries);
> +          grub_release_trusted_list ();
> +          grub_error (rc, "static trusted list creation failed");
>           }
> +      else
> +        grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
> +                     grub_db.key_entries);
> +
>       }
>     else if (grub_use_platform_keystore && check_sigs == check_sigs_forced)
>       {
> -      rc = grub_create_trusted_list ();
> +
> +      if (grub_platform_keystore.use_static_keys == 1)

if (grub_platform_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 = grub_load_static_keys (header, 1);
> +        }
> +      else
> +        rc = grub_create_trusted_list ();
> +
>         if (rc != GRUB_ERR_NONE)
>           {
>             grub_release_trusted_list ();


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 18/21] ieee1275: set use_static_keys flag
  2024-12-18 14:56 ` [PATCH v1 18/21] ieee1275: set use_static_keys flag Sudhakar Kuppusamy
@ 2025-01-02 13:22   ` Stefan Berger
  2025-02-27 15:24     ` sudhakar
  2025-02-07  6:46   ` Avnish Chouhan
  1 sibling, 1 reply; 83+ messages in thread
From: Stefan Berger @ 2025-01-02 13:22 UTC (permalink / raw)
  To: Sudhakar Kuppusamy, grub-devel
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, avnish,
	nayna, ssrish



On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
> if secure boot enabled with PKS, it set the use_static_keys flag

I was not sure at this point what the patch actually does so I 
reformulated it a bit. I would start the patch description with the 
reason why you are introducing the use_static_key:

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... or something like this.


> when DB variable is not present in PKS storage and the appendedsig (module)
> would use it later to extract the default DB key's from ELF Note and
> store it in trustedlist.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>   grub-core/kern/ieee1275/platform_keystore.c | 15 ++++++++++++++-
>   include/grub/platform_keystore.h            | 12 +++++++-----
>   2 files changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/grub-core/kern/ieee1275/platform_keystore.c b/grub-core/kern/ieee1275/platform_keystore.c
> index 1c564d5da..ddc11afd9 100644
> --- a/grub-core/kern/ieee1275/platform_keystore.c
> +++ b/grub-core/kern/ieee1275/platform_keystore.c
> @@ -34,7 +34,11 @@
>   /* Platform Keystore */
>   static grub_size_t pks_max_object_size;
>   grub_uint8_t grub_use_platform_keystore = 0;
> -grub_pks_t grub_platform_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 };
> +grub_pks_t grub_platform_keystore = { .db = NULL,
> +                                      .dbx = NULL,
> +                                      .db_entries = 0,
> +                                      .dbx_entries = 0,
> +                                      .use_static_keys = 0 };

Use false

>   
>   /* converts the esl data into the ESL */
>   static grub_esl_t *
> @@ -316,6 +320,15 @@ grub_platform_keystore_init (void)
>         /* DB */
>         rc = grub_read_secure_boot_variables (0, DB, &grub_platform_keystore.db,
>                                               &grub_platform_keystore.db_entries);
> +      if (rc == PKS_OBJECT_NOT_FOUND)
> +        {
> +          rc = GRUB_ERR_NONE;
> +          /*
> +           * DB variable won't be available by default in PKS.

The DB variable.

> +           * So, it will loads the Default Keys from ELF Note */

s/loads/load
-> If it is not available load the default keys from the ELF node (?)


> +          grub_platform_keystore.use_static_keys = 1;
> +        }
> +
>         if (rc == GRUB_ERR_NONE)
>           {
>             /* DBX */
> diff --git a/include/grub/platform_keystore.h b/include/grub/platform_keystore.h
> index 7a7378926..b333db7fd 100644
> --- a/include/grub/platform_keystore.h
> +++ b/include/grub/platform_keystore.h
> @@ -49,6 +49,7 @@
>   #define GRUB_UUID_SIZE 16
>   #define GRUB_MAX_HASH_SIZE 64
>   
> +typedef grub_uint8_t grub_bool_t;

This would be a candidate for types.h. term/tparam.c already defines it 
as char. bool also already exists and is also used in some places.

>   typedef struct grub_uuid grub_uuid_t;
>   typedef struct grub_esd grub_esd_t;
>   typedef struct grub_esl grub_esl_t;
> @@ -207,10 +208,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__
> @@ -225,7 +227,7 @@ extern grub_pks_t EXPORT_VAR(grub_platform_keystore);
>   #else
>   
>   #define grub_use_platform_keystore	0
> -grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0};
> +grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0, 0};

Use false

>   void grub_release_platform_keystore (void);
>   
>   #endif


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature
  2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
  2024-12-27 14:58   ` Stefan Berger
@ 2025-01-04 18:30   ` Vladimir 'phcoder' Serbinenko
  2025-01-06  6:25   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2025-01-04 18:30 UTC (permalink / raw)
  To: The development of GNU GRUB

Passing signature size to the tools looks very clumsy. How does the
user know the signature size? Can we somehow determine it
programmatically ourselves?

On Wed, Dec 18, 2024 at 5:58 PM Sudhakar Kuppusamy
<sudhakar@linux.ibm.com> wrote:
>
> From: Rashmica Gupta <rashmica.g@gmail.com>
>
> Add infrastructure to allow firmware to verify the integrity of grub
> by use of a Linux-kernel-module-style appended signature. We initially
> target powerpc-ieee1275, but the code should be extensible to other
> platforms.
>
> Usually these signatures are appended to a file without modifying the
> ELF file itself. (This is what the 'sign-file' tool does, for example.)
> The verifier loads the signed file from the file system and looks at the
> end of the file for the appended signature. However, on powerpc-ieee1275
> platforms, the bootloader is often stored directly in the PReP partition
> as raw bytes without a file-system. This makes determining the location
> of an appended signature more difficult.
>
> To address this, we add a new ELF note.
>
> The name field of shall be the string "Appended-Signature", zero-padded
> to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
> for the string "ASig"). It must be the final section in the ELF binary.
>
> The description shall contain the appended signature structure as defined
> by the Linux kernel. The description will also be padded to be a multiple
> of 4 bytes. The padding shall be added before the appended signature
> structure (not at the end) so that the final bytes of a signed ELF file
> are the appended signature magic.
>
> A subsequent patch documents how to create a grub core.img validly signed
> under this scheme.
>
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  include/grub/util/install.h |  7 +++++--
>  include/grub/util/mkimage.h |  4 ++--
>  util/grub-install-common.c  | 15 ++++++++++++---
>  util/grub-mkimage.c         | 11 +++++++++++
>  util/grub-mkimagexx.c       | 38 ++++++++++++++++++++++++++++++++++++-
>  util/mkimage.c              |  6 +++---
>  6 files changed, 70 insertions(+), 11 deletions(-)
>
> diff --git a/include/grub/util/install.h b/include/grub/util/install.h
> index 5c0a52ca2..3aabc4285 100644
> --- a/include/grub/util/install.h
> +++ b/include/grub/util/install.h
> @@ -69,6 +69,8 @@
>        N_("disable shim_lock verifier"), 0 },                           \
>    { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,             \
>      N_("disabled command line interface access"), 0 },                 \
> +  { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
> +    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
>    { "verbose", 'v', 0, 0,                                              \
>      N_("print verbose messages."), 1 }
>
> @@ -132,7 +134,8 @@ enum grub_install_options {
>    GRUB_INSTALL_OPTIONS_DTB,
>    GRUB_INSTALL_OPTIONS_SBAT,
>    GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
> -  GRUB_INSTALL_OPTIONS_DISABLE_CLI
> +  GRUB_INSTALL_OPTIONS_DISABLE_CLI,
> +  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
>  };
>
>  extern char *grub_install_source_directory;
> @@ -192,7 +195,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
>                              size_t npubkeys,
>                              char *config_path,
>                              const struct grub_install_image_target_desc *image_target,
> -                            int note,
> +                            int note, size_t appsig_size,
>                              grub_compression_t comp, const char *dtb_file,
>                              const char *sbat_path, const int disable_shim_lock,
>                              const int disable_cli);
> diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
> index 9d74f82c5..0d40383eb 100644
> --- a/include/grub/util/mkimage.h
> +++ b/include/grub/util/mkimage.h
> @@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
>                            const struct grub_install_image_target_desc *image_target);
>  void
>  grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
> -                            int note, char *sbat, char **core_img, size_t *core_size,
> +                            int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
>                              Elf32_Addr target_addr,
>                              struct grub_mkimage_layout *layout);
>  void
>  grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
> -                            int note, char *sbat, char **core_img, size_t *core_size,
> +                            int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
>                              Elf64_Addr target_addr,
>                              struct grub_mkimage_layout *layout);
>
> diff --git a/util/grub-install-common.c b/util/grub-install-common.c
> index 22bccb6a3..22f0e56cb 100644
> --- a/util/grub-install-common.c
> +++ b/util/grub-install-common.c
> @@ -467,10 +467,12 @@ static char *sbat;
>  static int disable_shim_lock;
>  static grub_compression_t compression;
>  static int disable_cli;
> +static size_t appsig_size;
>
>  int
>  grub_install_parse (int key, char *arg)
>  {
> +  const char *end;
>    switch (key)
>      {
>      case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
> @@ -571,6 +573,12 @@ grub_install_parse (int key, char *arg)
>        grub_util_error (_("Unrecognized compression `%s'"), arg);
>      case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
>        return 1;
> +    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
> +      grub_errno = 0;
> +      appsig_size = grub_strtol (arg, &end, 10);
> +      if (grub_errno)
> +        return 0;
> +      return 1;
>      default:
>        return 0;
>      }
> @@ -683,9 +691,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>    *p = '\0';
>
>    grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
> -                 " --format '%s' --compression '%s'%s%s%s%s\n",
> +                 " --format '%s' --compression '%s'"
> +                 " --appended-signature-size %zu %s %s %s %s\n",
>                   dir, prefix, outname,
> -                 mkimage_target, compnames[compression],
> +                 mkimage_target, compnames[compression], appsig_size,
>                   note ? " --note" : "",
>                   disable_shim_lock ? " --disable-shim-lock" : "",
>                   disable_cli ? " --disable-cli" : "", s);
> @@ -698,7 +707,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
>    grub_install_generate_image (dir, prefix, fp, outname,
>                                modules.entries, memdisk_path,
>                                pubkeys, npubkeys, config_path, tgt,
> -                              note, compression, dtb, sbat,
> +                              note, appsig_size, compression, dtb, sbat,
>                                disable_shim_lock, disable_cli);
>    while (dc--)
>      grub_install_pop_module ();
> diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
> index 547f7310f..6c5063ac2 100644
> --- a/util/grub-mkimage.c
> +++ b/util/grub-mkimage.c
> @@ -84,6 +84,7 @@ static struct argp_option options[] = {
>    {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
>    {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
>    {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
> +  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
>    {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
>    { 0, 0, 0, 0, 0, 0 }
>  };
> @@ -130,6 +131,7 @@ struct arguments
>    int note;
>    int disable_shim_lock;
>    int disable_cli;
> +  size_t appsig_size;
>    const struct grub_install_image_target_desc *image_target;
>    grub_compression_t comp;
>  };
> @@ -140,6 +142,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
>    /* Get the input argument from argp_parse, which we
>       know is a pointer to our arguments structure. */
>    struct arguments *arguments = state->input;
> +  const char* end;
>
>    switch (key)
>      {
> @@ -172,6 +175,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
>        arguments->note = 1;
>        break;
>
> +    case 'S':
> +      grub_errno = 0;
> +      arguments->appsig_size = grub_strtol (arg, &end, 10);
> +      if (grub_errno)
> +        return 0;
> +      break;
> +
>      case 'm':
>        if (arguments->memdisk)
>         free (arguments->memdisk);
> @@ -330,6 +340,7 @@ main (int argc, char *argv[])
>                                arguments.memdisk, arguments.pubkeys,
>                                arguments.npubkeys, arguments.config,
>                                arguments.image_target, arguments.note,
> +                              arguments.appsig_size,
>                                arguments.comp, arguments.dtb,
>                                arguments.sbat, arguments.disable_shim_lock,
>                                arguments.disable_cli);
> diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
> index 448862b2e..6fe348e5b 100644
> --- a/util/grub-mkimagexx.c
> +++ b/util/grub-mkimagexx.c
> @@ -115,6 +115,14 @@ struct grub_sbat_note {
>    char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
>  };
>
> +#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
> +#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
> +struct grub_appended_signature_note
> +{
> +  Elf32_Nhdr header;
> +  char name[ALIGN_UP (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
> +};
> +
>  static int
>  is_relocatable (const struct grub_install_image_target_desc *image_target)
>  {
> @@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
>
>  void
>  SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
> -                                   int note, char *sbat, char **core_img, size_t *core_size,
> +                                   int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
>                                     Elf_Addr target_addr,
>                                     struct grub_mkimage_layout *layout)
>  {
> @@ -237,6 +245,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
>        footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
>      }
>
> +  if (appsig_size)
> +    {
> +      phnum++;
> +      footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
> +    }
> +
>    if (image_target->id != IMAGE_LOONGSON_ELF)
>      phnum += 2;
>
> @@ -527,6 +541,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
>        phdr->p_filesz = grub_host_to_target32 (note_size);
>        phdr->p_memsz = 0;
>        phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
> +      footer += note_size;
> +      footer_offset += note_size;
> +    }
> +
> +  if (appsig_size)
> +    {
> +      int note_size = ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
> +      struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) footer;
> +      note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
> +      /* needs to sit at the end, so we round this up and sign some zero padding */
> +      note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP (appsig_size, 4));
> +      note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
> +      strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
> +      phdr++;
> +      phdr->p_type = grub_host_to_target32 (PT_NOTE);
> +      phdr->p_flags = grub_host_to_target32 (PF_R);
> +      phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
> +      phdr->p_vaddr = 0;
> +      phdr->p_paddr = 0;
> +      phdr->p_filesz = grub_host_to_target32 (note_size);
> +      phdr->p_memsz = 0;
> +      phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
>      }
>
>    {
> diff --git a/util/mkimage.c b/util/mkimage.c
> index b46df2909..f5c59f563 100644
> --- a/util/mkimage.c
> +++ b/util/mkimage.c
> @@ -885,7 +885,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
>                              char *memdisk_path, char **pubkey_paths,
>                              size_t npubkeys, char *config_path,
>                              const struct grub_install_image_target_desc *image_target,
> -                            int note, grub_compression_t comp, const char *dtb_path,
> +                            int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path,
>                              const char *sbat_path, int disable_shim_lock,
>                              int disable_cli)
>  {
> @@ -1833,10 +1833,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
>         else
>           target_addr = image_target->link_addr;
>         if (image_target->voidp_sizeof == 4)
> -         grub_mkimage_generate_elf32 (image_target, note, sbat, &core_img, &core_size,
> +         grub_mkimage_generate_elf32 (image_target, note, sbat, appsig_size, &core_img, &core_size,
>                                        target_addr, &layout);
>         else
> -         grub_mkimage_generate_elf64 (image_target, note, sbat, &core_img, &core_size,
> +         grub_mkimage_generate_elf64 (image_target, note, sbat, appsig_size, &core_img, &core_size,
>                                        target_addr, &layout);
>        }
>        break;
> --
> 2.43.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



-- 
Regards
Vladimir 'phcoder' Serbinenko

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature
  2024-12-18 14:56 ` [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature Sudhakar Kuppusamy
  2024-12-27 15:04   ` Stefan Berger
@ 2025-01-04 18:32   ` Vladimir 'phcoder' Serbinenko
  2025-01-24  9:44   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2025-01-04 18:32 UTC (permalink / raw)
  To: The development of GNU GRUB

May we instead invoke sign-file from grub-mkimage as to spare the user
the hassle?

On Wed, Dec 18, 2024 at 5:58 PM Sudhakar Kuppusamy
<sudhakar@linux.ibm.com> wrote:
>
> From: Daniel Axtens <dja@axtens.net>
>
> Signing grub for firmware that verifies an appended signature is a
> bit fiddly. I don't want people to have to figure it out from scratch
> so document it here.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
>
> diff --git a/docs/grub.texi b/docs/grub.texi
> index c07d5d0dc..6e483298d 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -9135,6 +9135,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It
>  will also be necessary to enrol the public key used into a relevant firmware
>  key database.
>
> +@section Signing GRUB with an appended signature
> +
> +The @file{core.img} itself can be signed with a Linux kernel module-style
> +appended signature.
> +
> +To support IEEE1275 platforms where the boot image is often loaded directly
> +from a disk partition rather than from a file system, the @file{core.img}
> +can specify the size and location of the appended signature with an ELF
> +note added by @command{grub-install}.
> +
> +An image can be signed this way using the @command{sign-file} command from
> +the Linux kernel:
> +
> +@example
> +@group
> +# grub.key is your private key and certificate.der is your public key
> +
> +# Determine the size of the appended signature. It depends on the signing
> +# certificate and the hash algorithm
> +touch empty
> +sign-file SHA256 grub.key certificate.der empty empty.sig
> +SIG_SIZE=`stat -c '%s' empty.sig`
> +rm empty empty.sig
> +
> +# Build a grub image with $SIG_SIZE reserved for the signature
> +grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
> +
> +# Replace the reserved size with a signature:
> +# cut off the last $SIG_SIZE bytes with truncate's minus modifier
> +truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
> +# sign the trimmed file with an appended signature, restoring the correct size
> +sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
> +
> +# Don't forget to install the signed image as required
> +# (e.g. on powerpc-ieee1275, to the PReP partition)
> +@end group
> +@end example
> +
> +As with UEFI secure boot, it is necessary to build in the required modules,
> +or sign them separately.
> +
> +
>  @node Platform limitations
>  @chapter Platform limitations
>
> --
> 2.43.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



-- 
Regards
Vladimir 'phcoder' Serbinenko

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target
  2024-12-18 14:56 ` [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target Sudhakar Kuppusamy
  2024-12-27 15:06   ` Stefan Berger
@ 2025-01-04 18:36   ` Vladimir 'phcoder' Serbinenko
  2025-01-24  9:47   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2025-01-04 18:36 UTC (permalink / raw)
  To: The development of GNU GRUB

grub-emu has 2 modes: full with all modules compiled-in and lite with
actual module loading (mostly useful for testing module loading
itself.
So just adding if (mod) ... is going to fix all cases and avoids ifdef

On Wed, Dec 18, 2024 at 5:58 PM Sudhakar Kuppusamy
<sudhakar@linux.ibm.com> wrote:
>
> From: Daniel Axtens <dja@axtens.net>
>
> Trying to start grub-emu with a module that calls grub_dl_set_persistent
> will crash because grub-emu fakes modules and passes NULL to the module
> init function.
>
> Provide an empty function for the emu case.
>
> Fixes: ee7808e2197c (dl: Add support for persistent modules)
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  include/grub/dl.h | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/include/grub/dl.h b/include/grub/dl.h
> index 750fc8d3d..fb4476797 100644
> --- a/include/grub/dl.h
> +++ b/include/grub/dl.h
> @@ -242,11 +242,22 @@ grub_dl_get (const char *name)
>    return 0;
>  }
>
> +#ifdef GRUB_MACHINE_EMU
> +/*
> + * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT.
> + * So we fake this out to avoid a NULL deref.
> + */
> +static inline void
> +grub_dl_set_persistent (grub_dl_t mod __attribute__((unused)))
> +{
> +}
> +#else
>  static inline void
>  grub_dl_set_persistent (grub_dl_t mod)
>  {
>    mod->persistent = 1;
>  }
> +#endif
>
>  static inline int
>  grub_dl_is_persistent (grub_dl_t mod)
> --
> 2.43.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



-- 
Regards
Vladimir 'phcoder' Serbinenko

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 05/21] pgp: factor out rsa_pad
  2024-12-18 14:56 ` [PATCH v1 05/21] pgp: factor out rsa_pad Sudhakar Kuppusamy
  2024-12-27 15:11   ` Stefan Berger
@ 2025-01-04 18:40   ` Vladimir 'phcoder' Serbinenko
  2025-02-27 15:26     ` sudhakar
  2025-01-24 10:40   ` Avnish Chouhan
  2 siblings, 1 reply; 83+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2025-01-04 18:40 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

rsa_pad will be removed when we update libgcrypt (see pending patch).
Can we accommodate for this?

On Wed, Dec 18, 2024 at 5:58 PM Sudhakar Kuppusamy
<sudhakar@linux.ibm.com> wrote:
>
> From: Daniel Axtens <dja@axtens.net>
>
> rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
> We want to use it in other RSA signature verification applications.
>
> I considered and rejected putting it in lib/crypto.c. That file doesn't
> currently require any MPI functions, but rsa_pad does. That's not so
> much of a problem for the grub kernel and modules, but crypto.c also
> gets built into all the grub utilities. So - despite the utils not
> using any asymmetric ciphers -  we would need to built the entire MPI
> infrastructure in to them.
>
> A better and simpler solution is just to spin rsa_pad out into its own
> PKCS#1 v1.5 module.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/Makefile.core.def |  8 +++++
>  grub-core/commands/pgp.c    | 28 ++----------------
>  grub-core/lib/pkcs1_v15.c   | 59 +++++++++++++++++++++++++++++++++++++
>  include/grub/pkcs1_v15.h    | 27 +++++++++++++++++
>  4 files changed, 96 insertions(+), 26 deletions(-)
>  create mode 100644 grub-core/lib/pkcs1_v15.c
>  create mode 100644 include/grub/pkcs1_v15.h
>
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index f70e02e69..60db2adc5 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2540,6 +2540,14 @@ module = {
>    cppflags = '$(CPPFLAGS_GCRY)';
>  };
>
> +module = {
> +  name = pkcs1_v15;
> +  common = lib/pkcs1_v15.c;
> +
> +  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
> +  cppflags = '$(CPPFLAGS_GCRY)';
> +};
> +
>  module = {
>    name = all_video;
>    common = lib/fake_module.c;
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index c6766f044..b084dc9a2 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -24,6 +24,7 @@
>  #include <grub/file.h>
>  #include <grub/command.h>
>  #include <grub/crypto.h>
> +#include <grub/pkcs1_v15.h>
>  #include <grub/i18n.h>
>  #include <grub/gcrypt/gcrypt.h>
>  #include <grub/pubkey.h>
> @@ -411,32 +412,7 @@ static int
>  rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>          const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
>  {
> -  grub_size_t tlen, emlen, fflen;
> -  grub_uint8_t *em, *emptr;
> -  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
> -  int ret;
> -  tlen = hash->mdlen + hash->asnlen;
> -  emlen = (nbits + 7) / 8;
> -  if (emlen < tlen + 11)
> -    return 1;
> -
> -  em = grub_malloc (emlen);
> -  if (!em)
> -    return 1;
> -
> -  em[0] = 0x00;
> -  em[1] = 0x01;
> -  fflen = emlen - tlen - 3;
> -  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
> -    *emptr = 0xff;
> -  *emptr++ = 0x00;
> -  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
> -  emptr += hash->asnlen;
> -  grub_memcpy (emptr, hval, hash->mdlen);
> -
> -  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
> -  grub_free (em);
> -  return ret;
> +  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
>  }
>
>  struct grub_pubkey_context
> diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
> new file mode 100644
> index 000000000..dbacd563d
> --- /dev/null
> +++ b/grub-core/lib/pkcs1_v15.c
> @@ -0,0 +1,59 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2013  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/dl.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +/*
> + * Given a hash value 'hval', of hash specification 'hash', perform
> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
> + * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
> + */
> +gcry_err_code_t
> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
> +                    const gcry_md_spec_t * hash, gcry_mpi_t mod)
> +{
> +  grub_size_t tlen, emlen, fflen;
> +  grub_uint8_t *em, *emptr;
> +  unsigned nbits = gcry_mpi_get_nbits (mod);
> +  int ret;
> +  tlen = hash->mdlen + hash->asnlen;
> +  emlen = (nbits + 7) / 8;
> +  if (emlen < tlen + 11)
> +    return GPG_ERR_TOO_SHORT;
> +
> +  em = grub_malloc (emlen);
> +  if (!em)
> +    return 1;
> +
> +  em[0] = 0x00;
> +  em[1] = 0x01;
> +  fflen = emlen - tlen - 3;
> +  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
> +    *emptr = 0xff;
> +  *emptr++ = 0x00;
> +  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
> +  emptr += hash->asnlen;
> +  grub_memcpy (emptr, hval, hash->mdlen);
> +
> +  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
> +  grub_free (em);
> +  return ret;
> +}
> diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
> new file mode 100644
> index 000000000..5c338c84a
> --- /dev/null
> +++ b/include/grub/pkcs1_v15.h
> @@ -0,0 +1,27 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2013  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/>.
> + */
> +
> +/*
> + * Given a hash value 'hval', of hash specification 'hash', perform
> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
> + * (See RFC 8017 s 9.2)
> + */
> +gcry_err_code_t
> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
> +                    const gcry_md_spec_t * hash, gcry_mpi_t mod);
> +
> --
> 2.43.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



-- 
Regards
Vladimir 'phcoder' Serbinenko

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c
  2024-12-18 14:56 ` [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
  2024-12-27 15:13   ` Stefan Berger
@ 2025-01-04 18:41   ` Vladimir 'phcoder' Serbinenko
  2025-01-24 10:42   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2025-01-04 18:41 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: dja, jan.setjeeilers, julian.klode, mate.kukri, pjones, stefanb,
	avnish, nayna, ssrish, Sudhakar Kuppusamy

Reviewed-By: Vladimir Serbinenko <phcoder@gmail.com>

On Wed, Dec 18, 2024 at 5:59 PM Sudhakar Kuppusamy
<sudhakar@linux.ibm.com> wrote:
>
> From: Daniel Axtens <dja@axtens.net>
>
> The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the
> pgp module is a bit quirky.
>
> include/grub/crypto.h contains:
>   extern struct gcry_pk_spec *grub_crypto_pk_rsa;
>
> commands/pgp.c contains the actual storage:
>   struct gcry_pk_spec *grub_crypto_pk_rsa;
>
> And the module itself saves to the storage in pgp.c:
>   GRUB_MOD_INIT(gcry_rsa)
>   {
>     grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa;
>   }
>
> This is annoying: gcry_rsa now has a dependency on pgp!
>
> We want to be able to bring in gcry_rsa without bringing in PGP,
> so move the storage to crypto.c.
>
> Previously, gcry_rsa depended on pgp and mpi. Now it depends on
> crypto and mpi. As pgp depends on crypto, this doesn't add any new
> module dependencies using the PGP verfier.
>
> [FWIW, the story is different for the symmetric ciphers. cryptodisk
> and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name()
> to get a cipher handle. That depends on grub_ciphers being populated
> by people calling grub_cipher_register. import_gcry.py ensures that the
> symmetric ciphers call it.]
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/pgp.c | 4 ----
>  grub-core/lib/crypto.c   | 4 ++++
>  2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index b084dc9a2..a45c2213c 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -147,10 +147,6 @@ const char *hashes[] = {
>    [0x0b] = "sha224"
>  };
>
> -struct gcry_pk_spec *grub_crypto_pk_dsa;
> -struct gcry_pk_spec *grub_crypto_pk_ecdsa;
> -struct gcry_pk_spec *grub_crypto_pk_rsa;
> -
>  static int
>  dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>          const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
> diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
> index 396f76410..d53ddbe2c 100644
> --- a/grub-core/lib/crypto.c
> +++ b/grub-core/lib/crypto.c
> @@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
>        }
>  }
>
> +struct gcry_pk_spec *grub_crypto_pk_dsa;
> +struct gcry_pk_spec *grub_crypto_pk_ecdsa;
> +struct gcry_pk_spec *grub_crypto_pk_rsa;
> +
>  void
>  grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
>                   grub_size_t inlen)
> --
> 2.43.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



-- 
Regards
Vladimir 'phcoder' Serbinenko

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature
  2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
  2024-12-27 14:58   ` Stefan Berger
  2025-01-04 18:30   ` Vladimir 'phcoder' Serbinenko
@ 2025-01-06  6:25   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-06  6:25 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, Rashmica Gupta

Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Rashmica Gupta <rashmica.g@gmail.com>
> 
> Add infrastructure to allow firmware to verify the integrity of grub
> by use of a Linux-kernel-module-style appended signature. We initially
> target powerpc-ieee1275, but the code should be extensible to other
> platforms.
> 
> Usually these signatures are appended to a file without modifying the
> ELF file itself. (This is what the 'sign-file' tool does, for example.)
> The verifier loads the signed file from the file system and looks at 
> the
> end of the file for the appended signature. However, on 
> powerpc-ieee1275
> platforms, the bootloader is often stored directly in the PReP 
> partition
> as raw bytes without a file-system. This makes determining the location
> of an appended signature more difficult.
> 
> To address this, we add a new ELF note.
> 
> The name field of shall be the string "Appended-Signature", zero-padded
> to 4 byte alignment. The type field shall be 0x41536967 (the ASCII 
> values
> for the string "ASig"). It must be the final section in the ELF binary.
> 
> The description shall contain the appended signature structure as 
> defined
> by the Linux kernel. The description will also be padded to be a 
> multiple
> of 4 bytes. The padding shall be added before the appended signature
> structure (not at the end) so that the final bytes of a signed ELF file
> are the appended signature magic.
> 
> A subsequent patch documents how to create a grub core.img validly 
> signed
> under this scheme.
> 
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  include/grub/util/install.h |  7 +++++--
>  include/grub/util/mkimage.h |  4 ++--
>  util/grub-install-common.c  | 15 ++++++++++++---
>  util/grub-mkimage.c         | 11 +++++++++++
>  util/grub-mkimagexx.c       | 38 ++++++++++++++++++++++++++++++++++++-
>  util/mkimage.c              |  6 +++---
>  6 files changed, 70 insertions(+), 11 deletions(-)
> 
> diff --git a/include/grub/util/install.h b/include/grub/util/install.h
> index 5c0a52ca2..3aabc4285 100644
> --- a/include/grub/util/install.h
> +++ b/include/grub/util/install.h
> @@ -69,6 +69,8 @@
>        N_("disable shim_lock verifier"), 0 },				\
>    { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
>      N_("disabled command line interface access"), 0 },			\
> +  { "appended-signature-size", 
> GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
> +    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an
> appended signature"), 1}, \
>    { "verbose", 'v', 0, 0,						\
>      N_("print verbose messages."), 1 }
> 
> @@ -132,7 +134,8 @@ enum grub_install_options {
>    GRUB_INSTALL_OPTIONS_DTB,
>    GRUB_INSTALL_OPTIONS_SBAT,
>    GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
> -  GRUB_INSTALL_OPTIONS_DISABLE_CLI
> +  GRUB_INSTALL_OPTIONS_DISABLE_CLI,
> +  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
>  };
> 
>  extern char *grub_install_source_directory;
> @@ -192,7 +195,7 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>  			     size_t npubkeys,
>  			     char *config_path,
>  			     const struct grub_install_image_target_desc *image_target,
> -			     int note,
> +			     int note, size_t appsig_size,
>  			     grub_compression_t comp, const char *dtb_file,
>  			     const char *sbat_path, const int disable_shim_lock,
>  			     const int disable_cli);
> diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
> index 9d74f82c5..0d40383eb 100644
> --- a/include/grub/util/mkimage.h
> +++ b/include/grub/util/mkimage.h
> @@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
>  			   const struct grub_install_image_target_desc *image_target);
>  void
>  grub_mkimage_generate_elf32 (const struct
> grub_install_image_target_desc *image_target,
> -			     int note, char *sbat, char **core_img, size_t *core_size,
> +			     int note, char *sbat, size_t appsig_size, char **core_img,
> size_t *core_size,
>  			     Elf32_Addr target_addr,
>  			     struct grub_mkimage_layout *layout);
>  void
>  grub_mkimage_generate_elf64 (const struct
> grub_install_image_target_desc *image_target,
> -			     int note, char *sbat, char **core_img, size_t *core_size,
> +			     int note, char *sbat, size_t appsig_size, char **core_img,
> size_t *core_size,
>  			     Elf64_Addr target_addr,
>  			     struct grub_mkimage_layout *layout);
> 
> diff --git a/util/grub-install-common.c b/util/grub-install-common.c
> index 22bccb6a3..22f0e56cb 100644
> --- a/util/grub-install-common.c
> +++ b/util/grub-install-common.c
> @@ -467,10 +467,12 @@ static char *sbat;
>  static int disable_shim_lock;
>  static grub_compression_t compression;
>  static int disable_cli;
> +static size_t appsig_size;
> 
>  int
>  grub_install_parse (int key, char *arg)
>  {
> +  const char *end;
>    switch (key)
>      {
>      case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
> @@ -571,6 +573,12 @@ grub_install_parse (int key, char *arg)
>        grub_util_error (_("Unrecognized compression `%s'"), arg);
>      case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
>        return 1;
> +    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
> +      grub_errno = 0;
> +      appsig_size = grub_strtol (arg, &end, 10);
> +      if (grub_errno)
> +        return 0;
> +      return 1;
>      default:
>        return 0;
>      }
> @@ -683,9 +691,10 @@ grub_install_make_image_wrap_file (const char
> *dir, const char *prefix,
>    *p = '\0';
> 
>    grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' 
> --output '%s'"
> -		  " --format '%s' --compression '%s'%s%s%s%s\n",
> +		  " --format '%s' --compression '%s'"
> +		  " --appended-signature-size %zu %s %s %s %s\n",
>  		  dir, prefix, outname,
> -		  mkimage_target, compnames[compression],
> +		  mkimage_target, compnames[compression], appsig_size,
>  		  note ? " --note" : "",
>  		  disable_shim_lock ? " --disable-shim-lock" : "",
>  		  disable_cli ? " --disable-cli" : "", s);
> @@ -698,7 +707,7 @@ grub_install_make_image_wrap_file (const char
> *dir, const char *prefix,
>    grub_install_generate_image (dir, prefix, fp, outname,
>  			       modules.entries, memdisk_path,
>  			       pubkeys, npubkeys, config_path, tgt,
> -			       note, compression, dtb, sbat,
> +			       note, appsig_size, compression, dtb, sbat,
>  			       disable_shim_lock, disable_cli);
>    while (dc--)
>      grub_install_pop_module ();
> diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
> index 547f7310f..6c5063ac2 100644
> --- a/util/grub-mkimage.c
> +++ b/util/grub-mkimage.c
> @@ -84,6 +84,7 @@ static struct argp_option options[] = {
>    {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
>    {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,
> N_("disable shim_lock verifier"), 0},
>    {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable
> command line interface access"), 0},
> +  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note
> segment reserving SIZE bytes for an appended signature"), 0},
>    {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
>    { 0, 0, 0, 0, 0, 0 }
>  };
> @@ -130,6 +131,7 @@ struct arguments
>    int note;
>    int disable_shim_lock;
>    int disable_cli;
> +  size_t appsig_size;
>    const struct grub_install_image_target_desc *image_target;
>    grub_compression_t comp;
>  };
> @@ -140,6 +142,7 @@ argp_parser (int key, char *arg, struct argp_state 
> *state)
>    /* Get the input argument from argp_parse, which we
>       know is a pointer to our arguments structure. */
>    struct arguments *arguments = state->input;
> +  const char* end;
> 
>    switch (key)
>      {
> @@ -172,6 +175,13 @@ argp_parser (int key, char *arg, struct argp_state 
> *state)
>        arguments->note = 1;
>        break;
> 
> +    case 'S':
> +      grub_errno = 0;
> +      arguments->appsig_size = grub_strtol (arg, &end, 10);
> +      if (grub_errno)
> +        return 0;
> +      break;
> +
>      case 'm':
>        if (arguments->memdisk)
>  	free (arguments->memdisk);
> @@ -330,6 +340,7 @@ main (int argc, char *argv[])
>  			       arguments.memdisk, arguments.pubkeys,
>  			       arguments.npubkeys, arguments.config,
>  			       arguments.image_target, arguments.note,
> +			       arguments.appsig_size,
>  			       arguments.comp, arguments.dtb,
>  			       arguments.sbat, arguments.disable_shim_lock,
>  			       arguments.disable_cli);
> diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
> index 448862b2e..6fe348e5b 100644
> --- a/util/grub-mkimagexx.c
> +++ b/util/grub-mkimagexx.c
> @@ -115,6 +115,14 @@ struct grub_sbat_note {
>    char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
>  };
> 
> +#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
> +#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
> +struct grub_appended_signature_note
> +{
> +  Elf32_Nhdr header;
> +  char name[ALIGN_UP (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
> +};
> +
>  static int
>  is_relocatable (const struct grub_install_image_target_desc 
> *image_target)
>  {
> @@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target,
> Elf32_Addr sym_addr)
> 
>  void
>  SUFFIX (grub_mkimage_generate_elf) (const struct
> grub_install_image_target_desc *image_target,
> -				    int note, char *sbat, char **core_img, size_t *core_size,
> +				    int note, char *sbat, size_t appsig_size, char **core_img,
> size_t *core_size,
>  				    Elf_Addr target_addr,
>  				    struct grub_mkimage_layout *layout)
>  {
> @@ -237,6 +245,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct
> grub_install_image_target_desc
>        footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) +
> layout->sbat_size, 4);
>      }
> 
> +  if (appsig_size)
> +    {
> +      phnum++;
> +      footer_size += ALIGN_UP (sizeof (struct
> grub_appended_signature_note) + appsig_size, 4);
> +    }
> +
>    if (image_target->id != IMAGE_LOONGSON_ELF)
>      phnum += 2;
> 
> @@ -527,6 +541,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct
> grub_install_image_target_desc
>        phdr->p_filesz = grub_host_to_target32 (note_size);
>        phdr->p_memsz = 0;
>        phdr->p_offset = grub_host_to_target32 (header_size +
> program_size + footer_offset);
> +      footer += note_size;
> +      footer_offset += note_size;
> +    }
> +
> +  if (appsig_size)
> +    {
> +      int note_size = ALIGN_UP (sizeof (struct
> grub_appended_signature_note) + appsig_size, 4);
> +      struct grub_appended_signature_note *note_ptr = (struct
> grub_appended_signature_note *) footer;
> +      note_ptr->header.n_namesz = grub_host_to_target32 (sizeof
> (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
> +      /* needs to sit at the end, so we round this up and sign some
> zero padding */
> +      note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP
> (appsig_size, 4));
> +      note_ptr->header.n_type = grub_host_to_target32
> (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
> +      strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
> +      phdr++;
> +      phdr->p_type = grub_host_to_target32 (PT_NOTE);
> +      phdr->p_flags = grub_host_to_target32 (PF_R);
> +      phdr->p_align = grub_host_to_target32 
> (image_target->voidp_sizeof);
> +      phdr->p_vaddr = 0;
> +      phdr->p_paddr = 0;
> +      phdr->p_filesz = grub_host_to_target32 (note_size);
> +      phdr->p_memsz = 0;
> +      phdr->p_offset = grub_host_to_target32 (header_size +
> program_size + footer_offset);
>      }
> 
>    {
> diff --git a/util/mkimage.c b/util/mkimage.c
> index b46df2909..f5c59f563 100644
> --- a/util/mkimage.c
> +++ b/util/mkimage.c
> @@ -885,7 +885,7 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>  			     char *memdisk_path, char **pubkey_paths,
>  			     size_t npubkeys, char *config_path,
>  			     const struct grub_install_image_target_desc *image_target,
> -			     int note, grub_compression_t comp, const char *dtb_path,
> +			     int note, size_t appsig_size, grub_compression_t comp, const
> char *dtb_path,
>  			     const char *sbat_path, int disable_shim_lock,
>  			     int disable_cli)
>  {
> @@ -1833,10 +1833,10 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>  	else
>  	  target_addr = image_target->link_addr;
>  	if (image_target->voidp_sizeof == 4)
> -	  grub_mkimage_generate_elf32 (image_target, note, sbat, &core_img,
> &core_size,
> +	  grub_mkimage_generate_elf32 (image_target, note, sbat,
> appsig_size, &core_img, &core_size,
>  				       target_addr, &layout);
>  	else
> -	  grub_mkimage_generate_elf64 (image_target, note, sbat, &core_img,
> &core_size,
> +	  grub_mkimage_generate_elf64 (image_target, note, sbat,
> appsig_size, &core_img, &core_size,
>  				       target_addr, &layout);
>        }
>        break;

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature
  2024-12-18 14:56 ` [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature Sudhakar Kuppusamy
  2024-12-27 15:04   ` Stefan Berger
  2025-01-04 18:32   ` Vladimir 'phcoder' Serbinenko
@ 2025-01-24  9:44   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24  9:44 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Signing grub for firmware that verifies an appended signature is a
> bit fiddly. I don't want people to have to figure it out from scratch
> so document it here.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index c07d5d0dc..6e483298d 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -9135,6 +9135,48 @@ image works under UEFI secure boot and can
> maintain the secure-boot chain. It
>  will also be necessary to enrol the public key used into a relevant 
> firmware
>  key database.
> 
> +@section Signing GRUB with an appended signature
> +
> +The @file{core.img} itself can be signed with a Linux kernel 
> module-style
> +appended signature.
> +
> +To support IEEE1275 platforms where the boot image is often loaded 
> directly
> +from a disk partition rather than from a file system, the 
> @file{core.img}
> +can specify the size and location of the appended signature with an 
> ELF
> +note added by @command{grub-install}.
> +
> +An image can be signed this way using the @command{sign-file} command 
> from
> +the Linux kernel:
> +
> +@example
> +@group
> +# grub.key is your private key and certificate.der is your public key
> +
> +# Determine the size of the appended signature. It depends on the 
> signing
> +# certificate and the hash algorithm
> +touch empty
> +sign-file SHA256 grub.key certificate.der empty empty.sig
> +SIG_SIZE=`stat -c '%s' empty.sig`
> +rm empty empty.sig
> +
> +# Build a grub image with $SIG_SIZE reserved for the signature
> +grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
> +
> +# Replace the reserved size with a signature:
> +# cut off the last $SIG_SIZE bytes with truncate's minus modifier
> +truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf 
> core.elf.unsigned
> +# sign the trimmed file with an appended signature, restoring the 
> correct size
> +sign-file SHA256 grub.key certificate.der core.elf.unsigned 
> core.elf.signed
> +
> +# Don't forget to install the signed image as required
> +# (e.g. on powerpc-ieee1275, to the PReP partition)
> +@end group
> +@end example
> +
> +As with UEFI secure boot, it is necessary to build in the required 
> modules,
> +or sign them separately.
> +
> +
>  @node Platform limitations
>  @chapter Platform limitations

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target
  2024-12-18 14:56 ` [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target Sudhakar Kuppusamy
  2024-12-27 15:06   ` Stefan Berger
  2025-01-04 18:36   ` Vladimir 'phcoder' Serbinenko
@ 2025-01-24  9:47   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24  9:47 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Trying to start grub-emu with a module that calls 
> grub_dl_set_persistent
> will crash because grub-emu fakes modules and passes NULL to the module
> init function.
> 
> Provide an empty function for the emu case.
> 
> Fixes: ee7808e2197c (dl: Add support for persistent modules)
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  include/grub/dl.h | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/include/grub/dl.h b/include/grub/dl.h
> index 750fc8d3d..fb4476797 100644
> --- a/include/grub/dl.h
> +++ b/include/grub/dl.h
> @@ -242,11 +242,22 @@ grub_dl_get (const char *name)
>    return 0;
>  }
> 
> +#ifdef GRUB_MACHINE_EMU
> +/*
> + * Under grub-emu, modules are faked and NULL is passed to 
> GRUB_MOD_INIT.
> + * So we fake this out to avoid a NULL deref.
> + */
> +static inline void
> +grub_dl_set_persistent (grub_dl_t mod __attribute__((unused)))
> +{
> +}
> +#else
>  static inline void
>  grub_dl_set_persistent (grub_dl_t mod)
>  {
>    mod->persistent = 1;
>  }
> +#endif
> 
>  static inline int
>  grub_dl_is_persistent (grub_dl_t mod)

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 05/21] pgp: factor out rsa_pad
  2024-12-18 14:56 ` [PATCH v1 05/21] pgp: factor out rsa_pad Sudhakar Kuppusamy
  2024-12-27 15:11   ` Stefan Berger
  2025-01-04 18:40   ` Vladimir 'phcoder' Serbinenko
@ 2025-01-24 10:40   ` Avnish Chouhan
  2025-02-27 15:28     ` sudhakar
  2 siblings, 1 reply; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24 10:40 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Indentation looks off in couple of places. Please fix it.

Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
> We want to use it in other RSA signature verification applications.
> 
> I considered and rejected putting it in lib/crypto.c. That file doesn't
> currently require any MPI functions, but rsa_pad does. That's not so
> much of a problem for the grub kernel and modules, but crypto.c also
> gets built into all the grub utilities. So - despite the utils not
> using any asymmetric ciphers -  we would need to built the entire MPI
> infrastructure in to them.
> 
> A better and simpler solution is just to spin rsa_pad out into its own
> PKCS#1 v1.5 module.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/Makefile.core.def |  8 +++++
>  grub-core/commands/pgp.c    | 28 ++----------------
>  grub-core/lib/pkcs1_v15.c   | 59 +++++++++++++++++++++++++++++++++++++
>  include/grub/pkcs1_v15.h    | 27 +++++++++++++++++
>  4 files changed, 96 insertions(+), 26 deletions(-)
>  create mode 100644 grub-core/lib/pkcs1_v15.c
>  create mode 100644 include/grub/pkcs1_v15.h
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index f70e02e69..60db2adc5 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2540,6 +2540,14 @@ module = {
>    cppflags = '$(CPPFLAGS_GCRY)';
>  };
> 
> +module = {
> +  name = pkcs1_v15;
> +  common = lib/pkcs1_v15.c;
> +
> +  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
> +  cppflags = '$(CPPFLAGS_GCRY)';
> +};
> +
>  module = {
>    name = all_video;
>    common = lib/fake_module.c;
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index c6766f044..b084dc9a2 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -24,6 +24,7 @@
>  #include <grub/file.h>
>  #include <grub/command.h>
>  #include <grub/crypto.h>
> +#include <grub/pkcs1_v15.h>
>  #include <grub/i18n.h>
>  #include <grub/gcrypt/gcrypt.h>
>  #include <grub/pubkey.h>
> @@ -411,32 +412,7 @@ static int
>  rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>  	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
>  {
> -  grub_size_t tlen, emlen, fflen;
> -  grub_uint8_t *em, *emptr;
> -  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
> -  int ret;
> -  tlen = hash->mdlen + hash->asnlen;
> -  emlen = (nbits + 7) / 8;
> -  if (emlen < tlen + 11)
> -    return 1;
> -
> -  em = grub_malloc (emlen);
> -  if (!em)
> -    return 1;
> -
> -  em[0] = 0x00;
> -  em[1] = 0x01;
> -  fflen = emlen - tlen - 3;
> -  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
> -    *emptr = 0xff;
> -  *emptr++ = 0x00;
> -  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
> -  emptr += hash->asnlen;
> -  grub_memcpy (emptr, hval, hash->mdlen);
> -
> -  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
> -  grub_free (em);
> -  return ret;
> +  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
>  }
> 
>  struct grub_pubkey_context
> diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
> new file mode 100644
> index 000000000..dbacd563d
> --- /dev/null
> +++ b/grub-core/lib/pkcs1_v15.c
> @@ -0,0 +1,59 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2013  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/dl.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +/*
> + * Given a hash value 'hval', of hash specification 'hash', perform
> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
> + * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
> + */
> +gcry_err_code_t
> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
> +		     const gcry_md_spec_t * hash, gcry_mpi_t mod)
> +{
> +  grub_size_t tlen, emlen, fflen;
> +  grub_uint8_t *em, *emptr;
> +  unsigned nbits = gcry_mpi_get_nbits (mod);
> +  int ret;
> +  tlen = hash->mdlen + hash->asnlen;
> +  emlen = (nbits + 7) / 8;
> +  if (emlen < tlen + 11)
> +    return GPG_ERR_TOO_SHORT;
> +
> +  em = grub_malloc (emlen);
> +  if (!em)
> +    return 1;
> +
> +  em[0] = 0x00;
> +  em[1] = 0x01;
> +  fflen = emlen - tlen - 3;
> +  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
> +    *emptr = 0xff;
> +  *emptr++ = 0x00;
> +  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
> +  emptr += hash->asnlen;
> +  grub_memcpy (emptr, hval, hash->mdlen);
> +
> +  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
> +  grub_free (em);
> +  return ret;
> +}
> diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
> new file mode 100644
> index 000000000..5c338c84a
> --- /dev/null
> +++ b/include/grub/pkcs1_v15.h
> @@ -0,0 +1,27 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2013  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/>.
> + */
> +
> +/*
> + * Given a hash value 'hval', of hash specification 'hash', perform
> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
> + * (See RFC 8017 s 9.2)
> + */
> +gcry_err_code_t
> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
> +		     const gcry_md_spec_t * hash, gcry_mpi_t mod);
> +

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c
  2024-12-18 14:56 ` [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
  2024-12-27 15:13   ` Stefan Berger
  2025-01-04 18:41   ` Vladimir 'phcoder' Serbinenko
@ 2025-01-24 10:42   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24 10:42 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> The way gcry_rsa and friends (the asymmetric ciphers) are loaded for 
> the
> pgp module is a bit quirky.
> 
> include/grub/crypto.h contains:
>   extern struct gcry_pk_spec *grub_crypto_pk_rsa;
> 
> commands/pgp.c contains the actual storage:
>   struct gcry_pk_spec *grub_crypto_pk_rsa;
> 
> And the module itself saves to the storage in pgp.c:
>   GRUB_MOD_INIT(gcry_rsa)
>   {
>     grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa;
>   }
> 
> This is annoying: gcry_rsa now has a dependency on pgp!
> 
> We want to be able to bring in gcry_rsa without bringing in PGP,
> so move the storage to crypto.c.
> 
> Previously, gcry_rsa depended on pgp and mpi. Now it depends on
> crypto and mpi. As pgp depends on crypto, this doesn't add any new
> module dependencies using the PGP verfier.
> 
> [FWIW, the story is different for the symmetric ciphers. cryptodisk
> and friends (zfs encryption etc) use 
> grub_crypto_lookup_cipher_by_name()
> to get a cipher handle. That depends on grub_ciphers being populated
> by people calling grub_cipher_register. import_gcry.py ensures that the
> symmetric ciphers call it.]
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/pgp.c | 4 ----
>  grub-core/lib/crypto.c   | 4 ++++
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index b084dc9a2..a45c2213c 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -147,10 +147,6 @@ const char *hashes[] = {
>    [0x0b] = "sha224"
>  };
> 
> -struct gcry_pk_spec *grub_crypto_pk_dsa;
> -struct gcry_pk_spec *grub_crypto_pk_ecdsa;
> -struct gcry_pk_spec *grub_crypto_pk_rsa;
> -
>  static int
>  dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>  	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
> diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
> index 396f76410..d53ddbe2c 100644
> --- a/grub-core/lib/crypto.c
> +++ b/grub-core/lib/crypto.c
> @@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
>        }
>  }
> 
> +struct gcry_pk_spec *grub_crypto_pk_dsa;
> +struct gcry_pk_spec *grub_crypto_pk_ecdsa;
> +struct gcry_pk_spec *grub_crypto_pk_rsa;
> +
>  void
>  grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void 
> *in,
>  		  grub_size_t inlen)

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 07/21] grub-install: support embedding x509 certificates
  2024-12-18 14:56 ` [PATCH v1 07/21] grub-install: support embedding x509 certificates Sudhakar Kuppusamy
  2024-12-27 16:08   ` Stefan Berger
@ 2025-01-24 10:45   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24 10:45 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, Alastair D'Silva,
	daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Alastair D'Silva <alastair@d-silva.org>
> 
> To support verification of appended signatures, we need a way to
> embed the necessary public keys. Existing appended signature schemes
> in the Linux kernel use X.509 certificates, so allow certificates to
> be embedded in the grub core image in the same way as PGP keys.
> 
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/pgp.c    |  2 +-
>  include/grub/kernel.h       |  2 ++
>  include/grub/util/install.h |  3 +++
>  util/grub-install-common.c  | 19 ++++++++++++++++++-
>  util/grub-mkimage.c         | 14 ++++++++++++--
>  util/mkimage.c              | 33 +++++++++++++++++++++++++++++++--
>  6 files changed, 67 insertions(+), 6 deletions(-)
> 
> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
> index a45c2213c..847a5046a 100644
> --- a/grub-core/commands/pgp.c
> +++ b/grub-core/commands/pgp.c
> @@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
>      grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
> 
>      /* Not an ELF module, skip.  */
> -    if (header->type != OBJ_TYPE_PUBKEY)
> +    if (header->type != OBJ_TYPE_GPG_PUBKEY)
>        continue;
> 
>      pseudo_file.fs = &pseudo_fs;
> diff --git a/include/grub/kernel.h b/include/grub/kernel.h
> index 6121c1e66..5c5ac129d 100644
> --- a/include/grub/kernel.h
> +++ b/include/grub/kernel.h
> @@ -29,6 +29,8 @@ enum
>    OBJ_TYPE_CONFIG,
>    OBJ_TYPE_PREFIX,
>    OBJ_TYPE_PUBKEY,
> +  OBJ_TYPE_GPG_PUBKEY,
> +  OBJ_TYPE_X509_PUBKEY,
>    OBJ_TYPE_DTB,
>    OBJ_TYPE_DISABLE_SHIM_LOCK,
>    OBJ_TYPE_DISABLE_CLI
> diff --git a/include/grub/util/install.h b/include/grub/util/install.h
> index 3aabc4285..52a667c37 100644
> --- a/include/grub/util/install.h
> +++ b/include/grub/util/install.h
> @@ -69,6 +69,8 @@
>        N_("disable shim_lock verifier"), 0 },				\
>    { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
>      N_("disabled command line interface access"), 0 },			\
> +  { "x509key",   'x', N_("FILE"), 0,					\
> +      N_("embed FILE as an x509 certificate for signature checking"), 
> 0}, \
>    { "appended-signature-size", 
> GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
>      "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an
> appended signature"), 1}, \
>    { "verbose", 'v', 0, 0,						\
> @@ -193,6 +195,7 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>  			     const char *outname, char *mods[],
>  			     char *memdisk_path, char **pubkey_paths,
>  			     size_t npubkeys,
> +			     char **x509key_paths, size_t nx509keys,
>  			     char *config_path,
>  			     const struct grub_install_image_target_desc *image_target,
>  			     int note, size_t appsig_size,
> diff --git a/util/grub-install-common.c b/util/grub-install-common.c
> index 22f0e56cb..29c45e26e 100644
> --- a/util/grub-install-common.c
> +++ b/util/grub-install-common.c
> @@ -463,6 +463,8 @@ handle_install_list (struct install_list *il,
> const char *val,
> 
>  static char **pubkeys;
>  static size_t npubkeys;
> +static char **x509keys;
> +static size_t nx509keys;
>  static char *sbat;
>  static int disable_shim_lock;
>  static grub_compression_t compression;
> @@ -510,6 +512,10 @@ grub_install_parse (int key, char *arg)
>      case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
>        disable_cli = 1;
>        return 1;
> +    case 'x':
> +      x509keys = xrealloc (x509keys, sizeof (x509keys[0]) * (nx509keys 
> + 1));
> +      x509keys[nx509keys++] = xstrdup (arg);
> +      return 1;
> 
>      case GRUB_INSTALL_OPTIONS_VERBOSITY:
>        verbosity++;
> @@ -640,6 +646,9 @@ grub_install_make_image_wrap_file (const char
> *dir, const char *prefix,
>    for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
>      slen += sizeof (" --pubkey ''") + grub_strlen (*pk);
> 
> +  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
> +    slen += sizeof (" --x509key ''") + grub_strlen (*pk);
> +
>    for (md = modules.entries; *md; md++)
>      slen += sizeof (" ''") + grub_strlen (*md);
> 
> @@ -680,6 +689,14 @@ grub_install_make_image_wrap_file (const char
> *dir, const char *prefix,
>        *p++ = '\'';
>      }
> 
> +  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
> +    {
> +      p = grub_stpcpy (p, "--x509key '");
> +      p = grub_stpcpy (p, *pk);
> +      *p++ = '\'';
> +      *p++ = ' ';
> +    }
> +
>    for (md = modules.entries; *md; md++)
>      {
>        *p++ = ' ';
> @@ -706,7 +723,7 @@ grub_install_make_image_wrap_file (const char
> *dir, const char *prefix,
> 
>    grub_install_generate_image (dir, prefix, fp, outname,
>  			       modules.entries, memdisk_path,
> -			       pubkeys, npubkeys, config_path, tgt,
> +			       pubkeys, npubkeys,  x509keys, nx509keys, config_path, tgt,
>  			       note, appsig_size, compression, dtb, sbat,
>  			       disable_shim_lock, disable_cli);
>    while (dc--)
> diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
> index 6c5063ac2..1f958e04b 100644
> --- a/util/grub-mkimage.c
> +++ b/util/grub-mkimage.c
> @@ -75,7 +75,8 @@ static struct argp_option options[] = {
>     /* TRANSLATORS: "embed" is a verb (command description).  "*/
>    {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early 
> config"), 0},
>     /* TRANSLATORS: "embed" is a verb (command description).  "*/
> -  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for
> signature checking"), 0},
> +  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for
> PGP signature checking"), 0},
> +  {"x509key",     'x', N_("FILE"), 0, N_("embed FILE as an x509
> certificate for appended signature checking"), 0},
>    /* TRANSLATORS: NOTE is a name of segment.  */
>    {"note",   'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
>    {"output",  'o', N_("FILE"), 0, N_("output a generated image to
> FILE [default=stdout]"), 0},
> @@ -125,6 +126,8 @@ struct arguments
>    char *dtb;
>    char **pubkeys;
>    size_t npubkeys;
> +  char **x509keys;
> +  size_t nx509keys;
>    char *font;
>    char *config;
>    char *sbat;
> @@ -208,6 +211,12 @@ argp_parser (int key, char *arg, struct argp_state 
> *state)
>        arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg);
>        break;
> 
> +    case 'x':
> +      arguments->x509keys = xrealloc (arguments->x509keys,
> +                                      sizeof (arguments->x509keys[0])
> * (arguments->nx509keys + 1));
> +      arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
> +      break;
> +
>      case 'c':
>        if (arguments->config)
>  	free (arguments->config);
> @@ -338,7 +347,8 @@ main (int argc, char *argv[])
>    grub_install_generate_image (arguments.dir, arguments.prefix, fp,
>  			       arguments.output, arguments.modules,
>  			       arguments.memdisk, arguments.pubkeys,
> -			       arguments.npubkeys, arguments.config,
> +			       arguments.npubkeys, arguments.x509keys,
> +			       arguments.nx509keys, arguments.config,
>  			       arguments.image_target, arguments.note,
>  			       arguments.appsig_size,
>  			       arguments.comp, arguments.dtb,
> diff --git a/util/mkimage.c b/util/mkimage.c
> index f5c59f563..7076d632b 100644
> --- a/util/mkimage.c
> +++ b/util/mkimage.c
> @@ -883,7 +883,7 @@ void
>  grub_install_generate_image (const char *dir, const char *prefix,
>  			     FILE *out, const char *outname, char *mods[],
>  			     char *memdisk_path, char **pubkey_paths,
> -			     size_t npubkeys, char *config_path,
> +			     size_t npubkeys, char **x509key_paths, size_t nx509keys, char
> *config_path,
>  			     const struct grub_install_image_target_desc *image_target,
>  			     int note, size_t appsig_size, grub_compression_t comp, const
> char *dtb_path,
>  			     const char *sbat_path, int disable_shim_lock,
> @@ -929,6 +929,18 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>        }
>    }
> 
> +  {
> +    size_t i;
> +    for (i = 0; i < nx509keys; i++)
> +      {
> +        size_t curs;
> +        curs = ALIGN_ADDR (grub_util_get_image_size 
> (x509key_paths[i]));
> +        grub_util_info ("the size of x509 public key %u is 0x%"
> GRUB_HOST_PRIxLONG_LONG,
> +                        (unsigned) i, (unsigned long long) curs);
> +        total_module_size += curs + sizeof (struct 
> grub_module_header);
> +      }
> +  }
> +
>    if (memdisk_path)
>      {
>        memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 
> 512);
> @@ -1053,7 +1065,7 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>  	curs = grub_util_get_image_size (pubkey_paths[i]);
> 
>  	header = (struct grub_module_header *) (kernel_img + offset);
> -	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
> +	header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY);
>  	header->size = grub_host_to_target32 (curs + sizeof (*header));
>  	offset += sizeof (*header);
> 
> @@ -1062,6 +1074,23 @@ grub_install_generate_image (const char *dir,
> const char *prefix,
>        }
>    }
> 
> +  {
> +    size_t i;
> +    for (i = 0; i < nx509keys; i++)
> +      {
> +        size_t curs;
> +        struct grub_module_header *header;
> +
> +        curs = grub_util_get_image_size (x509key_paths[i]);
> +        header = (struct grub_module_header *) (kernel_img + offset);
> +        header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
> +        header->size = grub_host_to_target32 (curs + sizeof 
> (*header));
> +        offset += sizeof (*header);
> +        grub_util_load_image (x509key_paths[i], kernel_img + offset);
> +        offset += ALIGN_ADDR (curs);
> +      }
> +  }
> +
>    if (memdisk_path)
>      {
>        struct grub_module_header *header;

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files
  2024-12-18 14:56 ` [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files Sudhakar Kuppusamy
  2024-12-28 19:02   ` Stefan Berger
@ 2025-01-24 10:47   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24 10:47 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> In order to parse PKCS#7 messages and X.509 certificates with libtasn1,
> we need some information about how they are encoded.
> 
> We get these from GNUTLS, which has the benefit that they support the
> features we need and are well tested.
> 
> The GNUTLS files are from:
> 
> -
> https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/gnutls_asn1_tab.c
> -
> https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/pkix_asn1_tab.c
> 
> The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing
> us to import it without issue.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  .../commands/appendedsig/gnutls_asn1_tab.c    | 121 +++++
>  .../commands/appendedsig/pkix_asn1_tab.c      | 484 ++++++++++++++++++
>  2 files changed, 605 insertions(+)
>  create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
>  create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c
> 
> diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> new file mode 100644
> index 000000000..ddd1314e6
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> @@ -0,0 +1,121 @@
> +#include <grub/mm.h>
> +#include <grub/libtasn1.h>
> +
> +const asn1_static_node gnutls_asn1_tab[] = {
> +  { "GNUTLS", 536872976, NULL },
> +  { NULL, 1073741836, NULL },
> +  { "RSAPublicKey", 1610612741, NULL },
> +  { "modulus", 1073741827, NULL },
> +  { "publicExponent", 3, NULL },
> +  { "RSAPrivateKey", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "modulus", 1073741827, NULL },
> +  { "publicExponent", 1073741827, NULL },
> +  { "privateExponent", 1073741827, NULL },
> +  { "prime1", 1073741827, NULL },
> +  { "prime2", 1073741827, NULL },
> +  { "exponent1", 1073741827, NULL },
> +  { "exponent2", 1073741827, NULL },
> +  { "coefficient", 1073741827, NULL },
> +  { "otherPrimeInfos", 16386, "OtherPrimeInfos"},
> +  { "ProvableSeed", 1610612741, NULL },
> +  { "algorithm", 1073741836, NULL },
> +  { "seed", 7, NULL },
> +  { "OtherPrimeInfos", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "OtherPrimeInfo"},
> +  { "OtherPrimeInfo", 1610612741, NULL },
> +  { "prime", 1073741827, NULL },
> +  { "exponent", 1073741827, NULL },
> +  { "coefficient", 3, NULL },
> +  { "AlgorithmIdentifier", 1610612741, NULL },
> +  { "algorithm", 1073741836, NULL },
> +  { "parameters", 541081613, NULL },
> +  { "algorithm", 1, NULL },
> +  { "DigestInfo", 1610612741, NULL },
> +  { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
> +  { "digest", 7, NULL },
> +  { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
> +  { "DSAPublicKey", 1073741827, NULL },
> +  { "DSAParameters", 1610612741, NULL },
> +  { "p", 1073741827, NULL },
> +  { "q", 1073741827, NULL },
> +  { "g", 3, NULL },
> +  { "DSASignatureValue", 1610612741, NULL },
> +  { "r", 1073741827, NULL },
> +  { "s", 3, NULL },
> +  { "DSAPrivateKey", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "p", 1073741827, NULL },
> +  { "q", 1073741827, NULL },
> +  { "g", 1073741827, NULL },
> +  { "Y", 1073741827, NULL },
> +  { "priv", 3, NULL },
> +  { "DHParameter", 1610612741, NULL },
> +  { "prime", 1073741827, NULL },
> +  { "base", 1073741827, NULL },
> +  { "privateValueLength", 16387, NULL },
> +  { "ECParameters", 1610612754, NULL },
> +  { "namedCurve", 12, NULL },
> +  { "ECPrivateKey", 1610612741, NULL },
> +  { "Version", 1073741827, NULL },
> +  { "privateKey", 1073741831, NULL },
> +  { "parameters", 1610637314, "ECParameters"},
> +  { NULL, 2056, "0"},
> +  { "publicKey", 536895494, NULL },
> +  { NULL, 2056, "1"},
> +  { "PrincipalName", 1610612741, NULL },
> +  { "name-type", 1610620931, NULL },
> +  { NULL, 2056, "0"},
> +  { "name-string", 536879115, NULL },
> +  { NULL, 1073743880, "1"},
> +  { NULL, 27, NULL },
> +  { "KRB5PrincipalName", 1610612741, NULL },
> +  { "realm", 1610620955, NULL },
> +  { NULL, 2056, "0"},
> +  { "principalName", 536879106, "PrincipalName"},
> +  { NULL, 2056, "1"},
> +  { "RSAPSSParameters", 1610612741, NULL },
> +  { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
> +  { NULL, 2056, "0"},
> +  { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
> +  { NULL, 2056, "1"},
> +  { "saltLength", 1610653699, NULL },
> +  { NULL, 1073741833, "20"},
> +  { NULL, 2056, "2"},
> +  { "trailerField", 536911875, NULL },
> +  { NULL, 1073741833, "1"},
> +  { NULL, 2056, "3"},
> +  { "GOSTParameters", 1610612741, NULL },
> +  { "publicKeyParamSet", 1073741836, NULL },
> +  { "digestParamSet", 16396, NULL },
> +  { "GOSTParametersOld", 1610612741, NULL },
> +  { "publicKeyParamSet", 1073741836, NULL },
> +  { "digestParamSet", 1073741836, NULL },
> +  { "encryptionParamSet", 16396, NULL },
> +  { "GOSTPrivateKey", 1073741831, NULL },
> +  { "GOSTPrivateKeyOld", 1073741827, NULL },
> +  { "IssuerSignTool", 1610612741, NULL },
> +  { "signTool", 1073741858, NULL },
> +  { "cATool", 1073741858, NULL },
> +  { "signToolCert", 1073741858, NULL },
> +  { "cAToolCert", 34, NULL },
> +  { "Gost28147-89-EncryptedKey", 1610612741, NULL },
> +  { "encryptedKey", 1073741831, NULL },
> +  { "maskKey", 1610637319, NULL },
> +  { NULL, 4104, "0"},
> +  { "macKey", 7, NULL },
> +  { "SubjectPublicKeyInfo", 1610612741, NULL },
> +  { "algorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "subjectPublicKey", 6, NULL },
> +  { "GostR3410-TransportParameters", 1610612741, NULL },
> +  { "encryptionParamSet", 1073741836, NULL },
> +  { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
> +  { NULL, 4104, "0"},
> +  { "ukm", 7, NULL },
> +  { "GostR3410-KeyTransport", 536870917, NULL },
> +  { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
> +  { "transportParameters", 536895490, 
> "GostR3410-TransportParameters"},
> +  { NULL, 4104, "0"},
> +  { NULL, 0, NULL }
> +};
> diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c
> b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> new file mode 100644
> index 000000000..adef69d95
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> @@ -0,0 +1,484 @@
> +#include <grub/mm.h>
> +#include <grub/libtasn1.h>
> +
> +const asn1_static_node pkix_asn1_tab[] = {
> +  { "PKIX1", 536875024, NULL },
> +  { NULL, 1073741836, NULL },
> +  { "PrivateKeyUsagePeriod", 1610612741, NULL },
> +  { "notBefore", 1610637349, NULL },
> +  { NULL, 4104, "0"},
> +  { "notAfter", 536895525, NULL },
> +  { NULL, 4104, "1"},
> +  { "AuthorityKeyIdentifier", 1610612741, NULL },
> +  { "keyIdentifier", 1610637319, NULL },
> +  { NULL, 4104, "0"},
> +  { "authorityCertIssuer", 1610637314, "GeneralNames"},
> +  { NULL, 4104, "1"},
> +  { "authorityCertSerialNumber", 536895490, 
> "CertificateSerialNumber"},
> +  { NULL, 4104, "2"},
> +  { "SubjectKeyIdentifier", 1073741831, NULL },
> +  { "KeyUsage", 1073741830, NULL },
> +  { "DirectoryString", 1610612754, NULL },
> +  { "teletexString", 1612709918, NULL },
> +  { "MAX", 524298, "1"},
> +  { "printableString", 1612709919, NULL },
> +  { "MAX", 524298, "1"},
> +  { "universalString", 1612709920, NULL },
> +  { "MAX", 524298, "1"},
> +  { "utf8String", 1612709922, NULL },
> +  { "MAX", 524298, "1"},
> +  { "bmpString", 1612709921, NULL },
> +  { "MAX", 524298, "1"},
> +  { "ia5String", 538968093, NULL },
> +  { "MAX", 524298, "1"},
> +  { "SubjectAltName", 1073741826, "GeneralNames"},
> +  { "GeneralNames", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "GeneralName"},
> +  { "GeneralName", 1610612754, NULL },
> +  { "otherName", 1610620930, "AnotherName"},
> +  { NULL, 4104, "0"},
> +  { "rfc822Name", 1610620957, NULL },
> +  { NULL, 4104, "1"},
> +  { "dNSName", 1610620957, NULL },
> +  { NULL, 4104, "2"},
> +  { "x400Address", 1610620941, NULL },
> +  { NULL, 4104, "3"},
> +  { "directoryName", 1610620939, NULL },
> +  { NULL, 1073743880, "4"},
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "ediPartyName", 1610620941, NULL },
> +  { NULL, 4104, "5"},
> +  { "uniformResourceIdentifier", 1610620957, NULL },
> +  { NULL, 4104, "6"},
> +  { "iPAddress", 1610620935, NULL },
> +  { NULL, 4104, "7"},
> +  { "registeredID", 536879116, NULL },
> +  { NULL, 4104, "8"},
> +  { "AnotherName", 1610612741, NULL },
> +  { "type-id", 1073741836, NULL },
> +  { "value", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "type-id", 1, NULL },
> +  { "IssuerAltName", 1073741826, "GeneralNames"},
> +  { "BasicConstraints", 1610612741, NULL },
> +  { "cA", 1610645508, NULL },
> +  { NULL, 131081, NULL },
> +  { "pathLenConstraint", 537411587, NULL },
> +  { "0", 10, "MAX"},
> +  { "CRLDistributionPoints", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "DistributionPoint"},
> +  { "DistributionPoint", 1610612741, NULL },
> +  { "distributionPoint", 1610637314, "DistributionPointName"},
> +  { NULL, 2056, "0"},
> +  { "reasons", 1610637314, "ReasonFlags"},
> +  { NULL, 4104, "1"},
> +  { "cRLIssuer", 536895490, "GeneralNames"},
> +  { NULL, 4104, "2"},
> +  { "DistributionPointName", 1610612754, NULL },
> +  { "fullName", 1610620930, "GeneralNames"},
> +  { NULL, 4104, "0"},
> +  { "nameRelativeToCRLIssuer", 536879106, 
> "RelativeDistinguishedName"},
> +  { NULL, 4104, "1"},
> +  { "ReasonFlags", 1073741830, NULL },
> +  { "ExtKeyUsageSyntax", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 12, NULL },
> +  { "AuthorityInfoAccessSyntax", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "AccessDescription"},
> +  { "AccessDescription", 1610612741, NULL },
> +  { "accessMethod", 1073741836, NULL },
> +  { "accessLocation", 2, "GeneralName"},
> +  { "Attribute", 1610612741, NULL },
> +  { "type", 1073741836, NULL },
> +  { "values", 536870927, NULL },
> +  { NULL, 13, NULL },
> +  { "AttributeTypeAndValue", 1610612741, NULL },
> +  { "type", 1073741836, NULL },
> +  { "value", 13, NULL },
> +  { "Name", 1610612754, NULL },
> +  { "rdnSequence", 536870923, NULL },
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "DistinguishedName", 1610612747, NULL },
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "RelativeDistinguishedName", 1612709903, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "AttributeTypeAndValue"},
> +  { "Certificate", 1610612741, NULL },
> +  { "tbsCertificate", 1073741826, "TBSCertificate"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 6, NULL },
> +  { "TBSCertificate", 1610612741, NULL },
> +  { "version", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 2056, "0"},
> +  { "serialNumber", 1073741826, "CertificateSerialNumber"},
> +  { "signature", 1073741826, "AlgorithmIdentifier"},
> +  { "issuer", 1073741826, "Name"},
> +  { "validity", 1073741826, "Validity"},
> +  { "subject", 1073741826, "Name"},
> +  { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
> +  { "issuerUniqueID", 1610637314, "UniqueIdentifier"},
> +  { NULL, 4104, "1"},
> +  { "subjectUniqueID", 1610637314, "UniqueIdentifier"},
> +  { NULL, 4104, "2"},
> +  { "extensions", 536895490, "Extensions"},
> +  { NULL, 2056, "3"},
> +  { "CertificateSerialNumber", 1073741827, NULL },
> +  { "Validity", 1610612741, NULL },
> +  { "notBefore", 1073741826, "Time"},
> +  { "notAfter", 2, "Time"},
> +  { "Time", 1610612754, NULL },
> +  { "utcTime", 1073741860, NULL },
> +  { "generalTime", 37, NULL },
> +  { "UniqueIdentifier", 1073741830, NULL },
> +  { "SubjectPublicKeyInfo", 1610612741, NULL },
> +  { "algorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "subjectPublicKey", 6, NULL },
> +  { "Extensions", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "Extension"},
> +  { "Extension", 1610612741, NULL },
> +  { "extnID", 1073741836, NULL },
> +  { "critical", 1610645508, NULL },
> +  { NULL, 131081, NULL },
> +  { "extnValue", 7, NULL },
> +  { "CertificateList", 1610612741, NULL },
> +  { "tbsCertList", 1073741826, "TBSCertList"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 6, NULL },
> +  { "TBSCertList", 1610612741, NULL },
> +  { "version", 1073758211, NULL },
> +  { "signature", 1073741826, "AlgorithmIdentifier"},
> +  { "issuer", 1073741826, "Name"},
> +  { "thisUpdate", 1073741826, "Time"},
> +  { "nextUpdate", 1073758210, "Time"},
> +  { "revokedCertificates", 1610629131, NULL },
> +  { NULL, 536870917, NULL },
> +  { "userCertificate", 1073741826, "CertificateSerialNumber"},
> +  { "revocationDate", 1073741826, "Time"},
> +  { "crlEntryExtensions", 16386, "Extensions"},
> +  { "crlExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "0"},
> +  { "AlgorithmIdentifier", 1610612741, NULL },
> +  { "algorithm", 1073741836, NULL },
> +  { "parameters", 541081613, NULL },
> +  { "algorithm", 1, NULL },
> +  { "Dss-Sig-Value", 1610612741, NULL },
> +  { "r", 1073741827, NULL },
> +  { "s", 3, NULL },
> +  { "Dss-Parms", 1610612741, NULL },
> +  { "p", 1073741827, NULL },
> +  { "q", 1073741827, NULL },
> +  { "g", 3, NULL },
> +  { "pkcs-7-ContentInfo", 1610612741, NULL },
> +  { "contentType", 1073741836, NULL },
> +  { "content", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "contentType", 1, NULL },
> +  { "pkcs-7-DigestInfo", 1610612741, NULL },
> +  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "digest", 7, NULL },
> +  { "pkcs-7-SignedData", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "digestAlgorithms", 1073741826, 
> "pkcs-7-DigestAlgorithmIdentifiers"},
> +  { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
> +  { "certificates", 1610637314, "pkcs-7-CertificateSet"},
> +  { NULL, 4104, "0"},
> +  { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
> +  { NULL, 4104, "1"},
> +  { "signerInfos", 2, "pkcs-7-SignerInfos"},
> +  { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
> +  { NULL, 2, "AlgorithmIdentifier"},
> +  { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
> +  { "eContentType", 1073741836, NULL },
> +  { "eContent", 536895501, NULL },
> +  { NULL, 2056, "0"},
> +  { "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
> +  { NULL, 13, NULL },
> +  { "pkcs-7-CertificateChoices", 1610612754, NULL },
> +  { "certificate", 13, NULL },
> +  { "pkcs-7-CertificateSet", 1610612751, NULL },
> +  { NULL, 2, "pkcs-7-CertificateChoices"},
> +  { "IssuerAndSerialNumber", 1610612741, NULL },
> +  { "issuer", 1073741826, "Name"},
> +  { "serialNumber", 2, "CertificateSerialNumber"},
> +  { "pkcs-7-SignerInfo", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "sid", 1073741826, "SignerIdentifier"},
> +  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signedAttrs", 1610637314, "SignedAttributes"},
> +  { NULL, 4104, "0"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 1073741831, NULL },
> +  { "unsignedAttrs", 536895490, "SignedAttributes"},
> +  { NULL, 4104, "1"},
> +  { "SignedAttributes", 1612709903, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "Attribute"},
> +  { "SignerIdentifier", 1610612754, NULL },
> +  { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
> +  { "subjectKeyIdentifier", 536879111, NULL },
> +  { NULL, 4104, "0"},
> +  { "pkcs-7-SignerInfos", 1610612751, NULL },
> +  { NULL, 2, "pkcs-7-SignerInfo"},
> +  { "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "subject", 1073741826, "Name"},
> +  { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
> +  { "attributes", 536879106, "Attributes"},
> +  { NULL, 4104, "0"},
> +  { "Attributes", 1610612751, NULL },
> +  { NULL, 2, "Attribute"},
> +  { "pkcs-10-CertificationRequest", 1610612741, NULL },
> +  { "certificationRequestInfo", 1073741826,
> "pkcs-10-CertificationRequestInfo"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 6, NULL },
> +  { "pkcs-9-at-challengePassword", 1879048204, NULL },
> +  { "iso", 1073741825, "1"},
> +  { "member-body", 1073741825, "2"},
> +  { "us", 1073741825, "840"},
> +  { "rsadsi", 1073741825, "113549"},
> +  { "pkcs", 1073741825, "1"},
> +  { NULL, 1073741825, "9"},
> +  { NULL, 1, "7"},
> +  { "pkcs-9-challengePassword", 1610612754, NULL },
> +  { "printableString", 1073741855, NULL },
> +  { "utf8String", 34, NULL },
> +  { "pkcs-9-localKeyId", 1073741831, NULL },
> +  { "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "privateKey", 1073741831, NULL },
> +  { "attributes", 536895490, "Attributes"},
> +  { NULL, 4104, "0"},
> +  { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
> +  { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "encryptedData", 2, "pkcs-8-EncryptedData"},
> +  { "pkcs-8-EncryptedData", 1073741831, NULL },
> +  { "pkcs-5-des-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "8"},
> +  { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "8"},
> +  { "pkcs-5-aes128-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "16"},
> +  { "pkcs-5-aes192-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "16"},
> +  { "pkcs-5-aes256-CBC-params", 1612709895, NULL },
> +  { NULL, 1048586, "16"},
> +  { "Gost28147-89-Parameters", 1610612741, NULL },
> +  { "iv", 1073741831, NULL },
> +  { "encryptionParamSet", 12, NULL },
> +  { "pkcs-5-PBE-params", 1610612741, NULL },
> +  { "salt", 1073741831, NULL },
> +  { "iterationCount", 3, NULL },
> +  { "pkcs-5-PBES2-params", 1610612741, NULL },
> +  { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
> +  { "encryptionScheme", 2, "AlgorithmIdentifier"},
> +  { "pkcs-5-PBKDF2-params", 1610612741, NULL },
> +  { "salt", 1610612754, NULL },
> +  { "specified", 1073741831, NULL },
> +  { "otherSource", 2, "AlgorithmIdentifier"},
> +  { "iterationCount", 1611137027, NULL },
> +  { "1", 10, "MAX"},
> +  { "keyLength", 1611153411, NULL },
> +  { "1", 10, "MAX"},
> +  { "prf", 16386, "AlgorithmIdentifier"},
> +  { "pkcs-12-PFX", 1610612741, NULL },
> +  { "version", 1610874883, NULL },
> +  { "v3", 1, "3"},
> +  { "authSafe", 1073741826, "pkcs-7-ContentInfo"},
> +  { "macData", 16386, "pkcs-12-MacData"},
> +  { "pkcs-12-PbeParams", 1610612741, NULL },
> +  { "salt", 1073741831, NULL },
> +  { "iterations", 3, NULL },
> +  { "pkcs-12-MacData", 1610612741, NULL },
> +  { "mac", 1073741826, "pkcs-7-DigestInfo"},
> +  { "macSalt", 1073741831, NULL },
> +  { "iterations", 536903683, NULL },
> +  { NULL, 9, "1"},
> +  { "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
> +  { NULL, 2, "pkcs-7-ContentInfo"},
> +  { "pkcs-12-SafeContents", 1610612747, NULL },
> +  { NULL, 2, "pkcs-12-SafeBag"},
> +  { "pkcs-12-SafeBag", 1610612741, NULL },
> +  { "bagId", 1073741836, NULL },
> +  { "bagValue", 1614815245, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "badId", 1, NULL },
> +  { "bagAttributes", 536887311, NULL },
> +  { NULL, 2, "Attribute"},
> +  { "pkcs-12-CertBag", 1610612741, NULL },
> +  { "certId", 1073741836, NULL },
> +  { "certValue", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "certId", 1, NULL },
> +  { "pkcs-12-CRLBag", 1610612741, NULL },
> +  { "crlId", 1073741836, NULL },
> +  { "crlValue", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "crlId", 1, NULL },
> +  { "pkcs-12-SecretBag", 1610612741, NULL },
> +  { "secretTypeId", 1073741836, NULL },
> +  { "secretValue", 541073421, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "secretTypeId", 1, NULL },
> +  { "pkcs-7-Data", 1073741831, NULL },
> +  { "pkcs-7-EncryptedData", 1610612741, NULL },
> +  { "version", 1073741827, NULL },
> +  { "encryptedContentInfo", 1073741826, 
> "pkcs-7-EncryptedContentInfo"},
> +  { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
> +  { NULL, 4104, "1"},
> +  { "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
> +  { "contentType", 1073741836, NULL },
> +  { "contentEncryptionAlgorithm", 1073741826,
> "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
> +  { "encryptedContent", 536895495, NULL },
> +  { NULL, 4104, "0"},
> +  { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826,
> "AlgorithmIdentifier"},
> +  { "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "Attribute"},
> +  { "ProxyCertInfo", 1610612741, NULL },
> +  { "pCPathLenConstraint", 1611153411, NULL },
> +  { "0", 10, "MAX"},
> +  { "proxyPolicy", 2, "ProxyPolicy"},
> +  { "ProxyPolicy", 1610612741, NULL },
> +  { "policyLanguage", 1073741836, NULL },
> +  { "policy", 16391, NULL },
> +  { "certificatePolicies", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "PolicyInformation"},
> +  { "PolicyInformation", 1610612741, NULL },
> +  { "policyIdentifier", 1073741836, NULL },
> +  { "policyQualifiers", 538984459, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "PolicyQualifierInfo"},
> +  { "PolicyQualifierInfo", 1610612741, NULL },
> +  { "policyQualifierId", 1073741836, NULL },
> +  { "qualifier", 541065229, NULL },
> +  { "policyQualifierId", 1, NULL },
> +  { "CPSuri", 1073741853, NULL },
> +  { "UserNotice", 1610612741, NULL },
> +  { "noticeRef", 1073758210, "NoticeReference"},
> +  { "explicitText", 16386, "DisplayText"},
> +  { "NoticeReference", 1610612741, NULL },
> +  { "organization", 1073741826, "DisplayText"},
> +  { "noticeNumbers", 536870923, NULL },
> +  { NULL, 3, NULL },
> +  { "DisplayText", 1610612754, NULL },
> +  { "ia5String", 1612709917, NULL },
> +  { "200", 524298, "1"},
> +  { "visibleString", 1612709923, NULL },
> +  { "200", 524298, "1"},
> +  { "bmpString", 1612709921, NULL },
> +  { "200", 524298, "1"},
> +  { "utf8String", 538968098, NULL },
> +  { "200", 524298, "1"},
> +  { "OCSPRequest", 1610612741, NULL },
> +  { "tbsRequest", 1073741826, "TBSRequest"},
> +  { "optionalSignature", 536895490, "Signature"},
> +  { NULL, 2056, "0"},
> +  { "TBSRequest", 1610612741, NULL },
> +  { "version", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 2056, "0"},
> +  { "requestorName", 1610637314, "GeneralName"},
> +  { NULL, 2056, "1"},
> +  { "requestList", 1610612747, NULL },
> +  { NULL, 2, "Request"},
> +  { "requestExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "2"},
> +  { "Signature", 1610612741, NULL },
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 1073741830, NULL },
> +  { "certs", 536895499, NULL },
> +  { NULL, 1073743880, "0"},
> +  { NULL, 2, "Certificate"},
> +  { "Request", 1610612741, NULL },
> +  { "reqCert", 1073741826, "CertID"},
> +  { "singleRequestExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "0"},
> +  { "CertID", 1610612741, NULL },
> +  { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "issuerNameHash", 1073741831, NULL },
> +  { "issuerKeyHash", 1073741831, NULL },
> +  { "serialNumber", 2, "CertificateSerialNumber"},
> +  { "OCSPResponse", 1610612741, NULL },
> +  { "responseStatus", 1073741826, "OCSPResponseStatus"},
> +  { "responseBytes", 536895490, "ResponseBytes"},
> +  { NULL, 2056, "0"},
> +  { "OCSPResponseStatus", 1610874901, NULL },
> +  { "successful", 1073741825, "0"},
> +  { "malformedRequest", 1073741825, "1"},
> +  { "internalError", 1073741825, "2"},
> +  { "tryLater", 1073741825, "3"},
> +  { "sigRequired", 1073741825, "5"},
> +  { "unauthorized", 1, "6"},
> +  { "ResponseBytes", 1610612741, NULL },
> +  { "responseType", 1073741836, NULL },
> +  { "response", 7, NULL },
> +  { "BasicOCSPResponse", 1610612741, NULL },
> +  { "tbsResponseData", 1073741826, "ResponseData"},
> +  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
> +  { "signature", 1073741830, NULL },
> +  { "certs", 536895499, NULL },
> +  { NULL, 1073743880, "0"},
> +  { NULL, 2, "Certificate"},
> +  { "ResponseData", 1610612741, NULL },
> +  { "version", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 2056, "0"},
> +  { "responderID", 1073741826, "ResponderID"},
> +  { "producedAt", 1073741861, NULL },
> +  { "responses", 1610612747, NULL },
> +  { NULL, 2, "SingleResponse"},
> +  { "responseExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "1"},
> +  { "ResponderID", 1610612754, NULL },
> +  { "byName", 1610620939, NULL },
> +  { NULL, 1073743880, "1"},
> +  { NULL, 2, "RelativeDistinguishedName"},
> +  { "byKey", 536879111, NULL },
> +  { NULL, 2056, "2"},
> +  { "SingleResponse", 1610612741, NULL },
> +  { "certID", 1073741826, "CertID"},
> +  { "certStatus", 1073741826, "CertStatus"},
> +  { "thisUpdate", 1073741861, NULL },
> +  { "nextUpdate", 1610637349, NULL },
> +  { NULL, 2056, "0"},
> +  { "singleExtensions", 536895490, "Extensions"},
> +  { NULL, 2056, "1"},
> +  { "CertStatus", 1610612754, NULL },
> +  { "good", 1610620948, NULL },
> +  { NULL, 4104, "0"},
> +  { "revoked", 1610620930, "RevokedInfo"},
> +  { NULL, 4104, "1"},
> +  { "unknown", 536879106, "UnknownInfo"},
> +  { NULL, 4104, "2"},
> +  { "RevokedInfo", 1610612741, NULL },
> +  { "revocationTime", 1073741861, NULL },
> +  { "revocationReason", 537157653, NULL },
> +  { NULL, 1073743880, "0"},
> +  { "unspecified", 1, "0"},
> +  { "UnknownInfo", 1073741844, NULL },
> +  { "NameConstraints", 1610612741, NULL },
> +  { "permittedSubtrees", 1610637314, "GeneralSubtrees"},
> +  { NULL, 4104, "0"},
> +  { "excludedSubtrees", 536895490, "GeneralSubtrees"},
> +  { NULL, 4104, "1"},
> +  { "GeneralSubtrees", 1612709899, NULL },
> +  { "MAX", 1074266122, "1"},
> +  { NULL, 2, "GeneralSubtree"},
> +  { "GeneralSubtree", 1610612741, NULL },
> +  { "base", 1073741826, "GeneralName"},
> +  { "minimum", 1610653699, NULL },
> +  { NULL, 1073741833, "0"},
> +  { NULL, 4104, "0"},
> +  { "maximum", 536895491, NULL },
> +  { NULL, 4104, "1"},
> +  { "TlsFeatures", 536870923, NULL },
> +  { NULL, 3, NULL },
> +  { NULL, 0, NULL }
> +};

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates
  2024-12-18 14:56 ` [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates Sudhakar Kuppusamy
  2024-12-28 19:46   ` Stefan Berger
@ 2025-01-24 11:10   ` Avnish Chouhan
  2025-02-27 15:31     ` sudhakar
  2025-01-24 11:23   ` Michal Suchánek
  2 siblings, 1 reply; 83+ messages in thread
From: Avnish Chouhan @ 2025-01-24 11:10 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, Javier Martinez Canillas,
	Michal Suchanek, daniel.kiper

Suggestion : It will be good if we can remove the brackets in one liner 
if conditions and loops!

Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> This code allows us to parse:
> 
>  - PKCS#7 signedData messages. Only a single signerInfo is supported,
>    which is all that the Linux sign-file utility supports creating
>    out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
>    Any certificate embedded in the PKCS#7 message will be ignored.
> 
>  - X.509 certificates: at least enough to verify the signatures on the
>    PKCS#7 messages. We expect that the certificates embedded in grub 
> will
>    be leaf certificates, not CA certificates. The parser enforces this.
> 
>  - X.509 certificates support the Extended Key Usage extension and 
> handle
>    it by verifying that the certificate has a single purpose, that is 
> code
>    signing. This is required because Red Hat certificates have both Key
>    Usage and Extended Key Usage extensions present.
> 
> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> # EKU 
> support
> Reported-by: Michal Suchanek <msuchanek@suse.com> # key usage issue
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/appendedsig/appendedsig.h | 110 +++
>  grub-core/commands/appendedsig/asn1util.c    |  99 ++
>  grub-core/commands/appendedsig/pkcs7.c       | 473 +++++++++
>  grub-core/commands/appendedsig/x509.c        | 981 +++++++++++++++++++
>  4 files changed, 1663 insertions(+)
>  create mode 100644 grub-core/commands/appendedsig/appendedsig.h
>  create mode 100644 grub-core/commands/appendedsig/asn1util.c
>  create mode 100644 grub-core/commands/appendedsig/pkcs7.c
>  create mode 100644 grub-core/commands/appendedsig/x509.c
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.h
> b/grub-core/commands/appendedsig/appendedsig.h
> new file mode 100644
> index 000000000..fa59302c8
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/appendedsig.h
> @@ -0,0 +1,110 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/crypto.h>
> +#include <grub/libtasn1.h>
> +
> +extern asn1_node _gnutls_gnutls_asn;
> +extern asn1_node _gnutls_pkix_asn;
> +
> +#define MAX_OID_LEN 32
> +
> +/*
> + * One or more x509 certificates.
> + * We do limited parsing: extracting only the serial, CN and RSA 
> public key.
> + */
> +struct x509_certificate
> +{
> +  struct x509_certificate *next;
> +  grub_uint8_t *serial;
> +  grub_size_t serial_len;
> +  char *subject;
> +  grub_size_t subject_len;
> +  /* We only support RSA public keys. This encodes [modulus, 
> publicExponent] */
> +  gcry_mpi_t mpis[2];
> +};
> +
> +/*
> + * A PKCS#7 signedData signerInfo.
> + */
> +struct pkcs7_signerInfo
> +{
> +  const gcry_md_spec_t *hash;
> +  gcry_mpi_t sig_mpi;
> +};
> +
> +/*
> + * A PKCS#7 signedData message.
> + * We make no attempt to match intelligently, so we don't save any 
> info about
> + * the signer.
> + */
> +struct pkcs7_signedData
> +{
> +  int signerInfo_count;
> +  struct pkcs7_signerInfo *signerInfos;
> +};
> +
> +/* Do libtasn1 init */
> +int
> +asn1_init (void);
> +
> +/*
> + * Import a DER-encoded certificate at 'data', of size 'size'.
> + * Place the results into 'results', which must be already allocated.
> + */
> +grub_err_t
> +parse_x509_certificate (const void *data, grub_size_t size, struct
> x509_certificate *results);
> +
> +/*
> + * Release all the storage associated with the x509 certificate.
> + * If the caller dynamically allocated the certificate, it must free 
> it.
> + * The caller is also responsible for maintenance of the linked list.
> + */
> +void
> +certificate_release (struct x509_certificate *cert);
> +
> +/*
> + * Parse a PKCS#7 message, which must be a signedData message.
> + * The message must be in 'sigbuf' and of size 'data_size'. The result 
> is
> + * placed in 'msg', which must already be allocated.
> + */
> +grub_err_t
> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size,
> struct pkcs7_signedData *msg);
> +
> +/*
> + * Release all the storage associated with the PKCS#7 message.
> + * If the caller dynamically allocated the message, it must free it.
> + */
> +void
> +pkcs7_signedData_release (struct pkcs7_signedData *msg);
> +
> +/*
> + * Read a value from an ASN1 node, allocating memory to store it.
> + * It will work for anything where the size libtasn1 returns is right:
> + *  - Integers
> + *  - Octet strings
> + *  - DER encoding of other structures
> + * It will _not_ work for things where libtasn1 size requires 
> adjustment:
> + *  - Strings that require an extra NULL byte at the end
> + *  - Bit strings because libtasn1 returns the length in bits, not 
> bytes.
> + *
> + * If the function returns a non-NULL value, the caller must free it.
> + */
> +void *
> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const
> char *friendly_name, int *content_size);
> diff --git a/grub-core/commands/appendedsig/asn1util.c
> b/grub-core/commands/appendedsig/asn1util.c
> new file mode 100644
> index 000000000..609d0ecf2
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/asn1util.c
> @@ -0,0 +1,99 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
> +#include <grub/types.h>
> +#include <grub/err.h>
> +#include <grub/mm.h>
> +#include <grub/crypto.h>
> +#include <grub/misc.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +#include "appendedsig.h"
> +
> +asn1_node _gnutls_gnutls_asn = NULL;
> +asn1_node _gnutls_pkix_asn = NULL;
> +
> +extern const asn1_static_node gnutls_asn1_tab[];
> +extern const asn1_static_node pkix_asn1_tab[];
> +
> +/*
> + * Read a value from an ASN1 node, allocating memory to store it.
> + * It will work for anything where the size libtasn1 returns is right:
> + *  - Integers
> + *  - Octet strings
> + *  - DER encoding of other structures
> + * It will _not_ work for things where libtasn1 size requires 
> adjustment:
> + *  - Strings that require an extra NULL byte at the end
> + *  - Bit strings because libtasn1 returns the length in bits, not 
> bytes.
> + * If the function returns a non-NULL value, the caller must free it.
> + */
> +void *
> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const
> char *friendly_name, int *content_size)
> +{
> +  int result;
> +  grub_uint8_t *tmpstr = NULL;
> +  int tmpstr_size = 0;
> +
> +  result = asn1_read_value (node, name, NULL, &tmpstr_size);
> +  if (result != ASN1_MEM_ERROR)
> +    {
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
> +                     _("Reading size of %s did not return expected
> status: %s"),
> +                     friendly_name, asn1_strerror (result));
> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
> +      return NULL;
> +    }
> +
> +  tmpstr = grub_malloc (tmpstr_size);
> +  if (tmpstr == NULL)
> +    {
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
> +                     "Could not allocate memory to store %s", 
> friendly_name);
> +      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
> +      return NULL;
> +    }
> +
> +  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      grub_free (tmpstr);
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error reading 
> %s: %s",
> +                     friendly_name, asn1_strerror (result));
> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
> +      return NULL;
> +    }
> +
> +  *content_size = tmpstr_size;
> +
> +  return tmpstr;
> +}
> +
> +int
> +asn1_init (void)
> +{
> +  int res;
> +  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return res;
> +    }
> +  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
> +  return res;
> +}
> diff --git a/grub-core/commands/appendedsig/pkcs7.c
> b/grub-core/commands/appendedsig/pkcs7.c
> new file mode 100644
> index 000000000..61e560854
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/pkcs7.c
> @@ -0,0 +1,473 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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 "appendedsig.h"
> +#include <grub/misc.h>
> +#include <grub/crypto.h>
> +#include <grub/gcrypt/gcrypt.h>
> +#include <sys/types.h>
> +
> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
> +
> +/*
> + * RFC 5652 s 5.1
> + */
> +static const char *signedData_oid = "1.2.840.113549.1.7.2";
> +
> +/*
> + * RFC 4055 s 2.1
> + */
> +static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
> +static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
> +
> +static grub_err_t
> +process_content (grub_uint8_t *content, int size, struct 
> pkcs7_signedData *msg)
> +{
> +  int res;
> +  asn1_node signed_part;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char algo_oid[MAX_OID_LEN];
> +  int algo_oid_size = sizeof (algo_oid);
> +  int algo_count;
> +  int signer_count;
> +  int i;
> +  char version;
> +  int version_size = sizeof (version);
> +  grub_uint8_t *result_buf;
> +  int result_size = 0;
> +  int crls_size = 0;
> +  gcry_error_t gcry_err;
> +  bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
> +  char *da_path;
> +  char *si_sig_path;
> +  char *si_da_path;
> +
> +  res = asn1_create_element (_gnutls_pkix_asn,
> "PKIX1.pkcs-7-SignedData", &signed_part);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for PKCS#7 
> signed "
> +                         "part.");
> +    }
> +
> +  res = asn1_der_decoding2 (&signed_part, content, &size,
> +                            ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Error reading PKCS#7 signed data: %s", 
> asn1_error);
> +      goto cleanup_signed_part;
> +    }
> +
> +  /*
> +   * SignedData ::= SEQUENCE {
> +   *     version CMSVersion,
> +   *     digestAlgorithms DigestAlgorithmIdentifiers,
> +   *     encapContentInfo EncapsulatedContentInfo,
> +   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
> +   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
> +   *     signerInfos SignerInfos }
> +   */
> +
> +  /* version per the algo in 5.1, must be 1 */
> +  res = asn1_read_value (signed_part, "version", &version, 
> &version_size);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading
> signedData version: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (version != 1)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Unexpected signature version v%d, only v1
> supported", version);
> +      goto cleanup_signed_part;
> +    }
> +
> +  /*
> +   * digestAlgorithms DigestAlgorithmIdentifiers
> +   *
> +   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
> +   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
> +   *
> +   * RFC 4055 s 2.1:
> +   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
> +   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
> +   *
> +   * We only support 1 element in the set, and we do not check 
> parameters atm.
> +   */
> +  res = asn1_number_of_elements (signed_part, "digestAlgorithms", 
> &algo_count);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting
> number of digest algorithms: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (algo_count <= 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "A minimum of 1 digest algorithm is 
> required");
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (algo_count > 2)
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                        "A maximum of 2 digest algorithms are 
> supported");
> +      goto cleanup_signed_part;
> +    }
> +
> +  sha256_in_da = false;
> +  sha512_in_da = false;
> +
> +  for (i = 0; i < algo_count; i++)
> +    {
> +      da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 
> 1);
> +      if (!da_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                            "Could not allocate path for digest 
> algorithm "
> +                            "parsing path");
> +          goto cleanup_signed_part;
> +        }
> +
> +      algo_oid_size = sizeof (algo_oid);
> +      res = asn1_read_value (signed_part, da_path, algo_oid, 
> &algo_oid_size);
> +      if (res != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading
> digest algorithm: %s",
> +                            asn1_strerror (res));
> +          grub_free (da_path);
> +          goto cleanup_signed_part;
> +        }
> +
> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha512_in_da)
> +            {
> +              sha512_in_da = true;
> +            }
> +          else
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                                "SHA-512 specified twice in digest 
> algorithm "
> +                                "list");
> +              grub_free (da_path);
> +              goto cleanup_signed_part;
> +            }
> +        }
> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 
> 0)
> +        {
> +          if (!sha256_in_da)
> +            {
> +              sha256_in_da = true;
> +            }
> +          else
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                                "SHA-256 specified twice in digest 
> algorithm "
> +                                "list");
> +              grub_free (da_path);
> +              goto cleanup_signed_part;
> +            }
> +        }
> +      else
> +        {
> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only
> SHA-256 and SHA-512 hashes are supported, found OID %s",
> +                            algo_oid);
> +          grub_free (da_path);
> +          goto cleanup_signed_part;
> +        }
> +
> +      grub_free (da_path);
> +    }
> +
> +  /* at this point, at least one of sha{256,512}_in_da must be true */
> +
> +  /*
> +   * We ignore the certificates, but we don't permit CRLs.
> +   * A CRL entry might be revoking the certificate we're using, and we 
> have
> +   * no way of dealing with that at the moment.
> +   */
> +  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
> +  if (res != ASN1_ELEMENT_NOT_FOUND)
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                        "PKCS#7 messages with embedded CRLs are not
> supported");
> +      goto cleanup_signed_part;
> +    }
> +
> +  /* read the signatures */
> +
> +  res = asn1_number_of_elements (signed_part, "signerInfos", 
> &signer_count);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting
> number of signers: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (signer_count <= 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "A minimum of 1 signer is required");
> +      goto cleanup_signed_part;
> +    }
> +
> +  msg->signerInfos = grub_calloc (signer_count, sizeof (struct
> pkcs7_signerInfo));
> +  if (!msg->signerInfos)
> +    {
> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                        "Could not allocate space for %d signers",
> signer_count);
> +      goto cleanup_signed_part;
> +    }
> +
> +  msg->signerInfo_count = 0;
> +  for (i = 0; i < signer_count; i++)
> +    {
> +      si_da_path = grub_xasprintf
> ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
> +      if (!si_da_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
> allocate path for signer %d's digest algorithm parsing path",
> +                            i);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      algo_oid_size = sizeof (algo_oid);
> +      res = asn1_read_value (signed_part, si_da_path, algo_oid,
> &algo_oid_size);
> +      if (res != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Error reading signer %d's digest
> algorithm: %s", i,
> +                            asn1_strerror (res));
> +          grub_free (si_da_path);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      grub_free (si_da_path);
> +
> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha512_in_da)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d
> claims a SHA-512 signature "
> +                                "which was not specified in the outer
> DigestAlgorithms", i);
> +              goto cleanup_signerInfos;
> +            }
> +          else
> +            {
> +              sha512_in_si = true;
> +              msg->signerInfos[i].hash =
> +                      grub_crypto_lookup_md_by_name ("sha512");
> +            }
> +        }
> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 
> 0)
> +        {
> +          if (!sha256_in_da)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d
> claims a SHA-256 signature "
> +                                "which was not specified in the outer
> DigestAlgorithms", i);
> +              goto cleanup_signerInfos;
> +            }
> +          else
> +            {
> +              sha256_in_si = true;
> +              msg->signerInfos[i].hash =
> +                      grub_crypto_lookup_md_by_name ("sha256");
> +            }
> +        }
> +      else
> +        {
> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                            "Only SHA-256 and SHA-512 hashes are
> supported, found OID %s",
> +                            algo_oid);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      if (!msg->signerInfos[i].hash)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Hash algorithm for signer %d (OID %s)
> not loaded", i, algo_oid);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 
> 1);
> +      if (!si_sig_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                            "Could not allocate path for signer %d's
> signature parsing path", i);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      result_buf = grub_asn1_allocate_and_read (signed_part, 
> si_sig_path,
> +                                                "signature data",
> &result_size);
> +      grub_free (si_sig_path);
> +
> +      if (!result_buf)
> +        {
> +          err = grub_errno;
> +          goto cleanup_signerInfos;
> +        }
> +
> +      gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi),
> GCRYMPI_FMT_USG,
> +                                result_buf, result_size, NULL);
> +
> +      grub_free (result_buf);
> +
> +      if (gcry_err != GPG_ERR_NO_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Error loading signature %d into MPI
> structure: %d",
> +                            i, gcry_err);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      /*
> +       * use msg->signerInfo_count to track fully populated 
> signerInfos so we
> +       * know how many we need to clean up
> +       */
> +      msg->signerInfo_count++;
> +    }
> +
> +  /*
> +   * Final consistency check of signerInfo.*.digestAlgorithm vs
> +   * digestAlgorithms.*.algorithm. An algorithm must be present in 
> both
> +   * digestAlgorithms and signerInfo or in neither. We have already 
> checked
> +   * for an algorithm in signerInfo that is not in digestAlgorithms, 
> here we
> +   * check for algorithms in digestAlgorithms but not in signerInfos.
> +   */
> +  if (sha512_in_da && !sha512_in_si)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "SHA-512 specified in DigestAlgorithms but did 
> not "
> +                        "appear in SignerInfos");
> +      goto cleanup_signerInfos;
> +    }
> +
> +  if (sha256_in_da && !sha256_in_si)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "SHA-256 specified in DigestAlgorithms but did 
> not "
> +                        "appear in SignerInfos");
> +      goto cleanup_signerInfos;
> +    }
> +
> +  asn1_delete_structure (&signed_part);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_signerInfos:
> +  for (i = 0; i < msg->signerInfo_count; i++)
> +    gcry_mpi_release (msg->signerInfos[i].sig_mpi);
> +  grub_free (msg->signerInfos);
> +cleanup_signed_part:
> +  asn1_delete_structure (&signed_part);
> +  return err;
> +}
> +
> +grub_err_t
> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size,
> struct pkcs7_signedData *msg)
> +{
> +  int res;
> +  asn1_node content_info;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char content_oid[MAX_OID_LEN];
> +  grub_uint8_t *content;
> +  int content_size;
> +  int content_oid_size = sizeof (content_oid);
> +  int size;
> +
> +  if (data_size > GRUB_INT_MAX)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 
> message "
> +                                              "where data size > 
> INT_MAX");
> +  size = (int) data_size;
> +
> +  res = asn1_create_element (_gnutls_pkix_asn,
> "PKIX1.pkcs-7-ContentInfo", &content_info);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for PKCS#7
> data: %s",
> +                         asn1_strerror (res));
> +    }
> +
> +  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
> +                            ASN1_DECODE_FLAG_STRICT_DER |
> ASN1_DECODE_FLAG_ALLOW_PADDING,
> +                            asn1_error);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Error decoding PKCS#7 message DER: %s", 
> asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * ContentInfo ::= SEQUENCE {
> +   *     contentType ContentType,
> +   *     content [0] EXPLICIT ANY DEFINED BY contentType }
> +   *
> +   * ContentType ::= OBJECT IDENTIFIER
> +   */
> +  res = asn1_read_value (content_info, "contentType", content_oid,
> &content_oid_size);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7
> content type: %s",
> +                        asn1_strerror (res));
> +      goto cleanup;
> +    }
> +
> +  /* OID for SignedData defined in 5.1 */
> +  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 
> 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Unexpected content type in PKCS#7 message:
> OID %s", content_oid);
> +      goto cleanup;
> +    }
> +
> +  content = grub_asn1_allocate_and_read (content_info, "content",
> +                                         "PKCS#7 message content",
> &content_size);
> +  if (!content)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  err = process_content (content, content_size, msg);
> +  grub_free (content);
> +
> +cleanup:
> +  asn1_delete_structure (&content_info);
> +  return err;
> +}
> +
> +/*
> + * Release all the storage associated with the PKCS#7 message.
> + * If the caller dynamically allocated the message, it must free it.
> + */
> +void
> +pkcs7_signedData_release (struct pkcs7_signedData *msg)
> +{
> +  grub_ssize_t i;
> +
> +  for (i = 0; i < msg->signerInfo_count; i++)
> +    {
> +      gcry_mpi_release (msg->signerInfos[i].sig_mpi);
> +    }
> +  grub_free (msg->signerInfos);
> +}
> diff --git a/grub-core/commands/appendedsig/x509.c
> b/grub-core/commands/appendedsig/x509.c
> new file mode 100644
> index 000000000..eb9a1ca0f
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/x509.c
> @@ -0,0 +1,981 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
> +#include <grub/types.h>
> +#include <grub/err.h>
> +#include <grub/mm.h>
> +#include <grub/crypto.h>
> +#include <grub/misc.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +#include "appendedsig.h"
> +
> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
> +
> +/*
> + * RFC 3279 2.3.1  RSA Keys
> + */
> +static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
> +
> +/*
> + * RFC 5280 Appendix A
> + */
> +static const char *commonName_oid = "2.5.4.3";
> +
> +/*
> + * RFC 5280 4.2.1.3 Key Usage
> + */
> +static const char *keyUsage_oid = "2.5.29.15";
> +
> +static const grub_uint8_t digitalSignatureUsage = 0x80;
> +
> +/*
> + * RFC 5280 4.2.1.9 Basic Constraints
> + */
> +static const char *basicConstraints_oid = "2.5.29.19";
> +
> +/*
> + * RFC 5280 4.2.1.12 Extended Key Usage
> + */
> +static const char *extendedKeyUsage_oid = "2.5.29.37";
> +static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
> +
> +/*
> + * RFC 3279 2.3.1
> + *
> + *  The RSA public key MUST be encoded using the ASN.1 type 
> RSAPublicKey:
> + *
> + *     RSAPublicKey ::= SEQUENCE {
> + *        modulus            INTEGER,    -- n
> + *        publicExponent     INTEGER  }  -- e
> + *
> + *  where modulus is the modulus n, and publicExponent is the public
> + *  exponent e.
> + */
> +static grub_err_t
> +grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct
> x509_certificate *certificate)
> +{
> +  int result;
> +  asn1_node spk = NULL;
> +  grub_uint8_t *m_data, *e_data;
> +  int m_size, e_size;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  gcry_error_t gcry_err;
> +
> +  result = asn1_create_element (_gnutls_gnutls_asn,
> "GNUTLS.RSAPublicKey", &spk);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Cannot create storage for public key ASN.1 
> data");
> +    }
> +
> +  result = asn1_der_decoding2 (&spk, der, &dersize,
> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Cannot decode certificate public key DER:
> %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA
> modulus", &m_size);
> +  if (!m_data)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  e_data = grub_asn1_allocate_and_read (spk, "publicExponent",
> +                                        "RSA public exponent", 
> &e_size);
> +  if (!e_data)
> +    {
> +      err = grub_errno;
> +      goto cleanup_m_data;
> +    }
> +
> +  /*
> +   * convert m, e to mpi
> +   *
> +   * nscanned is not set for FMT_USG, it's only set for FMT_PGP,
> +   * so we can't verify it
> +   */
> +  gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG,
> m_data, m_size, NULL);
> +  if (gcry_err != GPG_ERR_NO_ERROR)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error loading RSA modulus into MPI
> structure: %d", gcry_err);
> +      goto cleanup_e_data;
> +    }
> +
> +  gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG,
> e_data, e_size, NULL);
> +  if (gcry_err != GPG_ERR_NO_ERROR)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error loading RSA exponent into MPI
> structure: %d", gcry_err);
> +      goto cleanup_m_mpi;
> +    }
> +
> +  grub_free (e_data);
> +  grub_free (m_data);
> +  asn1_delete_structure (&spk);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_m_mpi:
> +  gcry_mpi_release (certificate->mpis[0]);
> +cleanup_e_data:
> +  grub_free (e_data);
> +cleanup_m_data:
> +  grub_free (m_data);
> +cleanup:
> +  asn1_delete_structure (&spk);
> +  return err;
> +}
> +
> +/*
> + * RFC 5280:
> + *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
> + *       algorithm            AlgorithmIdentifier,
> + *       subjectPublicKey     BIT STRING  }
> + *
> + * AlgorithmIdentifiers come from RFC 3279, we are not strictly 
> compilant as we
> + * only support RSA Encryption.
> + */
> +
> +static grub_err_t
> +grub_x509_read_subject_public_key (asn1_node asn, struct
> x509_certificate *results)
> +{
> +  int result;
> +  grub_err_t err;
> +  const char *algo_name =
> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
> +  const char *params_name =
> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
> +  const char *pk_name = 
> "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
> +  char algo_oid[MAX_OID_LEN];
> +  int algo_size = sizeof (algo_oid);
> +  char params_value[2];
> +  int params_size = sizeof (params_value);
> +  grub_uint8_t *key_data = NULL;
> +  int key_size = 0;
> +  unsigned int key_type;
> +
> +  /* algorithm: see notes for rsaEncryption_oid */
> +  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509
> public key algorithm: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof
> (rsaEncryption_oid)) != 0)
> +    {
> +      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                         "Unsupported x509 public key algorithm: %s",
> algo_oid);
> +    }
> +
> +  /*
> +   * RFC 3279 2.3.1
> +   * The rsaEncryption OID is intended to be used in the algorithm 
> field
> +   * of a value of type AlgorithmIdentifier.  The parameters field 
> MUST
> +   * have ASN.1 type NULL for this algorithm identifier.
> +   */
> +  result = asn1_read_value (asn, params_name, params_value, 
> &params_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509
> public key parameters: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (params_value[0] != ASN1_TAG_NULL)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                         "Invalid x509 public key parameters: expected 
> NULL");
> +    }
> +
> +  /*
> +   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of the 
> BIT
> +   * STRING subjectPublicKey.
> +   */
> +  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, 
> &key_type);
> +  if (result != ASN1_MEM_ERROR)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size
> of x509 public key: %s",
> +                         asn1_strerror (result));
> +    }
> +  if (key_type != ASN1_ETYPE_BIT_STRING)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1
> type when reading x509 public key: %x",
> +                         key_type);
> +    }
> +
> +  /* length is in bits */
> +  key_size = (key_size + 7) / 8;
> +
> +  key_data = grub_malloc (key_size);
> +  if (!key_data)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Out of memory for x509 public key");
> +    }
> +
> +  result = asn1_read_value (asn, pk_name, key_data, &key_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      grub_free (key_data);
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                         "Error reading public key data");
> +    }
> +  key_size = (key_size + 7) / 8;
> +
> +  err = grub_parse_rsa_pubkey (key_data, key_size, results);
> +  grub_free (key_data);
> +
> +  return err;
> +}
> +
> +/* Decode a string as defined in Appendix A */
> +static grub_err_t
> +decode_string (char *der, int der_size, char **string, grub_size_t
> *string_size)
> +{
> +  asn1_node strasn;
> +  int result;
> +  char *choice;
> +  int choice_size = 0;
> +  int tmp_size = 0;
> +  grub_err_t err = GRUB_ERR_NONE;
> +
> +  result = asn1_create_element (_gnutls_pkix_asn,
> "PKIX1.DirectoryString", &strasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for
> certificate: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  result = asn1_der_decoding2 (&strasn, der, &der_size,
> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Could not parse DER for DirectoryString:
> %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString
> choice", &choice_size);
> +  if (!choice)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  if (grub_strncmp ("utf8String", choice, choice_size) == 0)
> +    {
> +      result = asn1_read_value (strasn, "utf8String", NULL, 
> &tmp_size);
> +      if (result != ASN1_MEM_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
> size of UTF-8 string: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_choice;
> +        }
> +    }
> +  else if (grub_strncmp ("printableString", choice, choice_size) == 0)
> +    {
> +      result = asn1_read_value (strasn, "printableString", NULL, 
> &tmp_size);
> +      if (result != ASN1_MEM_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
> size of UTF-8 string: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_choice;
> +        }
> +    }
> +  else
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and
> printable DirectoryStrings are supported, got %s",
> +                        choice);
> +      goto cleanup_choice;
> +    }
> +
> +  /* read size does not include trailing null */
> +  tmp_size++;
> +
> +  *string = grub_malloc (tmp_size);
> +  if (!*string)
> +    {
> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                        "Cannot allocate memory for DirectoryString 
> contents");
> +      goto cleanup_choice;
> +    }
> +
> +  result = asn1_read_value (strasn, choice, *string, &tmp_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s
> in DirectoryString: %s",
> +                        choice, asn1_strerror (result));
> +      grub_free (*string);
> +      goto cleanup_choice;
> +    }
> +  *string_size = tmp_size + 1;
> +  (*string)[tmp_size] = '\0';
> +
> +cleanup_choice:
> +  grub_free (choice);
> +cleanup:
> +  asn1_delete_structure (&strasn);
> +  return err;
> +}
> +
> +/*
> + * TBSCertificate  ::=  SEQUENCE  {
> + *       version         [0]  EXPLICIT Version DEFAULT v1,
> + * ...
> + *
> + * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
> + */
> +static grub_err_t
> +check_version (asn1_node certificate)
> +{
> +  int rc;
> +  const char *name = "tbsCertificate.version";
> +  grub_uint8_t version;
> +  int len = sizeof (version);
> +
> +  rc = asn1_read_value (certificate, name, &version, &len);
> +
> +  /* require version 3 */
> +  if (rc != ASN1_SUCCESS || len != 1)
> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                       "Error reading certificate version");
> +
> +  if (version != 0x02)
> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509
> certificate version, expected v3 (0x02), got 0x%02x",
> +                       version);
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * This is an X.501 Name, which is complex.
> + *
> + * For simplicity, we extract only the CN.
> + */
> +static grub_err_t
> +read_name (asn1_node asn, const char *name_path, char **name,
> grub_size_t *name_size)
> +{
> +  int seq_components, set_components;
> +  int result;
> +  int i, j;
> +  char *top_path, *set_path, *type_path, *val_path;
> +  char type[MAX_OID_LEN];
> +  int type_len = sizeof (type);
> +  int string_size = 0;
> +  char *string_der;
> +  grub_err_t err;
> +
> +  *name = NULL;
> +
> +  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
> +  if (!top_path)
> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                       "Could not allocate memory for %s name parsing
> path", name_path);
> +
> +  result = asn1_number_of_elements (asn, top_path, &seq_components);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name
> components: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  for (i = 1; i <= seq_components; i++)
> +    {
> +      set_path = grub_xasprintf ("%s.?%d", top_path, i);
> +      if (!set_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
> allocate memory for %s name set parsing path",
> +                            name_path);
> +          goto cleanup_set;
> +        }
> +      /* this brings us, hopefully, to a set */
> +      result = asn1_number_of_elements (asn, set_path, 
> &set_components);
> +      if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting
> name sub-components components (element %d): %s",
> +                            i, asn1_strerror (result));
> +          goto cleanup_set;
> +        }
> +      for (j = 1; j <= set_components; j++)
> +        {
> +          type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, 
> j);
> +          if (!type_path)
> +            {
> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
> allocate memory for %s name component type path",
> +                                name_path);
> +              goto cleanup_set;
> +            }
> +          type_len = sizeof (type);
> +          result = asn1_read_value (asn, type_path, type, &type_len);
> +          if (result != ASN1_SUCCESS)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error
> reading %s name component type: %s",
> +                                name_path, asn1_strerror (result));
> +              goto cleanup_type;
> +            }
> +
> +          if (grub_strncmp (type, commonName_oid, type_len) != 0)
> +            {
> +              grub_free (type_path);
> +              continue;
> +            }
> +
> +          val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, 
> j);
> +          if (!val_path)
> +            {
> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
> allocate memory for %s name component value path",
> +                                name_path);
> +              goto cleanup_set;
> +            }
> +
> +          string_der = grub_asn1_allocate_and_read (asn, val_path,
> name_path, &string_size);
> +          if (!string_der)
> +            {
> +              err = grub_errno;
> +              goto cleanup_val_path;
> +            }
> +
> +          err = decode_string (string_der, string_size, name, 
> name_size);
> +          if (err)
> +            goto cleanup_string;
> +
> +          grub_free (string_der);
> +          grub_free (type_path);
> +          grub_free (val_path);
> +          break;
> +        }
> +      grub_free (set_path);
> +
> +      if (*name)
> +        break;
> +    }
> +
> +  grub_free (top_path);
> +
> +  return GRUB_ERR_NONE;
> +
> +cleanup_string:
> +  grub_free (string_der);
> +cleanup_val_path:
> +  grub_free (val_path);
> +cleanup_type:
> +  grub_free (type_path);
> +cleanup_set:
> +  grub_free (set_path);
> +cleanup:
> +  grub_free (top_path);
> +  return err;
> +}
> +
> +/*
> + * Verify the Key Usage extension.
> + * We require the Digital signature usage.
> + */
> +static grub_err_t
> +verify_key_usage (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node usageasn;
> +  int result;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  grub_uint8_t usage = 0xff;
> +  int usage_size = sizeof (usage_size);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", 
> &usageasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for key 
> usage");
> +    }
> +
> +  result = asn1_der_decoding2 (&usageasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, 
> asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Key Usage: %s", 
> asn1_error);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (usageasn, "", &usage, &usage_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key
> Usage value: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (!(usage & digitalSignatureUsage))
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Key Usage (0x%x) missing Digital Signature
> usage", usage);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&usageasn);
> +  return err;
> +}
> +
> +/*
> + * BasicConstraints ::= SEQUENCE {
> + *       cA                      BOOLEAN DEFAULT FALSE,
> + *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
> + */
> +static grub_err_t
> +verify_basic_constraints (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node basicasn;
> +  int result;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char cA[6]; /* FALSE or TRUE */
> +  int cA_size = sizeof (cA);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn,
> "PKIX1.BasicConstraints", &basicasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for Basic "
> +                         "Constraints");
> +    }
> +
> +  result = asn1_der_decoding2 (&basicasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, 
> asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Basic Constraints:
> %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
> +  if (result == ASN1_ELEMENT_NOT_FOUND)
> +    {
> +      /* Not present, default is False, so this is OK */
> +      err = GRUB_ERR_NONE;
> +      goto cleanup;
> +    }
> +  else if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic
> Constraints cA value: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  /* The certificate must not be a CA certificate */
> +  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: 
> %s", cA);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&basicasn);
> +  return err;
> +}
> +
> +/*
> + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
> + *
> + * KeyPurposeId ::= OBJECT IDENTIFIER
> + */
> +static grub_err_t
> +verify_extended_key_usage (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node extendedasn;
> +  int result, count;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char usage[MAX_OID_LEN];
> +  int usage_size = sizeof (usage);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn,
> "PKIX1.ExtKeyUsageSyntax", &extendedasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for 
> Extended Key "
> +                         "Usage");
> +    }
> +
> +  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, 
> asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Extended Key Usage:
> %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * If EKUs are present, there must be exactly 1 usage and it must be 
> a
> +   * codeSigning usage. (If we get to this point, we are parsing an 
> EKU
> +   * extension and therefore must have a usage. The code that makes 
> having an
> +   * EKU extension optional is in verify_extensions.)
> +   */
> +  result = asn1_number_of_elements (extendedasn, "", &count);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting
> number of Extended Key Usages: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (count != 1)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of
> Extended Key Usages: %d, 1 expected",
> +                        count);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
> Extended Key Usage: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Unexpected Extended Key Usage OID, got: %s", 
> usage);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&extendedasn);
> +  return err;
> +}
> +
> +/*
> + * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
> + *
> + * Extension  ::=  SEQUENCE  {
> + *      extnID      OBJECT IDENTIFIER,
> + *      critical    BOOLEAN DEFAULT FALSE,
> + *      extnValue   OCTET STRING
> + *                  -- contains the DER encoding of an ASN.1 value
> + *                  -- corresponding to the extension type identified
> + *                  -- by extnID
> + * }
> + *
> + * A certificate must:
> + *  - contain the Digital Signature usage only
> + *  - not be a CA
> + *  - contain no extended usages, or only a code signing extended 
> usage
> + *  - not contain any other critical extensions (RFC 5280 s 4.2)
> + */
> +static grub_err_t
> +verify_extensions (asn1_node cert)
> +{
> +  int result;
> +  int ext, num_extensions = 0;
> +  int usage_present = 0, constraints_present = 0, 
> extended_usage_present = 0;
> +  char *oid_path, *critical_path, *value_path;
> +  char extnID[MAX_OID_LEN];
> +  int extnID_size;
> +  grub_err_t err;
> +  char critical[6]; /* we get either "TRUE" or "FALSE" */
> +  int critical_size;
> +  grub_uint8_t *value;
> +  int value_size;
> +
> +  result = asn1_number_of_elements (cert,
> "tbsCertificate.extensions", &num_extensions);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting
> number of extensions: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (num_extensions < 2)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Insufficient number
> of extensions for "
> +                         "certificate, need at least 2, got %d",
> +                         num_extensions);
> +    }
> +
> +  for (ext = 1; ext <= num_extensions; ext++)
> +    {
> +      oid_path = grub_xasprintf 
> ("tbsCertificate.extensions.?%d.extnID", ext);
> +
> +      extnID_size = sizeof (extnID);
> +      result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
> +      if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
> extension OID: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_oid_path;
> +        }
> +
> +      critical_path = grub_xasprintf
> ("tbsCertificate.extensions.?%d.critical", ext);
> +      critical_size = sizeof (critical);
> +      result = asn1_read_value (cert, critical_path, critical, 
> &critical_size);
> +      if (result == ASN1_ELEMENT_NOT_FOUND)
> +        {
> +          critical[0] = '\0';
> +        }
> +      else if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
> extension criticality: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_critical_path;
> +        }
> +
> +      value_path = grub_xasprintf
> ("tbsCertificate.extensions.?%d.extnValue", ext);
> +      value = grub_asn1_allocate_and_read (cert, value_path,
> +                                           "certificate extension
> value", &value_size);
> +      if (!value)
> +        {
> +          err = grub_errno;
> +          goto cleanup_value_path;
> +        }
> +
> +      /*
> +       * Now we must see if we recognise the OID.
> +       * If we have an unrecognised critical extension we MUST bail.
> +       */
> +      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_key_usage (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          usage_present++;
> +        }
> +      else if (grub_strncmp (basicConstraints_oid, extnID, 
> extnID_size) == 0)
> +        {
> +          err = verify_basic_constraints (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          constraints_present++;
> +        }
> +      else if (grub_strncmp (extendedKeyUsage_oid, extnID, 
> extnID_size) == 0)
> +        {
> +          err = verify_extended_key_usage (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          extended_usage_present++;
> +        }
> +      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
> +        {
> +          /*
> +           * per the RFC, we must not process a certificate with
> +           * a critical extension we do not understand.
> +           */
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                            "Unhandled critical x509 extension with
> OID %s", extnID);
> +          goto cleanup_value;
> +        }
> +
> +      grub_free (value);
> +      grub_free (value_path);
> +      grub_free (critical_path);
> +      grub_free (oid_path);
> +    }
> +
> +  if (usage_present != 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number
> of Key Usage extensions "
> +                         "- expected 1, got %d", usage_present);
> +    }
> +  if (constraints_present != 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number
> of basic constraints extensions "
> +                         "- expected 1, got %d", constraints_present);
> +    }
> +  if (extended_usage_present > 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number
> of Extended Key Usage extensions "
> +                         "- expected 0 or 1, got %d", 
> extended_usage_present);
> +    }
> +  return GRUB_ERR_NONE;
> +
> +cleanup_value:
> +  grub_free (value);
> +cleanup_value_path:
> +  grub_free (value_path);
> +cleanup_critical_path:
> +  grub_free (critical_path);
> +cleanup_oid_path:
> +  grub_free (oid_path);
> +  return err;
> +}
> +
> +/*
> + * Parse a certificate whose DER-encoded form is in @data, of size 
> @data_size.
> + * Return the results in @results, which must point to an allocated
> x509 certificate.
> + */
> +grub_err_t
> +parse_x509_certificate (const void *data, grub_size_t data_size,
> struct x509_certificate *results)
> +{
> +  int result = 0;
> +  asn1_node cert;
> +  grub_err_t err;
> +  int size;
> +  int tmp_size;
> +
> +  if (data_size > GRUB_INT_MAX)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE,
> +                       "Cannot parse a certificate where data size > 
> INT_MAX");
> +  size = (int) data_size;
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", 
> &cert);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for
> certificate: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  result = asn1_der_decoding2 (&cert, data, &size,
> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Could not parse DER for certificate: %s", 
> asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE {
> +   *     version         [0]  EXPLICIT Version DEFAULT v1
> +   */
> +  err = check_version (cert);
> +  if (err != GRUB_ERR_NONE)
> +    {
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * serialNumber         CertificateSerialNumber,
> +   *
> +   * CertificateSerialNumber  ::=  INTEGER
> +   */
> +  results->serial = grub_asn1_allocate_and_read (cert,
> "tbsCertificate.serialNumber",
> +                                                 "certificate serial
> number", &tmp_size);
> +  if (!results->serial)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +  /*
> +   * It's safe to cast the signed int to an unsigned here, we know
> +   * length is non-negative
> +   */
> +  results->serial_len = tmp_size;
> +
> +  /*
> +   * signature            AlgorithmIdentifier,
> +   *
> +   * We don't load the signature or issuer at the moment,
> +   * as we don't attempt x509 verification.
> +   */
> +
> +  /*
> +   * issuer               Name,
> +   *
> +   * The RFC only requires the serial number to be unique within
> +   * issuers, so to avoid ambiguity we _technically_ ought to make
> +   * this available.
> +   */
> +
> +  /*
> +   * validity             Validity,
> +   *
> +   * Validity ::= SEQUENCE {
> +   *     notBefore      Time,
> +   *     notAfter       Time }
> +   *
> +   * We can't validate this reasonably, we have no true time source on 
> several
> +   * platforms. For now we do not parse them.
> +   */
> +
> +  /*
> +   * subject              Name,
> +   *
> +   * This is an X501 name, we parse out just the CN.
> +   */
> +  err = read_name (cert, "tbsCertificate.subject", &results->subject,
> &results->subject_len);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_serial;
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE  {
> +   *    ...
> +   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
> +   *    ...
> +   */
> +  err = grub_x509_read_subject_public_key (cert, results);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_name;
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE  {
> +   *    ...
> +   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
> +   *                         -- If present, version MUST be v3
> +   * }
> +   */
> +
> +  err = verify_extensions (cert);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_mpis;
> +
> +  /*
> +   * We do not read or check the signature on the certificate:
> +   * as discussed we do not try to validate the certificate but trust
> +   * it implictly.
> +   */
> +
> +  asn1_delete_structure (&cert);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_mpis:
> +  gcry_mpi_release (results->mpis[0]);
> +  gcry_mpi_release (results->mpis[1]);
> +cleanup_name:
> +  grub_free (results->subject);
> +cleanup_serial:
> +  grub_free (results->serial);
> +cleanup:
> +  asn1_delete_structure (&cert);
> +  return err;
> +}
> +
> +/*
> + * Release all the storage associated with the x509 certificate.
> + * If the caller dynamically allocated the certificate, it must free 
> it.
> + * The caller is also responsible for maintenance of the linked list.
> + */
> +void
> +certificate_release (struct x509_certificate *cert)
> +{
> +  grub_free (cert->subject);
> +  grub_free (cert->serial);
> +  gcry_mpi_release (cert->mpis[0]);
> +  gcry_mpi_release (cert->mpis[1]);
> +}

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates
  2024-12-18 14:56 ` [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates Sudhakar Kuppusamy
  2024-12-28 19:46   ` Stefan Berger
  2025-01-24 11:10   ` Avnish Chouhan
@ 2025-01-24 11:23   ` Michal Suchánek
  2 siblings, 0 replies; 83+ messages in thread
From: Michal Suchánek @ 2025-01-24 11:23 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, avnish, nayna, ssrish, Javier Martinez Canillas

Hello,

On Wed, Dec 18, 2024 at 08:26:35PM +0530, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> This code allows us to parse:
> 
>  - PKCS#7 signedData messages. Only a single signerInfo is supported,
>    which is all that the Linux sign-file utility supports creating
>    out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
>    Any certificate embedded in the PKCS#7 message will be ignored.
> 
>  - X.509 certificates: at least enough to verify the signatures on the
>    PKCS#7 messages. We expect that the certificates embedded in grub will
>    be leaf certificates, not CA certificates. The parser enforces this.
> 
>  - X.509 certificates support the Extended Key Usage extension and handle
>    it by verifying that the certificate has a single purpose, that is code
>    signing. This is required because Red Hat certificates have both Key

This is needless hardcoding of policy into what's supposed to be genral
purpose code.

It might be good idea to allow only code signing with a certificate, and
not other purposes. However, that's a policy that the administrator
should decide, not the OS code.

The OS code should check that the purpose for which it is using the key
is allowed, not that other purposes are disalllowd.

Thanks

Michal

>    Usage and Extended Key Usage extensions present.
> 
> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> # EKU support
> Reported-by: Michal Suchanek <msuchanek@suse.com> # key usage issue
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/appendedsig/appendedsig.h | 110 +++
>  grub-core/commands/appendedsig/asn1util.c    |  99 ++
>  grub-core/commands/appendedsig/pkcs7.c       | 473 +++++++++
>  grub-core/commands/appendedsig/x509.c        | 981 +++++++++++++++++++
>  4 files changed, 1663 insertions(+)
>  create mode 100644 grub-core/commands/appendedsig/appendedsig.h
>  create mode 100644 grub-core/commands/appendedsig/asn1util.c
>  create mode 100644 grub-core/commands/appendedsig/pkcs7.c
>  create mode 100644 grub-core/commands/appendedsig/x509.c
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
> new file mode 100644
> index 000000000..fa59302c8
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/appendedsig.h
> @@ -0,0 +1,110 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/crypto.h>
> +#include <grub/libtasn1.h>
> +
> +extern asn1_node _gnutls_gnutls_asn;
> +extern asn1_node _gnutls_pkix_asn;
> +
> +#define MAX_OID_LEN 32
> +
> +/*
> + * One or more x509 certificates.
> + * We do limited parsing: extracting only the serial, CN and RSA public key.
> + */
> +struct x509_certificate
> +{
> +  struct x509_certificate *next;
> +  grub_uint8_t *serial;
> +  grub_size_t serial_len;
> +  char *subject;
> +  grub_size_t subject_len;
> +  /* We only support RSA public keys. This encodes [modulus, publicExponent] */
> +  gcry_mpi_t mpis[2];
> +};
> +
> +/*
> + * A PKCS#7 signedData signerInfo.
> + */
> +struct pkcs7_signerInfo
> +{
> +  const gcry_md_spec_t *hash;
> +  gcry_mpi_t sig_mpi;
> +};
> +
> +/*
> + * A PKCS#7 signedData message.
> + * We make no attempt to match intelligently, so we don't save any info about
> + * the signer.
> + */
> +struct pkcs7_signedData
> +{
> +  int signerInfo_count;
> +  struct pkcs7_signerInfo *signerInfos;
> +};
> +
> +/* Do libtasn1 init */
> +int
> +asn1_init (void);
> +
> +/*
> + * Import a DER-encoded certificate at 'data', of size 'size'.
> + * Place the results into 'results', which must be already allocated.
> + */
> +grub_err_t
> +parse_x509_certificate (const void *data, grub_size_t size, struct x509_certificate *results);
> +
> +/*
> + * Release all the storage associated with the x509 certificate.
> + * If the caller dynamically allocated the certificate, it must free it.
> + * The caller is also responsible for maintenance of the linked list.
> + */
> +void
> +certificate_release (struct x509_certificate *cert);
> +
> +/*
> + * Parse a PKCS#7 message, which must be a signedData message.
> + * The message must be in 'sigbuf' and of size 'data_size'. The result is
> + * placed in 'msg', which must already be allocated.
> + */
> +grub_err_t
> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg);
> +
> +/*
> + * Release all the storage associated with the PKCS#7 message.
> + * If the caller dynamically allocated the message, it must free it.
> + */
> +void
> +pkcs7_signedData_release (struct pkcs7_signedData *msg);
> +
> +/*
> + * Read a value from an ASN1 node, allocating memory to store it.
> + * It will work for anything where the size libtasn1 returns is right:
> + *  - Integers
> + *  - Octet strings
> + *  - DER encoding of other structures
> + * It will _not_ work for things where libtasn1 size requires adjustment:
> + *  - Strings that require an extra NULL byte at the end
> + *  - Bit strings because libtasn1 returns the length in bits, not bytes.
> + *
> + * If the function returns a non-NULL value, the caller must free it.
> + */
> +void *
> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size);
> diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
> new file mode 100644
> index 000000000..609d0ecf2
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/asn1util.c
> @@ -0,0 +1,99 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
> +#include <grub/types.h>
> +#include <grub/err.h>
> +#include <grub/mm.h>
> +#include <grub/crypto.h>
> +#include <grub/misc.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +#include "appendedsig.h"
> +
> +asn1_node _gnutls_gnutls_asn = NULL;
> +asn1_node _gnutls_pkix_asn = NULL;
> +
> +extern const asn1_static_node gnutls_asn1_tab[];
> +extern const asn1_static_node pkix_asn1_tab[];
> +
> +/*
> + * Read a value from an ASN1 node, allocating memory to store it.
> + * It will work for anything where the size libtasn1 returns is right:
> + *  - Integers
> + *  - Octet strings
> + *  - DER encoding of other structures
> + * It will _not_ work for things where libtasn1 size requires adjustment:
> + *  - Strings that require an extra NULL byte at the end
> + *  - Bit strings because libtasn1 returns the length in bits, not bytes.
> + * If the function returns a non-NULL value, the caller must free it.
> + */
> +void *
> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size)
> +{
> +  int result;
> +  grub_uint8_t *tmpstr = NULL;
> +  int tmpstr_size = 0;
> +
> +  result = asn1_read_value (node, name, NULL, &tmpstr_size);
> +  if (result != ASN1_MEM_ERROR)
> +    {
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
> +                     _("Reading size of %s did not return expected status: %s"),
> +                     friendly_name, asn1_strerror (result));
> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
> +      return NULL;
> +    }
> +
> +  tmpstr = grub_malloc (tmpstr_size);
> +  if (tmpstr == NULL)
> +    {
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
> +                     "Could not allocate memory to store %s", friendly_name);
> +      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
> +      return NULL;
> +    }
> +
> +  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      grub_free (tmpstr);
> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error reading %s: %s",
> +                     friendly_name, asn1_strerror (result));
> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
> +      return NULL;
> +    }
> +
> +  *content_size = tmpstr_size;
> +
> +  return tmpstr;
> +}
> +
> +int
> +asn1_init (void)
> +{
> +  int res;
> +  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return res;
> +    }
> +  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
> +  return res;
> +}
> diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c
> new file mode 100644
> index 000000000..61e560854
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/pkcs7.c
> @@ -0,0 +1,473 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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 "appendedsig.h"
> +#include <grub/misc.h>
> +#include <grub/crypto.h>
> +#include <grub/gcrypt/gcrypt.h>
> +#include <sys/types.h>
> +
> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
> +
> +/*
> + * RFC 5652 s 5.1
> + */
> +static const char *signedData_oid = "1.2.840.113549.1.7.2";
> +
> +/*
> + * RFC 4055 s 2.1
> + */
> +static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
> +static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
> +
> +static grub_err_t
> +process_content (grub_uint8_t *content, int size, struct pkcs7_signedData *msg)
> +{
> +  int res;
> +  asn1_node signed_part;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char algo_oid[MAX_OID_LEN];
> +  int algo_oid_size = sizeof (algo_oid);
> +  int algo_count;
> +  int signer_count;
> +  int i;
> +  char version;
> +  int version_size = sizeof (version);
> +  grub_uint8_t *result_buf;
> +  int result_size = 0;
> +  int crls_size = 0;
> +  gcry_error_t gcry_err;
> +  bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
> +  char *da_path;
> +  char *si_sig_path;
> +  char *si_da_path;
> +
> +  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for PKCS#7 signed "
> +                         "part.");
> +    }
> +
> +  res = asn1_der_decoding2 (&signed_part, content, &size,
> +                            ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Error reading PKCS#7 signed data: %s", asn1_error);
> +      goto cleanup_signed_part;
> +    }
> +
> +  /*
> +   * SignedData ::= SEQUENCE {
> +   *     version CMSVersion,
> +   *     digestAlgorithms DigestAlgorithmIdentifiers,
> +   *     encapContentInfo EncapsulatedContentInfo,
> +   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
> +   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
> +   *     signerInfos SignerInfos }
> +   */
> +
> +  /* version per the algo in 5.1, must be 1 */
> +  res = asn1_read_value (signed_part, "version", &version, &version_size);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading signedData version: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (version != 1)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Unexpected signature version v%d, only v1 supported", version);
> +      goto cleanup_signed_part;
> +    }
> +
> +  /*
> +   * digestAlgorithms DigestAlgorithmIdentifiers
> +   *
> +   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
> +   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
> +   *
> +   * RFC 4055 s 2.1:
> +   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
> +   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
> +   *
> +   * We only support 1 element in the set, and we do not check parameters atm.
> +   */
> +  res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of digest algorithms: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (algo_count <= 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "A minimum of 1 digest algorithm is required");
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (algo_count > 2)
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                        "A maximum of 2 digest algorithms are supported");
> +      goto cleanup_signed_part;
> +    }
> +
> +  sha256_in_da = false;
> +  sha512_in_da = false;
> +
> +  for (i = 0; i < algo_count; i++)
> +    {
> +      da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1);
> +      if (!da_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                            "Could not allocate path for digest algorithm "
> +                            "parsing path");
> +          goto cleanup_signed_part;
> +        }
> +
> +      algo_oid_size = sizeof (algo_oid);
> +      res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size);
> +      if (res != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading digest algorithm: %s",
> +                            asn1_strerror (res));
> +          grub_free (da_path);
> +          goto cleanup_signed_part;
> +        }
> +
> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha512_in_da)
> +            {
> +              sha512_in_da = true;
> +            }
> +          else
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                                "SHA-512 specified twice in digest algorithm "
> +                                "list");
> +              grub_free (da_path);
> +              goto cleanup_signed_part;
> +            }
> +        }
> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha256_in_da)
> +            {
> +              sha256_in_da = true;
> +            }
> +          else
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                                "SHA-256 specified twice in digest algorithm "
> +                                "list");
> +              grub_free (da_path);
> +              goto cleanup_signed_part;
> +            }
> +        }
> +      else
> +        {
> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
> +                            algo_oid);
> +          grub_free (da_path);
> +          goto cleanup_signed_part;
> +        }
> +
> +      grub_free (da_path);
> +    }
> +
> +  /* at this point, at least one of sha{256,512}_in_da must be true */
> +
> +  /*
> +   * We ignore the certificates, but we don't permit CRLs.
> +   * A CRL entry might be revoking the certificate we're using, and we have
> +   * no way of dealing with that at the moment.
> +   */
> +  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
> +  if (res != ASN1_ELEMENT_NOT_FOUND)
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                        "PKCS#7 messages with embedded CRLs are not supported");
> +      goto cleanup_signed_part;
> +    }
> +
> +  /* read the signatures */
> +
> +  res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of signers: %s",
> +                        asn1_strerror (res));
> +      goto cleanup_signed_part;
> +    }
> +
> +  if (signer_count <= 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "A minimum of 1 signer is required");
> +      goto cleanup_signed_part;
> +    }
> +
> +  msg->signerInfos = grub_calloc (signer_count, sizeof (struct pkcs7_signerInfo));
> +  if (!msg->signerInfos)
> +    {
> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                        "Could not allocate space for %d signers", signer_count);
> +      goto cleanup_signed_part;
> +    }
> +
> +  msg->signerInfo_count = 0;
> +  for (i = 0; i < signer_count; i++)
> +    {
> +      si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
> +      if (!si_da_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate path for signer %d's digest algorithm parsing path",
> +                            i);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      algo_oid_size = sizeof (algo_oid);
> +      res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size);
> +      if (res != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Error reading signer %d's digest algorithm: %s", i,
> +                            asn1_strerror (res));
> +          grub_free (si_da_path);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      grub_free (si_da_path);
> +
> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha512_in_da)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d claims a SHA-512 signature "
> +                                "which was not specified in the outer DigestAlgorithms", i);
> +              goto cleanup_signerInfos;
> +            }
> +          else
> +            {
> +              sha512_in_si = true;
> +              msg->signerInfos[i].hash =
> +                      grub_crypto_lookup_md_by_name ("sha512");
> +            }
> +        }
> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
> +        {
> +          if (!sha256_in_da)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d claims a SHA-256 signature "
> +                                "which was not specified in the outer DigestAlgorithms", i);
> +              goto cleanup_signerInfos;
> +            }
> +          else
> +            {
> +              sha256_in_si = true;
> +              msg->signerInfos[i].hash =
> +                      grub_crypto_lookup_md_by_name ("sha256");
> +            }
> +        }
> +      else
> +        {
> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                            "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
> +                            algo_oid);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      if (!msg->signerInfos[i].hash)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1);
> +      if (!si_sig_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                            "Could not allocate path for signer %d's signature parsing path", i);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path,
> +                                                "signature data", &result_size);
> +      grub_free (si_sig_path);
> +
> +      if (!result_buf)
> +        {
> +          err = grub_errno;
> +          goto cleanup_signerInfos;
> +        }
> +
> +      gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi), GCRYMPI_FMT_USG,
> +                                result_buf, result_size, NULL);
> +
> +      grub_free (result_buf);
> +
> +      if (gcry_err != GPG_ERR_NO_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                            "Error loading signature %d into MPI structure: %d",
> +                            i, gcry_err);
> +          goto cleanup_signerInfos;
> +        }
> +
> +      /*
> +       * use msg->signerInfo_count to track fully populated signerInfos so we
> +       * know how many we need to clean up
> +       */
> +      msg->signerInfo_count++;
> +    }
> +
> +  /*
> +   * Final consistency check of signerInfo.*.digestAlgorithm vs
> +   * digestAlgorithms.*.algorithm. An algorithm must be present in both
> +   * digestAlgorithms and signerInfo or in neither. We have already checked
> +   * for an algorithm in signerInfo that is not in digestAlgorithms, here we
> +   * check for algorithms in digestAlgorithms but not in signerInfos.
> +   */
> +  if (sha512_in_da && !sha512_in_si)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "SHA-512 specified in DigestAlgorithms but did not "
> +                        "appear in SignerInfos");
> +      goto cleanup_signerInfos;
> +    }
> +
> +  if (sha256_in_da && !sha256_in_si)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "SHA-256 specified in DigestAlgorithms but did not "
> +                        "appear in SignerInfos");
> +      goto cleanup_signerInfos;
> +    }
> +
> +  asn1_delete_structure (&signed_part);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_signerInfos:
> +  for (i = 0; i < msg->signerInfo_count; i++)
> +    gcry_mpi_release (msg->signerInfos[i].sig_mpi);
> +  grub_free (msg->signerInfos);
> +cleanup_signed_part:
> +  asn1_delete_structure (&signed_part);
> +  return err;
> +}
> +
> +grub_err_t
> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg)
> +{
> +  int res;
> +  asn1_node content_info;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char content_oid[MAX_OID_LEN];
> +  grub_uint8_t *content;
> +  int content_size;
> +  int content_oid_size = sizeof (content_oid);
> +  int size;
> +
> +  if (data_size > GRUB_INT_MAX)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 message "
> +                                              "where data size > INT_MAX");
> +  size = (int) data_size;
> +
> +  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for PKCS#7 data: %s",
> +                         asn1_strerror (res));
> +    }
> +
> +  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
> +                            ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING,
> +                            asn1_error);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Error decoding PKCS#7 message DER: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * ContentInfo ::= SEQUENCE {
> +   *     contentType ContentType,
> +   *     content [0] EXPLICIT ANY DEFINED BY contentType }
> +   *
> +   * ContentType ::= OBJECT IDENTIFIER
> +   */
> +  res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size);
> +  if (res != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7 content type: %s",
> +                        asn1_strerror (res));
> +      goto cleanup;
> +    }
> +
> +  /* OID for SignedData defined in 5.1 */
> +  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> +                        "Unexpected content type in PKCS#7 message: OID %s", content_oid);
> +      goto cleanup;
> +    }
> +
> +  content = grub_asn1_allocate_and_read (content_info, "content",
> +                                         "PKCS#7 message content", &content_size);
> +  if (!content)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  err = process_content (content, content_size, msg);
> +  grub_free (content);
> +
> +cleanup:
> +  asn1_delete_structure (&content_info);
> +  return err;
> +}
> +
> +/*
> + * Release all the storage associated with the PKCS#7 message.
> + * If the caller dynamically allocated the message, it must free it.
> + */
> +void
> +pkcs7_signedData_release (struct pkcs7_signedData *msg)
> +{
> +  grub_ssize_t i;
> +
> +  for (i = 0; i < msg->signerInfo_count; i++)
> +    {
> +      gcry_mpi_release (msg->signerInfos[i].sig_mpi);
> +    }
> +  grub_free (msg->signerInfos);
> +}
> diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
> new file mode 100644
> index 000000000..eb9a1ca0f
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/x509.c
> @@ -0,0 +1,981 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
> +#include <grub/types.h>
> +#include <grub/err.h>
> +#include <grub/mm.h>
> +#include <grub/crypto.h>
> +#include <grub/misc.h>
> +#include <grub/gcrypt/gcrypt.h>
> +
> +#include "appendedsig.h"
> +
> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
> +
> +/*
> + * RFC 3279 2.3.1  RSA Keys
> + */
> +static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
> +
> +/*
> + * RFC 5280 Appendix A
> + */
> +static const char *commonName_oid = "2.5.4.3";
> +
> +/*
> + * RFC 5280 4.2.1.3 Key Usage
> + */
> +static const char *keyUsage_oid = "2.5.29.15";
> +
> +static const grub_uint8_t digitalSignatureUsage = 0x80;
> +
> +/*
> + * RFC 5280 4.2.1.9 Basic Constraints
> + */
> +static const char *basicConstraints_oid = "2.5.29.19";
> +
> +/*
> + * RFC 5280 4.2.1.12 Extended Key Usage
> + */
> +static const char *extendedKeyUsage_oid = "2.5.29.37";
> +static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
> +
> +/*
> + * RFC 3279 2.3.1
> + *
> + *  The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
> + *
> + *     RSAPublicKey ::= SEQUENCE {
> + *        modulus            INTEGER,    -- n
> + *        publicExponent     INTEGER  }  -- e
> + *
> + *  where modulus is the modulus n, and publicExponent is the public
> + *  exponent e.
> + */
> +static grub_err_t
> +grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct x509_certificate *certificate)
> +{
> +  int result;
> +  asn1_node spk = NULL;
> +  grub_uint8_t *m_data, *e_data;
> +  int m_size, e_size;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  gcry_error_t gcry_err;
> +
> +  result = asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Cannot create storage for public key ASN.1 data");
> +    }
> +
> +  result = asn1_der_decoding2 (&spk, der, &dersize, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Cannot decode certificate public key DER: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
> +  if (!m_data)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  e_data = grub_asn1_allocate_and_read (spk, "publicExponent",
> +                                        "RSA public exponent", &e_size);
> +  if (!e_data)
> +    {
> +      err = grub_errno;
> +      goto cleanup_m_data;
> +    }
> +
> +  /*
> +   * convert m, e to mpi
> +   *
> +   * nscanned is not set for FMT_USG, it's only set for FMT_PGP,
> +   * so we can't verify it
> +   */
> +  gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, NULL);
> +  if (gcry_err != GPG_ERR_NO_ERROR)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error loading RSA modulus into MPI structure: %d", gcry_err);
> +      goto cleanup_e_data;
> +    }
> +
> +  gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, NULL);
> +  if (gcry_err != GPG_ERR_NO_ERROR)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error loading RSA exponent into MPI structure: %d", gcry_err);
> +      goto cleanup_m_mpi;
> +    }
> +
> +  grub_free (e_data);
> +  grub_free (m_data);
> +  asn1_delete_structure (&spk);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_m_mpi:
> +  gcry_mpi_release (certificate->mpis[0]);
> +cleanup_e_data:
> +  grub_free (e_data);
> +cleanup_m_data:
> +  grub_free (m_data);
> +cleanup:
> +  asn1_delete_structure (&spk);
> +  return err;
> +}
> +
> +/*
> + * RFC 5280:
> + *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
> + *       algorithm            AlgorithmIdentifier,
> + *       subjectPublicKey     BIT STRING  }
> + *
> + * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
> + * only support RSA Encryption.
> + */
> +
> +static grub_err_t
> +grub_x509_read_subject_public_key (asn1_node asn, struct x509_certificate *results)
> +{
> +  int result;
> +  grub_err_t err;
> +  const char *algo_name =
> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
> +  const char *params_name =
> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
> +  const char *pk_name = "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
> +  char algo_oid[MAX_OID_LEN];
> +  int algo_size = sizeof (algo_oid);
> +  char params_value[2];
> +  int params_size = sizeof (params_value);
> +  grub_uint8_t *key_data = NULL;
> +  int key_size = 0;
> +  unsigned int key_type;
> +
> +  /* algorithm: see notes for rsaEncryption_oid */
> +  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key algorithm: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) != 0)
> +    {
> +      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                         "Unsupported x509 public key algorithm: %s", algo_oid);
> +    }
> +
> +  /*
> +   * RFC 3279 2.3.1
> +   * The rsaEncryption OID is intended to be used in the algorithm field
> +   * of a value of type AlgorithmIdentifier.  The parameters field MUST
> +   * have ASN.1 type NULL for this algorithm identifier.
> +   */
> +  result = asn1_read_value (asn, params_name, params_value, &params_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key parameters: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (params_value[0] != ASN1_TAG_NULL)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                         "Invalid x509 public key parameters: expected NULL");
> +    }
> +
> +  /*
> +   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of the BIT
> +   * STRING subjectPublicKey.
> +   */
> +  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
> +  if (result != ASN1_MEM_ERROR)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of x509 public key: %s",
> +                         asn1_strerror (result));
> +    }
> +  if (key_type != ASN1_ETYPE_BIT_STRING)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1 type when reading x509 public key: %x",
> +                         key_type);
> +    }
> +
> +  /* length is in bits */
> +  key_size = (key_size + 7) / 8;
> +
> +  key_data = grub_malloc (key_size);
> +  if (!key_data)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Out of memory for x509 public key");
> +    }
> +
> +  result = asn1_read_value (asn, pk_name, key_data, &key_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      grub_free (key_data);
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                         "Error reading public key data");
> +    }
> +  key_size = (key_size + 7) / 8;
> +
> +  err = grub_parse_rsa_pubkey (key_data, key_size, results);
> +  grub_free (key_data);
> +
> +  return err;
> +}
> +
> +/* Decode a string as defined in Appendix A */
> +static grub_err_t
> +decode_string (char *der, int der_size, char **string, grub_size_t *string_size)
> +{
> +  asn1_node strasn;
> +  int result;
> +  char *choice;
> +  int choice_size = 0;
> +  int tmp_size = 0;
> +  grub_err_t err = GRUB_ERR_NONE;
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for certificate: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  result = asn1_der_decoding2 (&strasn, der, &der_size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Could not parse DER for DirectoryString: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", &choice_size);
> +  if (!choice)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  if (grub_strncmp ("utf8String", choice, choice_size) == 0)
> +    {
> +      result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
> +      if (result != ASN1_MEM_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_choice;
> +        }
> +    }
> +  else if (grub_strncmp ("printableString", choice, choice_size) == 0)
> +    {
> +      result = asn1_read_value (strasn, "printableString", NULL, &tmp_size);
> +      if (result != ASN1_MEM_ERROR)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_choice;
> +        }
> +    }
> +  else
> +    {
> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and printable DirectoryStrings are supported, got %s",
> +                        choice);
> +      goto cleanup_choice;
> +    }
> +
> +  /* read size does not include trailing null */
> +  tmp_size++;
> +
> +  *string = grub_malloc (tmp_size);
> +  if (!*string)
> +    {
> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                        "Cannot allocate memory for DirectoryString contents");
> +      goto cleanup_choice;
> +    }
> +
> +  result = asn1_read_value (strasn, choice, *string, &tmp_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s in DirectoryString: %s",
> +                        choice, asn1_strerror (result));
> +      grub_free (*string);
> +      goto cleanup_choice;
> +    }
> +  *string_size = tmp_size + 1;
> +  (*string)[tmp_size] = '\0';
> +
> +cleanup_choice:
> +  grub_free (choice);
> +cleanup:
> +  asn1_delete_structure (&strasn);
> +  return err;
> +}
> +
> +/*
> + * TBSCertificate  ::=  SEQUENCE  {
> + *       version         [0]  EXPLICIT Version DEFAULT v1,
> + * ...
> + *
> + * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
> + */
> +static grub_err_t
> +check_version (asn1_node certificate)
> +{
> +  int rc;
> +  const char *name = "tbsCertificate.version";
> +  grub_uint8_t version;
> +  int len = sizeof (version);
> +
> +  rc = asn1_read_value (certificate, name, &version, &len);
> +
> +  /* require version 3 */
> +  if (rc != ASN1_SUCCESS || len != 1)
> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                       "Error reading certificate version");
> +
> +  if (version != 0x02)
> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x",
> +                       version);
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * This is an X.501 Name, which is complex.
> + *
> + * For simplicity, we extract only the CN.
> + */
> +static grub_err_t
> +read_name (asn1_node asn, const char *name_path, char **name, grub_size_t *name_size)
> +{
> +  int seq_components, set_components;
> +  int result;
> +  int i, j;
> +  char *top_path, *set_path, *type_path, *val_path;
> +  char type[MAX_OID_LEN];
> +  int type_len = sizeof (type);
> +  int string_size = 0;
> +  char *string_der;
> +  grub_err_t err;
> +
> +  *name = NULL;
> +
> +  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
> +  if (!top_path)
> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                       "Could not allocate memory for %s name parsing path", name_path);
> +
> +  result = asn1_number_of_elements (asn, top_path, &seq_components);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name components: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  for (i = 1; i <= seq_components; i++)
> +    {
> +      set_path = grub_xasprintf ("%s.?%d", top_path, i);
> +      if (!set_path)
> +        {
> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name set parsing path",
> +                            name_path);
> +          goto cleanup_set;
> +        }
> +      /* this brings us, hopefully, to a set */
> +      result = asn1_number_of_elements (asn, set_path, &set_components);
> +      if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name sub-components components (element %d): %s",
> +                            i, asn1_strerror (result));
> +          goto cleanup_set;
> +        }
> +      for (j = 1; j <= set_components; j++)
> +        {
> +          type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
> +          if (!type_path)
> +            {
> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component type path",
> +                                name_path);
> +              goto cleanup_set;
> +            }
> +          type_len = sizeof (type);
> +          result = asn1_read_value (asn, type_path, type, &type_len);
> +          if (result != ASN1_SUCCESS)
> +            {
> +              err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading %s name component type: %s",
> +                                name_path, asn1_strerror (result));
> +              goto cleanup_type;
> +            }
> +
> +          if (grub_strncmp (type, commonName_oid, type_len) != 0)
> +            {
> +              grub_free (type_path);
> +              continue;
> +            }
> +
> +          val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
> +          if (!val_path)
> +            {
> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component value path",
> +                                name_path);
> +              goto cleanup_set;
> +            }
> +
> +          string_der = grub_asn1_allocate_and_read (asn, val_path, name_path, &string_size);
> +          if (!string_der)
> +            {
> +              err = grub_errno;
> +              goto cleanup_val_path;
> +            }
> +
> +          err = decode_string (string_der, string_size, name, name_size);
> +          if (err)
> +            goto cleanup_string;
> +
> +          grub_free (string_der);
> +          grub_free (type_path);
> +          grub_free (val_path);
> +          break;
> +        }
> +      grub_free (set_path);
> +
> +      if (*name)
> +        break;
> +    }
> +
> +  grub_free (top_path);
> +
> +  return GRUB_ERR_NONE;
> +
> +cleanup_string:
> +  grub_free (string_der);
> +cleanup_val_path:
> +  grub_free (val_path);
> +cleanup_type:
> +  grub_free (type_path);
> +cleanup_set:
> +  grub_free (set_path);
> +cleanup:
> +  grub_free (top_path);
> +  return err;
> +}
> +
> +/*
> + * Verify the Key Usage extension.
> + * We require the Digital signature usage.
> + */
> +static grub_err_t
> +verify_key_usage (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node usageasn;
> +  int result;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  grub_uint8_t usage = 0xff;
> +  int usage_size = sizeof (usage_size);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for key usage");
> +    }
> +
> +  result = asn1_der_decoding2 (&usageasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Key Usage: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (usageasn, "", &usage, &usage_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key Usage value: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (!(usage & digitalSignatureUsage))
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Key Usage (0x%x) missing Digital Signature usage", usage);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&usageasn);
> +  return err;
> +}
> +
> +/*
> + * BasicConstraints ::= SEQUENCE {
> + *       cA                      BOOLEAN DEFAULT FALSE,
> + *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
> + */
> +static grub_err_t
> +verify_basic_constraints (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node basicasn;
> +  int result;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char cA[6]; /* FALSE or TRUE */
> +  int cA_size = sizeof (cA);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", &basicasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for Basic "
> +                         "Constraints");
> +    }
> +
> +  result = asn1_der_decoding2 (&basicasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Basic Constraints: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
> +  if (result == ASN1_ELEMENT_NOT_FOUND)
> +    {
> +      /* Not present, default is False, so this is OK */
> +      err = GRUB_ERR_NONE;
> +      goto cleanup;
> +    }
> +  else if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic Constraints cA value: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  /* The certificate must not be a CA certificate */
> +  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", cA);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&basicasn);
> +  return err;
> +}
> +
> +/*
> + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
> + *
> + * KeyPurposeId ::= OBJECT IDENTIFIER
> + */
> +static grub_err_t
> +verify_extended_key_usage (grub_uint8_t *value, int value_size)
> +{
> +  asn1_node extendedasn;
> +  int result, count;
> +  grub_err_t err = GRUB_ERR_NONE;
> +  char usage[MAX_OID_LEN];
> +  int usage_size = sizeof (usage);
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", &extendedasn);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for Extended Key "
> +                         "Usage");
> +    }
> +
> +  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
> +                               ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Error parsing DER for Extended Key Usage: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * If EKUs are present, there must be exactly 1 usage and it must be a
> +   * codeSigning usage. (If we get to this point, we are parsing an EKU
> +   * extension and therefore must have a usage. The code that makes having an
> +   * EKU extension optional is in verify_extensions.)
> +   */
> +  result = asn1_number_of_elements (extendedasn, "", &count);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of Extended Key Usages: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (count != 1)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usages: %d, 1 expected",
> +                        count);
> +      goto cleanup;
> +    }
> +
> +  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Extended Key Usage: %s",
> +                        asn1_strerror (result));
> +      goto cleanup;
> +    }
> +
> +  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Unexpected Extended Key Usage OID, got: %s", usage);
> +      goto cleanup;
> +    }
> +
> +cleanup:
> +  asn1_delete_structure (&extendedasn);
> +  return err;
> +}
> +
> +/*
> + * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
> + *
> + * Extension  ::=  SEQUENCE  {
> + *      extnID      OBJECT IDENTIFIER,
> + *      critical    BOOLEAN DEFAULT FALSE,
> + *      extnValue   OCTET STRING
> + *                  -- contains the DER encoding of an ASN.1 value
> + *                  -- corresponding to the extension type identified
> + *                  -- by extnID
> + * }
> + *
> + * A certificate must:
> + *  - contain the Digital Signature usage only
> + *  - not be a CA
> + *  - contain no extended usages, or only a code signing extended usage
> + *  - not contain any other critical extensions (RFC 5280 s 4.2)
> + */
> +static grub_err_t
> +verify_extensions (asn1_node cert)
> +{
> +  int result;
> +  int ext, num_extensions = 0;
> +  int usage_present = 0, constraints_present = 0, extended_usage_present = 0;
> +  char *oid_path, *critical_path, *value_path;
> +  char extnID[MAX_OID_LEN];
> +  int extnID_size;
> +  grub_err_t err;
> +  char critical[6]; /* we get either "TRUE" or "FALSE" */
> +  int critical_size;
> +  grub_uint8_t *value;
> +  int value_size;
> +
> +  result = asn1_number_of_elements (cert, "tbsCertificate.extensions", &num_extensions);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of extensions: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  if (num_extensions < 2)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Insufficient number of extensions for "
> +                         "certificate, need at least 2, got %d",
> +                         num_extensions);
> +    }
> +
> +  for (ext = 1; ext <= num_extensions; ext++)
> +    {
> +      oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);
> +
> +      extnID_size = sizeof (extnID);
> +      result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
> +      if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension OID: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_oid_path;
> +        }
> +
> +      critical_path = grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);
> +      critical_size = sizeof (critical);
> +      result = asn1_read_value (cert, critical_path, critical, &critical_size);
> +      if (result == ASN1_ELEMENT_NOT_FOUND)
> +        {
> +          critical[0] = '\0';
> +        }
> +      else if (result != ASN1_SUCCESS)
> +        {
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension criticality: %s",
> +                            asn1_strerror (result));
> +          goto cleanup_critical_path;
> +        }
> +
> +      value_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);
> +      value = grub_asn1_allocate_and_read (cert, value_path,
> +                                           "certificate extension value", &value_size);
> +      if (!value)
> +        {
> +          err = grub_errno;
> +          goto cleanup_value_path;
> +        }
> +
> +      /*
> +       * Now we must see if we recognise the OID.
> +       * If we have an unrecognised critical extension we MUST bail.
> +       */
> +      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_key_usage (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          usage_present++;
> +        }
> +      else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_basic_constraints (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          constraints_present++;
> +        }
> +      else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
> +        {
> +          err = verify_extended_key_usage (value, value_size);
> +          if (err != GRUB_ERR_NONE)
> +            {
> +              goto cleanup_value;
> +            }
> +          extended_usage_present++;
> +        }
> +      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
> +        {
> +          /*
> +           * per the RFC, we must not process a certificate with
> +           * a critical extension we do not understand.
> +           */
> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                            "Unhandled critical x509 extension with OID %s", extnID);
> +          goto cleanup_value;
> +        }
> +
> +      grub_free (value);
> +      grub_free (value_path);
> +      grub_free (critical_path);
> +      grub_free (oid_path);
> +    }
> +
> +  if (usage_present != 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Key Usage extensions "
> +                         "- expected 1, got %d", usage_present);
> +    }
> +  if (constraints_present != 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of basic constraints extensions "
> +                         "- expected 1, got %d", constraints_present);
> +    }
> +  if (extended_usage_present > 1)
> +    {
> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usage extensions "
> +                         "- expected 0 or 1, got %d", extended_usage_present);
> +    }
> +  return GRUB_ERR_NONE;
> +
> +cleanup_value:
> +  grub_free (value);
> +cleanup_value_path:
> +  grub_free (value_path);
> +cleanup_critical_path:
> +  grub_free (critical_path);
> +cleanup_oid_path:
> +  grub_free (oid_path);
> +  return err;
> +}
> +
> +/*
> + * Parse a certificate whose DER-encoded form is in @data, of size @data_size.
> + * Return the results in @results, which must point to an allocated x509 certificate.
> + */
> +grub_err_t
> +parse_x509_certificate (const void *data, grub_size_t data_size, struct x509_certificate *results)
> +{
> +  int result = 0;
> +  asn1_node cert;
> +  grub_err_t err;
> +  int size;
> +  int tmp_size;
> +
> +  if (data_size > GRUB_INT_MAX)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE,
> +                       "Cannot parse a certificate where data size > INT_MAX");
> +  size = (int) data_size;
> +
> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +                         "Could not create ASN.1 structure for certificate: %s",
> +                         asn1_strerror (result));
> +    }
> +
> +  result = asn1_der_decoding2 (&cert, data, &size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
> +  if (result != ASN1_SUCCESS)
> +    {
> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
> +                        "Could not parse DER for certificate: %s", asn1_error);
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE {
> +   *     version         [0]  EXPLICIT Version DEFAULT v1
> +   */
> +  err = check_version (cert);
> +  if (err != GRUB_ERR_NONE)
> +    {
> +      goto cleanup;
> +    }
> +
> +  /*
> +   * serialNumber         CertificateSerialNumber,
> +   *
> +   * CertificateSerialNumber  ::=  INTEGER
> +   */
> +  results->serial = grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
> +                                                 "certificate serial number", &tmp_size);
> +  if (!results->serial)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +  /*
> +   * It's safe to cast the signed int to an unsigned here, we know
> +   * length is non-negative
> +   */
> +  results->serial_len = tmp_size;
> +
> +  /*
> +   * signature            AlgorithmIdentifier,
> +   *
> +   * We don't load the signature or issuer at the moment,
> +   * as we don't attempt x509 verification.
> +   */
> +
> +  /*
> +   * issuer               Name,
> +   *
> +   * The RFC only requires the serial number to be unique within
> +   * issuers, so to avoid ambiguity we _technically_ ought to make
> +   * this available.
> +   */
> +
> +  /*
> +   * validity             Validity,
> +   *
> +   * Validity ::= SEQUENCE {
> +   *     notBefore      Time,
> +   *     notAfter       Time }
> +   *
> +   * We can't validate this reasonably, we have no true time source on several
> +   * platforms. For now we do not parse them.
> +   */
> +
> +  /*
> +   * subject              Name,
> +   *
> +   * This is an X501 name, we parse out just the CN.
> +   */
> +  err = read_name (cert, "tbsCertificate.subject", &results->subject, &results->subject_len);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_serial;
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE  {
> +   *    ...
> +   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
> +   *    ...
> +   */
> +  err = grub_x509_read_subject_public_key (cert, results);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_name;
> +
> +  /*
> +   * TBSCertificate  ::=  SEQUENCE  {
> +   *    ...
> +   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
> +   *                         -- If present, version MUST be v3
> +   * }
> +   */
> +
> +  err = verify_extensions (cert);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup_mpis;
> +
> +  /*
> +   * We do not read or check the signature on the certificate:
> +   * as discussed we do not try to validate the certificate but trust
> +   * it implictly.
> +   */
> +
> +  asn1_delete_structure (&cert);
> +  return GRUB_ERR_NONE;
> +
> +cleanup_mpis:
> +  gcry_mpi_release (results->mpis[0]);
> +  gcry_mpi_release (results->mpis[1]);
> +cleanup_name:
> +  grub_free (results->subject);
> +cleanup_serial:
> +  grub_free (results->serial);
> +cleanup:
> +  asn1_delete_structure (&cert);
> +  return err;
> +}
> +
> +/*
> + * Release all the storage associated with the x509 certificate.
> + * If the caller dynamically allocated the certificate, it must free it.
> + * The caller is also responsible for maintenance of the linked list.
> + */
> +void
> +certificate_release (struct x509_certificate *cert)
> +{
> +  grub_free (cert->subject);
> +  grub_free (cert->serial);
> +  gcry_mpi_release (cert->mpis[0]);
> +  gcry_mpi_release (cert->mpis[1]);
> +}
> -- 
> 2.43.5
> 

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 10/21] appended signatures: support verifying appended signatures
  2024-12-18 14:56 ` [PATCH v1 10/21] appended signatures: support verifying appended signatures Sudhakar Kuppusamy
  2024-12-29 16:37   ` Stefan Berger
@ 2025-02-06  6:10   ` Avnish Chouhan
  2025-02-27 15:33     ` sudhakar
  1 sibling, 1 reply; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-06  6:10 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> Building on the parsers and the ability to embed x509 certificates, as
> well as the existing gcrypt functionality, add a module for verifying
> appended signatures.
> 
> This includes a verifier that requires that Linux kernels and grub 
> modules
> have appended signatures, and commands to manage the list of trusted
> certificates for verification.
> 
> Verification must be enabled by setting check_appended_signatures. If
> GRUB is locked down when the module is loaded, verification will be
> enabled and locked automatically.
> 
> As with the PGP verifier, it is not a complete secure-boot solution:
> other mechanisms, such as a password or lockdown, must be used to 
> ensure
> that a user cannot drop to the grub shell and disable verification.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/Makefile.core.def                   |  14 +
>  grub-core/commands/appendedsig/appendedsig.c  | 620 ++++++++++++++++++
>  grub-core/commands/appendedsig/appendedsig.h  |   2 +-
>  grub-core/commands/appendedsig/asn1util.c     |   2 +-
>  .../commands/appendedsig/gnutls_asn1_tab.c    |   2 +-
>  .../commands/appendedsig/pkix_asn1_tab.c      |   2 +-
>  grub-core/commands/appendedsig/x509.c         |   2 +-
>  include/grub/file.h                           |   2 +
>  8 files changed, 641 insertions(+), 5 deletions(-)
>  create mode 100644 grub-core/commands/appendedsig/appendedsig.c
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 60db2adc5..d693986c6 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -979,6 +979,20 @@ module = {
>    cppflags = '-I$(srcdir)/lib/posix_wrap';
>  };
> 
> +module = {
> +  name = appendedsig;
> +  common = commands/appendedsig/appendedsig.c;
> +  common = commands/appendedsig/x509.c;
> +  common = commands/appendedsig/pkcs7.c;
> +  common = commands/appendedsig/asn1util.c;
> +  common = commands/appendedsig/gnutls_asn1_tab.c;
> +  common = commands/appendedsig/pkix_asn1_tab.c;
> +
> +  // posix wrapper required for gcry to get sys/types.h
> +  cflags = '$(CFLAGS_POSIX)';
> +  cppflags = '-I$(srcdir)/lib/posix_wrap 
> -I$(srcdir)/lib/libtasn1-grub';
> +};
> +
>  module = {
>    name = hdparm;
>    common = commands/hdparm.c;
> diff --git a/grub-core/commands/appendedsig/appendedsig.c
> b/grub-core/commands/appendedsig/appendedsig.c
> new file mode 100644
> index 000000000..5c82b96a4
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -0,0 +1,620 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2021, 2022 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/types.h>
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +#include <grub/err.h>
> +#include <grub/dl.h>
> +#include <grub/file.h>
> +#include <grub/command.h>
> +#include <grub/crypto.h>
> +#include <grub/pkcs1_v15.h>
> +#include <grub/i18n.h>
> +#include <grub/gcrypt/gcrypt.h>
> +#include <grub/kernel.h>
> +#include <grub/extcmd.h>
> +#include <grub/verify.h>
> +#include <libtasn1.h>
> +#include <grub/env.h>
> +#include <grub/lockdown.h>
> +
> +#include "appendedsig.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +const char magic[] = "~Module signature appended~\n";
> +
> +/*
> + * This structure is extracted from scripts/sign-file.c in the linux 
> kernel
> + * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
> + */
> +struct module_signature
> +{
> +  grub_uint8_t algo;       /* Public-key crypto algorithm [0] */
> +  grub_uint8_t hash;       /* Digest algorithm [0] */
> +  grub_uint8_t id_type;    /* Key identifier type [PKEY_ID_PKCS7] */
> +  grub_uint8_t signer_len; /* Length of signer's name [0] */
> +  grub_uint8_t key_id_len; /* Length of key identifier [0] */
> +  grub_uint8_t __pad[3];
> +  grub_uint32_t sig_len;   /* Length of signature data */
> +} GRUB_PACKED;
> +
> +/* This represents an entire, parsed, appended signature */
> +struct grub_appended_signature
> +{
> +  grub_size_t signature_len;            /* Length of PKCS#7 data +
> metadata + magic */
> +  struct module_signature sig_metadata; /* Module signature metadata 
> */
> +  struct pkcs7_signedData pkcs7;        /* Parsed PKCS#7 data */
> +};
> +
> +/* Trusted certificates for verifying appended signatures */
> +struct x509_certificate *grub_trusted_key;
> +
> +/*
> + * Force gcry_rsa to be a module dependency.
> + *
> + * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't 
> be built
> + * in if you add 'appendedsig' to grub-install --modules. You would 
> need to
> + * add 'gcry_rsa' too. That's confusing and seems suboptimal, 
> especially when
> + * we only support RSA.
> + *
> + * Dynamic loading also causes some concerns. We can't load gcry_rsa 
> from the
> + * the filesystem after we install the verifier - we won't be able to 
> verify
> + * it without having it already present. We also shouldn't load it 
> before we
> + * install the verifier, because that would mean it wouldn't be 
> verified - an
> + * attacker could insert any code they wanted into the module.
> + *
> + * So instead, reference the internal symbol from gcry_rsa. That 
> creates a
> + * direct dependency on gcry_rsa, so it will be built in when this 
> module
> + * is built in. Being built in (assuming the core image is itself 
> signed!)
> + * also resolves our concerns about loading from the filesystem.
> + */
> +extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
> +
> +static enum
> +{
> +  check_sigs_no = 0,
> +  check_sigs_enforce = 1,
> +  check_sigs_forced = 2
> +} check_sigs = check_sigs_no;
> +
> +static const char *
> +grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
> +                   const char *val __attribute__ ((unused)))
> +{
> +  if (check_sigs == check_sigs_forced)
> +    return "forced";
> +  else if (check_sigs == check_sigs_enforce)
> +    return "enforce";
> +  else
> +    return "no";
> +}
> +
> +static char *
> +grub_env_write_sec (struct grub_env_var *var __attribute__
> ((unused)), const char *val)
> +{
> +  /* Do not allow the value to be changed if set to forced */
> +  if (check_sigs == check_sigs_forced)
> +    return grub_strdup ("forced");
> +
> +  if ((*val == '2') || (*val == 'f'))
> +    check_sigs = check_sigs_forced;
> +  else if ((*val == '1') || (*val == 'e'))
> +    check_sigs = check_sigs_enforce;
> +  else if ((*val == '0') || (*val == 'n'))
> +    check_sigs = check_sigs_no;
> +
> +  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"),

Hi,

Indentation seems off here!

> +                             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)
> +{
> +  grub_size_t pkcs7_size;
> +  grub_size_t remaining_len;
> +  const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen 
> (magic);
> +
> +  if (bufsize < grub_strlen (magic))
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for
> signature magic"));
> +
> +  if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen 
> (magic)))
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Missing or invalid
> signature magic"));
> +
> +  remaining_len = bufsize - grub_strlen (magic);
> +
> +  if (remaining_len < sizeof (struct module_signature))
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for
> signature metadata"));
> +
> +  appsigdata -= sizeof (struct module_signature);
> +
> +  /* extract the metadata */
> +  grub_memcpy (&(sig->sig_metadata), appsigdata, sizeof (struct
> module_signature));
> +
> +  remaining_len -= sizeof (struct module_signature);
> +
> +  if (sig->sig_metadata.id_type != 2)
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature 
> type"));
> +
> +  pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len);
> +
> +  if (pkcs7_size > remaining_len)
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for
> PKCS#7 message"));
> +
> +  grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", 
> pkcs7_size);
> +
> +  sig->signature_len = grub_strlen (magic) + sizeof (struct
> module_signature) + pkcs7_size;
> +
> +  /* rewind pointer and parse pkcs7 data */
> +  appsigdata -= pkcs7_size;
> +
> +  return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
> +}
> +
> +static grub_err_t
> +grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t 
> bufsize)
> +{
> +  grub_err_t err = GRUB_ERR_NONE;
> +  grub_size_t datasize;
> +  void *context;
> +  unsigned char *hash;
> +  gcry_mpi_t hashmpi;
> +  gcry_err_code_t rc;
> +  struct x509_certificate *pk;
> +  struct grub_appended_signature sig;
> +  struct pkcs7_signerInfo *si;
> +  int i;
> +
> +  if (!grub_trusted_key)
> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to
> verify against"));
> +
> +  err = extract_appended_signature (buf, bufsize, &sig);
> +  if (err != GRUB_ERR_NONE)
> +    return err;
> +
> +  datasize = bufsize - sig.signature_len;
> +
> +  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
> +    {
> +      /*
> +       * 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 = grub_trusted_key; pk; pk = pk->next)
> +        {
> +          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;
> +            }
> +
> +          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi,
> &si->sig_mpi, pk->mpis, NULL, NULL);
> +          gcry_mpi_release (hashmpi);
> +
> +          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", "verify signer %d with key
> '%s' failed with %d\n",
> +                        i, pk->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);
> +
> +  return err;
> +}
> +
> +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;
> +
> +  if (argc < 1)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument 
> expected"));
> +
> +  grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
> +
> +  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
> +  if (!f)
> +    {
> +      err = grub_errno;
> +      goto cleanup;
> +    }
> +
> +  err = file_read_all (f, &data, &file_size);
> +  if (err != GRUB_ERR_NONE)
> +    goto cleanup;
> +
> +  err = grub_verify_appended_signature (data, file_size);
> +
> +  grub_free (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)
> +{
> +  unsigned long cert_num, i;
> +  struct x509_certificate *cert, *prev;
> +
> +  if (argc != 1)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument 
> expected"));
> +
> +  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"));
> +
> +  if (cert_num == 1)
> +    {
> +      cert = grub_trusted_key;
> +      grub_trusted_key = cert->next;
> +
> +      certificate_release (cert);
> +      grub_free (cert);
> +      return GRUB_ERR_NONE;
> +    }
> +  i = 2;
> +  prev = grub_trusted_key;
> +  cert = grub_trusted_key->next;
> +  while (cert)
> +    {
> +      if (i == cert_num)
> +        {
> +          prev->next = cert->next;
> +          certificate_release (cert);
> +          grub_free (cert);
> +          return GRUB_ERR_NONE;
> +        }
> +      i++;
> +      prev = cert;
> +      cert = 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);
> +}
> +
> +static grub_err_t
> +grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int
> argc, char **args)
> +{
> +  grub_file_t certf;
> +  struct x509_certificate *cert = NULL;
> +  grub_err_t err;
> +
> +  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"));
> +
> +  err = read_cert_from_file (certf, cert);
> +  grub_file_close (certf);
> +  if (err != GRUB_ERR_NONE)
> +    {
> +      grub_free (cert);
> +      return err;
> +    }
> +  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
> cert->subject);
> +
> +  cert->next = grub_trusted_key;
> +  grub_trusted_key = cert;
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +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;
> +
> +  for (cert = grub_trusted_key; cert; cert = cert->next)
> +    {
> +      grub_printf (N_("Certificate %d:\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++;
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +appendedsig_init (grub_file_t io __attribute__ ((unused)), enum
> grub_file_type type,
> +                  void **context __attribute__ ((unused)), enum
> grub_verify_flags *flags)
> +{
> +  if (check_sigs == check_sigs_no)
> +    {
> +      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
> +      return GRUB_ERR_NONE;
> +    }
> +
> +  switch (type & GRUB_FILE_TYPE_MASK)
> +    {
> +      case GRUB_FILE_TYPE_CERTIFICATE_TRUST:
> +        /*
> +         * This is a certificate to add to trusted keychain.
> +         *
> +         * This needs to be verified or blocked. Ideally we'd write an 
> x509
> +         * verifier, but we lack the hubris required to take this on. 
> Instead,
> +         * require that it have an appended signature.
> +         */
> +
> +        /* Fall through */
> +
> +      case GRUB_FILE_TYPE_LINUX_KERNEL:
> +      case GRUB_FILE_TYPE_GRUB_MODULE:
> +        /*
> +         * Appended signatures are only defined for ELF binaries.
> +         * Out of an abundance of caution, we only verify Linux 
> kernels and
> +         * GRUB modules at this point.
> +         */
> +        *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
> +        return GRUB_ERR_NONE;
> +
> +      case GRUB_FILE_TYPE_ACPI_TABLE:
> +      case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
> +        /*
> +         * It is possible to use appended signature verification 
> without
> +         * lockdown - like the PGP verifier. When combined with an 
> embedded
> +         * config file in a signed grub binary, this could still be a
> meaningful
> +         * secure-boot chain - so long as it isn't subverted by
> something like a
> +         * rouge ACPI table or DT image. Defer them explicitly.
> +         */
> +        *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
> +        return GRUB_ERR_NONE;
> +
> +      default:
> +        *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
> +        return GRUB_ERR_NONE;
> +    }
> +}
> +
> +static grub_err_t
> +appendedsig_write (void *ctxt __attribute__ ((unused)), void *buf,
> grub_size_t size)
> +{
> +  return grub_verify_appended_signature (buf, size);
> +}
> +
> +struct grub_file_verifier grub_appendedsig_verifier = {
> +  .name = "appendedsig",
> +  .init = appendedsig_init,
> +  .write = appendedsig_write,
> +};
> +
> +static grub_ssize_t
> +pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
> +{
> +  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
> +  return 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;
> +
> +GRUB_MOD_INIT (appendedsig)
> +{
> +  int rc;
> +  struct grub_module_header *header;
> +
> +  /* If in lockdown, immediately enter forced mode */
> +  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");
> +
> +  rc = asn1_init ();
> +  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;
> +
> +    /* Not an X.509 certificate, skip. */
> +    if (header->type != OBJ_TYPE_X509_PUBKEY)
> +      continue;
> +
> +    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");
> +      }

Suggestion : Good to have without brackets if just one line condition!
Thank you!

Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

> +
> +    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;
> +  }
> +
> +  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_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."));
> +
> +  grub_verifier_register (&grub_appendedsig_verifier);
> +  grub_dl_set_persistent (mod);
> +}
> +
> +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);
> +}
> diff --git a/grub-core/commands/appendedsig/appendedsig.h
> b/grub-core/commands/appendedsig/appendedsig.h
> index fa59302c8..60ee0f2fa 100644
> --- a/grub-core/commands/appendedsig/appendedsig.h
> +++ b/grub-core/commands/appendedsig/appendedsig.h
> @@ -18,7 +18,7 @@
>   */
> 
>  #include <grub/crypto.h>
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
> 
>  extern asn1_node _gnutls_gnutls_asn;
>  extern asn1_node _gnutls_pkix_asn;
> diff --git a/grub-core/commands/appendedsig/asn1util.c
> b/grub-core/commands/appendedsig/asn1util.c
> index 609d0ecf2..a2c46724a 100644
> --- a/grub-core/commands/appendedsig/asn1util.c
> +++ b/grub-core/commands/appendedsig/asn1util.c
> @@ -17,7 +17,7 @@
>   *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
>   */
> 
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>  #include <grub/types.h>
>  #include <grub/err.h>
>  #include <grub/mm.h>
> diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> index ddd1314e6..8c4eb81d7 100644
> --- a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> +++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
> @@ -1,5 +1,5 @@
>  #include <grub/mm.h>
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
> 
>  const asn1_static_node gnutls_asn1_tab[] = {
>    { "GNUTLS", 536872976, NULL },
> diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c
> b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> index adef69d95..8eeeac047 100644
> --- a/grub-core/commands/appendedsig/pkix_asn1_tab.c
> +++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
> @@ -1,5 +1,5 @@
>  #include <grub/mm.h>
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
> 
>  const asn1_static_node pkix_asn1_tab[] = {
>    { "PKIX1", 536875024, NULL },
> diff --git a/grub-core/commands/appendedsig/x509.c
> b/grub-core/commands/appendedsig/x509.c
> index eb9a1ca0f..b113ac38b 100644
> --- a/grub-core/commands/appendedsig/x509.c
> +++ b/grub-core/commands/appendedsig/x509.c
> @@ -17,7 +17,7 @@
>   *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
>   */
> 
> -#include <grub/libtasn1.h>
> +#include <libtasn1.h>
>  #include <grub/types.h>
>  #include <grub/err.h>
>  #include <grub/mm.h>
> diff --git a/include/grub/file.h b/include/grub/file.h
> index a5bf3a792..d678de063 100644
> --- a/include/grub/file.h
> +++ b/include/grub/file.h
> @@ -80,6 +80,8 @@ enum grub_file_type
>      GRUB_FILE_TYPE_PUBLIC_KEY,
>      /* File holding public key to add to trused keys.  */
>      GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
> +    /* File holding x509 certificiate to add to trusted keys.  */
> +    GRUB_FILE_TYPE_CERTIFICATE_TRUST,
>      /* File of which we intend to print a blocklist to the user.  */
>      GRUB_FILE_TYPE_PRINT_BLOCKLIST,
>      /* File we intend to use for test loading or testing speed.  */

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot
  2024-12-18 14:56 ` [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot Sudhakar Kuppusamy
  2024-12-30 22:02   ` Stefan Berger
@ 2025-02-06  6:23   ` Avnish Chouhan
  2025-02-27 15:34     ` sudhakar
  1 sibling, 1 reply; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-06  6:23 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> If the 'ibm,secure-boot' property of the root node is 2 or greater,
> enter lockdown.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  docs/grub.texi                 |  4 ++--
>  grub-core/Makefile.core.def    |  1 +
>  grub-core/kern/ieee1275/init.c | 28 ++++++++++++++++++++++++++++
>  include/grub/lockdown.h        |  3 ++-
>  4 files changed, 33 insertions(+), 3 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index f71ce9ffc..6b634f111 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -8959,8 +8959,8 @@ platforms.
>  @section Lockdown when booting on a secure setup
> 
>  The GRUB can be locked down when booted on a secure boot environment,
> for example
> -if the UEFI secure boot is enabled. On a locked down configuration,
> the GRUB will
> -be restricted and some operations/commands cannot be executed.
> +if UEFI or Power secure boot is enabled. On a locked down 
> configuration, the
> +GRUB will be restricted and some operations/commands cannot be 
> executed.
> 
>  The @samp{lockdown} variable is set to @samp{y} when the GRUB is 
> locked down.
>  Otherwise it does not exit.
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 9cf4a6009..1ed55b0e3 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -331,6 +331,7 @@ kernel = {
>    powerpc_ieee1275 = kern/powerpc/cache.S;
>    powerpc_ieee1275 = kern/powerpc/dl.c;
>    powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
> +  powerpc_ieee1275 = kern/lockdown.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 dfbd0b899..59984b605 100644
> --- a/grub-core/kern/ieee1275/init.c
> +++ b/grub-core/kern/ieee1275/init.c
> @@ -49,6 +49,7 @@
>  #if defined(__powerpc__) || defined(__i386__)
>  #include <grub/ieee1275/alloc.h>
>  #endif
> +#include <grub/lockdown.h>
> 
>  /* The maximum heap size we're going to claim at boot. Not used by 
> sparc. */
>  #ifdef __i386__
> @@ -953,6 +954,31 @@ grub_parse_cmdline (void)
>      }
>  }
> 
> +static void
> +grub_get_ieee1275_secure_boot (void)
> +{
> +  grub_ieee1275_phandle_t root;
> +  int rc;
> +  grub_uint32_t is_sb;
> +
> +  grub_ieee1275_finddevice ("/", &root);

Hi,

Failure check condition is missing!

Thank you,
Avnish Chouhan

> +
> +  rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", 
> &is_sb,
> +                                           sizeof (is_sb), 0);
> +
> +  /*
> +   * ibm,secure-boot:
> +   * 0 - disabled
> +   * 1 - audit
> +   * 2 - enforce
> +   * 3 - enforce + OS-specific behaviour
> +   *
> +   * We only support enforce.
> +   */
> +  if (rc >= 0 && is_sb >= 2)
> +    grub_lockdown ();
> +}
> +
>  grub_addr_t grub_modbase;
> 
>  void
> @@ -978,6 +1004,8 @@ grub_machine_init (void)
>  #else
>    grub_install_get_time_ms (grub_rtc_get_time_ms);
>  #endif
> +
> +  grub_get_ieee1275_secure_boot ();
>  }
> 
>  void
> diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
> index 40531fa82..ebfee4bf0 100644
> --- a/include/grub/lockdown.h
> +++ b/include/grub/lockdown.h
> @@ -24,7 +24,8 @@
>  #define GRUB_LOCKDOWN_DISABLED       0
>  #define GRUB_LOCKDOWN_ENABLED        1
> 
> -#ifdef GRUB_MACHINE_EFI
> +#if defined(GRUB_MACHINE_EFI) || \
> +    (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
>  extern void
>  EXPORT_FUNC (grub_lockdown) (void);
>  extern int

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support
  2024-12-18 14:56 ` [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support Sudhakar Kuppusamy
  2024-12-30 22:14   ` Stefan Berger
@ 2025-02-06  9:09   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-06  9:09 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> 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>
> ---
>  grub-core/kern/ieee1275/ieee1275.c | 117 +++++++++++++++++++++++++++++
>  include/grub/ieee1275/ieee1275.h   |  14 ++++
>  2 files changed, 131 insertions(+)
> 
> diff --git a/grub-core/kern/ieee1275/ieee1275.c
> b/grub-core/kern/ieee1275/ieee1275.c
> index 36ca2dbfc..8d0048844 100644
> --- a/grub-core/kern/ieee1275/ieee1275.c
> +++ b/grub-core/kern/ieee1275/ieee1275.c
> @@ -807,3 +807,120 @@ grub_ieee1275_get_block_size
> (grub_ieee1275_ihandle_t ihandle)
> 
>    return args.size;
>  }
> +
> +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/ieee1275/ieee1275.h 
> b/include/grub/ieee1275/ieee1275.h
> index c445d0499..edd8cd0eb 100644
> --- a/include/grub/ieee1275/ieee1275.h
> +++ b/include/grub/ieee1275/ieee1275.h
> @@ -230,6 +230,20 @@ char *EXPORT_FUNC(grub_ieee1275_encode_uint4)
> (grub_ieee1275_ihandle_t ihandle,
>                                               grub_size_t *size);
>  int EXPORT_FUNC(grub_ieee1275_get_block_size)
> (grub_ieee1275_ihandle_t ihandle);
> 
> +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);
> +
>  grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t 
> size);
> 
>  int

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables
  2024-12-18 14:56 ` [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables Sudhakar Kuppusamy
  2024-12-30 23:01   ` Stefan Berger
  2024-12-30 23:04   ` Stefan Berger
@ 2025-02-07  5:57   ` Avnish Chouhan
  2 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07  5:57 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper

Suggestion : Can we use grub_dprintf instead of grub_printf, unless it 
is extremely necessary!

Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> 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>
> ---
>  grub-core/Makefile.am                       |   1 +
>  grub-core/Makefile.core.def                 |   1 +
>  grub-core/kern/ieee1275/init.c              |  14 +-
>  grub-core/kern/ieee1275/platform_keystore.c | 337 ++++++++++++++++++++
>  include/grub/platform_keystore.h            | 233 ++++++++++++++
>  5 files changed, 584 insertions(+), 2 deletions(-)
>  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 e50db8106..afb25dc4f 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 1ed55b0e3..2fd060123 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 59984b605..7d96c38f3 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__
> @@ -959,7 +960,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);
> 
> @@ -976,7 +977,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..1c564d5da
> --- /dev/null
> +++ b/grub-core/kern/ieee1275/platform_keystore.c
> @@ -0,0 +1,337 @@
> +/*
> + *  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/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 ((grub_err_t) -7)
> +
> +/* Platform Keystore */
> +static grub_size_t pks_max_object_size;
> +grub_uint8_t grub_use_platform_keystore = 0;
> +grub_pks_t grub_platform_keystore = { .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;
> +}
> +
> +/*
> + * reads the secure boot version from PKS as an object.
> + * caller must free result
> + */
> +static grub_err_t
> +grub_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
> +grub_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
> +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_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 = grub_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 = grub_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) */
> +static grub_err_t
> +grub_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 = grub_read_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_get_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_read_secure_boot_variables (0, DB, 
> &grub_platform_keystore.db,
> +
> &grub_platform_keystore.db_entries);
> +      if (rc == GRUB_ERR_NONE)
> +        {
> +          /* DBX */
> +          rc = grub_read_secure_boot_variables (0, DBX,
> &grub_platform_keystore.dbx,
> +
> &grub_platform_keystore.dbx_entries);
> +          if (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..7a7378926
> --- /dev/null
> +++ b/include/grub/platform_keystore.h
> @@ -0,0 +1,233 @@
> +/*
> + * 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_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];
> +};
> +
> +/*
> + * 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_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 = {NULL, NULL, 0, 0};
> +void grub_release_platform_keystore (void);
> +
> +#endif
> +
> +#endif

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists
  2024-12-18 14:56 ` [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists Sudhakar Kuppusamy
  2024-12-31 17:21   ` Stefan Berger
@ 2025-02-07  6:39   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07  6:39 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> 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 integerity of the kernel, the extracted data
> would be 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 would be stored in the buffer db.
> 
> Note:-
> 
> if the trusted certificate nor binary hash exists in the distrusted 
> list (DBX),
> rejected it while extracting it from the platform keystore buffer.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/appendedsig/appendedsig.c | 636 +++++++++++++++++--
>  1 file changed, 592 insertions(+), 44 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c
> b/grub-core/commands/appendedsig/appendedsig.c
> index 5c82b96a4..31649e800 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -34,7 +34,7 @@
>  #include <libtasn1.h>
>  #include <grub/env.h>
>  #include <grub/lockdown.h>
> -
> +#include <grub/platform_keystore.h>
>  #include "appendedsig.h"
> 
>  GRUB_MOD_LICENSE ("GPLv3+");
> @@ -64,9 +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 grub_db = {.keys = NULL, .key_entries = 0,
> .signatures = NULL,
> +                                .signature_size = NULL,
> .signature_entries = 0};
> 
> +/* Distrusted list */
> +struct grub_database grub_dbx = {.signatures = NULL, .signature_size = 
> NULL,
> +                                 .signature_entries = 0};
>  /*
>   * Force gcry_rsa to be a module dependency.
>   *
> @@ -87,6 +101,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;
> +
> +/* releasing trusted list memory */
> +static void grub_release_trusted_list (void);
> +/* releasing distrusted list memory */
> +static void grub_release_distrusted_list (void);
> 
>  static enum
>  {
> @@ -95,6 +116,248 @@ 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
> +grub_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_ERR_UNKNOWN_COMMAND;
> +
> +  grub_memset (hash, 0x00, GRUB_MAX_HASH_SIZE);
> +  grub_crypto_hash (hash_func, hash, data, data_size);
> +  *hash_size =  hash_func->mdlen;
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/* adding the certificate/binary hash into the trusted/distrusted list 
> */
> +static grub_err_t
> +grub_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");
> +
> +  if (signatures == NULL && signature_size == NULL)
> +    {
> +      signatures = grub_zalloc (sizeof (grub_uint8_t *));
> +      signature_size = grub_zalloc (sizeof (grub_size_t));
> +    }
> +  else
> +    {
> +      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
> +       * grub_release_trusted_list/grub_release_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 grub_err_t
> +grub_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 grub_err_t
> +grub_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, if it is present, return a bad signature.
> + * else, no errors.
> + */
> +static grub_err_t
> +grub_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_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data == NULL &&
> +          grub_platform_keystore.dbx[i].data_size == 0)
> +        continue;
> +
> +      if (grub_is_x509 (&grub_platform_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_platform_keystore.dbx[i].data,
> +
> grub_platform_keystore.dbx[i].data_size, distrusted_cert);
> +          if (rc != GRUB_ERR_NONE)
> +            {
> +              grub_free (distrusted_cert);
> +              continue;
> +            }
> +
> +          if (grub_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_platform_keystore.dbx[i].data);
> +              grub_memset (&grub_platform_keystore.dbx[i], 0x00,
> sizeof (grub_pks_sd_t));
> +              certificate_release (distrusted_cert);
> +              grub_free (distrusted_cert);
> +              return GRUB_ERR_BAD_SIGNATURE;
> +            }
> +
> +          certificate_release (distrusted_cert);
> +          grub_free (distrusted_cert);
> +        }
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/* adding the certificate into the trusted/distrusted list */
> +static grub_err_t
> +grub_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_printf ("Warning: skipping %s certificate (%d)\n",
> +                   (is_db ? "trusted":"distrused"), rc);
> +      grub_free (cert);
> +      return rc;
> +    }
> +
> +  if (is_db)
> +    {
> +      rc = grub_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":"distrused"), cert->subject);
> +
> +  key_entries++;
> +  cert->next = database->keys;
> +  database->keys = cert;
> +  database->key_entries = key_entries;
> +
> +  return rc;
> +}
> +
> +static 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 parse the unknown 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;
> +}
> +
>  static const char *
>  grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
>                     const char *val __attribute__ ((unused)))
> @@ -248,7 +511,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 (!grub_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 +542,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 = grub_db.keys; pk; pk = pk->next)
>          {
>            rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, 
> pk->mpis[0]);
>            if (rc)
> @@ -376,16 +639,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 = grub_db.keys;
> +      grub_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 = grub_db.keys;
> +  cert = grub_db.keys->next;
>    while (cert)
>      {
>        if (i == cert_num)
> @@ -432,8 +695,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 = grub_db.keys;
> +  grub_db.keys = cert;
> 
>    return GRUB_ERR_NONE;
>  }
> @@ -446,7 +709,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 = grub_db.keys; cert; cert = cert->next)
>      {
>        grub_printf (N_("Certificate %d:\n"), cert_num);
> 
> @@ -539,6 +802,280 @@ 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, if it is present, return a bad signature.
> + * else, no errors.
> + */
> +static grub_err_t
> +grub_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_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data == NULL &&
> +          grub_platform_keystore.dbx[i].data_size == 0)
> +        continue;
> +
> +      rc = grub_get_hash (&grub_platform_keystore.dbx[i].guid, data, 
> data_size,
> +                          cert_hash, &cert_hash_size);
> +      if (rc != GRUB_ERR_NONE)
> +        continue;
> +
> +      if (cert_hash_size == grub_platform_keystore.dbx[i].data_size &&
> +          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
> +          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof
> (grub_pks_sd_t));
> +          return GRUB_ERR_BAD_SIGNATURE;
> +        }
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * verify the trusted binary hash against the platform keystore 
> buffer's
> + * distrusted list, if it is present, return a bad signature.
> + * else, no errors.
> + */
> +static grub_err_t
> +grub_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_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data == NULL &&
> +          grub_platform_keystore.dbx[i].data_size == 0)
> +        continue;
> +
> +      if (binary_hash_size == grub_platform_keystore.dbx[i].data_size 
> &&
> +          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
> +          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof
> (grub_pks_sd_t));
> +          return GRUB_ERR_BAD_SIGNATURE;
> +        }
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * extracts the binary hashes from the platform keystore buffer,
> + * and adds it to the trusted list if not exists in distrusted list.
> + */
> +static grub_err_t
> +grub_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 = grub_is_distrusted_binary_hash (*data, data_size);
> +  if (rc != GRUB_ERR_NONE)
> +    return rc;
> +
> +  rc = grub_add_hash (data, data_size, &grub_db.signatures,
> &grub_db.signature_size,
> +                      &grub_db.signature_entries);
> +  return rc;
> +}
> +
> +static grub_err_t
> +grub_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;
> +}
> +
> +/*
> + * extracts the x509 certificates/binary hashes from the platform
> keystore buffer,
> + * parses it, and adds it to the trusted list.
> + */
> +static grub_err_t
> +grub_create_trusted_list (void)
> +{
> +  grub_err_t rc = GRUB_ERR_NONE;
> +  grub_size_t i = 0;
> +
> +  for (i = 0; i < grub_platform_keystore.db_entries; i++)
> +    {
> +      if (grub_is_hash (&grub_platform_keystore.db[i].guid) == 
> GRUB_ERR_NONE)
> +        {
> +          rc = grub_add_trusted_binary_hash ((const grub_uint8_t **)
> +
> &grub_platform_keystore.db[i].data,
> +
> grub_platform_keystore.db[i].data_size);
> +          if (rc == GRUB_ERR_OUT_OF_MEMORY)
> +            return rc;
> +
> +          continue;
> +        }
> +      else if (grub_is_x509 (&grub_platform_keystore.db[i].guid) ==
> GRUB_ERR_NONE)
> +        {
> +
> +          rc = grub_is_distrusted_cert_hash 
> (grub_platform_keystore.db[i].data,
> +
> grub_platform_keystore.db[i].data_size);
> +          if (rc != GRUB_ERR_NONE)
> +            continue;
> +
> +          rc = grub_add_certificate 
> (grub_platform_keystore.db[i].data,
> +
> grub_platform_keystore.db[i].data_size, &grub_db, 1);
> +          if (rc == GRUB_ERR_OUT_OF_MEMORY)
> +            return rc;
> +          else if (rc != GRUB_ERR_NONE)
> +            continue;
> +        }
> +      else
> +        grub_printf ("Warning: unsupported signature data type and "
> +                     "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i 
> + 1);
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +/*
> + * extracts the certificates, certificate/binary hashes out of the
> platform keystore buffer,
> + * and adds it to the distrusted list.
> + */
> +static grub_err_t
> +grub_create_distrusted_list (void)
> +{
> +  grub_err_t rc = GRUB_ERR_NONE;
> +  grub_size_t i = 0;
> +
> +  for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
> +    {
> +      if (grub_platform_keystore.dbx[i].data != NULL &&
> +          grub_platform_keystore.dbx[i].data_size > 0)
> +        {
> +          if (grub_is_x509 (&grub_platform_keystore.dbx[i].guid) ==
> GRUB_ERR_NONE)
> +            {
> +              rc = grub_add_certificate 
> (grub_platform_keystore.dbx[i].data,
> +
> grub_platform_keystore.dbx[i].data_size, &grub_dbx, 0);
> +              if (rc == GRUB_ERR_OUT_OF_MEMORY)
> +                return rc;
> +            }
> +          else if (grub_is_hash (&grub_platform_keystore.dbx[i].guid)
> == GRUB_ERR_NONE)
> +            {
> +              rc = grub_add_hash ((const grub_uint8_t **)
> &grub_platform_keystore.dbx[i].data,
> +                                  
> grub_platform_keystore.dbx[i].data_size,
> +                                  &grub_dbx.signatures,
> &grub_dbx.signature_size,
> +                                  &grub_dbx.signature_entries);
> +              if (rc != GRUB_ERR_NONE)
> +                return rc;
> +            }
> +          else
> +            grub_printf ("Warning: unsupported signature data type and 
> "
> +                         "skipping distrusted data (%" PRIuGRUB_SIZE
> ")\n", i + 1);
> +        }
> +    }
> +
> +  return rc;
> +}
> +
> +/*
> + * extracts the x509 certificates from the ELF note header,
> + * parses it, and adds it to the trusted list.
> + */
> +static grub_err_t
> +grub_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 = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
> +  if (cert_data != NULL)
> +    grub_free (cert_data);
> +
> +  return err;
> +}
> +
> +/* releasing memory */
> +static void
> +grub_release_trusted_list (void)
> +{
> +  struct x509_certificate *cert;
> +  grub_size_t i = 0;
> +
> +  while (grub_db.keys != NULL)
> +    {
> +      cert = grub_db.keys;
> +      grub_db.keys = grub_db.keys->next;
> +      certificate_release (cert);
> +      grub_free (cert);
> +    }
> +
> +  for (i = 0; i < grub_db.signature_entries; i++)
> +    grub_free (grub_db.signatures[i]);
> +
> +  grub_free (grub_db.signatures);
> +  grub_free (grub_db.signature_size);
> +  grub_memset (&grub_db, 0x00, sizeof (grub_db));
> +}
> +
> +/* releasing memory */
> +static void
> +grub_release_distrusted_list (void)
> +{
> +  struct x509_certificate *cert;
> +  grub_size_t i = 0;
> +
> +  while (grub_dbx.keys != NULL)
> +    {
> +      cert = grub_dbx.keys;
> +      grub_dbx.keys = grub_dbx.keys->next;
> +      certificate_release (cert);
> +      grub_free (cert);
> +    }
> +
> +  for (i = 0; i < grub_dbx.signature_entries; i++)
> +    grub_free (grub_dbx.signatures[i]);
> +
> +  grub_free (grub_dbx.signatures);
> +  grub_free (grub_dbx.signature_size);
> +  grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
> +}
> +
>  GRUB_MOD_INIT (appendedsig)
>  {
>    int rc;
> @@ -548,7 +1085,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,39 +1092,51 @@ 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;
> -
> -    /* Not an X.509 certificate, skip. */
> -    if (header->type != OBJ_TYPE_X509_PUBKEY)
> -      continue;
> -
> -    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);
> +  if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
> +    {
> +      FOR_MODULES (header)
> +        {
> +          /* Not an ELF module, skip.  */
> +          if (header->type != OBJ_TYPE_X509_PUBKEY)
> +            continue;
> 
> -    grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", 
> pk->subject);
> +          rc = grub_build_static_trusted_list (header);
> +          if (rc != GRUB_ERR_NONE)
> +            {
> +              grub_release_trusted_list ();
> +              grub_error (rc, "static trusted list creation failed");
> +            }
> +          else
> +            grub_printf ("appendedsig: the trusted list now has %"
> PRIuGRUB_SIZE " static keys\n",
> +                         grub_db.key_entries);
> +        }
> +    }
> +  else if (grub_use_platform_keystore && check_sigs == 
> check_sigs_forced)
> +    {
> +      rc = grub_create_trusted_list ();
> +      if (rc != GRUB_ERR_NONE)
> +        {
> +          grub_release_trusted_list ();
> +          grub_error (rc, "trusted list creation failed");
> +        }
> +      else
> +        {
> +          rc = grub_create_distrusted_list ();
> +          if (rc != GRUB_ERR_NONE)
> +            {
> +              grub_release_trusted_list ();
> +              grub_release_distrusted_list ();
> +              grub_error (rc, "distrusted list creation failed");
> +            }
> +          else
> +            grub_printf ("appendedsig: the trusted list now has %"
> PRIuGRUB_SIZE " keys.\n"
> +                         "appendedsig: the distrusted list now has %"
> PRIuGRUB_SIZE " keys.\n",
> +                         grub_db.signature_entries + 
> grub_db.key_entries,
> +                         grub_dbx.signature_entries);
> +        }
> 
> -    pk->next = grub_trusted_key;
> -    grub_trusted_key = pk;
> -  }
> +      grub_release_platform_keystore ();
> +    }
> 
>    cmd_trust = grub_register_command ("trust_certificate",
> grub_cmd_trust, N_("X509_CERTIFICATE"),
>                                       N_("Add X509_CERTIFICATE to
> trusted certificates."));

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 17/21] appendedsig: While verifying the kernel, use trusted and distrusted lists
  2024-12-18 14:56 ` [PATCH v1 17/21] appendedsig: While verifying the kernel, use " Sudhakar Kuppusamy
  2024-12-31 17:37   ` Stefan Berger
@ 2025-02-07  6:44   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07  6:44 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> To verify the kernel's: verify the kernel binary against list of binary 
> hashes
> that are distrusted and trusted. If it is not listed in both trusted
> and distrusted,
> the trusted keys from trusted key list used to verify the signature.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/appendedsig/appendedsig.c | 188 +++++++++++++------
>  1 file changed, 133 insertions(+), 55 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c
> b/grub-core/commands/appendedsig/appendedsig.c
> index 31649e800..8b084087e 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -497,6 +497,81 @@ 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
> +grub_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 grub_get_hash (&guid, data, data_size, hash, hash_size);
> +}
> +
> +/*
> + * verify binary hash against the list of binary hashes that are 
> distrusted
> + * and trusted.
> + */
> +static grub_err_t
> +grub_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 < grub_dbx.signature_entries; i++)
> +    {
> +      rc = grub_get_binary_hash (grub_dbx.signature_size[i], data, 
> data_size,
> +                                 hash, &hash_size);
> +      if (rc != GRUB_ERR_NONE)
> +        continue;
> +
> +      if (hash_size == grub_dbx.signature_size[i] &&
> +          grub_memcmp (grub_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 < grub_db.signature_entries; i++)
> +    {
> +      rc = grub_get_binary_hash (grub_db.signature_size[i], data, 
> data_size,
> +                                 hash, &hash_size);
> +      if (rc != GRUB_ERR_NONE)
> +        continue;
> +
> +      if (hash_size == grub_db.signature_size[i] &&
> +          grub_memcmp (grub_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)
>  {
> @@ -506,12 +581,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 (!grub_db.key_entries)
> +  if (!grub_db.key_entries && !grub_db.signature_entries)
>      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to
> verify against"));
> 
>    err = extract_appended_signature (buf, bufsize, &sig);
> @@ -520,68 +595,71 @@ grub_verify_appended_signature (const
> grub_uint8_t *buf, grub_size_t bufsize)
> 
>    datasize = bufsize - sig.signature_len;
> 
> -  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
> +  err = grub_verify_binary_hash (buf, datasize);
> +  if (err == GRUB_ERR_EOF)
>      {
> -      /*
> -       * 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 = grub_db.keys; pk; pk = pk->next)
> +      for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
>          {
> -          rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, 
> pk->mpis[0]);
> -          if (rc)
> +          /*
> +           * 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(grub_db.keys * pkcs7 signers) 
> approach.
> +           */
> +          si = &sig.pkcs7.signerInfos[i];
> +          context = grub_zalloc (si->hash->contextsize);
> +          if (context == NULL)
> +            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 (cert = grub_db.keys; cert; cert = cert->next)
>              {
> -              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
> -                                N_("Error padding hash for RSA
> verification: %d"), rc);
> -              grub_free (context);
> -              goto cleanup;
> +              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;
> +                }
> +
> +              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;
> +                }
> +
> +              grub_dprintf ("appendedsig", "verify signer %d with key
> '%s' failed with %d\n",
> +                            i, cert->subject, rc);
>              }
> 
> -          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi,
> &si->sig_mpi, pk->mpis, NULL, NULL);
> -          gcry_mpi_release (hashmpi);
> -
> -          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", "verify signer %d with key
> '%s' failed with %d\n",
> -                        i, pk->subject, rc);
> -        }
> -
> -      grub_free (context);
> -
> -      if (err == GRUB_ERR_NONE)
> -        break;
> +          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_printf ("appendedsig: successfully verified the signature
> with a trusted key\n");
> +
>    return err;
>  }

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 18/21] ieee1275: set use_static_keys flag
  2024-12-18 14:56 ` [PATCH v1 18/21] ieee1275: set use_static_keys flag Sudhakar Kuppusamy
  2025-01-02 13:22   ` Stefan Berger
@ 2025-02-07  6:46   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07  6:46 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> if secure boot enabled with PKS, it set the use_static_keys flag
> when DB variable is not present in PKS storage and the appendedsig 
> (module)
> would use it later to extract the default DB key's from ELF Note and
> store it in trustedlist.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/kern/ieee1275/platform_keystore.c | 15 ++++++++++++++-
>  include/grub/platform_keystore.h            | 12 +++++++-----
>  2 files changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/grub-core/kern/ieee1275/platform_keystore.c
> b/grub-core/kern/ieee1275/platform_keystore.c
> index 1c564d5da..ddc11afd9 100644
> --- a/grub-core/kern/ieee1275/platform_keystore.c
> +++ b/grub-core/kern/ieee1275/platform_keystore.c
> @@ -34,7 +34,11 @@
>  /* Platform Keystore */
>  static grub_size_t pks_max_object_size;
>  grub_uint8_t grub_use_platform_keystore = 0;
> -grub_pks_t grub_platform_keystore = { .db = NULL, .dbx = NULL,
> .db_entries = 0, .dbx_entries = 0 };
> +grub_pks_t grub_platform_keystore = { .db = NULL,
> +                                      .dbx = NULL,
> +                                      .db_entries = 0,
> +                                      .dbx_entries = 0,
> +                                      .use_static_keys = 0 };
> 
>  /* converts the esl data into the ESL */
>  static grub_esl_t *
> @@ -316,6 +320,15 @@ grub_platform_keystore_init (void)
>        /* DB */
>        rc = grub_read_secure_boot_variables (0, DB, 
> &grub_platform_keystore.db,
> 
> &grub_platform_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 loads the Default Keys from ELF Note */
> +          grub_platform_keystore.use_static_keys = 1;
> +        }
> +
>        if (rc == GRUB_ERR_NONE)
>          {
>            /* DBX */
> diff --git a/include/grub/platform_keystore.h 
> b/include/grub/platform_keystore.h
> index 7a7378926..b333db7fd 100644
> --- a/include/grub/platform_keystore.h
> +++ b/include/grub/platform_keystore.h
> @@ -49,6 +49,7 @@
>  #define GRUB_UUID_SIZE 16
>  #define GRUB_MAX_HASH_SIZE 64
> 
> +typedef grub_uint8_t grub_bool_t;
>  typedef struct grub_uuid grub_uuid_t;
>  typedef struct grub_esd grub_esd_t;
>  typedef struct grub_esl grub_esl_t;
> @@ -207,10 +208,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__
> @@ -225,7 +227,7 @@ extern grub_pks_t 
> EXPORT_VAR(grub_platform_keystore);
>  #else
> 
>  #define grub_use_platform_keystore	0
> -grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0};
> +grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0, 0};
>  void grub_release_platform_keystore (void);
> 
>  #endif

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note
  2024-12-18 14:56 ` [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note Sudhakar Kuppusamy
  2025-01-02 13:19   ` Stefan Berger
@ 2025-02-07  6:54   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07  6:54 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> if secure boot enabled with PKS and set use_static_keys flag, it
> reads the DB default keys from ELF Note and store it in trusted list 
> buffer.
> 
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/commands/appendedsig/appendedsig.c | 58 ++++++++++++++------
>  1 file changed, 41 insertions(+), 17 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c
> b/grub-core/commands/appendedsig/appendedsig.c
> index 8b084087e..9a9f4ef1c 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -1082,7 +1082,7 @@ grub_create_distrusted_list (void)
>   * parses it, and adds it to the trusted list.
>   */
>  static grub_err_t
> -grub_build_static_trusted_list (const struct grub_module_header 
> *header)
> +grub_build_static_trusted_list (const struct grub_module_header
> *header, const grub_bool_t mode)
>  {
>    grub_err_t err = GRUB_ERR_NONE;
>    struct grub_file pseudo_file;
> @@ -1101,7 +1101,14 @@ grub_build_static_trusted_list (const struct
> grub_module_header *header)
>    if (err != GRUB_ERR_NONE)
>      return err;
> 
> -  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
> +  if (mode)
> +    {
> +      err = grub_is_distrusted_cert_hash (cert_data, cert_data_size);
> +      if (err != GRUB_ERR_NONE)
> +        return err;
> +    }
> +
> +  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 
> mode);
>    if (cert_data != NULL)
>      grub_free (cert_data);
> 
> @@ -1154,6 +1161,20 @@ grub_release_distrusted_list (void)
>    grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
>  }
> 
> +static grub_err_t
> +grub_load_static_keys (const struct grub_module_header *header, const
> grub_bool_t mode)
> +{
> +  int rc = GRUB_ERR_NONE;
> +  FOR_MODULES (header)
> +    {
> +      /* Not an ELF module, skip.  */
> +      if (header->type != OBJ_TYPE_X509_PUBKEY)
> +        continue;
> +      rc = grub_build_static_trusted_list (header, mode);
> +    }
> +  return rc;
> +}
> +
>  GRUB_MOD_INIT (appendedsig)
>  {
>    int rc;
> @@ -1172,26 +1193,29 @@ GRUB_MOD_INIT (appendedsig)
> 
>    if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
>      {
> -      FOR_MODULES (header)
> +      rc = grub_load_static_keys (header, 0);
> +      if (rc != GRUB_ERR_NONE)
>          {
> -          /* Not an ELF module, skip.  */
> -          if (header->type != OBJ_TYPE_X509_PUBKEY)
> -            continue;
> -
> -          rc = grub_build_static_trusted_list (header);
> -          if (rc != GRUB_ERR_NONE)
> -            {
> -              grub_release_trusted_list ();
> -              grub_error (rc, "static trusted list creation failed");
> -            }
> -          else
> -            grub_printf ("appendedsig: the trusted list now has %"
> PRIuGRUB_SIZE " static keys\n",
> -                         grub_db.key_entries);
> +          grub_release_trusted_list ();
> +          grub_error (rc, "static trusted list creation failed");
>          }
> +      else
> +        grub_printf ("appendedsig: the trusted list now has %"
> PRIuGRUB_SIZE " static keys\n",
> +                     grub_db.key_entries);
> +
>      }
>    else if (grub_use_platform_keystore && check_sigs == 
> check_sigs_forced)
>      {
> -      rc = grub_create_trusted_list ();
> +
> +      if (grub_platform_keystore.use_static_keys == 1)
> +        {
> +          grub_printf ("Warning: db variable is not available at PKS
> and using a static keys "
> +                       "as a default key in trusted list\n");
> +          rc = grub_load_static_keys (header, 1);
> +        }
> +      else
> +        rc = grub_create_trusted_list ();
> +
>        if (rc != GRUB_ERR_NONE)
>          {
>            grub_release_trusted_list ();

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 21/21] appendedsig: documentation
  2024-12-18 14:56 ` [PATCH v1 21/21] appendedsig: documentation Sudhakar Kuppusamy
@ 2025-02-07 10:00   ` Avnish Chouhan
  0 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07 10:00 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> 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>
> ---
>  docs/grub.texi | 110 +++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 78 insertions(+), 32 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 6b634f111..477e25376 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -6382,7 +6382,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
>  * efitextmode::                 Set/Get text output mode resolution
> @@ -6401,7 +6403,6 @@ you forget a command, you can run the command
> @command{help}
>  * hexdump::                     Show raw contents of a file or memory
>  * insmod::                      Insert a module
>  * keystatus::                   Check key modifier status
> -* 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
> @@ -6442,7 +6443,9 @@ you forget a command, you can run the command
> @command{help}
>  * tpm2_key_protector_clear::    Clear the TPM2 key protector
>  * 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
> @@ -6790,15 +6793,15 @@ These keys are used to validate signatures
> when environment variable
>  GPG-style digital signatures}, for more information.
>  @end deffn
> 
> -@node distrust_certificate
> -@subsection distrust_certificate
> +@node distrusted_certificate
> +@subsection distrusted_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}
> @@ -6807,6 +6810,28 @@ variable @code{check_appended_signatures} is
> set to @code{enforce}
>  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
> 
> @@ -7195,20 +7220,6 @@ without any options, the @command{keystatus}
> command returns true if and
>  only if checking key modifier status is supported.
>  @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
> 
> @@ -8111,17 +8122,17 @@ 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 a 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
>  variable @code{check_appended_signatures} is set to @code{enforce}.
> 
>  Note that if @code{check_appended_signatures} is set to @code{enforce}
> -when @command{trust_certificate} is executed, then 
> @var{x509_certificate}
> +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 signatures 
> within x509
> @@ -8130,6 +8141,33 @@ 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
> 
> @@ -8153,8 +8191,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.
> 
> @@ -8824,13 +8862,21 @@ To enable appended signature verification,
> load the appendedsig module and an
>  x509 certificate for verification. Building the appendedsig module 
> into the
>  core grub image is recommended.
> 
> -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.
> 
> -Only signatures made with the SHA-256 or SHA-512 hash algorithm are 
> supported,
> +Only signatures made with the SHA-256, SHA-384 and SHA-512 hash
> algorithm are supported,
>  and only RSA signatures are supported.
> 
>  A file can be signed with the @command{sign-file} utility supplied 
> with the

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 20/21] appendedsig: The grub command's trusted and distrusted support
  2024-12-18 14:56 ` [PATCH v1 20/21] appendedsig: The grub command's trusted and distrusted support Sudhakar Kuppusamy
@ 2025-02-07 10:16   ` Avnish Chouhan
  0 siblings, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-07 10:16 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> 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>
> ---
>  grub-core/commands/appendedsig/appendedsig.c | 517 +++++++++++++------
>  1 file changed, 351 insertions(+), 166 deletions(-)
> 
> diff --git a/grub-core/commands/appendedsig/appendedsig.c
> b/grub-core/commands/appendedsig/appendedsig.c
> index 9a9f4ef1c..bb70e00b5 100644
> --- a/grub-core/commands/appendedsig/appendedsig.c
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -116,6 +116,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
> +grub_printhex (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.
> @@ -387,72 +417,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)
> @@ -666,145 +630,347 @@ 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)
> -    {
> -      err = grub_errno;
> -      goto cleanup;
> -    }
> +  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 = file_read_all (f, &data, &file_size);
> +  err = grub_read_file (signed_file, &signed_data, &signed_data_size);
>    if (err != GRUB_ERR_NONE)
> -    goto cleanup;
> -
> -  err = grub_verify_appended_signature (data, file_size);
> +    {
> +      grub_file_close (signed_file);
> +      return err;
> +    }
> 
> -  grub_free (data);
> +  grub_file_close (signed_file);
> +  err = grub_verify_appended_signature (signed_data, 
> signed_data_size);
> +  grub_free (signed_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_list (grub_command_t cmd __attribute__((unused)),
> +                       int argc __attribute__((unused)), char **args
> __attribute__((unused)))
>  {
> -  unsigned long cert_num, i;
> -  struct x509_certificate *cert, *prev;
> +  struct x509_certificate *cert = NULL;
> +  grub_size_t i = 0, cert_num = 1;
> 
> -  if (argc != 1)
> -    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument 
> expected"));
> +  for (cert = grub_db.keys; cert; cert = cert->next)
> +    {
> +      grub_printf (N_("trusted certificate %" PRIuGRUB_SIZE ":\n"), 
> cert_num);
> +      grub_printf (N_("\tserial: "));
> 
> -  grub_errno = GRUB_ERR_NONE;
> -  cert_num = grub_strtoul (args[0], NULL, 10);
> -  if (grub_errno != GRUB_ERR_NONE)
> -    return grub_errno;
> +      for (i = 0; i < cert->serial_len - 1; i++)
> +        grub_printf ("%02x:", cert->serial[i]);
> 
> -  if (cert_num < 1)
> -    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> -                       N_("Certificate number too small - numbers
> start at 1"));
> +      grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
> +      grub_printf ("\tCN: %s\n\n", cert->subject);
> +      cert_num++;
> +    }
> 
> -  if (cert_num == 1)
> +  for (i = 0; i < grub_db.signature_entries; i++)
>      {
> -      cert = grub_db.keys;
> -      grub_db.keys = cert->next;
> +      grub_printf (N_("trusted binary hash %" PRIuGRUB_SIZE ":\n"), 
> i+1);
> +      grub_printf (N_("\thash: "));
> +      grub_printhex (grub_db.signatures[i], 
> grub_db.signature_size[i]);
> +    }
> 
> -      certificate_release (cert);
> -      grub_free (cert);
> -      return GRUB_ERR_NONE;
> +  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 = grub_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++;
>      }
> -  i = 2;
> -  prev = grub_db.keys;
> -  cert = grub_db.keys->next;
> -  while (cert)
> +
> +  for (i = 0; i < grub_dbx.signature_entries; i++)
>      {
> -      if (i == cert_num)
> -        {
> -          prev->next = cert->next;
> -          certificate_release (cert);
> -          grub_free (cert);
> -          return GRUB_ERR_NONE;
> -        }
> -      i++;
> -      prev = cert;
> -      cert = cert->next;
> +      grub_printf (N_("distrusted certificate/binary hash %"
> PRIuGRUB_SIZE ":\n"), i+1);
> +      grub_printf (N_("\thash: "));
> +      grub_printhex (grub_dbx.signatures[i], 
> grub_dbx.signature_size[i]);
>      }
> 
> -  return grub_error (GRUB_ERR_BAD_ARGUMENT,
> -                     N_("No certificate number %lu found - only %lu
> certificates in the store"),
> -                     cert_num, i - 1);
> +  return GRUB_ERR_NONE;
>  }
> 
>  static grub_err_t
> -grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int
> argc, char **args)
> +grub_cmd_trusted_cert (grub_command_t cmd __attribute__((unused)),
> +                       int argc, char **args)
>  {
> -  grub_file_t certf;
> -  struct x509_certificate *cert = NULL;
> -  grub_err_t err;
> +  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)
> -    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument 
> expected"));
> +    {
> +      grub_printf (N_("a trusted X.509 certificate file is expected\n"
> +                      "Example:\n\ttrusted_certificate <CERT 
> FILE>\n"));
> +      return GRUB_ERR_BAD_ARGUMENT;
> +    }
> 
> -  certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST |
> GRUB_FILE_TYPE_NO_DECOMPRESS);
> -  if (!certf)
> -    return grub_errno;
> +  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;
> +    }
> 
> -  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 (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 = read_cert_from_file (certf, cert);
> -  grub_file_close (certf);
> +  err = grub_read_file (cert_file, &cert_data, &cert_data_size);
>    if (err != GRUB_ERR_NONE)
>      {
> -      grub_free (cert);
> +      grub_file_close (cert_file);
>        return err;
>      }
> -  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
> cert->subject);
> 
> -  cert->next = grub_db.keys;
> -  grub_db.keys = cert;
> +  grub_file_close (cert_file);
> +  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 1);
> +  if (err != GRUB_ERR_NONE)
> +    {
> +      grub_release_trusted_list ();
> +      grub_release_distrusted_list ();
> +      grub_error (err, "adding of trusted certificate failed");
> +    }
> 
> -  return GRUB_ERR_NONE;
> +  grub_free (cert_data);
> +
> +  return err;
>  }
> 
>  static grub_err_t
> -grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc
> __attribute__ ((unused)),
> -               char **args __attribute__ ((unused)))
> +grub_cmd_trusted_hash (grub_command_t cmd __attribute__((unused)),
> int argc, char**args)
>  {
> -  struct x509_certificate *cert;
> -  int cert_num = 1;
> -  grub_size_t i;
> +  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;
> 
> -  for (cert = grub_db.keys; cert; cert = cert->next)
> +  if (argc != 1)
>      {
> -      grub_printf (N_("Certificate %d:\n"), cert_num);
> +      grub_printf (N_("a trusted binary hash file is expected\n"
> +                      "Example:\n\ttrusted_signature <BINARY HASH 
> FILE>\n"));
> +      return GRUB_ERR_BAD_ARGUMENT;
> +    }
> 
> -      grub_printf (N_("\tSerial: "));
> -      for (i = 0; i < cert->serial_len - 1; i++)
> +  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 = grub_add_hash ((const grub_uint8_t **) &hash_data,
> hash_data_size, &grub_db.signatures,
> +                      &grub_db.signature_size, 
> &grub_db.signature_entries);
> +  if (rc != GRUB_ERR_NONE)
> +    {
> +      grub_release_trusted_list ();
> +      grub_release_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 = grub_db.keys;
> +  struct x509_certificate *previous_cert = grub_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;
> +    }
> +
> +  cert_num = grub_strtoul (args[0], NULL, 10);
> +  if (cert_num < 1)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       N_("trusted certificate number should to begin
> with 1"));
> +
> +  if (cert_num > grub_db.key_entries)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       N_("trusted certificate number should not
> exceed %" PRIuGRUB_SIZE ""),
> +                       grub_db.key_entries);
> +  else if (cert_num < grub_db.key_entries)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT,
> +                       N_("there is no certificate on the trusted
> list. so, not permitted"));
> +
> +  for (i = 1; i < grub_db.key_entries; i++)
> +    {
> +      if (cert_num == 1)
>          {
> -          grub_printf ("%02x:", cert->serial[i]);
> +          previous_cert = current_cert->next;
> +          break;
> +        }
> +      else if (cert_num == i)
> +        {
> +          previous_cert->next = current_cert->next;
> +          break;
>          }
> -      grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
> 
> -      grub_printf ("\tCN: %s\n\n", cert->subject);
> -      cert_num++;
> +      previous_cert = current_cert;
> +      current_cert = current_cert->next;
>      }
> 
> +  certificate_release (current_cert);
> +  grub_free (current_cert);
> +
>    return GRUB_ERR_NONE;
>  }
> 
> +static grub_err_t
> +grub_cmd_distrusted_hash (grub_extcmd_context_t ctxt, int argc, char 
> **args)
> +{
> +  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 != 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;
> +    }
> +
> +  if (check_sigs == check_sigs_forced)
> +    {
> +      grub_printf ("Warning: since secure boot is enabled, "
> +                   "adding of distrusted certificate/binary hash is
> not permitted!\n");
> +      return grub_errno;
> +    }
> +
> +  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"));
> +
> +  if (grub_strlen (args[1]) == 0)
> +    return grub_error (GRUB_ERR_BAD_FILENAME,
> +                       N_("missing distrusted certificate/binary hash 
> file"));
> +
> +  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"));
> +
> +  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 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"));
> +    }
> +
> +  rc = grub_add_hash ((const grub_uint8_t **) &hash_data,
> hash_data_size, &grub_dbx.signatures,
> +                      &grub_dbx.signature_size, 
> &grub_dbx.signature_entries);
> +  if (rc != GRUB_ERR_NONE)
> +    {
> +      grub_release_trusted_list ();
> +      grub_release_distrusted_list ();
> +      grub_error (rc, "adding of distrusted binary/certificate hash 
> failed");
> +    }
> +
> +  grub_free (hash_data);
> +
> +  return rc;
> +}
> +
>  static grub_err_t
>  appendedsig_init (grub_file_t io __attribute__ ((unused)), enum
> grub_file_type type,
>                    void **context __attribute__ ((unused)), enum
> grub_verify_flags *flags)
> @@ -878,8 +1044,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, if it is present, return a bad signature.
> @@ -1175,6 +1339,10 @@ grub_load_static_keys (const struct
> grub_module_header *header, const grub_bool_
>    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;
> @@ -1240,16 +1408,31 @@ GRUB_MOD_INIT (appendedsig)
>        grub_release_platform_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);
> @@ -1261,10 +1444,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);
>  }

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 11/21] appended signatures: verification tests
  2024-12-18 14:56 ` [PATCH v1 11/21] appended signatures: verification tests Sudhakar Kuppusamy
  2024-12-30 15:39   ` Stefan Berger
@ 2025-02-14 10:27   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-14 10:27 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> These tests are run through all_functional_test and test a range
> of commands and behaviours.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  grub-core/Makefile.core.def               |   6 +
>  grub-core/tests/appended_signature_test.c | 258 ++++++
>  grub-core/tests/appended_signatures.h     | 975 ++++++++++++++++++++++
>  grub-core/tests/lib/functional_test.c     |   1 +
>  4 files changed, 1240 insertions(+)
>  create mode 100644 grub-core/tests/appended_signature_test.c
>  create mode 100644 grub-core/tests/appended_signatures.h
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index d693986c6..9cf4a6009 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2194,6 +2194,12 @@ module = {
>    common = tests/setjmp_test.c;
>  };
> 
> +module = {
> +  name = appended_signature_test;
> +  common = tests/appended_signature_test.c;
> +  common = tests/appended_signatures.h;
> +};
> +
>  module = {
>    name = signature_test;
>    common = tests/signature_test.c;
> diff --git a/grub-core/tests/appended_signature_test.c
> b/grub-core/tests/appended_signature_test.c
> new file mode 100644
> index 000000000..3d5b97391
> --- /dev/null
> +++ b/grub-core/tests/appended_signature_test.c
> @@ -0,0 +1,258 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2022 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/time.h>
> +#include <grub/misc.h>
> +#include <grub/dl.h>
> +#include <grub/command.h>
> +#include <grub/env.h>
> +#include <grub/test.h>
> +#include <grub/mm.h>
> +#include <grub/procfs.h>
> +#include <grub/file.h>
> +
> +#include "appended_signatures.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +#define PROC_FILE(identifier, file_name)                               
>      \
> +  static char *get_##identifier (grub_size_t *sz)                      
>      \
> +  {                                                                    
>      \
> +    char *ret;                                                         
>      \
> +                                                                       
>      \
> +    *sz = identifier##_len;                                            
>      \
> +    ret = grub_malloc (*sz);                                           
>      \
> +    if (ret)                                                           
>      \
> +      grub_memcpy (ret, identifier, *sz);                              
>      \
> +    return ret;                                                        
>      \
> +  }                                                                    
>      \
> +                                                                       
>      \
> +  static struct grub_procfs_entry identifier##_entry = { .name = 
> file_name, \
> +
> .get_contents = get_##identifier };
> +
> +#define DEFINE_TEST_CASE(case_name) PROC_FILE (case_name, #case_name)
> +
> +#define DO_TEST(case_name, is_valid)                       \
> +  {                                                        \
> +    grub_procfs_register (#case_name, &case_name##_entry); \
> +    do_verify ("(proc)/" #case_name, is_valid);            \
> +    grub_procfs_unregister (&case_name##_entry);           \
> +  }
> +
> +DEFINE_TEST_CASE (hi_signed);
> +DEFINE_TEST_CASE (hi_signed_sha256);
> +DEFINE_TEST_CASE (hj_signed);
> +DEFINE_TEST_CASE (short_msg);
> +DEFINE_TEST_CASE (unsigned_msg);
> +DEFINE_TEST_CASE (hi_signed_2nd);
> +DEFINE_TEST_CASE (hi_double);
> +DEFINE_TEST_CASE (hi_double_extended);
> +
> +PROC_FILE (certificate_der, "certificate.der")
> +PROC_FILE (certificate2_der, "certificate2.der")
> +PROC_FILE (certificate_printable_der, "certificate_printable.der")
> +PROC_FILE (certificate_eku_der, "certificate_eku.der")
> +
> +static void
> +do_verify (const char *f, int is_valid)
> +{
> +  grub_command_t cmd;
> +  char *args[] = { (char *) f, NULL };
> +  grub_err_t err;
> +
> +  cmd = grub_command_find ("verify_appended");
> +  if (!cmd)
> +    {
> +      grub_test_assert (0, "can't find command `%s'", 
> "verify_appended");
> +      return;
> +    }
> +  err = (cmd->func) (cmd, 1, args);
> +  if (is_valid)
> +    {
> +      grub_test_assert (err == GRUB_ERR_NONE, "verification of %s
> failed: %d: %s",
> +                        f, grub_errno, grub_errmsg);
> +    }
> +  else
> +    {
> +      grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE,
> +                        "verification of %s unexpectedly succeeded", 
> f);
> +    }
> +  grub_errno = GRUB_ERR_NONE;
> +}
> +
> +static void
> +appended_signature_test (void)
> +{
> +  grub_command_t cmd_trust, cmd_distrust;
> +  char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
> +  char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
> +  char *trust_args_printable[] = { (char *)
> "(proc)/certificate_printable.der", NULL };
> +  char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", 
> NULL };
> +  char *distrust_args[] = { (char *) "1", NULL };
> +  char *distrust2_args[] = { (char *) "2", NULL };
> +  grub_err_t err;
> +
> +  grub_procfs_register ("certificate.der", &certificate_der_entry);
> +  grub_procfs_register ("certificate2.der", &certificate2_der_entry);
> +  grub_procfs_register ("certificate_printable.der",
> &certificate_printable_der_entry);
> +  grub_procfs_register ("certificate_eku.der", 
> &certificate_eku_der_entry);
> +
> +  cmd_trust = grub_command_find ("trust_certificate");
> +  if (!cmd_trust)
> +    {
> +      grub_test_assert (0, "can't find command `%s'", 
> "trust_certificate");
> +      return;
> +    }
> +  grub_errno = GRUB_ERR_NONE;
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
> +
> +  grub_test_assert (err == GRUB_ERR_NONE, "loading certificate failed: 
> %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  /* If we have no certificate the remainder of the tests are 
> meaningless */
> +  if (err != GRUB_ERR_NONE)
> +    return;
> +
> +  /*
> +   * Reload the command: this works around some 'interesting' 
> behaviour in the
> +   * dynamic command dispatcher. The first time you call cmd->func you 
> get a
> +   * dispatcher that loads the module, finds the real cmd, calls it, 
> and then
> +   * releases some internal storage. This means it's not safe to call 
> a second
> +   * time and we need to reload it.
> +   */
> +  cmd_trust = grub_command_find ("trust_certificate");
> +
> +  /* hi, signed with key 1, SHA-512 */
> +  DO_TEST (hi_signed, 1);
> +
> +  /* hi, signed with key 1, SHA-256 */
> +  DO_TEST (hi_signed_sha256, 1);
> +
> +  /* hi, key 1, SHA-512, second byte corrupted */
> +  DO_TEST (hj_signed, 0);
> +
> +  /* message too short for a signature */
> +  DO_TEST (short_msg, 0);
> +
> +  /* lorem ipsum */
> +  DO_TEST (unsigned_msg, 0);
> +
> +  /* hi, signed with both keys, SHA-512 */
> +  DO_TEST (hi_double, 1);
> +
> +  /*
> +   * hi, signed with both keys and with empty space to test we haven't 
> broken
> +   * support for adding more signatures after the fact
> +   */
> +  DO_TEST (hi_double_extended, 1);
> +
> +  /*
> +   * in enforcing mode, we shouldn't be able to load a certificate 
> that isn't
> +   * signed by an existing trusted key.
> +   *
> +   * However, procfs files automatically skip the verification test,
> so we can't
> +   * easily test this.
> +   */
> +
> +  /*
> +   * verify that testing with 2 trusted certs works
> +   */
> +  DO_TEST (hi_signed_2nd, 0);
> +
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
> +
> +  grub_test_assert (err == GRUB_ERR_NONE, "loading certificate 2
> failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  if (err != GRUB_ERR_NONE)
> +    return;
> +
> +  DO_TEST (hi_signed_2nd, 1);
> +  DO_TEST (hi_signed, 1);
> +  DO_TEST (hi_double, 1);
> +  DO_TEST (hi_double_extended, 1);
> +
> +  /*
> +   * Check certificate removal. They're added to the _top_ of the list 
> and
> +   * removed by position in the list. Current the list looks like [#2, 
> #1].
> +   *
> +   * First test removing the second certificate in the list, which is
> +   * certificate #1, giving us just [#2].
> +   */
> +  cmd_distrust = grub_command_find ("distrust_certificate");
> +  if (!cmd_distrust)
> +    {
> +      grub_test_assert (0, "can't find command `%s'", 
> "distrust_certificate");
> +      return;
> +    }
> +
> +  err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args);
> +  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1
> failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed_2nd, 1);
> +  DO_TEST (hi_signed, 0);
> +  DO_TEST (hi_double, 1);
> +
> +  /*
> +   * Now reload certificate #1. This will make the list look like [#1, 
> #2]
> +   */
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
> +
> +  grub_test_assert (err == GRUB_ERR_NONE, "reloading certificate 1
> failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed, 1);
> +
> +  /* Remove the first certificate in the list, giving us just [#2] */
> +  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
> +  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1
> (first time) failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed_2nd, 1);
> +  DO_TEST (hi_signed, 0);
> +
> +  /*
> +   * Remove the first certificate again, giving an empty list.
> +   *
> +   * verify_appended should fail if there are no certificates to
> verify against.
> +   */
> +  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
> +  grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1
> (second time) failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +  DO_TEST (hi_signed_2nd, 0);
> +  DO_TEST (hi_double, 0);
> +
> +  /*
> +   * Lastly, check a certificate that uses printableString rather than
> +   * utf8String loads properly, and that a certificate with an 
> appropriate
> +   * extended key usage loads.
> +   */
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
> +  grub_test_assert (err == GRUB_ERR_NONE, "trusting printable
> certificate failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku);
> +  grub_test_assert (err == GRUB_ERR_NONE, "trusting certificate with
> extended key usage failed: %d: %s",
> +                    grub_errno, grub_errmsg);
> +
> +  grub_procfs_unregister (&certificate_der_entry);
> +  grub_procfs_unregister (&certificate2_der_entry);
> +  grub_procfs_unregister (&certificate_printable_der_entry);
> +  grub_procfs_unregister (&certificate_eku_der_entry);
> +}
> +
> +GRUB_FUNCTIONAL_TEST (appended_signature_test, 
> appended_signature_test);
> diff --git a/grub-core/tests/appended_signatures.h
> b/grub-core/tests/appended_signatures.h
> new file mode 100644
> index 000000000..c6aa12d86
> --- /dev/null
> +++ b/grub-core/tests/appended_signatures.h
> @@ -0,0 +1,975 @@
> +unsigned char certificate_der[] = {
> +  0x30, 0x82, 0x05, 0x5d, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 
> 0x01,
> +  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 
> 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 
> 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 
> 0x0b,
> +  0x05, 0x00, 0x30, 0x3d, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 
> 0x04,
> +  0x03, 0x0c, 0x32, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 
> 0x65,
> +  0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 
> 0x75,
> +  0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 
> 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 
> 0x68,
> +  0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 
> 0x30,
> +  0x36, 0x32, 0x39, 0x30, 0x38, 0x33, 0x36, 0x31, 0x33, 0x5a, 0x18, 
> 0x0f,
> +  0x32, 0x31, 0x32, 0x31, 0x30, 0x36, 0x30, 0x35, 0x30, 0x38, 0x33, 
> 0x36,
> +  0x31, 0x33, 0x5a, 0x30, 0x33, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 
> 0x55,
> +  0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 
> 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 
> 0x74,
> +  0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 
> 0x67,
> +  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, 
> 0x22,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 
> 0x0a,
> +  0x02, 0x82, 0x02, 0x01, 0x00, 0xb9, 0x09, 0xb2, 0xf6, 0x24, 0x34, 
> 0xdc,
> +  0x62, 0xe6, 0x4e, 0xee, 0x04, 0xdb, 0x29, 0xdc, 0x94, 0xcc, 0xee, 
> 0x8a,
> +  0x5b, 0xc3, 0x9e, 0x06, 0xba, 0xa7, 0x9b, 0xa4, 0x5f, 0x15, 0x59, 
> 0x8e,
> +  0xb8, 0x6e, 0x3c, 0xeb, 0x2e, 0xf2, 0xac, 0x21, 0x42, 0xbd, 0x30, 
> 0xa1,
> +  0x39, 0xe5, 0xb9, 0x4f, 0xa0, 0x53, 0xd5, 0x42, 0xdc, 0x8a, 0x87, 
> 0x30,
> +  0x38, 0x93, 0x44, 0x80, 0x3b, 0x1a, 0x7e, 0x9e, 0x8e, 0x3e, 0xea, 
> 0x45,
> +  0xa0, 0x11, 0x8b, 0xfb, 0x78, 0xe4, 0xbc, 0x65, 0x6b, 0x73, 0xea, 
> 0x6e,
> +  0xdf, 0x7c, 0x5b, 0x63, 0x7e, 0x5b, 0x0a, 0x1c, 0xe6, 0x76, 0x19, 
> 0xb5,
> +  0x01, 0xde, 0xf6, 0x65, 0x51, 0x30, 0x0a, 0x56, 0x69, 0x69, 0xe8, 
> 0x20,
> +  0xf9, 0x13, 0xf1, 0xbf, 0x6f, 0xdd, 0xce, 0x94, 0x96, 0x6e, 0x63, 
> 0xd6,
> +  0xfa, 0xa4, 0x91, 0x5f, 0xb3, 0x9c, 0xc7, 0xfa, 0xa9, 0xff, 0x66, 
> 0x5f,
> +  0xf3, 0xab, 0x5e, 0xdf, 0x4e, 0xca, 0x11, 0xcf, 0xbf, 0xf8, 0xad, 
> 0x65,
> +  0xb1, 0x49, 0x8b, 0xe9, 0x2a, 0xad, 0x7d, 0xf3, 0x0b, 0xfa, 0x5b, 
> 0x6a,
> +  0x6a, 0x20, 0x12, 0x77, 0xef, 0x4b, 0xb6, 0xbe, 0x92, 0xba, 0x14, 
> 0x9c,
> +  0x5e, 0xea, 0xdc, 0x56, 0x6d, 0x92, 0xd3, 0x64, 0x22, 0xf6, 0x12, 
> 0xe8,
> +  0x7d, 0x5e, 0x9c, 0xd6, 0xf9, 0x75, 0x68, 0x7f, 0x8f, 0xd3, 0x6e, 
> 0x05,
> +  0x94, 0x91, 0x4f, 0xa1, 0xd6, 0x50, 0x72, 0x3b, 0x11, 0x1f, 0x28, 
> 0x13,
> +  0xe8, 0x25, 0x6b, 0xdf, 0xff, 0x72, 0x46, 0x25, 0xe9, 0x05, 0x6f, 
> 0x02,
> +  0xc7, 0x1e, 0xc9, 0xcf, 0x99, 0xe9, 0xa7, 0xe2, 0xae, 0xbc, 0xc1, 
> 0x22,
> +  0x32, 0x73, 0x2d, 0xa3, 0x70, 0x8f, 0xa7, 0x8d, 0xbf, 0x5f, 0x74, 
> 0x05,
> +  0x1b, 0x5e, 0xfe, 0x97, 0x3c, 0xe7, 0x3b, 0x86, 0x0d, 0xf6, 0x38, 
> 0xdb,
> +  0xd2, 0x39, 0x47, 0x82, 0x00, 0x44, 0x6c, 0x7b, 0x40, 0x24, 0x0b, 
> 0x3a,
> +  0xd4, 0x19, 0x31, 0xba, 0x4e, 0x8e, 0xa3, 0x33, 0xa6, 0x78, 0xef, 
> 0x72,
> +  0x9f, 0x06, 0x37, 0x01, 0x9b, 0x79, 0x0d, 0x04, 0xbf, 0xba, 0xd5, 
> 0x1f,
> +  0x27, 0xdc, 0x85, 0xbb, 0xef, 0xd2, 0x60, 0xda, 0xa0, 0x3f, 0x66, 
> 0xce,
> +  0x9f, 0xa2, 0x7e, 0xa8, 0x8d, 0xee, 0x14, 0x4b, 0xcb, 0x93, 0xf1, 
> 0x38,
> +  0xac, 0x4f, 0xd8, 0x29, 0xf3, 0x6f, 0xd4, 0xfd, 0x4d, 0x34, 0x77, 
> 0x58,
> +  0x99, 0xdb, 0x16, 0xc1, 0xd0, 0xc7, 0x43, 0x41, 0x70, 0xc4, 0xad, 
> 0x01,
> +  0x29, 0x65, 0x22, 0x43, 0x00, 0x6f, 0xb3, 0x00, 0x27, 0x38, 0xc1, 
> 0x4f,
> +  0xda, 0x28, 0x96, 0x42, 0xdc, 0xbc, 0x3e, 0x34, 0x8e, 0x14, 0xb8, 
> 0xf3,
> +  0x86, 0x4a, 0xea, 0x16, 0x90, 0xf9, 0x0e, 0x9e, 0x8f, 0x66, 0x0c, 
> 0xbf,
> +  0x29, 0xd3, 0x8f, 0xfc, 0x4d, 0x38, 0x68, 0xe2, 0xe7, 0x64, 0x32, 
> 0x47,
> +  0xdd, 0x56, 0xc9, 0xe4, 0x47, 0x9f, 0x18, 0x89, 0xfc, 0x30, 0x7a, 
> 0xae,
> +  0x63, 0xe4, 0xec, 0x93, 0x04, 0xd4, 0x61, 0xe7, 0xbf, 0x0a, 0x06, 
> 0x29,
> +  0xc2, 0xa6, 0xd5, 0x53, 0x5d, 0x65, 0x6d, 0x4a, 0xd0, 0xb7, 0x68, 
> 0x4d,
> +  0x46, 0x0a, 0xb5, 0xff, 0x52, 0x5e, 0x92, 0x7e, 0x75, 0x08, 0xa4, 
> 0x63,
> +  0x0a, 0x6c, 0x31, 0x7a, 0xaa, 0x0c, 0x52, 0xf4, 0x2e, 0xcd, 0x08, 
> 0xeb,
> +  0xb3, 0xbd, 0xad, 0x8b, 0x8b, 0x9b, 0x8d, 0x71, 0x42, 0x30, 0x8e, 
> 0xc7,
> +  0xfd, 0xec, 0xb7, 0xe6, 0x26, 0x96, 0xf2, 0x74, 0x1b, 0x78, 0x95, 
> 0x22,
> +  0x14, 0xf3, 0xc9, 0xd3, 0x79, 0x11, 0xd9, 0xb7, 0x4d, 0x0d, 0x61, 
> 0x60,
> +  0x5c, 0x47, 0x50, 0xf3, 0xca, 0x84, 0x4c, 0x5c, 0x30, 0x2c, 0x6a, 
> 0x18,
> +  0x26, 0xb0, 0xf3, 0xd1, 0x15, 0x19, 0x39, 0xc3, 0x23, 0x13, 0x0f, 
> 0x9c,
> +  0x97, 0x2b, 0x97, 0x93, 0xf9, 0xf8, 0x18, 0x9b, 0x4a, 0x4d, 0xd6, 
> 0xd3,
> +  0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 
> 0x0c,
> +  0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 
> 0x00,
> +  0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 
> 0x07,
> +  0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 
> 0x14,
> +  0x8f, 0xba, 0x8b, 0xf5, 0xf4, 0x77, 0xb2, 0xa4, 0x19, 0xef, 0x43, 
> 0xb1,
> +  0x8b, 0x03, 0x4b, 0x45, 0x47, 0xb5, 0x2a, 0x48, 0x30, 0x1f, 0x06, 
> 0x03,
> +  0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x59, 0x1c, 
> 0xb5,
> +  0x52, 0x62, 0x83, 0x05, 0x3b, 0x41, 0x4c, 0x63, 0x4d, 0x5b, 0xf4, 
> 0x8c,
> +  0xe6, 0xd7, 0xda, 0x87, 0x54, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 
> 0x01,
> +  0x00, 0x36, 0x2d, 0x0a, 0xcb, 0x49, 0x54, 0x75, 0xd7, 0xca, 0x21, 
> 0x86,
> +  0xae, 0x40, 0x0f, 0x63, 0x10, 0x35, 0xfd, 0xbc, 0xba, 0x28, 0x31, 
> 0x33,
> +  0x07, 0x08, 0x64, 0x03, 0x6c, 0xd3, 0xd5, 0xf7, 0xb7, 0x79, 0x11, 
> 0x0c,
> +  0xa8, 0x9e, 0xfd, 0x34, 0xa2, 0xba, 0x77, 0x15, 0x15, 0x2d, 0x2c, 
> 0x96,
> +  0xae, 0x47, 0xbb, 0x82, 0x89, 0x09, 0x7f, 0xd1, 0x95, 0x69, 0x9b, 
> 0xfe,
> +  0xd7, 0x6f, 0x4e, 0x68, 0xf6, 0xe7, 0x5f, 0x54, 0xa1, 0x3a, 0xeb, 
> 0xa4,
> +  0xbf, 0x7a, 0xb6, 0x7f, 0xaa, 0xd8, 0xd7, 0x99, 0xcb, 0xae, 0x88, 
> 0x6d,
> +  0x7a, 0xf3, 0xfa, 0x9e, 0x44, 0x2f, 0x30, 0xa8, 0xe6, 0xb9, 0x75, 
> 0xa0,
> +  0x82, 0xd6, 0xb0, 0xe3, 0x03, 0xb3, 0x12, 0xa3, 0xdc, 0xb9, 0x4d, 
> 0x93,
> +  0xd4, 0x30, 0xea, 0xce, 0x96, 0x92, 0x07, 0xf8, 0xba, 0xe4, 0x0f, 
> 0x41,
> +  0xe3, 0x04, 0xaa, 0x8c, 0x07, 0x1a, 0x34, 0x60, 0xfc, 0xc0, 0x05, 
> 0xd2,
> +  0x5a, 0xa8, 0x66, 0xef, 0xe0, 0x94, 0xc5, 0x2f, 0x0f, 0xff, 0xdc, 
> 0x70,
> +  0xfb, 0xe2, 0x9d, 0x61, 0x51, 0x25, 0x02, 0xff, 0x4b, 0x69, 0xfd, 
> 0x66,
> +  0xb9, 0xeb, 0x0c, 0xc8, 0x50, 0xd3, 0xb1, 0x08, 0x1e, 0x09, 0x54, 
> 0x87,
> +  0xe8, 0xa3, 0x4b, 0xef, 0x0c, 0x32, 0x0a, 0x6c, 0xec, 0x27, 0x22, 
> 0xba,
> +  0x7f, 0xdc, 0x52, 0x27, 0x31, 0x14, 0x9a, 0xa8, 0xf7, 0xf9, 0xeb, 
> 0xc8,
> +  0xb5, 0x8d, 0x12, 0xed, 0x94, 0xab, 0x3d, 0x9a, 0xfb, 0x4e, 0x04, 
> 0x05,
> +  0xd2, 0x3c, 0x7c, 0x8a, 0xed, 0x46, 0x1b, 0x7c, 0xb5, 0x6c, 0x40, 
> 0xb8,
> +  0xc1, 0xbf, 0xb0, 0xd2, 0x93, 0x8e, 0xa8, 0x0f, 0xde, 0x78, 0xf3, 
> 0x8c,
> +  0xd8, 0x9f, 0xf8, 0xdc, 0xa1, 0x23, 0x20, 0x40, 0x17, 0xb4, 0xdb, 
> 0xb7,
> +  0x09, 0x74, 0xa7, 0x80, 0xc2, 0x12, 0xd9, 0x76, 0x79, 0x5b, 0x71, 
> 0xa9,
> +  0x6c, 0xd4, 0x57, 0x48, 0xe8, 0xfe, 0xc5, 0xc2, 0x6e, 0xe7, 0x83, 
> 0x5a,
> +  0x07, 0xf0, 0x33, 0xc1, 0xc1, 0x1d, 0x34, 0xd4, 0xc8, 0xb0, 0xb7, 
> 0xdb,
> +  0xeb, 0xe9, 0xe3, 0x59, 0xdc, 0x7f, 0x36, 0x58, 0xa9, 0xb8, 0x52, 
> 0xdd,
> +  0xf9, 0xfd, 0x1c, 0x22, 0x2f, 0x93, 0x3d, 0x53, 0x89, 0x80, 0xde, 
> 0xa2,
> +  0xb5, 0xa5, 0x36, 0xbd, 0xc3, 0x92, 0x03, 0xf3, 0x93, 0xc8, 0xc7, 
> 0x4a,
> +  0x0b, 0x8b, 0x62, 0xfe, 0xd0, 0xf8, 0x0d, 0x7a, 0x32, 0xb4, 0x39, 
> 0x1a,
> +  0xb7, 0x4e, 0xaa, 0xc4, 0x33, 0x32, 0x90, 0x8c, 0xab, 0xd4, 0xae, 
> 0xa5,
> +  0xa4, 0x85, 0xcf, 0xba, 0xe1, 0x1b, 0x26, 0x7f, 0x74, 0x02, 0x12, 
> 0x09,
> +  0x89, 0x56, 0xe4, 0xe7, 0x9d, 0x91, 0xde, 0x88, 0xe7, 0x1c, 0xed, 
> 0x80,
> +  0x05, 0xa8, 0x58, 0x9a, 0x3e, 0x16, 0x97, 0xd5, 0xbc, 0x54, 0xcc, 
> 0xf0,
> +  0x32, 0xf2, 0x93, 0x09, 0x94, 0x9f, 0x3c, 0xd9, 0x58, 0xca, 0x68, 
> 0x0b,
> +  0xde, 0x3f, 0x73, 0x64, 0xb7, 0xf4, 0xd7, 0x5f, 0x2b, 0xe7, 0x7b, 
> 0x06,
> +  0xca, 0xb1, 0x3e, 0xed, 0xd2, 0xb9, 0x29, 0xc1, 0x95, 0x87, 0xad, 
> 0xd6,
> +  0x63, 0x69, 0xb8, 0x1f, 0x70, 0xdb, 0xeb, 0xc7, 0x11, 0x7d, 0xe2, 
> 0x99,
> +  0x64, 0x6a, 0xf5, 0x3f, 0x30, 0x74, 0x5f, 0x2a, 0x21, 0xda, 0xef, 
> 0x44,
> +  0x1d, 0xad, 0x97, 0xa1, 0xfe, 0x14, 0xa7, 0x88, 0x99, 0xd0, 0x1e, 
> 0xb0,
> +  0x61, 0x88, 0x09, 0xc9, 0xfa, 0xd1, 0xb3, 0xcb, 0x1d, 0x76, 0x04, 
> 0xbe,
> +  0x06, 0x44, 0xd2, 0x30, 0x5e, 0x95, 0x4b, 0x96, 0xc0, 0xd6, 0xbe, 
> 0xd0,
> +  0x4d, 0xf2, 0xf4, 0x71, 0x72, 0xa9, 0xbd, 0x07, 0x4f, 0xbc, 0xb3, 
> 0x78,
> +  0xb4, 0x8a, 0x44, 0xbd, 0x58, 0xd5, 0x21, 0xb6, 0x47, 0x9c, 0x88, 
> 0x1f,
> +  0xbc, 0xbd, 0x54, 0xfa, 0x1d, 0x49, 0xec, 0x51, 0xd9, 0x43, 0x49, 
> 0x9c,
> +  0x0c, 0xfa, 0x18, 0xdb, 0xeb, 0x05, 0x77, 0xa2, 0x9a
> +};
> +unsigned int certificate_der_len = 1377;
> +
> +unsigned char hi_signed[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 
> 0x82,
> +  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 
> 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 
> 0x02,
> +  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 
> 0x3d,
> +  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 
> 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 
> 0x64,
> +  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 
> 0x54,
> +  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 
> 0x63,
> +  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 
> 0x74,
> +  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 
> 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 
> 0x30,
> +  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 
> 0x03,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 
> 0x77,
> +  0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 
> 0x03,
> +  0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 
> 0x6e,
> +  0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 
> 0x52,
> +  0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 
> 0x01,
> +  0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 
> 0x75,
> +  0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 
> 0xb1,
> +  0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 
> 0x8d,
> +  0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 
> 0x1e,
> +  0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 
> 0x7f,
> +  0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 
> 0xae,
> +  0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 
> 0xd5,
> +  0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 
> 0x7a,
> +  0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 
> 0x33,
> +  0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 
> 0xc2,
> +  0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 
> 0xa9,
> +  0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 
> 0x70,
> +  0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 
> 0x67,
> +  0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 
> 0x3a,
> +  0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 
> 0xe3,
> +  0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 
> 0x33,
> +  0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 
> 0xc4,
> +  0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 
> 0xd1,
> +  0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 
> 0x26,
> +  0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 
> 0x41,
> +  0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 
> 0xda,
> +  0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 
> 0xe3,
> +  0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 
> 0x98,
> +  0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 
> 0xe5,
> +  0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 
> 0x0e,
> +  0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 
> 0xbe,
> +  0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 
> 0x5c,
> +  0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 
> 0xa6,
> +  0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 
> 0xc5,
> +  0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 
> 0x1f,
> +  0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 
> 0xcb,
> +  0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 
> 0xe0,
> +  0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 
> 0xd4,
> +  0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 
> 0x2b,
> +  0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 
> 0x52,
> +  0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 
> 0x6f,
> +  0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 
> 0x1c,
> +  0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 
> 0x17,
> +  0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
> 0x00,
> +  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 
> 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 
> 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_signed_len = 739;
> +
> +unsigned char hj_signed[] = {
> +  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 
> 0x82,
> +  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 
> 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 
> 0x02,
> +  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 
> 0x3d,
> +  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 
> 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 
> 0x64,
> +  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 
> 0x54,
> +  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 
> 0x63,
> +  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 
> 0x74,
> +  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 
> 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 
> 0x30,
> +  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 
> 0x03,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 
> 0x77,
> +  0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 
> 0x03,
> +  0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 
> 0x6e,
> +  0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 
> 0x52,
> +  0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 
> 0x01,
> +  0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 
> 0x75,
> +  0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 
> 0xb1,
> +  0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 
> 0x8d,
> +  0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 
> 0x1e,
> +  0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 
> 0x7f,
> +  0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 
> 0xae,
> +  0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 
> 0xd5,
> +  0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 
> 0x7a,
> +  0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 
> 0x33,
> +  0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 
> 0xc2,
> +  0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 
> 0xa9,
> +  0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 
> 0x70,
> +  0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 
> 0x67,
> +  0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 
> 0x3a,
> +  0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 
> 0xe3,
> +  0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 
> 0x33,
> +  0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 
> 0xc4,
> +  0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 
> 0xd1,
> +  0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 
> 0x26,
> +  0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 
> 0x41,
> +  0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 
> 0xda,
> +  0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 
> 0xe3,
> +  0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 
> 0x98,
> +  0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 
> 0xe5,
> +  0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 
> 0x0e,
> +  0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 
> 0xbe,
> +  0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 
> 0x5c,
> +  0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 
> 0xa6,
> +  0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 
> 0xc5,
> +  0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 
> 0x1f,
> +  0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 
> 0xcb,
> +  0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 
> 0xe0,
> +  0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 
> 0xd4,
> +  0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 
> 0x2b,
> +  0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 
> 0x52,
> +  0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 
> 0x6f,
> +  0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 
> 0x1c,
> +  0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 
> 0x17,
> +  0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
> 0x00,
> +  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 
> 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 
> 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hj_signed_len = 739;
> +
> +unsigned char hi_signed_sha256[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 
> 0x82,
> +  0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 
> 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 
> 0x02,
> +  0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 
> 0x3d,
> +  0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 
> 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 
> 0x64,
> +  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 
> 0x54,
> +  0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 
> 0x63,
> +  0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 
> 0x74,
> +  0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 
> 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 
> 0x30,
> +  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 
> 0x01,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0x96, 0x02, 0x7b, 0xa4, 
> 0x07,
> +  0xa7, 0x39, 0x8d, 0xa6, 0x0b, 0xde, 0x33, 0xdd, 0xf8, 0xec, 0x24, 
> 0x5d,
> +  0x06, 0x81, 0xe7, 0x3c, 0x2d, 0x0c, 0x53, 0xfb, 0x7e, 0x5a, 0xf3, 
> 0xee,
> +  0xe5, 0x4c, 0x7c, 0xf7, 0xe7, 0x8f, 0x36, 0x62, 0x35, 0xb8, 0x99, 
> 0xc3,
> +  0xeb, 0x85, 0x1d, 0x2e, 0x40, 0x6e, 0x2a, 0xb4, 0x3a, 0x76, 0x48, 
> 0x4f,
> +  0x8b, 0x29, 0xd4, 0x9e, 0x5c, 0xd2, 0x41, 0x4d, 0xc1, 0x72, 0x0f, 
> 0x97,
> +  0xe0, 0x7d, 0x88, 0xed, 0x1a, 0xb0, 0xde, 0x1b, 0x21, 0xa6, 0x0c, 
> 0x19,
> +  0xd8, 0xb0, 0x12, 0x54, 0x7b, 0xd8, 0x19, 0x03, 0xbd, 0x77, 0x83, 
> 0x23,
> +  0xeb, 0xeb, 0x68, 0x0a, 0x7b, 0x3a, 0x4d, 0x25, 0x44, 0xe1, 0x64, 
> 0x8d,
> +  0x43, 0x5a, 0x1c, 0x9f, 0x74, 0x79, 0x31, 0x3f, 0xc7, 0x8e, 0xae, 
> 0xe1,
> +  0xf9, 0x1e, 0x54, 0x12, 0x36, 0x85, 0xf2, 0x55, 0xba, 0x42, 0x60, 
> 0x64,
> +  0x25, 0x9f, 0x73, 0x62, 0x42, 0xd2, 0x1c, 0x5e, 0x39, 0x4f, 0x7d, 
> 0x91,
> +  0xb8, 0xf9, 0x59, 0x3c, 0x13, 0x6b, 0x84, 0x76, 0x6d, 0x8a, 0xc3, 
> 0xcb,
> +  0x2d, 0x14, 0x27, 0x16, 0xdc, 0x20, 0x2c, 0xbc, 0x6b, 0xc9, 0xda, 
> 0x9f,
> +  0xef, 0xe2, 0x2d, 0xc3, 0x83, 0xd8, 0xf9, 0x94, 0x18, 0xbc, 0xfe, 
> 0x8f,
> +  0xa9, 0x44, 0xad, 0xff, 0x1b, 0xcb, 0x86, 0x30, 0x96, 0xa8, 0x3c, 
> 0x7a,
> +  0x4b, 0x73, 0x1b, 0xa9, 0xc3, 0x3b, 0xaa, 0xd7, 0x44, 0xa8, 0x4d, 
> 0xd6,
> +  0x92, 0xb6, 0x00, 0x04, 0x09, 0x05, 0x4a, 0x95, 0x02, 0x90, 0x19, 
> 0x8c,
> +  0x9a, 0xa5, 0xee, 0x58, 0x24, 0xb0, 0xca, 0x5e, 0x6f, 0x73, 0xdb, 
> 0xf5,
> +  0xa1, 0xf4, 0xf0, 0xa9, 0xeb, 0xe4, 0xdc, 0x55, 0x9f, 0x8f, 0x7a, 
> 0xd0,
> +  0xf7, 0xb6, 0xaa, 0xa6, 0xb5, 0xb4, 0xab, 0xb8, 0x65, 0xad, 0x12, 
> 0x32,
> +  0x1c, 0xe6, 0x99, 0x71, 0x93, 0xe8, 0xb4, 0x1e, 0x21, 0x27, 0x52, 
> 0xea,
> +  0x8c, 0xc8, 0x79, 0x96, 0x2e, 0x48, 0x60, 0x57, 0x1c, 0x7d, 0x8c, 
> 0x0d,
> +  0x07, 0xa7, 0x12, 0x83, 0x0a, 0x76, 0x6a, 0x64, 0xed, 0xbe, 0x8d, 
> 0xaf,
> +  0xdf, 0x51, 0x05, 0xdd, 0xf2, 0xd3, 0xb8, 0x93, 0xa9, 0x13, 0xa5, 
> 0x96,
> +  0xe8, 0xfa, 0x82, 0x02, 0x18, 0x71, 0x7a, 0x71, 0xbb, 0x39, 0x6f, 
> 0x85,
> +  0xee, 0x16, 0x82, 0x27, 0x42, 0x9f, 0x83, 0xc8, 0xab, 0x6a, 0x3b, 
> 0x99,
> +  0xba, 0x38, 0x92, 0x38, 0xae, 0x59, 0xfa, 0xaa, 0x40, 0x2b, 0x52, 
> 0x95,
> +  0xca, 0x5e, 0xe1, 0x9b, 0x00, 0xbd, 0xb9, 0x63, 0x25, 0x8d, 0xc7, 
> 0x22,
> +  0xaf, 0xe5, 0x67, 0x76, 0x91, 0xf4, 0xda, 0xc9, 0x7e, 0x9e, 0xec, 
> 0x9b,
> +  0x1f, 0x7d, 0x3b, 0xfe, 0xa1, 0x20, 0x52, 0xac, 0xd0, 0xe5, 0xa6, 
> 0xf1,
> +  0xfd, 0x4c, 0x08, 0x59, 0x7d, 0x50, 0xbb, 0x0c, 0xcf, 0xd8, 0xb6, 
> 0x0f,
> +  0xc7, 0x19, 0xcb, 0x7a, 0x96, 0x6f, 0x0f, 0x6c, 0x71, 0x56, 0x72, 
> 0xd1,
> +  0x06, 0x29, 0x0f, 0x08, 0xa2, 0x46, 0x3e, 0x58, 0x42, 0xc4, 0x8c, 
> 0xe0,
> +  0x6e, 0xe9, 0x37, 0xd5, 0x2f, 0x74, 0x36, 0x1d, 0x14, 0xcb, 0x10, 
> 0x0e,
> +  0x7d, 0x67, 0xbd, 0x38, 0x0e, 0xa4, 0x27, 0x1d, 0x3c, 0x78, 0x4d, 
> 0x0d,
> +  0x15, 0x42, 0x70, 0x20, 0xe0, 0x1d, 0x83, 0x6c, 0x4d, 0xf1, 0x02, 
> 0xa1,
> +  0x51, 0xc4, 0xc5, 0x5d, 0x69, 0x90, 0x58, 0x82, 0x94, 0x50, 0x36, 
> 0x22,
> +  0xb3, 0xa4, 0x15, 0x77, 0xdc, 0x44, 0xb0, 0x50, 0xa2, 0x3f, 0xd0, 
> 0x0e,
> +  0x1b, 0xfc, 0xf4, 0x5b, 0x3b, 0x7d, 0x63, 0x94, 0x22, 0xf3, 0x87, 
> 0x0a,
> +  0x41, 0x8a, 0x27, 0x48, 0xcb, 0x6c, 0xfd, 0x70, 0x66, 0x5f, 0x11, 
> 0x6f,
> +  0x74, 0x2c, 0x42, 0xaf, 0x74, 0x45, 0x3f, 0x0c, 0x03, 0xc8, 0x80, 
> 0xe2,
> +  0x71, 0x08, 0x93, 0xbd, 0x4d, 0x18, 0x78, 0x1e, 0x8e, 0xb9, 0x3a, 
> 0xd6,
> +  0x1a, 0xde, 0xf9, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
> 0x00,
> +  0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 
> 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 
> 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_signed_sha256_len = 739;
> +
> +unsigned char short_msg[] = {
> +  0x68, 0x69, 0x0a
> +};
> +unsigned int short_msg_len = 3;
> +
> +unsigned char unsigned_msg[] = {
> +  0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 
> 0x70,
> +  0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 
> 0x65,
> +  0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 
> 0x20,
> +  0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 
> 0x20,
> +  0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 
> 0x74,
> +  0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 
> 0x69,
> +  0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 
> 0x75,
> +  0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 
> 0x6d,
> +  0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 
> 0x20,
> +  0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 
> 0x71,
> +  0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 
> 0x65,
> +  0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 
> 0x76,
> +  0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 
> 0x74,
> +  0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 
> 0x73,
> +  0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 
> 0x6f,
> +  0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 
> 0x61,
> +  0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 
> 0x74,
> +  0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 
> 0x20,
> +  0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 
> 0x70,
> +  0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 
> 0x74,
> +  0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 
> 0x75,
> +  0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 
> 0x70,
> +  0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 
> 0x20,
> +  0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 
> 0x67,
> +  0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 
> 0x61,
> +  0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 
> 0x75,
> +  0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 
> 0x6f,
> +  0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 
> 0x20,
> +  0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 
> 0x75,
> +  0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 
> 0x69,
> +  0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 
> 0x4e,
> +  0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 
> 0x71,
> +  0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 
> 0x2c,
> +  0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 
> 0x6d,
> +  0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 
> 0x20,
> +  0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 
> 0x6d,
> +  0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 
> 0x65,
> +  0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 
> 0x63,
> +  0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 
> 0x64,
> +  0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 
> 0x75,
> +  0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 
> 0x6d,
> +  0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 
> 0x20,
> +  0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 
> 0x20,
> +  0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 
> 0x6f,
> +  0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 
> 0x20,
> +  0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 
> 0x65,
> +  0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 
> 0x74,
> +  0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 
> 0x20,
> +  0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 
> 0x65,
> +  0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 
> 0x6e,
> +  0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 
> 0x63,
> +  0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 
> 0x6c,
> +  0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 
> 0x73,
> +  0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 
> 0x61,
> +  0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 
> 0x69,
> +  0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 
> 0x69,
> +  0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 
> 0x6d,
> +  0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 
> 0x61,
> +  0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 
> 0x75,
> +  0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 
> 0x20,
> +  0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 
> 0x65,
> +  0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 
> 0x69,
> +  0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 
> 0x61,
> +  0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 
> 0x73,
> +  0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 
> 0x6c,
> +  0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 
> 0x63,
> +  0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 
> 0x20,
> +  0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 
> 0x75,
> +  0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 
> 0x75,
> +  0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 
> 0x6f,
> +  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 
> 0x75,
> +  0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 
> 0x72,
> +  0x3f, 0x0a
> +};
> +unsigned int unsigned_msg_len = 866;
> +
> +unsigned char certificate2_der[] = {
> +  0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 
> 0x01,
> +  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 
> 0xc5,
> +  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 
> 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 
> 0x0b,
> +  0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 
> 0x04,
> +  0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 
> 0x20,
> +  0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 
> 0x20,
> +  0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 
> 0x69,
> +  0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 
> 0x69,
> +  0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 
> 0x38,
> +  0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 
> 0x32,
> +  0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 
> 0x5a,
> +  0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 
> 0x0c,
> +  0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 
> 0x65,
> +  0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 
> 0x69,
> +  0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 
> 0x02,
> +  0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 
> 0x01,
> +  0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 
> 0x02,
> +  0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 
> 0x0e,
> +  0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 
> 0xe3,
> +  0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 
> 0x93,
> +  0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 
> 0xca,
> +  0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 
> 0x19,
> +  0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 
> 0x4a,
> +  0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 
> 0x14,
> +  0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 
> 0x29,
> +  0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 
> 0x55,
> +  0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 
> 0x37,
> +  0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 
> 0xdb,
> +  0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 
> 0x70,
> +  0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 
> 0x34,
> +  0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 
> 0x24,
> +  0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 
> 0xb6,
> +  0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 
> 0x9f,
> +  0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 
> 0x89,
> +  0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 
> 0xca,
> +  0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 
> 0xcc,
> +  0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 
> 0x26,
> +  0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 
> 0xe0,
> +  0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 
> 0x7a,
> +  0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 
> 0x63,
> +  0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 
> 0xa4,
> +  0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 
> 0xbb,
> +  0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 
> 0xf7,
> +  0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 
> 0xb8,
> +  0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 
> 0x04,
> +  0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 
> 0x8c,
> +  0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 
> 0xf2,
> +  0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 
> 0x24,
> +  0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 
> 0x66,
> +  0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 
> 0x51,
> +  0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 
> 0x0b,
> +  0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 
> 0xa2,
> +  0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 
> 0xb1,
> +  0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 
> 0x1c,
> +  0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 
> 0x73,
> +  0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 
> 0x41,
> +  0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 
> 0x98,
> +  0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 
> 0xbe,
> +  0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 
> 0xc5,
> +  0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 
> 0x24,
> +  0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 
> 0x30,
> +  0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 
> 0x30,
> +  0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 
> 0x02,
> +  0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 
> 0x04,
> +  0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 
> 0xe1,
> +  0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 
> 0x06,
> +  0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 
> 0x94,
> +  0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 
> 0xdb,
> +  0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 
> 0x86,
> +  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 
> 0x02,
> +  0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 
> 0xcf,
> +  0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 
> 0x64,
> +  0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 
> 0x1b,
> +  0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 
> 0x12,
> +  0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 
> 0x0d,
> +  0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 
> 0x91,
> +  0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 
> 0x5d,
> +  0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 
> 0x60,
> +  0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 
> 0x2c,
> +  0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 
> 0xe4,
> +  0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 
> 0xa1,
> +  0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 
> 0x79,
> +  0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 
> 0xfd,
> +  0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 
> 0x4a,
> +  0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 
> 0xb7,
> +  0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 
> 0x60,
> +  0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 
> 0x70,
> +  0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 
> 0xba,
> +  0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 
> 0x70,
> +  0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 
> 0x75,
> +  0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 
> 0x2d,
> +  0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 
> 0xda,
> +  0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 
> 0x86,
> +  0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 
> 0x0e,
> +  0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 
> 0x11,
> +  0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 
> 0xd9,
> +  0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 
> 0x95,
> +  0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 
> 0x3f,
> +  0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 
> 0x20,
> +  0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 
> 0x48,
> +  0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 
> 0xac,
> +  0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 
> 0x8b,
> +  0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 
> 0x75,
> +  0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 
> 0x71,
> +  0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 
> 0x8e,
> +  0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 
> 0x4a,
> +  0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 
> 0xa6,
> +  0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 
> 0x59,
> +  0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 
> 0x91,
> +  0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 
> 0x88,
> +  0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 
> 0x87,
> +  0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 
> 0x19,
> +  0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48
> +};
> +unsigned int certificate2_der_len = 1366;
> +
> +unsigned char hi_signed_2nd[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 
> 0x82,
> +  0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 
> 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 
> 0x02,
> +  0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 
> 0x3a,
> +  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 
> 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 
> 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 
> 0x74,
> +  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 
> 0x65,
> +  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 
> 0x14,
> +  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 
> 0x07,
> +  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 
> 0x06,
> +  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 
> 0x00,
> +  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 
> 0x90,
> +  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 
> 0x99,
> +  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 
> 0x07,
> +  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 
> 0xfe,
> +  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 
> 0x5f,
> +  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 
> 0x4f,
> +  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 
> 0x6f,
> +  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 
> 0x53,
> +  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 
> 0xd2,
> +  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 
> 0xc0,
> +  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 
> 0xdf,
> +  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 
> 0x05,
> +  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 
> 0x3d,
> +  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 
> 0x7d,
> +  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 
> 0x81,
> +  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 
> 0x36,
> +  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 
> 0xd5,
> +  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 
> 0xcc,
> +  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 
> 0x70,
> +  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 
> 0x94,
> +  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 
> 0xe3,
> +  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 
> 0x20,
> +  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 
> 0xc2,
> +  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 
> 0xac,
> +  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 
> 0xdb,
> +  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 
> 0x49,
> +  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 
> 0xb0,
> +  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 
> 0xcb,
> +  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 
> 0x76,
> +  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 
> 0xa5,
> +  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 
> 0x49,
> +  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 
> 0x6b,
> +  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 
> 0x25,
> +  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 
> 0x2e,
> +  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 
> 0xa0,
> +  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 
> 0x98,
> +  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 
> 0x8b,
> +  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 
> 0x83,
> +  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 
> 0x3e,
> +  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 
> 0x8a,
> +  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 
> 0xb7,
> +  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 
> 0x26,
> +  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 
> 0xac,
> +  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 
> 0xb5,
> +  0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 
> 0x6e,
> +  0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 
> 0x64,
> +  0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_signed_2nd_len = 736;
> +
> +unsigned char hi_double[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 
> 0x82,
> +  0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 
> 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 
> 0x04,
> +  0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 
> 0x3a,
> +  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 
> 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 
> 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 
> 0x74,
> +  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 
> 0x65,
> +  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 
> 0x14,
> +  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 
> 0x07,
> +  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 
> 0x06,
> +  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 
> 0x00,
> +  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 
> 0x90,
> +  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 
> 0x99,
> +  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 
> 0x07,
> +  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 
> 0xfe,
> +  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 
> 0x5f,
> +  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 
> 0x4f,
> +  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 
> 0x6f,
> +  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 
> 0x53,
> +  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 
> 0xd2,
> +  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 
> 0xc0,
> +  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 
> 0xdf,
> +  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 
> 0x05,
> +  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 
> 0x3d,
> +  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 
> 0x7d,
> +  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 
> 0x81,
> +  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 
> 0x36,
> +  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 
> 0xd5,
> +  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 
> 0xcc,
> +  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 
> 0x70,
> +  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 
> 0x94,
> +  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 
> 0xe3,
> +  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 
> 0x20,
> +  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 
> 0xc2,
> +  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 
> 0xac,
> +  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 
> 0xdb,
> +  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 
> 0x49,
> +  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 
> 0xb0,
> +  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 
> 0xcb,
> +  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 
> 0x76,
> +  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 
> 0xa5,
> +  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 
> 0x49,
> +  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 
> 0x6b,
> +  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 
> 0x25,
> +  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 
> 0x2e,
> +  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 
> 0xa0,
> +  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 
> 0x98,
> +  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 
> 0x8b,
> +  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 
> 0x83,
> +  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 
> 0x3e,
> +  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 
> 0x8a,
> +  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 
> 0xb7,
> +  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 
> 0x26,
> +  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 
> 0xac,
> +  0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 
> 0x31,
> +  0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 
> 0x72,
> +  0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 
> 0x20,
> +  0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 
> 0x65,
> +  0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 
> 0x61,
> +  0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 
> 0x79,
> +  0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 
> 0x3a,
> +  0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 
> 0x0b,
> +  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 
> 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 
> 0x01,
> +  0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 
> 0x97,
> +  0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 
> 0xdf,
> +  0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 
> 0x77,
> +  0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 
> 0x55,
> +  0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 
> 0xc2,
> +  0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 
> 0x88,
> +  0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 
> 0xd1,
> +  0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 
> 0xe3,
> +  0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 
> 0x45,
> +  0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 
> 0x86,
> +  0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 
> 0xcd,
> +  0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 
> 0x27,
> +  0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 
> 0xf1,
> +  0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 
> 0x1a,
> +  0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 
> 0x8d,
> +  0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 
> 0xc5,
> +  0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 
> 0xa1,
> +  0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 
> 0x04,
> +  0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 
> 0x9a,
> +  0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 
> 0x1c,
> +  0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 
> 0xd6,
> +  0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 
> 0xe9,
> +  0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 
> 0x60,
> +  0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 
> 0x83,
> +  0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 
> 0xd7,
> +  0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 
> 0x35,
> +  0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 
> 0x0f,
> +  0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 
> 0xa0,
> +  0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 
> 0xaa,
> +  0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 
> 0xe2,
> +  0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 
> 0xc3,
> +  0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 
> 0x24,
> +  0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 
> 0xe6,
> +  0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 
> 0x5e,
> +  0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 
> 0x74,
> +  0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 
> 0x3b,
> +  0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 
> 0x8a,
> +  0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 
> 0xdc,
> +  0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 
> 0x83,
> +  0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 
> 0x21,
> +  0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 
> 0x51,
> +  0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 
> 0x19,
> +  0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 
> 0x35,
> +  0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
> 0x00,
> +  0x05, 0x33, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 
> 0x69,
> +  0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 
> 0x65,
> +  0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_double_len = 1374;
> +
> +unsigned char hi_double_extended[] = {
> +  0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 
> 0x48,
> +  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 
> 0x82,
> +  0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 
> 0x60,
> +  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 
> 0x04,
> +  0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 
> 0x3a,
> +  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 
> 0x47,
> +  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 
> 0x74,
> +  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 
> 0x74,
> +  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 
> 0x65,
> +  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 
> 0x14,
> +  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 
> 0x07,
> +  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 
> 0x09,
> +  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 
> 0x06,
> +  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 
> 0x00,
> +  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 
> 0x90,
> +  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 
> 0x99,
> +  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 
> 0x07,
> +  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 
> 0xfe,
> +  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 
> 0x5f,
> +  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 
> 0x4f,
> +  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 
> 0x6f,
> +  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 
> 0x53,
> +  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 
> 0xd2,
> +  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 
> 0xc0,
> +  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 
> 0xdf,
> +  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 
> 0x05,
> +  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 
> 0x3d,
> +  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 
> 0x7d,
> +  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 
> 0x81,
> +  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 
> 0x36,
> +  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 
> 0xd5,
> +  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 
> 0xcc,
> +  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 
> 0x70,
> +  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 
> 0x94,
> +  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 
> 0xe3,
> +  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 
> 0x20,
> +  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 
> 0xc2,
> +  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 
> 0xac,
> +  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 
> 0xdb,
> +  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 
> 0x49,
> +  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 
> 0xb0,
> +  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 
> 0xcb,
> +  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 
> 0x76,
> +  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 
> 0xa5,
> +  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 
> 0x49,
> +  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 
> 0x6b,
> +  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 
> 0x25,
> +  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 
> 0x2e,
> +  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 
> 0xa0,
> +  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 
> 0x98,
> +  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 
> 0x8b,
> +  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 
> 0x83,
> +  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 
> 0x3e,
> +  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 
> 0x8a,
> +  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 
> 0xb7,
> +  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 
> 0x26,
> +  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 
> 0xac,
> +  0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 
> 0x31,
> +  0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 
> 0x72,
> +  0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 
> 0x20,
> +  0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 
> 0x65,
> +  0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 
> 0x61,
> +  0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 
> 0x79,
> +  0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 
> 0x3a,
> +  0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 
> 0x0b,
> +  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 
> 0x30,
> +  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 
> 0x01,
> +  0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 
> 0x97,
> +  0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 
> 0xdf,
> +  0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 
> 0x77,
> +  0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 
> 0x55,
> +  0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 
> 0xc2,
> +  0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 
> 0x88,
> +  0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 
> 0xd1,
> +  0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 
> 0xe3,
> +  0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 
> 0x45,
> +  0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 
> 0x86,
> +  0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 
> 0xcd,
> +  0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 
> 0x27,
> +  0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 
> 0xf1,
> +  0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 
> 0x1a,
> +  0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 
> 0x8d,
> +  0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 
> 0xc5,
> +  0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 
> 0xa1,
> +  0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 
> 0x04,
> +  0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 
> 0x9a,
> +  0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 
> 0x1c,
> +  0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 
> 0xd6,
> +  0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 
> 0xe9,
> +  0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 
> 0x60,
> +  0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 
> 0x83,
> +  0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 
> 0xd7,
> +  0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 
> 0x35,
> +  0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 
> 0x0f,
> +  0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 
> 0xa0,
> +  0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 
> 0xaa,
> +  0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 
> 0xe2,
> +  0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 
> 0xc3,
> +  0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 
> 0x24,
> +  0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 
> 0xe6,
> +  0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 
> 0x5e,
> +  0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 
> 0x74,
> +  0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 
> 0x3b,
> +  0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 
> 0x8a,
> +  0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 
> 0xdc,
> +  0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 
> 0x83,
> +  0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 
> 0x21,
> +  0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 
> 0x51,
> +  0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 
> 0x19,
> +  0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 
> 0x35,
> +  0x23, 0x2d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
> 0x00,
> +  0x00, 0x05, 0x34, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 
> 0x73,
> +  0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 
> 0x70,
> +  0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a
> +};
> +unsigned int hi_double_extended_len = 1375;
> +
> +unsigned char certificate_printable_der[] = {
> +  0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 
> 0x01,
> +  0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 
> 0x02,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 
> 0x55,
> +  0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 
> 0x20,
> +  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 
> 0x20,
> +  0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 
> 0x30,
> +  0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 
> 0x31,
> +  0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 
> 0x35,
> +  0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 
> 0x30,
> +  0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 
> 0x20,
> +  0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 
> 0x42,
> +  0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 
> 0x20,
> +  0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 
> 0x22,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 
> 0x0a,
> +  0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 
> 0x15,
> +  0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 
> 0xe2,
> +  0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 
> 0x9b,
> +  0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 
> 0x0b,
> +  0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 
> 0x11,
> +  0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 
> 0x3d,
> +  0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 
> 0x74,
> +  0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 
> 0x4d,
> +  0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 
> 0x39,
> +  0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 
> 0xd4,
> +  0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 
> 0x6b,
> +  0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 
> 0x4b,
> +  0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 
> 0x20,
> +  0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 
> 0xbf,
> +  0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 
> 0x3c,
> +  0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 
> 0x9b,
> +  0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 
> 0x0e,
> +  0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 
> 0xbf,
> +  0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 
> 0xa5,
> +  0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 
> 0x6f,
> +  0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 
> 0x34,
> +  0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 
> 0x01,
> +  0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 
> 0x1d,
> +  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 
> 0x03,
> +  0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 
> 0x06,
> +  0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 
> 0xca,
> +  0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 
> 0x8d,
> +  0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 
> 0x04,
> +  0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 
> 0xed,
> +  0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 
> 0xb3,
> +  0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 
> 0x01,
> +  0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 
> 0x3d,
> +  0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 
> 0x19,
> +  0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 
> 0xf6,
> +  0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 
> 0xfd,
> +  0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 
> 0x47,
> +  0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 
> 0x03,
> +  0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 
> 0x4d,
> +  0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 
> 0x93,
> +  0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 
> 0xa9,
> +  0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 
> 0x6c,
> +  0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 
> 0xe1,
> +  0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 
> 0x8d,
> +  0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 
> 0xdf,
> +  0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 
> 0x93,
> +  0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 
> 0xb1,
> +  0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 
> 0xae,
> +  0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 
> 0xf5,
> +  0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 
> 0x25,
> +  0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 
> 0x49,
> +  0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 
> 0x64,
> +  0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 
> 0x67,
> +  0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 
> 0x56,
> +  0xd2
> +};
> +unsigned int certificate_printable_der_len = 829;
> +
> +unsigned char certificate_eku_der[] = {
> +  0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 
> 0x01,
> +  0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 
> 0x45,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 
> 0x55,
> +  0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 
> 0x20,
> +  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 
> 0x20,
> +  0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 
> 0x86,
> +  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 
> 0x63,
> +  0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 
> 0x74,
> +  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 
> 0x32,
> +  0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 
> 0x33,
> +  0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 
> 0x5a,
> +  0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 
> 0x0c,
> +  0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 
> 0x63,
> +  0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 
> 0x67,
> +  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 
> 0x20,
> +  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 
> 0x16,
> +  0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 
> 0x65,
> +  0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 
> 0x22,
> +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 
> 0x01,
> +  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 
> 0x0a,
> +  0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 
> 0x15,
> +  0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 
> 0x85,
> +  0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 
> 0x06,
> +  0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 
> 0xb5,
> +  0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 
> 0x76,
> +  0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 
> 0xdd,
> +  0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 
> 0x1c,
> +  0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 
> 0xa9,
> +  0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 
> 0x78,
> +  0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 
> 0x29,
> +  0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 
> 0xcb,
> +  0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 
> 0x09,
> +  0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 
> 0xc6,
> +  0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 
> 0x27,
> +  0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 
> 0xc7,
> +  0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 
> 0x55,
> +  0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 
> 0x68,
> +  0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 
> 0x90,
> +  0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 
> 0x62,
> +  0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 
> 0x16,
> +  0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 
> 0x9b,
> +  0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 
> 0x01,
> +  0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 
> 0x1d,
> +  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 
> 0x03,
> +  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 
> 0x80,
> +  0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 
> 0x0c,
> +  0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 
> 0x03,
> +  0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 
> 0x6c,
> +  0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 
> 0x5f,
> +  0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 
> 0x55,
> +  0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 
> 0xab,
> +  0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 
> 0xb4,
> +  0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 
> 0x86,
> +  0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 
> 0x00,
> +  0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 
> 0xb9,
> +  0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 
> 0xef,
> +  0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 
> 0x29,
> +  0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 
> 0x7b,
> +  0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 
> 0xbf,
> +  0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 
> 0x32,
> +  0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 
> 0xa9,
> +  0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 
> 0x74,
> +  0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 
> 0xcb,
> +  0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 
> 0xd0,
> +  0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 
> 0x24,
> +  0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 
> 0x06,
> +  0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 
> 0x57,
> +  0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 
> 0x61,
> +  0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 
> 0x21,
> +  0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 
> 0xc1,
> +  0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 
> 0x81,
> +  0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 
> 0xa3,
> +  0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 
> 0x7e,
> +  0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 
> 0xdd,
> +  0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 
> 0x21,
> +  0x89, 0xa0, 0x55, 0xf7
> +};
> +unsigned int certificate_eku_der_len = 916;
> diff --git a/grub-core/tests/lib/functional_test.c
> b/grub-core/tests/lib/functional_test.c
> index 38e981f2c..23048919d 100644
> --- a/grub-core/tests/lib/functional_test.c
> +++ b/grub-core/tests/lib/functional_test.c
> @@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t
> ctxt __attribute__ ((unused)),
>    grub_dl_load ("xnu_uuid_test");
>    grub_dl_load ("pbkdf2_test");
>    grub_dl_load ("signature_test");
> +  grub_dl_load ("appended_signature_test");
>    grub_dl_load ("sleep_test");
>    grub_dl_load ("bswap_test");
>    grub_dl_load ("ctz_test");

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 12/21] appended signatures: documentation
  2024-12-18 14:56 ` [PATCH v1 12/21] appended signatures: documentation Sudhakar Kuppusamy
  2024-12-30 15:50   ` Stefan Berger
@ 2025-02-14 10:39   ` Avnish Chouhan
  1 sibling, 0 replies; 83+ messages in thread
From: Avnish Chouhan @ 2025-02-14 10:39 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper


Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>

On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
> From: Daniel Axtens <dja@axtens.net>
> 
> This explains how appended signatures can be used to form part of
> a secure boot chain, and documents the commands and variables
> introduced.
> 
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
> ---
>  docs/grub.texi | 185 ++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 167 insertions(+), 18 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 6e483298d..f71ce9ffc 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -3274,6 +3274,7 @@ These variables have special meaning to GRUB.
> 
>  @menu
>  * biosnum::
> +* check_appended_signatures::
>  * check_signatures::
>  * chosen::
>  * cmdpath::
> @@ -3336,12 +3337,16 @@ this.
>  For an alternative approach which also changes BIOS drive mappings for 
> the
>  chain-loaded system, @pxref{drivemap}.
> 
> +@node check_appended_signatures
> +@subsection check_appended_signatures
> +This variable controls whether GRUB enforces appended signature 
> validation on
> +certain loaded files. @xref{Using appended signatures}.
> 
>  @node check_signatures
>  @subsection check_signatures
> 
> -This variable controls whether GRUB enforces digital signature
> -validation on loaded files. @xref{Using digital signatures}.
> +This variable controls whether GRUB enforces GPG-style digital 
> signature
> +validation on loaded files. @xref{Using GPG-style digital signatures}.
> 
>  @node chosen
>  @subsection chosen
> @@ -6377,6 +6382,7 @@ 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
>  * drivemap::                    Map a drive to another
>  * echo::                        Display a line of text
>  * efitextmode::                 Set/Get text output mode resolution
> @@ -6395,6 +6401,7 @@ you forget a command, you can run the command
> @command{help}
>  * hexdump::                     Show raw contents of a file or memory
>  * insmod::                      Insert a module
>  * keystatus::                   Check key modifier status
> +* 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
> @@ -6435,8 +6442,10 @@ you forget a command, you can run the command
> @command{help}
>  * tpm2_key_protector_clear::    Clear the TPM2 key protector
>  * 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
>  * unset::                       Unset an environment variable
>  @comment * vbeinfo::                     List available video modes
> +* verify_appended::             Verify appended digital signature
>  * verify_detached::             Verify detached digital signature
>  * videoinfo::                   List available video modes
>  * wrmsr::                       Write values to model-specific 
> registers
> @@ -6778,7 +6787,24 @@ These keys are used to validate signatures when
> environment variable
>  @code{check_signatures} is set to @code{enforce}
>  (@pxref{check_signatures}), and by some invocations of
>  @command{verify_detached} (@pxref{verify_detached}).  @xref{Using
> -digital signatures}, for more information.
> +GPG-style digital signatures}, for more information.
> +@end deffn
> +
> +@node distrust_certificate
> +@subsection distrust_certificate
> +
> +@deffn Command distrust_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}).
> +
> +These certificates are used to validate appended signatures when 
> environment
> +variable @code{check_appended_signatures} is set to @code{enforce}
> +(@pxref{check_appended_signatures}), and by @command{verify_appended}
> +(@pxref{verify_appended}). See @xref{Using appended signatures} for 
> more
> +information.
>  @end deffn
> 
>  @node drivemap
> @@ -7169,6 +7195,19 @@ without any options, the @command{keystatus}
> command returns true if and
>  only if checking key modifier status is supported.
>  @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
> @@ -7189,7 +7228,7 @@ The output is in GPG's v4 key fingerprint format
> (i.e., the output of
>  @code{gpg --fingerprint}).  The least significant four bytes (last
>  eight hexadecimal digits) can be used as an argument to
>  @command{distrust} (@pxref{distrust}).
> -@xref{Using digital signatures}, for more information about uses for
> +@xref{Using GPG-style digital signatures}, for more information about 
> uses for
>  these keys.
>  @end deffn
> 
> @@ -7224,8 +7263,11 @@ When used with care, @option{--skip-sig} and
> the whitelist enable an
>  administrator to configure a system to boot only signed
>  configurations, but to allow the user to select from among multiple
>  configurations, and to enable ``one-shot'' boot attempts and
> -``savedefault'' behavior.  @xref{Using digital signatures}, for more
> +``savedefault'' behavior.  @xref{Using GPG-style digital signatures}, 
> for more
>  information.
> +Extra care should be taken when combining this command with appended 
> signatures
> +(@pxref{Using appended signatures}), as this file is not validated by 
> an
> +appended signature and could set @code{check_appended_signatures=no}.
>  @end deffn
> 
> 
> @@ -7596,7 +7638,7 @@ read.  It is possible to modify a digitally
> signed environment block
>  file from within GRUB using this command, such that its signature will
>  no longer be valid on subsequent boots.  Care should be taken in such
>  advanced configurations to avoid rendering the system
> -unbootable. @xref{Using digital signatures}, for more information.
> +unbootable. @xref{Using GPG-style digital signatures}, for more 
> information.
>  @end deffn
> 
> 
> @@ -8064,11 +8106,30 @@ signatures when environment variable
> @code{check_signatures} is set to
>  must itself be properly signed.  The @option{--skip-sig} option can be
>  used to disable signature-checking when reading @var{pubkey_file}
>  itself. It is expected that @option{--skip-sig} is useful for testing
> -and manual booting. @xref{Using digital signatures}, for more
> +and manual booting. @xref{Using GPG-style digital signatures}, for 
> more
>  information.
>  @end deffn
> 
> 
> +@node trust_certificate
> +@subsection trust_certificate
> +
> +@deffn Command trust_certificate x509_certificate
> +Read a 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
> +variable @code{check_appended_signatures} is set to @code{enforce}.
> +
> +Note that if @code{check_appended_signatures} is set to @code{enforce}
> +when @command{trust_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 signatures 
> within x509
> +certificates themselves.)
> +
> +See @xref{Using appended signatures} for more information.
> +@end deffn
> +
>  @node unset
>  @subsection unset
> 
> @@ -8087,6 +8148,18 @@ only on PC BIOS platforms.
>  @end deffn
>  @end ignore
> 
> +@node verify_appended
> +@subsection verify_appended
> +
> +@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}).
> +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.
> +@end deffn
> 
>  @node verify_detached
>  @subsection verify_detached
> @@ -8105,7 +8178,7 @@ tried.
> 
>  Exit code @code{$?} is set to 0 if the signature validates
>  successfully.  If validation fails, it is set to a non-zero value.
> -@xref{Using digital signatures}, for more information.
> +@xref{Using GPG-style digital signatures}, for more information.
>  @end deffn
> 
>  @node videoinfo
> @@ -8565,14 +8638,15 @@ environment variables and commands are listed
> in the same order.
>  @chapter Security
> 
>  @menu
> -* Authentication and authorisation:: Users and access control
> -* Using digital signatures::         Booting digitally signed code
> -* UEFI secure boot and shim::        Booting digitally signed PE files
> -* Secure Boot Advanced Targeting::   Embedded information for
> generation number based revocation
> -* Measured Boot::                    Measuring boot components
> -* Lockdown::                         Lockdown when booting on a secure 
> setup
> -* TPM2 key protector::               Managing disk key with TPM2 key 
> protector
> -* Signing GRUB itself::              Ensuring the integrity of the
> GRUB core image
> +* Authentication and authorisation::   Users and access control
> +* Using GPG-style digital signatures:: Booting digitally signed code
> +* Using appended signatures::          An alternative approach to
> booting digitally signed code
> +* UEFI secure boot and shim::          Booting digitally signed PE 
> files
> +* Secure Boot Advanced Targeting::     Embedded information for
> generation number based revocation
> +* Measured Boot::                      Measuring boot components
> +* Lockdown::                           Lockdown when booting on a 
> secure setup
> +* TPM2 key protector::                 Managing disk key with TPM2
> key protector
> +* Signing GRUB itself::                Ensuring the integrity of the
> GRUB core image
>  @end menu
> 
>  @node Authentication and authorisation
> @@ -8648,8 +8722,8 @@ generating configuration files with
> authentication.  You can use
>  adding @kbd{set superusers=} and @kbd{password} or 
> @kbd{password_pbkdf2}
>  commands.
> 
> -@node Using digital signatures
> -@section Using digital signatures in GRUB
> +@node Using GPG-style digital signatures
> +@section Using GPG-style digital signatures in GRUB
> 
>  GRUB's @file{core.img} can optionally provide enforcement that all 
> files
>  subsequently read from disk are covered by a valid digital signature.
> @@ -8732,6 +8806,81 @@ or BIOS) configuration to cause the machine to
> boot from a different
>  (attacker-controlled) device.  GRUB is at best only one link in a
>  secure boot chain.
> 
> +@node Using appended signatures
> +@section Using appended signatures in GRUB
> +
> +GRUB supports verifying Linux-style 'appended signatures' for secure 
> boot.
> +Appended signatures are PKCS#7 messages containing a signature over 
> the
> +contents of a file, plus some metadata, appended to the end of a file. 
> A file
> +with an appended signature ends with the magic string:
> +
> +@example
> +~Module signature appended~\n
> +@end example
> +
> +where @code{\n} represents the carriage-return character, @code{0x0a}.
> +
> +To enable appended signature verification, load the appendedsig module 
> and an
> +x509 certificate for verification. Building the appendedsig module 
> into the
> +core grub image is recommended.
> +
> +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}.
> +A file can be explictly verified using the @pxref{verify_appended} 
> command.
> +
> +Only signatures made with the SHA-256 or SHA-512 hash algorithm are 
> supported,
> +and only RSA signatures are supported.
> +
> +A file can be signed with the @command{sign-file} utility supplied 
> with the
> +Linux kernel source. For example, if you have @code{signing.key} as 
> the private
> +key and @code{certificate.der} as the x509 certificate containing the
> public key:
> +
> +@example
> +sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
> +@end example
> +
> +Enforcement of signature verification is controlled by the
> +@code{check_appended_signatures} variable. Verification will only take 
> place
> +when files are loaded if the variable is set to @code{enforce}. If a
> +certificate is built into the grub core image with the @code{--x509} 
> parameter,
> +the variable will be automatically set to @code{enforce} when the 
> appendedsig
> +module is loaded.
> +
> +Unlike GPG-style signatures, not all files loaded by GRUB are required 
> to be
> +signed. Once verification is turned on, the following file types must 
> carry
> +appended signatures:
> +
> +@enumerate
> +@item Linux, Multiboot, BSD, XNU and Plan9 kernels
> +@item Grub modules, except those built in to the core image
> +@item Any new certificate files to be trusted
> +@end enumerate
> +
> +ACPI tables and Device Tree images will not be checked for appended 
> signatures
> +but must be verified by another mechanism such as GPG-style signatures 
> before
> +they will be loaded.
> +
> +No attempt is made to validate any other file type. In particular,
> +chain-loaded binaries are not verified - if your platform supports
> +chain-loading and this cannot be disabled, consider an alternative 
> secure
> +boot mechanism.
> +
> +As with GPG-style appended signatures, signature checking does 
> @strong{not}
> +stop an attacker with console access from dropping manually to the 
> GRUB
> +console and executing:
> +
> +@example
> +set check_appended_signatures=no
> +@end example
> +
> +Refer to the section on password-protecting GRUB 
> (@pxref{Authentication
> +and authorisation}) for more information on preventing this.
> +
> +Additionally, special care must be taken around the @command{loadenv} 
> command,
> +which can be used to turn off @code{check_appended_signature}.
> +
>  @node UEFI secure boot and shim
>  @section UEFI secure boot and shim support

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature
  2024-12-27 14:58   ` Stefan Berger
@ 2025-02-26  4:24     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-26  4:24 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish, Rashmica Gupta

On 2024-12-27 20:28, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> From: Rashmica Gupta <rashmica.g@gmail.com>
>> 
>> Add infrastructure to allow firmware to verify the integrity of grub
>> by use of a Linux-kernel-module-style appended signature. We initially
>> target powerpc-ieee1275, but the code should be extensible to other
>> platforms.
>> 
>> Usually these signatures are appended to a file without modifying the
>> ELF file itself. (This is what the 'sign-file' tool does, for 
>> example.)
>> The verifier loads the signed file from the file system and looks at 
>> the
>> end of the file for the appended signature. However, on 
>> powerpc-ieee1275
>> platforms, the bootloader is often stored directly in the PReP 
>> partition
>> as raw bytes without a file-system. This makes determining the 
>> location
>> of an appended signature more difficult.
>> 
>> To address this, we add a new ELF note.
>> 
>> The name field of shall be the string "Appended-Signature", 
>> zero-padded
>> to 4 byte alignment. The type field shall be 0x41536967 (the ASCII 
>> values
>> for the string "ASig"). It must be the final section in the ELF 
>> binary.
>> 
>> The description shall contain the appended signature structure as 
>> defined
>> by the Linux kernel. The description will also be padded to be a 
>> multiple
>> of 4 bytes. The padding shall be added before the appended signature
>> structure (not at the end) so that the final bytes of a signed ELF 
>> file
>> are the appended signature magic.
>> 
>> A subsequent patch documents how to create a grub core.img validly 
>> signed
>> under this scheme.
>> 
>> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   include/grub/util/install.h |  7 +++++--
>>   include/grub/util/mkimage.h |  4 ++--
>>   util/grub-install-common.c  | 15 ++++++++++++---
>>   util/grub-mkimage.c         | 11 +++++++++++
>>   util/grub-mkimagexx.c       | 38 
>> ++++++++++++++++++++++++++++++++++++-
>>   util/mkimage.c              |  6 +++---
>>   6 files changed, 70 insertions(+), 11 deletions(-)
>> 
>> diff --git a/include/grub/util/install.h b/include/grub/util/install.h
>> index 5c0a52ca2..3aabc4285 100644
>> --- a/include/grub/util/install.h
>> +++ b/include/grub/util/install.h
>> @@ -69,6 +69,8 @@
>>         N_("disable shim_lock verifier"), 0 },				\
>>     { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0,		\
>>       N_("disabled command line interface access"), 0 },			\
>> +  { "appended-signature-size", 
>> GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,  \
>> +    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an 
>> appended signature"), 1}, \
>>     { "verbose", 'v', 0, 0,						\
>>       N_("print verbose messages."), 1 }
>>   @@ -132,7 +134,8 @@ enum grub_install_options {
>>     GRUB_INSTALL_OPTIONS_DTB,
>>     GRUB_INSTALL_OPTIONS_SBAT,
>>     GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
>> -  GRUB_INSTALL_OPTIONS_DISABLE_CLI
>> +  GRUB_INSTALL_OPTIONS_DISABLE_CLI,
>> +  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
>>   };
>>     extern char *grub_install_source_directory;
>> @@ -192,7 +195,7 @@ grub_install_generate_image (const char *dir, 
>> const char *prefix,
>>   			     size_t npubkeys,
>>   			     char *config_path,
>>   			     const struct grub_install_image_target_desc *image_target,
>> -			     int note,
>> +			     int note, size_t appsig_size,
>>   			     grub_compression_t comp, const char *dtb_file,
>>   			     const char *sbat_path, const int disable_shim_lock,
>>   			     const int disable_cli);
>> diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
>> index 9d74f82c5..0d40383eb 100644
>> --- a/include/grub/util/mkimage.h
>> +++ b/include/grub/util/mkimage.h
>> @@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char 
>> *kernel_path,
>>   			   const struct grub_install_image_target_desc *image_target);
>>   void
>>   grub_mkimage_generate_elf32 (const struct 
>> grub_install_image_target_desc *image_target,
>> -			     int note, char *sbat, char **core_img, size_t *core_size,
>> +			     int note, char *sbat, size_t appsig_size, char **core_img, 
>> size_t *core_size,
>>   			     Elf32_Addr target_addr,
>>   			     struct grub_mkimage_layout *layout);
>>   void
>>   grub_mkimage_generate_elf64 (const struct 
>> grub_install_image_target_desc *image_target,
>> -			     int note, char *sbat, char **core_img, size_t *core_size,
>> +			     int note, char *sbat, size_t appsig_size, char **core_img, 
>> size_t *core_size,
>>   			     Elf64_Addr target_addr,
>>   			     struct grub_mkimage_layout *layout);
>>   diff --git a/util/grub-install-common.c b/util/grub-install-common.c
>> index 22bccb6a3..22f0e56cb 100644
>> --- a/util/grub-install-common.c
>> +++ b/util/grub-install-common.c
>> @@ -467,10 +467,12 @@ static char *sbat;
>>   static int disable_shim_lock;
>>   static grub_compression_t compression;
>>   static int disable_cli;
>> +static size_t appsig_size;
>>     int
>>   grub_install_parse (int key, char *arg)
>>   {
>> +  const char *end;
>>     switch (key)
>>       {
>>       case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
>> @@ -571,6 +573,12 @@ grub_install_parse (int key, char *arg)
>>         grub_util_error (_("Unrecognized compression `%s'"), arg);
>>       case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
>>         return 1;
>> +    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
>> +      grub_errno = 0;
>> +      appsig_size = grub_strtol (arg, &end, 10);
>> +      if (grub_errno)
>> +        return 0;
>> +      return 1;
>>       default:
>>         return 0;
>>       }
>> @@ -683,9 +691,10 @@ grub_install_make_image_wrap_file (const char 
>> *dir, const char *prefix,
>>     *p = '\0';
>>       grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' 
>> --output '%s'"
>> -		  " --format '%s' --compression '%s'%s%s%s%s\n",
>> +		  " --format '%s' --compression '%s'"
>> +		  " --appended-signature-size %zu %s %s %s %s\n",
>>   		  dir, prefix, outname,
>> -		  mkimage_target, compnames[compression],
>> +		  mkimage_target, compnames[compression], appsig_size,
>>   		  note ? " --note" : "",
>>   		  disable_shim_lock ? " --disable-shim-lock" : "",
>>   		  disable_cli ? " --disable-cli" : "", s);
>> @@ -698,7 +707,7 @@ grub_install_make_image_wrap_file (const char 
>> *dir, const char *prefix,
>>     grub_install_generate_image (dir, prefix, fp, outname,
>>   			       modules.entries, memdisk_path,
>>   			       pubkeys, npubkeys, config_path, tgt,
>> -			       note, compression, dtb, sbat,
>> +			       note, appsig_size, compression, dtb, sbat,
>>   			       disable_shim_lock, disable_cli);
>>     while (dc--)
>>       grub_install_pop_module ();
>> diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
>> index 547f7310f..6c5063ac2 100644
>> --- a/util/grub-mkimage.c
>> +++ b/util/grub-mkimage.c
>> @@ -84,6 +84,7 @@ static struct argp_option options[] = {
>>     {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
>>     {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 
>> 0, N_("disable shim_lock verifier"), 0},
>>     {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, 
>> N_("disable command line interface access"), 0},
>> +  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note 
>> segment reserving SIZE bytes for an appended signature"), 0},
>>     {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
>>     { 0, 0, 0, 0, 0, 0 }
>>   };
>> @@ -130,6 +131,7 @@ struct arguments
>>     int note;
>>     int disable_shim_lock;
>>     int disable_cli;
>> +  size_t appsig_size;
>>     const struct grub_install_image_target_desc *image_target;
>>     grub_compression_t comp;
>>   };
>> @@ -140,6 +142,7 @@ argp_parser (int key, char *arg, struct argp_state 
>> *state)
>>     /* Get the input argument from argp_parse, which we
>>        know is a pointer to our arguments structure. */
>>     struct arguments *arguments = state->input;
>> +  const char* end;
> 
> const char *end;
> 
> 
>>       switch (key)
>>       {
>> @@ -172,6 +175,13 @@ argp_parser (int key, char *arg, struct 
>> argp_state *state)
>>         arguments->note = 1;
>>         break;
>>   +    case 'S':
>> +      grub_errno = 0;
>> +      arguments->appsig_size = grub_strtol (arg, &end, 10);
>> +      if (grub_errno)
>> +        return 0;
>> +      break;
>> +
>>       case 'm':
>>         if (arguments->memdisk)
>>   	free (arguments->memdisk);
>> @@ -330,6 +340,7 @@ main (int argc, char *argv[])
>>   			       arguments.memdisk, arguments.pubkeys,
>>   			       arguments.npubkeys, arguments.config,
>>   			       arguments.image_target, arguments.note,
>> +			       arguments.appsig_size,
>>   			       arguments.comp, arguments.dtb,
>>   			       arguments.sbat, arguments.disable_shim_lock,
>>   			       arguments.disable_cli);
>> diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
>> index 448862b2e..6fe348e5b 100644
>> --- a/util/grub-mkimagexx.c
>> +++ b/util/grub-mkimagexx.c
>> @@ -115,6 +115,14 @@ struct grub_sbat_note {
>>     char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
>>   };
>>   +#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
>> +#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
>> +struct grub_appended_signature_note
>> +{
>> +  Elf32_Nhdr header;
>> +  char name[ALIGN_UP (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 
>> 4)];
>> +};
>> +
>>   static int
>>   is_relocatable (const struct grub_install_image_target_desc 
>> *image_target)
>>   {
>> @@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, 
>> Elf32_Addr sym_addr)
>>     void
>>   SUFFIX (grub_mkimage_generate_elf) (const struct 
>> grub_install_image_target_desc *image_target,
>> -				    int note, char *sbat, char **core_img, size_t *core_size,
>> +				    int note, char *sbat, size_t appsig_size, char **core_img, 
>> size_t *core_size,
>>   				    Elf_Addr target_addr,
>>   				    struct grub_mkimage_layout *layout)
>>   {
>> @@ -237,6 +245,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct 
>> grub_install_image_target_desc
>>         footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + 
>> layout->sbat_size, 4);
>>       }
>>   +  if (appsig_size)
>> +    {
>> +      phnum++;
>> +      footer_size += ALIGN_UP (sizeof (struct 
>> grub_appended_signature_note) + appsig_size, 4);
>> +    }
>> +
>>     if (image_target->id != IMAGE_LOONGSON_ELF)
>>       phnum += 2;
>>   @@ -527,6 +541,28 @@ SUFFIX (grub_mkimage_generate_elf) (const 
>> struct grub_install_image_target_desc
>>         phdr->p_filesz = grub_host_to_target32 (note_size);
>>         phdr->p_memsz = 0;
>>         phdr->p_offset = grub_host_to_target32 (header_size + 
>> program_size + footer_offset);
>> +      footer += note_size;
>> +      footer_offset += note_size;
>> +    }
>> +
>> +  if (appsig_size)
>> +    {
>> +      int note_size = ALIGN_UP (sizeof (struct 
>> grub_appended_signature_note) + appsig_size, 4);
>> +      struct grub_appended_signature_note *note_ptr = (struct 
>> grub_appended_signature_note *) footer;
>> +      note_ptr->header.n_namesz = grub_host_to_target32 (sizeof 
>> (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
>> +      /* needs to sit at the end, so we round this up and sign some 
>> zero padding */
>> +      note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP 
>> (appsig_size, 4));
>> +      note_ptr->header.n_type = grub_host_to_target32 
>> (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
>> +      strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
>> +      phdr++;
>> +      phdr->p_type = grub_host_to_target32 (PT_NOTE);
>> +      phdr->p_flags = grub_host_to_target32 (PF_R);
>> +      phdr->p_align = grub_host_to_target32 
>> (image_target->voidp_sizeof);
>> +      phdr->p_vaddr = 0;
>> +      phdr->p_paddr = 0;
>> +      phdr->p_filesz = grub_host_to_target32 (note_size);
>> +      phdr->p_memsz = 0;
>> +      phdr->p_offset = grub_host_to_target32 (header_size + 
>> program_size + footer_offset);
>>       }
>>       {
>> diff --git a/util/mkimage.c b/util/mkimage.c
>> index b46df2909..f5c59f563 100644
>> --- a/util/mkimage.c
>> +++ b/util/mkimage.c
>> @@ -885,7 +885,7 @@ grub_install_generate_image (const char *dir, 
>> const char *prefix,
>>   			     char *memdisk_path, char **pubkey_paths,
>>   			     size_t npubkeys, char *config_path,
>>   			     const struct grub_install_image_target_desc *image_target,
>> -			     int note, grub_compression_t comp, const char *dtb_path,
>> +			     int note, size_t appsig_size, grub_compression_t comp, const 
>> char *dtb_path,
>>   			     const char *sbat_path, int disable_shim_lock,
>>   			     int disable_cli)
>>   {
>> @@ -1833,10 +1833,10 @@ grub_install_generate_image (const char *dir, 
>> const char *prefix,
>>   	else
>>   	  target_addr = image_target->link_addr;
>>   	if (image_target->voidp_sizeof == 4)
>> -	  grub_mkimage_generate_elf32 (image_target, note, sbat, &core_img, 
>> &core_size,
>> +	  grub_mkimage_generate_elf32 (image_target, note, sbat, 
>> appsig_size, &core_img, &core_size,
>>   				       target_addr, &layout);
>>   	else
>> -	  grub_mkimage_generate_elf64 (image_target, note, sbat, &core_img, 
>> &core_size,
>> +	  grub_mkimage_generate_elf64 (image_target, note, sbat, 
>> appsig_size, &core_img, &core_size,
>>   				       target_addr, &layout);
>>         }
>>         break;
> 
> With nit fixed:
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

Thank you Stefan. fixed it.

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates
  2024-12-28 19:46   ` Stefan Berger
@ 2025-02-26  4:26     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-26  4:26 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish, Javier Martinez Canillas,
	Michal Suchanek

On 2024-12-29 01:16, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> This code allows us to parse:
>> 
>>   - PKCS#7 signedData messages. Only a single signerInfo is supported,
>>     which is all that the Linux sign-file utility supports creating
>>     out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
>>     Any certificate embedded in the PKCS#7 message will be ignored.
>> 
>>   - X.509 certificates: at least enough to verify the signatures on 
>> the
>>     PKCS#7 messages. We expect that the certificates embedded in grub 
>> will
>>     be leaf certificates, not CA certificates. The parser enforces 
>> this.
>> 
>>   - X.509 certificates support the Extended Key Usage extension and 
>> handle
>>     it by verifying that the certificate has a single purpose, that is 
>> code
>>     signing. This is required because Red Hat certificates have both 
>> Key
>>     Usage and Extended Key Usage extensions present.
>> 
>> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> # EKU 
>> support
>> Reported-by: Michal Suchanek <msuchanek@suse.com> # key usage issue
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   grub-core/commands/appendedsig/appendedsig.h | 110 +++
>>   grub-core/commands/appendedsig/asn1util.c    |  99 ++
>>   grub-core/commands/appendedsig/pkcs7.c       | 473 +++++++++
>>   grub-core/commands/appendedsig/x509.c        | 981 
>> +++++++++++++++++++
>>   4 files changed, 1663 insertions(+)
>>   create mode 100644 grub-core/commands/appendedsig/appendedsig.h
>>   create mode 100644 grub-core/commands/appendedsig/asn1util.c
>>   create mode 100644 grub-core/commands/appendedsig/pkcs7.c
>>   create mode 100644 grub-core/commands/appendedsig/x509.c
>> 
>> diff --git a/grub-core/commands/appendedsig/appendedsig.h 
>> b/grub-core/commands/appendedsig/appendedsig.h
>> new file mode 100644
>> index 000000000..fa59302c8
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/appendedsig.h
>> @@ -0,0 +1,110 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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/crypto.h>
>> +#include <grub/libtasn1.h>
>> +
>> +extern asn1_node _gnutls_gnutls_asn;
>> +extern asn1_node _gnutls_pkix_asn;
>> +
>> +#define MAX_OID_LEN 32
>> +
>> +/*
>> + * One or more x509 certificates.
>> + * We do limited parsing: extracting only the serial, CN and RSA 
>> public key.
>> + */
>> +struct x509_certificate
>> +{
>> +  struct x509_certificate *next;
>> +  grub_uint8_t *serial;
>> +  grub_size_t serial_len;
>> +  char *subject;
>> +  grub_size_t subject_len;
>> +  /* We only support RSA public keys. This encodes [modulus, 
>> publicExponent] */
>> +  gcry_mpi_t mpis[2];
>> +};
>> +
>> +/*
>> + * A PKCS#7 signedData signerInfo.
>> + */
>> +struct pkcs7_signerInfo
>> +{
>> +  const gcry_md_spec_t *hash;
>> +  gcry_mpi_t sig_mpi;
>> +};
>> +
>> +/*
>> + * A PKCS#7 signedData message.
>> + * We make no attempt to match intelligently, so we don't save any 
>> info about
>> + * the signer.
>> + */
>> +struct pkcs7_signedData
>> +{
>> +  int signerInfo_count;
>> +  struct pkcs7_signerInfo *signerInfos;
>> +};
>> +
>> +/* Do libtasn1 init */
>> +int
>> +asn1_init (void);
>> +
>> +/*
>> + * Import a DER-encoded certificate at 'data', of size 'size'.
>> + * Place the results into 'results', which must be already allocated.
>> + */
>> +grub_err_t
>> +parse_x509_certificate (const void *data, grub_size_t size, struct 
>> x509_certificate *results);
>> +
>> +/*
>> + * Release all the storage associated with the x509 certificate.
>> + * If the caller dynamically allocated the certificate, it must free 
>> it.
>> + * The caller is also responsible for maintenance of the linked list.
>> + */
>> +void
>> +certificate_release (struct x509_certificate *cert);
>> +
>> +/*
>> + * Parse a PKCS#7 message, which must be a signedData message.
>> + * The message must be in 'sigbuf' and of size 'data_size'. The 
>> result is
>> + * placed in 'msg', which must already be allocated.
>> + */
>> +grub_err_t
>> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, 
>> struct pkcs7_signedData *msg);
>> +
>> +/*
>> + * Release all the storage associated with the PKCS#7 message.
>> + * If the caller dynamically allocated the message, it must free it.
>> + */
>> +void
>> +pkcs7_signedData_release (struct pkcs7_signedData *msg);
>> +
>> +/*
>> + * Read a value from an ASN1 node, allocating memory to store it.
>> + * It will work for anything where the size libtasn1 returns is 
>> right:
>> + *  - Integers
>> + *  - Octet strings
>> + *  - DER encoding of other structures
>> + * It will _not_ work for things where libtasn1 size requires 
>> adjustment:
>> + *  - Strings that require an extra NULL byte at the end
> 
> NUL byte.
> 
>> + *  - Bit strings because libtasn1 returns the length in bits, not 
>> bytes.
>> + *
>> + * If the function returns a non-NULL value, the caller must free it.
>> + */
>> +void *
>> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const 
>> char *friendly_name, int *content_size);
>> diff --git a/grub-core/commands/appendedsig/asn1util.c 
>> b/grub-core/commands/appendedsig/asn1util.c
>> new file mode 100644
>> index 000000000..609d0ecf2
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/asn1util.c
>> @@ -0,0 +1,99 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
>> +#include <grub/types.h>
>> +#include <grub/err.h>
>> +#include <grub/mm.h>
>> +#include <grub/crypto.h>
>> +#include <grub/misc.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +
>> +#include "appendedsig.h"
>> +
>> +asn1_node _gnutls_gnutls_asn = NULL;
>> +asn1_node _gnutls_pkix_asn = NULL;
>> +
>> +extern const asn1_static_node gnutls_asn1_tab[];
>> +extern const asn1_static_node pkix_asn1_tab[];
>> +
>> +/*
>> + * Read a value from an ASN1 node, allocating memory to store it.
>> + * It will work for anything where the size libtasn1 returns is 
>> right:
>> + *  - Integers
>> + *  - Octet strings
>> + *  - DER encoding of other structures
>> + * It will _not_ work for things where libtasn1 size requires 
>> adjustment:
>> + *  - Strings that require an extra NULL byte at the end
>> + *  - Bit strings because libtasn1 returns the length in bits, not 
>> bytes.
>> + * If the function returns a non-NULL value, the caller must free it.
>> + */
>> +void *
>> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const 
>> char *friendly_name, int *content_size)
>> +{
>> +  int result;
>> +  grub_uint8_t *tmpstr = NULL;
>> +  int tmpstr_size = 0;
>> +
>> +  result = asn1_read_value (node, name, NULL, &tmpstr_size);
>> +  if (result != ASN1_MEM_ERROR)
>> +    {
>> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
>> +                     _("Reading size of %s did not return expected 
>> status: %s"),
>> +                     friendly_name, asn1_strerror (result));
>> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
>> +      return NULL;
>> +    }
>> +
>> +  tmpstr = grub_malloc (tmpstr_size);
>> +  if (tmpstr == NULL)
>> +    {
>> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
>> +                     "Could not allocate memory to store %s", 
>> friendly_name);
>> +      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
>> +      return NULL;
>> +    }
>> +
>> +  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      grub_free (tmpstr);
>> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error 
>> reading %s: %s",
>> +                     friendly_name, asn1_strerror (result));
>> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
>> +      return NULL;
>> +    }
>> +
>> +  *content_size = tmpstr_size;
>> +
>> +  return tmpstr;
>> +}
>> +
>> +int
>> +asn1_init (void)
>> +{
>> +  int res;
>> +  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      return res;
>> +    }
>> +  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
>> +  return res;
>> +}
>> diff --git a/grub-core/commands/appendedsig/pkcs7.c 
>> b/grub-core/commands/appendedsig/pkcs7.c
>> new file mode 100644
>> index 000000000..61e560854
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/pkcs7.c
>> @@ -0,0 +1,473 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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 "appendedsig.h"
>> +#include <grub/misc.h>
>> +#include <grub/crypto.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +#include <sys/types.h>
>> +
>> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
>> +
>> +/*
>> + * RFC 5652 s 5.1
>> + */
>> +static const char *signedData_oid = "1.2.840.113549.1.7.2";
>> +
>> +/*
>> + * RFC 4055 s 2.1
>> + */
>> +static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
>> +static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
>> +
>> +static grub_err_t
>> +process_content (grub_uint8_t *content, int size, struct 
>> pkcs7_signedData *msg)
>> +{
>> +  int res;
>> +  asn1_node signed_part;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char algo_oid[MAX_OID_LEN];
>> +  int algo_oid_size = sizeof (algo_oid);
>> +  int algo_count;
>> +  int signer_count;
>> +  int i;
>> +  char version;
>> +  int version_size = sizeof (version);
>> +  grub_uint8_t *result_buf;
>> +  int result_size = 0;
>> +  int crls_size = 0;
>> +  gcry_error_t gcry_err;
>> +  bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
>> +  char *da_path;
>> +  char *si_sig_path;
>> +  char *si_da_path;
>> +
>> +  res = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.pkcs-7-SignedData", &signed_part);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for PKCS#7 
>> signed "
>> +                         "part.");
>> +    }
>> +
>> +  res = asn1_der_decoding2 (&signed_part, content, &size,
>> +                            ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Error reading PKCS#7 signed data: %s", 
>> asn1_error);
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  /*
>> +   * SignedData ::= SEQUENCE {
>> +   *     version CMSVersion,
>> +   *     digestAlgorithms DigestAlgorithmIdentifiers,
>> +   *     encapContentInfo EncapsulatedContentInfo,
>> +   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
>> +   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
>> +   *     signerInfos SignerInfos }
>> +   */
>> +
>> +  /* version per the algo in 5.1, must be 1 */
>> +  res = asn1_read_value (signed_part, "version", &version, 
>> &version_size);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading 
>> signedData version: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (version != 1)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Unexpected signature version v%d, only v1 
>> supported", version);
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  /*
>> +   * digestAlgorithms DigestAlgorithmIdentifiers
>> +   *
>> +   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
>> +   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier 
>> (10.1.1)
>> +   *
>> +   * RFC 4055 s 2.1:
>> +   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
>> +   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
>> +   *
>> +   * We only support 1 element in the set, and we do not check 
>> parameters atm.
>> +   */
>> +  res = asn1_number_of_elements (signed_part, "digestAlgorithms", 
>> &algo_count);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting 
>> number of digest algorithms: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (algo_count <= 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "A minimum of 1 digest algorithm is 
>> required");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (algo_count > 2)
>> +    {
>> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                        "A maximum of 2 digest algorithms are 
>> supported");
> 
> s/are/is - it's the maximum that 'is' supported
> 
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  sha256_in_da = false;
>> +  sha512_in_da = false;
>> +
>> +  for (i = 0; i < algo_count; i++)
>> +    {
>> +      da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 
>> 1);
>> +      if (!da_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                            "Could not allocate path for digest 
>> algorithm "
>> +                            "parsing path");
>> +          goto cleanup_signed_part;
>> +        }
>> +
>> +      algo_oid_size = sizeof (algo_oid);
>> +      res = asn1_read_value (signed_part, da_path, algo_oid, 
>> &algo_oid_size);
>> +      if (res != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading 
>> digest algorithm: %s",
>> +                            asn1_strerror (res));
>> +          grub_free (da_path);
>> +          goto cleanup_signed_part;
>> +        }
>> +
>> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
>> +        {
>> +          if (!sha512_in_da)
>> +            {
>> +              sha512_in_da = true;
>> +            }
>> +          else
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                                "SHA-512 specified twice in digest 
>> algorithm "
>> +                                "list");
> 
> Move "list" to line above
> 
>> +              grub_free (da_path);
>> +              goto cleanup_signed_part;
>> +            }
>> +        }
>> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 
>> 0)
>> +        {
>> +          if (!sha256_in_da)
>> +            {
>> +              sha256_in_da = true;
>> +            }
>> +          else
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                                "SHA-256 specified twice in digest 
>> algorithm "
>> +                                "list");
> 
> Same here
> 
>> +              grub_free (da_path);
>> +              goto cleanup_signed_part;
>> +            }
>> +        }
>> +      else
>> +        {
>> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only 
>> SHA-256 and SHA-512 hashes are supported, found OID %s",
>> +                            algo_oid);
>> +          grub_free (da_path);
>> +          goto cleanup_signed_part;
>> +        }
>> +
>> +      grub_free (da_path);
>> +    }
>> +
>> +  /* at this point, at least one of sha{256,512}_in_da must be true 
>> */
>> +
>> +  /*
>> +   * We ignore the certificates, but we don't permit CRLs.
>> +   * A CRL entry might be revoking the certificate we're using, and 
>> we have
>> +   * no way of dealing with that at the moment.
>> +   */
>> +  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
>> +  if (res != ASN1_ELEMENT_NOT_FOUND)
>> +    {
>> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                        "PKCS#7 messages with embedded CRLs are not 
>> supported");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  /* read the signatures */
>> +
>> +  res = asn1_number_of_elements (signed_part, "signerInfos", 
>> &signer_count);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting 
>> number of signers: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (signer_count <= 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "A minimum of 1 signer is required");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  msg->signerInfos = grub_calloc (signer_count, sizeof (struct 
>> pkcs7_signerInfo));
>> +  if (!msg->signerInfos)
>> +    {
>> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                        "Could not allocate space for %d signers", 
>> signer_count);
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  msg->signerInfo_count = 0;
>> +  for (i = 0; i < signer_count; i++)
>> +    {
>> +      si_da_path = grub_xasprintf 
>> ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
>> +      if (!si_da_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not 
>> allocate path for signer %d's digest algorithm parsing path",
>> +                            i);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      algo_oid_size = sizeof (algo_oid);
>> +      res = asn1_read_value (signed_part, si_da_path, algo_oid, 
>> &algo_oid_size);
>> +      if (res != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                            "Error reading signer %d's digest 
>> algorithm: %s", i,
>> +                            asn1_strerror (res));
>> +          grub_free (si_da_path);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      grub_free (si_da_path);
>> +
>> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
>> +        {
>> +          if (!sha512_in_da)
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d 
>> claims a SHA-512 signature "
>> +                                "which was not specified in the outer 
>> DigestAlgorithms", i);
> 
> Merge into one string.
> 
>> +              goto cleanup_signerInfos;
>> +            }
>> +          else
>> +            {
>> +              sha512_in_si = true;
>> +              msg->signerInfos[i].hash =
>> +                      grub_crypto_lookup_md_by_name ("sha512");
> 
> Not sure what the char-per-line limit is, but I have seen 87 chars, so
> probably can move this one up.
> 
>> +            }
>> +        }
>> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 
>> 0)
>> +        {
>> +          if (!sha256_in_da)
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d 
>> claims a SHA-256 signature "
>> +                                "which was not specified in the outer 
>> DigestAlgorithms", i);
> 
> Merge the string?
> 
>> +              goto cleanup_signerInfos;
>> +            }
>> +          else
>> +            {
>> +              sha256_in_si = true;
>> +              msg->signerInfos[i].hash =
>> +                      grub_crypto_lookup_md_by_name ("sha256");
> 
> also this one up
> 
>> +            }
>> +        }
>> +      else
>> +        {
>> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                            "Only SHA-256 and SHA-512 hashes are 
>> supported, found OID %s",
>> +                            algo_oid);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      if (!msg->signerInfos[i].hash)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                            "Hash algorithm for signer %d (OID %s) 
>> not loaded", i, algo_oid);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 
>> 1);
>> +      if (!si_sig_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                            "Could not allocate path for signer %d's 
>> signature parsing path", i);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      result_buf = grub_asn1_allocate_and_read (signed_part, 
>> si_sig_path,
>> +                                                "signature data", 
>> &result_size);
>> +      grub_free (si_sig_path);
>> +
>> +      if (!result_buf)
>> +        {
>> +          err = grub_errno;
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi), 
>> GCRYMPI_FMT_USG,
>> +                                result_buf, result_size, NULL);
>> +
>> +      grub_free (result_buf);
>> +
>> +      if (gcry_err != GPG_ERR_NO_ERROR)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                            "Error loading signature %d into MPI 
>> structure: %d",
>> +                            i, gcry_err);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      /*
>> +       * use msg->signerInfo_count to track fully populated 
>> signerInfos so we
>> +       * know how many we need to clean up
>> +       */
>> +      msg->signerInfo_count++;
>> +    }
>> +
>> +  /*
>> +   * Final consistency check of signerInfo.*.digestAlgorithm vs
>> +   * digestAlgorithms.*.algorithm. An algorithm must be present in 
>> both
>> +   * digestAlgorithms and signerInfo or in neither. We have already 
>> checked
>> +   * for an algorithm in signerInfo that is not in digestAlgorithms, 
>> here we
>> +   * check for algorithms in digestAlgorithms but not in signerInfos.
>> +   */
>> +  if (sha512_in_da && !sha512_in_si)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "SHA-512 specified in DigestAlgorithms but 
>> did not "
>> +                        "appear in SignerInfos");
>> +      goto cleanup_signerInfos;
>> +    }
>> +
>> +  if (sha256_in_da && !sha256_in_si)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "SHA-256 specified in DigestAlgorithms but 
>> did not "
>> +                        "appear in SignerInfos");
>> +      goto cleanup_signerInfos;
>> +    }
>> +
>> +  asn1_delete_structure (&signed_part);
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_signerInfos:
>> +  for (i = 0; i < msg->signerInfo_count; i++)
>> +    gcry_mpi_release (msg->signerInfos[i].sig_mpi);
>> +  grub_free (msg->signerInfos);
>> +cleanup_signed_part:
>> +  asn1_delete_structure (&signed_part);
>> +  return err;
>> +}
>> +
>> +grub_err_t
>> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, 
>> struct pkcs7_signedData *msg)
>> +{
>> +  int res;
>> +  asn1_node content_info;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char content_oid[MAX_OID_LEN];
>> +  grub_uint8_t *content;
>> +  int content_size;
>> +  int content_oid_size = sizeof (content_oid);
>> +  int size;
>> +
>> +  if (data_size > GRUB_INT_MAX)
>> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 
>> message "
>> +                                              "where data size > 
>> INT_MAX");
>> +  size = (int) data_size;
>> +
>> +  res = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.pkcs-7-ContentInfo", &content_info);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for PKCS#7 
>> data: %s",
>> +                         asn1_strerror (res));
>> +    }
>> +
>> +  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
>> +                            ASN1_DECODE_FLAG_STRICT_DER | 
>> ASN1_DECODE_FLAG_ALLOW_PADDING,
>> +                            asn1_error);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Error decoding PKCS#7 message DER: %s", 
>> asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * ContentInfo ::= SEQUENCE {
>> +   *     contentType ContentType,
>> +   *     content [0] EXPLICIT ANY DEFINED BY contentType }
>> +   *
>> +   * ContentType ::= OBJECT IDENTIFIER
>> +   */
>> +  res = asn1_read_value (content_info, "contentType", content_oid, 
>> &content_oid_size);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7 
>> content type: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup;
>> +    }
>> +
>> +  /* OID for SignedData defined in 5.1 */
>> +  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 
>> 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Unexpected content type in PKCS#7 message: 
>> OID %s", content_oid);
>> +      goto cleanup;
>> +    }
>> +
>> +  content = grub_asn1_allocate_and_read (content_info, "content",
>> +                                         "PKCS#7 message content", 
>> &content_size);
>> +  if (!content)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  err = process_content (content, content_size, msg);
>> +  grub_free (content);
>> +
>> +cleanup:
>> +  asn1_delete_structure (&content_info);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Release all the storage associated with the PKCS#7 message.
>> + * If the caller dynamically allocated the message, it must free it.
>> + */
>> +void
>> +pkcs7_signedData_release (struct pkcs7_signedData *msg)
>> +{
>> +  grub_ssize_t i;
>> +
>> +  for (i = 0; i < msg->signerInfo_count; i++)
>> +    {
>> +      gcry_mpi_release (msg->signerInfos[i].sig_mpi);
>> +    }
>> +  grub_free (msg->signerInfos);
>> +}
>> diff --git a/grub-core/commands/appendedsig/x509.c 
>> b/grub-core/commands/appendedsig/x509.c
>> new file mode 100644
>> index 000000000..eb9a1ca0f
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/x509.c
>> @@ -0,0 +1,981 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
>> +#include <grub/types.h>
>> +#include <grub/err.h>
>> +#include <grub/mm.h>
>> +#include <grub/crypto.h>
>> +#include <grub/misc.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +
>> +#include "appendedsig.h"
>> +
>> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
>> +
>> +/*
>> + * RFC 3279 2.3.1  RSA Keys
>> + */
>> +static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
>> +
>> +/*
>> + * RFC 5280 Appendix A
>> + */
>> +static const char *commonName_oid = "2.5.4.3";
>> +
>> +/*
>> + * RFC 5280 4.2.1.3 Key Usage
>> + */
>> +static const char *keyUsage_oid = "2.5.29.15";
>> +
>> +static const grub_uint8_t digitalSignatureUsage = 0x80;
>> +
>> +/*
>> + * RFC 5280 4.2.1.9 Basic Constraints
>> + */
>> +static const char *basicConstraints_oid = "2.5.29.19";
>> +
>> +/*
>> + * RFC 5280 4.2.1.12 Extended Key Usage
>> + */
>> +static const char *extendedKeyUsage_oid = "2.5.29.37";
>> +static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
>> +
>> +/*
>> + * RFC 3279 2.3.1
>> + *
>> + *  The RSA public key MUST be encoded using the ASN.1 type 
>> RSAPublicKey:
>> + *
>> + *     RSAPublicKey ::= SEQUENCE {
>> + *        modulus            INTEGER,    -- n
>> + *        publicExponent     INTEGER  }  -- e
>> + *
>> + *  where modulus is the modulus n, and publicExponent is the public
>> + *  exponent e.
>> + */
>> +static grub_err_t
>> +grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct 
>> x509_certificate *certificate)
>> +{
>> +  int result;
>> +  asn1_node spk = NULL;
>> +  grub_uint8_t *m_data, *e_data;
>> +  int m_size, e_size;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  gcry_error_t gcry_err;
>> +
>> +  result = asn1_create_element (_gnutls_gnutls_asn, 
>> "GNUTLS.RSAPublicKey", &spk);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Cannot create storage for public key ASN.1 
>> data");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&spk, der, &dersize, 
>> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Cannot decode certificate public key DER: 
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA 
>> modulus", &m_size);
>> +  if (!m_data)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  e_data = grub_asn1_allocate_and_read (spk, "publicExponent",
>> +                                        "RSA public exponent", 
>> &e_size);
>> +  if (!e_data)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup_m_data;
>> +    }
>> +
>> +  /*
>> +   * convert m, e to mpi
>> +   *
>> +   * nscanned is not set for FMT_USG, it's only set for FMT_PGP,
>> +   * so we can't verify it
>> +   */
>> +  gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, 
>> m_data, m_size, NULL);
>> +  if (gcry_err != GPG_ERR_NO_ERROR)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error loading RSA modulus into MPI 
>> structure: %d", gcry_err);
>> +      goto cleanup_e_data;
>> +    }
>> +
>> +  gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, 
>> e_data, e_size, NULL);
>> +  if (gcry_err != GPG_ERR_NO_ERROR)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error loading RSA exponent into MPI 
>> structure: %d", gcry_err);
>> +      goto cleanup_m_mpi;
>> +    }
>> +
>> +  grub_free (e_data);
>> +  grub_free (m_data);
>> +  asn1_delete_structure (&spk);
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_m_mpi:
>> +  gcry_mpi_release (certificate->mpis[0]);
>> +cleanup_e_data:
>> +  grub_free (e_data);
>> +cleanup_m_data:
>> +  grub_free (m_data);
>> +cleanup:
>> +  asn1_delete_structure (&spk);
>> +  return err;
>> +}
>> +
>> +/*
>> + * RFC 5280:
>> + *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
>> + *       algorithm            AlgorithmIdentifier,
>> + *       subjectPublicKey     BIT STRING  }
>> + *
>> + * AlgorithmIdentifiers come from RFC 3279, we are not strictly 
>> compilant as we
>> + * only support RSA Encryption.
>> + */
>> +
>> +static grub_err_t
>> +grub_x509_read_subject_public_key (asn1_node asn, struct 
>> x509_certificate *results)
>> +{
>> +  int result;
>> +  grub_err_t err;
>> +  const char *algo_name =
>> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
>> +  const char *params_name =
>> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
>> +  const char *pk_name = 
>> "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
>> +  char algo_oid[MAX_OID_LEN];
>> +  int algo_size = sizeof (algo_oid);
>> +  char params_value[2];
>> +  int params_size = sizeof (params_value);
>> +  grub_uint8_t *key_data = NULL;
>> +  int key_size = 0;
>> +  unsigned int key_type;
>> +
>> +  /* algorithm: see notes for rsaEncryption_oid */
>> +  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 
>> public key algorithm: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof 
>> (rsaEncryption_oid)) != 0)
>> +    {
>> +      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                         "Unsupported x509 public key algorithm: %s", 
>> algo_oid);
>> +    }
>> +
>> +  /*
>> +   * RFC 3279 2.3.1
>> +   * The rsaEncryption OID is intended to be used in the algorithm 
>> field
>> +   * of a value of type AlgorithmIdentifier.  The parameters field 
>> MUST
>> +   * have ASN.1 type NULL for this algorithm identifier.
>> +   */
>> +  result = asn1_read_value (asn, params_name, params_value, 
>> &params_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 
>> public key parameters: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  if (params_value[0] != ASN1_TAG_NULL)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                         "Invalid x509 public key parameters: 
>> expected NULL");
>> +    }
>> +
>> +  /*
>> +   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of 
>> the BIT
>> +   * STRING subjectPublicKey.
>> +   */
>> +  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, 
>> &key_type);
>> +  if (result != ASN1_MEM_ERROR)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size 
>> of x509 public key: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +  if (key_type != ASN1_ETYPE_BIT_STRING)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1 
>> type when reading x509 public key: %x",
>> +                         key_type);
>> +    }
>> +
>> +  /* length is in bits */
>> +  key_size = (key_size + 7) / 8;
>> +
>> +  key_data = grub_malloc (key_size);
>> +  if (!key_data)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Out of memory for x509 public key");
>> +    }
>> +
>> +  result = asn1_read_value (asn, pk_name, key_data, &key_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      grub_free (key_data);
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                         "Error reading public key data");
>> +    }
>> +  key_size = (key_size + 7) / 8;
>> +
>> +  err = grub_parse_rsa_pubkey (key_data, key_size, results);
>> +  grub_free (key_data);
>> +
>> +  return err;
>> +}
>> +
>> +/* Decode a string as defined in Appendix A */
>> +static grub_err_t
>> +decode_string (char *der, int der_size, char **string, grub_size_t 
>> *string_size)
>> +{
>> +  asn1_node strasn;
>> +  int result;
>> +  char *choice;
>> +  int choice_size = 0;
>> +  int tmp_size = 0;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.DirectoryString", &strasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for 
>> certificate: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&strasn, der, &der_size, 
>> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Could not parse DER for DirectoryString: 
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString 
>> choice", &choice_size);
>> +  if (!choice)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  if (grub_strncmp ("utf8String", choice, choice_size) == 0)
>> +    {
>> +      result = asn1_read_value (strasn, "utf8String", NULL, 
>> &tmp_size);
>> +      if (result != ASN1_MEM_ERROR)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading 
>> size of UTF-8 string: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_choice;
>> +        }
>> +    }
>> +  else if (grub_strncmp ("printableString", choice, choice_size) == 
>> 0)
>> +    {
>> +      result = asn1_read_value (strasn, "printableString", NULL, 
>> &tmp_size);
>> +      if (result != ASN1_MEM_ERROR)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading 
>> size of UTF-8 string: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_choice;
>> +        }
>> +    }
>> +  else
>> +    {
>> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and 
>> printable DirectoryStrings are supported, got %s",
>> +                        choice);
>> +      goto cleanup_choice;
>> +    }
>> +
>> +  /* read size does not include trailing null */
>> +  tmp_size++;
>> +
>> +  *string = grub_malloc (tmp_size);
>> +  if (!*string)
>> +    {
>> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                        "Cannot allocate memory for DirectoryString 
>> contents");
>> +      goto cleanup_choice;
>> +    }
>> +
>> +  result = asn1_read_value (strasn, choice, *string, &tmp_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s 
>> in DirectoryString: %s",
>> +                        choice, asn1_strerror (result));
>> +      grub_free (*string);
> 
> *string = NULL;
> 
>> +      goto cleanup_choice;
>> +    }
>> +  *string_size = tmp_size + 1;
>> +  (*string)[tmp_size] = '\0';
>> +
>> +cleanup_choice:
>> +  grub_free (choice);
>> +cleanup:
>> +  asn1_delete_structure (&strasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * TBSCertificate  ::=  SEQUENCE  {
>> + *       version         [0]  EXPLICIT Version DEFAULT v1,
>> + * ...
>> + *
>> + * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
>> + */
>> +static grub_err_t
>> +check_version (asn1_node certificate)
>> +{
>> +  int rc;
>> +  const char *name = "tbsCertificate.version";
>> +  grub_uint8_t version;
>> +  int len = sizeof (version);
>> +
>> +  rc = asn1_read_value (certificate, name, &version, &len);
>> +
>> +  /* require version 3 */
>> +  if (rc != ASN1_SUCCESS || len != 1)
>> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                       "Error reading certificate version");
>> +
>> +  if (version != 0x02)
>> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509 
>> certificate version, expected v3 (0x02), got 0x%02x",
>> +                       version);
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/*
>> + * This is an X.501 Name, which is complex.
>> + *
>> + * For simplicity, we extract only the CN.
>> + */
>> +static grub_err_t
>> +read_name (asn1_node asn, const char *name_path, char **name, 
>> grub_size_t *name_size)
>> +{
>> +  int seq_components, set_components;
>> +  int result;
>> +  int i, j;
>> +  char *top_path, *set_path, *type_path, *val_path;
>> +  char type[MAX_OID_LEN];
>> +  int type_len = sizeof (type);
>> +  int string_size = 0;
>> +  char *string_der;
>> +  grub_err_t err;
>> +
>> +  *name = NULL;
>> +
>> +  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
>> +  if (!top_path)
>> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                       "Could not allocate memory for %s name parsing 
>> path", name_path);
>> +
>> +  result = asn1_number_of_elements (asn, top_path, &seq_components);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name 
>> components: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  for (i = 1; i <= seq_components; i++)
>> +    {
>> +      set_path = grub_xasprintf ("%s.?%d", top_path, i);
>> +      if (!set_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not 
>> allocate memory for %s name set parsing path",
>> +                            name_path);
>> +          goto cleanup_set;
>> +        }
>> +      /* this brings us, hopefully, to a set */
>> +      result = asn1_number_of_elements (asn, set_path, 
>> &set_components);
>> +      if (result != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting 
>> name sub-components components (element %d): %s",
>> +                            i, asn1_strerror (result));
>> +          goto cleanup_set;
>> +        }
>> +      for (j = 1; j <= set_components; j++)
>> +        {
>> +          type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, 
>> j);
>> +          if (!type_path)
>> +            {
>> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not 
>> allocate memory for %s name component type path",
>> +                                name_path);
>> +              goto cleanup_set;
>> +            }
>> +          type_len = sizeof (type);
>> +          result = asn1_read_value (asn, type_path, type, &type_len);
>> +          if (result != ASN1_SUCCESS)
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error 
>> reading %s name component type: %s",
>> +                                name_path, asn1_strerror (result));
>> +              goto cleanup_type;
>> +            }
>> +
>> +          if (grub_strncmp (type, commonName_oid, type_len) != 0)
>> +            {
>> +              grub_free (type_path);
>> +              continue;
>> +            }
>> +
>> +          val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, 
>> j);
>> +          if (!val_path)
>> +            {
>> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not 
>> allocate memory for %s name component value path",
>> +                                name_path);
>> +              goto cleanup_set;
> 
> goto cleanup_type;
> 
> 
>> +            }
>> +
>> +          string_der = grub_asn1_allocate_and_read (asn, val_path, 
>> name_path, &string_size);
>> +          if (!string_der)
>> +            {
>> +              err = grub_errno;
>> +              goto cleanup_val_path;
>> +            }
>> +
>> +          err = decode_string (string_der, string_size, name, 
>> name_size);
>> +          if (err)
>> +            goto cleanup_string;
>> +
>> +          grub_free (string_der);
>> +          grub_free (type_path);
>> +          grub_free (val_path);
>> +          break;
>> +        }
>> +      grub_free (set_path);
>> +
>> +      if (*name)
>> +        break;
>> +    }
>> +
>> +  grub_free (top_path);
>> +
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_string:
>> +  grub_free (string_der);
>> +cleanup_val_path:
>> +  grub_free (val_path);
>> +cleanup_type:
>> +  grub_free (type_path);
>> +cleanup_set:
>> +  grub_free (set_path);
>> +cleanup:
>> +  grub_free (top_path);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Verify the Key Usage extension.
>> + * We require the Digital signature usage.
>> + */
>> +static grub_err_t
>> +verify_key_usage (grub_uint8_t *value, int value_size)
>> +{
>> +  asn1_node usageasn;
>> +  int result;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  grub_uint8_t usage = 0xff;
>> +  int usage_size = sizeof (usage_size);
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", 
>> &usageasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for key 
>> usage");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&usageasn, value, &value_size,
>> +                               ASN1_DECODE_FLAG_STRICT_DER, 
>> asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error parsing DER for Key Usage: %s", 
>> asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  result = asn1_read_value (usageasn, "", &usage, &usage_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key 
>> Usage value: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  if (!(usage & digitalSignatureUsage))
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Key Usage (0x%x) missing Digital Signature 
>> usage", usage);
>> +      goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +  asn1_delete_structure (&usageasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * BasicConstraints ::= SEQUENCE {
>> + *       cA                      BOOLEAN DEFAULT FALSE,
>> + *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
>> + */
>> +static grub_err_t
>> +verify_basic_constraints (grub_uint8_t *value, int value_size)
>> +{
>> +  asn1_node basicasn;
>> +  int result;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char cA[6]; /* FALSE or TRUE */
>> +  int cA_size = sizeof (cA);
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.BasicConstraints", &basicasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for Basic 
>> "
>> +                         "Constraints");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&basicasn, value, &value_size,
>> +                               ASN1_DECODE_FLAG_STRICT_DER, 
>> asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error parsing DER for Basic Constraints: 
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
>> +  if (result == ASN1_ELEMENT_NOT_FOUND)
>> +    {
>> +      /* Not present, default is False, so this is OK */
>> +      err = GRUB_ERR_NONE;
>> +      goto cleanup;
>> +    }
>> +  else if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic 
>> Constraints cA value: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  /* The certificate must not be a CA certificate */
>> +  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: 
>> %s", cA);
>> +      goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +  asn1_delete_structure (&basicasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
>> + *
>> + * KeyPurposeId ::= OBJECT IDENTIFIER
>> + */
>> +static grub_err_t
>> +verify_extended_key_usage (grub_uint8_t *value, int value_size)
>> +{
>> +  asn1_node extendedasn;
>> +  int result, count;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char usage[MAX_OID_LEN];
>> +  int usage_size = sizeof (usage);
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.ExtKeyUsageSyntax", &extendedasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for 
>> Extended Key "
>> +                         "Usage");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
>> +                               ASN1_DECODE_FLAG_STRICT_DER, 
>> asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error parsing DER for Extended Key Usage: 
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * If EKUs are present, there must be exactly 1 usage and it must 
>> be a
>> +   * codeSigning usage. (If we get to this point, we are parsing an 
>> EKU
>> +   * extension and therefore must have a usage. The code that makes 
>> having an
>> +   * EKU extension optional is in verify_extensions.)
>> +   */
>> +  result = asn1_number_of_elements (extendedasn, "", &count);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting 
>> number of Extended Key Usages: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  if (count != 1)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of 
>> Extended Key Usages: %d, 1 expected",
>> +                        count);
>> +      goto cleanup;
>> +    }
>> +
>> +  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading 
>> Extended Key Usage: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Unexpected Extended Key Usage OID, got: %s", 
>> usage);
>> +      goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +  asn1_delete_structure (&extendedasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
>> + *
>> + * Extension  ::=  SEQUENCE  {
>> + *      extnID      OBJECT IDENTIFIER,
>> + *      critical    BOOLEAN DEFAULT FALSE,
>> + *      extnValue   OCTET STRING
>> + *                  -- contains the DER encoding of an ASN.1 value
>> + *                  -- corresponding to the extension type identified
>> + *                  -- by extnID
>> + * }
>> + *
>> + * A certificate must:
>> + *  - contain the Digital Signature usage only
>> + *  - not be a CA
>> + *  - contain no extended usages, or only a code signing extended 
>> usage
>> + *  - not contain any other critical extensions (RFC 5280 s 4.2)
>> + */
>> +static grub_err_t
>> +verify_extensions (asn1_node cert)
>> +{
>> +  int result;
>> +  int ext, num_extensions = 0;
>> +  int usage_present = 0, constraints_present = 0, 
>> extended_usage_present = 0;
>> +  char *oid_path, *critical_path, *value_path;
>> +  char extnID[MAX_OID_LEN];
>> +  int extnID_size;
>> +  grub_err_t err;
>> +  char critical[6]; /* we get either "TRUE" or "FALSE" */
>> +  int critical_size;
>> +  grub_uint8_t *value;
>> +  int value_size;
>> +
>> +  result = asn1_number_of_elements (cert, 
>> "tbsCertificate.extensions", &num_extensions);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting 
>> number of extensions: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  if (num_extensions < 2)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Insufficient number 
>> of extensions for "
>> +                         "certificate, need at least 2, got %d",
>> +                         num_extensions);
>> +    }
>> +
>> +  for (ext = 1; ext <= num_extensions; ext++)
>> +    {
>> +      oid_path = grub_xasprintf 
>> ("tbsCertificate.extensions.?%d.extnID", ext);
> 
> if (!oid_path) ...
>    err = ...
>    return err;
> 
>> +
>> +      extnID_size = sizeof (extnID);
>> +      result = asn1_read_value (cert, oid_path, extnID, 
>> &extnID_size);
>> +      if (result != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading 
>> extension OID: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_oid_path;
>> +        }
>> +
>> +      critical_path = grub_xasprintf 
>> ("tbsCertificate.extensions.?%d.critical", ext);
> 
> if (!critical_path) ...
>    err =
>    goto cleanup_oid_path
> 
>> +      critical_size = sizeof (critical);
>> +      result = asn1_read_value (cert, critical_path, critical, 
>> &critical_size);
>> +      if (result == ASN1_ELEMENT_NOT_FOUND)
>> +        {
>> +          critical[0] = '\0';
>> +        }
>> +      else if (result != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading 
>> extension criticality: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_critical_path;
>> +        }
>> +
>> +      value_path = grub_xasprintf 
>> ("tbsCertificate.extensions.?%d.extnValue", ext);
> 
> if (!value_path) ...
>    err = ...
>    goto cleanup_critical_path
> 
>> +      value = grub_asn1_allocate_and_read (cert, value_path,
>> +                                           "certificate extension 
>> value", &value_size);
>> +      if (!value)
>> +        {
>> +          err = grub_errno;
>> +          goto cleanup_value_path;
>> +        }
>> +
>> +      /*
>> +       * Now we must see if we recognise the OID.
>> +       * If we have an unrecognised critical extension we MUST bail.
>> +       */
>> +      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
>> +        {
>> +          err = verify_key_usage (value, value_size);
>> +          if (err != GRUB_ERR_NONE)
>> +            {
>> +              goto cleanup_value;
>> +            }
>> +          usage_present++;
>> +        }
>> +      else if (grub_strncmp (basicConstraints_oid, extnID, 
>> extnID_size) == 0)
>> +        {
>> +          err = verify_basic_constraints (value, value_size);
>> +          if (err != GRUB_ERR_NONE)
>> +            {
>> +              goto cleanup_value;
>> +            }
>> +          constraints_present++;
>> +        }
>> +      else if (grub_strncmp (extendedKeyUsage_oid, extnID, 
>> extnID_size) == 0)
>> +        {
>> +          err = verify_extended_key_usage (value, value_size);
>> +          if (err != GRUB_ERR_NONE)
>> +            {
>> +              goto cleanup_value;
>> +            }
>> +          extended_usage_present++;
>> +        }
>> +      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
>> +        {
>> +          /*
>> +           * per the RFC, we must not process a certificate with
>> +           * a critical extension we do not understand.
>> +           */
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                            "Unhandled critical x509 extension with 
>> OID %s", extnID);
>> +          goto cleanup_value;
>> +        }
>> +
>> +      grub_free (value);
>> +      grub_free (value_path);
>> +      grub_free (critical_path);
>> +      grub_free (oid_path);
>> +    }
>> +
>> +  if (usage_present != 1)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number 
>> of Key Usage extensions "
>> +                         "- expected 1, got %d", usage_present);
>> +    }
>> +  if (constraints_present != 1)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number 
>> of basic constraints extensions "
>> +                         "- expected 1, got %d", 
>> constraints_present);
>> +    }
>> +  if (extended_usage_present > 1)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number 
>> of Extended Key Usage extensions "
>> +                         "- expected 0 or 1, got %d", 
>> extended_usage_present);
>> +    }
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_value:
>> +  grub_free (value);
>> +cleanup_value_path:
>> +  grub_free (value_path);
>> +cleanup_critical_path:
>> +  grub_free (critical_path);
>> +cleanup_oid_path:
>> +  grub_free (oid_path);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Parse a certificate whose DER-encoded form is in @data, of size 
>> @data_size.
>> + * Return the results in @results, which must point to an allocated 
>> x509 certificate.
>> + */
>> +grub_err_t
>> +parse_x509_certificate (const void *data, grub_size_t data_size, 
>> struct x509_certificate *results)
>> +{
>> +  int result = 0;
>> +  asn1_node cert;
>> +  grub_err_t err;
>> +  int size;
>> +  int tmp_size;
>> +
>> +  if (data_size > GRUB_INT_MAX)
>> +    return grub_error (GRUB_ERR_OUT_OF_RANGE,
>> +                       "Cannot parse a certificate where data size > 
>> INT_MAX");
>> +  size = (int) data_size;
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.Certificate", &cert);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for 
>> certificate: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&cert, data, &size, 
>> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Could not parse DER for certificate: %s", 
>> asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * TBSCertificate  ::=  SEQUENCE {
>> +   *     version         [0]  EXPLICIT Version DEFAULT v1
>> +   */
>> +  err = check_version (cert);
>> +  if (err != GRUB_ERR_NONE)
>> +    {
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * serialNumber         CertificateSerialNumber,
>> +   *
>> +   * CertificateSerialNumber  ::=  INTEGER
>> +   */
>> +  results->serial = grub_asn1_allocate_and_read (cert, 
>> "tbsCertificate.serialNumber",
>> +                                                 "certificate serial 
>> number", &tmp_size);
>> +  if (!results->serial)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +  /*
>> +   * It's safe to cast the signed int to an unsigned here, we know
>> +   * length is non-negative
>> +   */
>> +  results->serial_len = tmp_size;
>> +
>> +  /*
>> +   * signature            AlgorithmIdentifier,
>> +   *
>> +   * We don't load the signature or issuer at the moment,
>> +   * as we don't attempt x509 verification.
>> +   */
>> +
>> +  /*
>> +   * issuer               Name,
>> +   *
>> +   * The RFC only requires the serial number to be unique within
>> +   * issuers, so to avoid ambiguity we _technically_ ought to make
>> +   * this available.
>> +   */
>> +
>> +  /*
>> +   * validity             Validity,
>> +   *
>> +   * Validity ::= SEQUENCE {
>> +   *     notBefore      Time,
>> +   *     notAfter       Time }
>> +   *
>> +   * We can't validate this reasonably, we have no true time source 
>> on several
>> +   * platforms. For now we do not parse them.
>> +   */
>> +
>> +  /*
>> +   * subject              Name,
>> +   *
>> +   * This is an X501 name, we parse out just the CN.
>> +   */
>> +  err = read_name (cert, "tbsCertificate.subject", &results->subject, 
>> &results->subject_len);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup_serial;
>> +
>> +  /*
>> +   * TBSCertificate  ::=  SEQUENCE  {
>> +   *    ...
>> +   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
>> +   *    ...
>> +   */
>> +  err = grub_x509_read_subject_public_key (cert, results);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup_name;
>> +
>> +  /*
>> +   * TBSCertificate  ::=  SEQUENCE  {
>> +   *    ...
>> +   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
>> +   *                         -- If present, version MUST be v3
>> +   * }
>> +   */
>> +
>> +  err = verify_extensions (cert);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup_mpis;
>> +
>> +  /*
>> +   * We do not read or check the signature on the certificate:
>> +   * as discussed we do not try to validate the certificate but trust
>> +   * it implictly.
>> +   */
>> +
>> +  asn1_delete_structure (&cert);
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_mpis:
>> +  gcry_mpi_release (results->mpis[0]);
>> +  gcry_mpi_release (results->mpis[1]);
>> +cleanup_name:
>> +  grub_free (results->subject);
>> +cleanup_serial:
>> +  grub_free (results->serial);
>> +cleanup:
>> +  asn1_delete_structure (&cert);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Release all the storage associated with the x509 certificate.
>> + * If the caller dynamically allocated the certificate, it must free 
>> it.
>> + * The caller is also responsible for maintenance of the linked list.
>> + */
>> +void
>> +certificate_release (struct x509_certificate *cert)
>> +{
>> +  grub_free (cert->subject);
>> +  grub_free (cert->serial);
>> +  gcry_mpi_release (cert->mpis[0]);
>> +  gcry_mpi_release (cert->mpis[1]);
>> +}

Thank you Stefan. fixed it.

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 12/21] appended signatures: documentation
  2024-12-30 15:50   ` Stefan Berger
@ 2025-02-26  4:28     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-26  4:28 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2024-12-30 21:20, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> This explains how appended signatures can be used to form part of
>> a secure boot chain, and documents the commands and variables
>> introduced.
>> 
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   docs/grub.texi | 185 
>> ++++++++++++++++++++++++++++++++++++++++++++-----
>>   1 file changed, 167 insertions(+), 18 deletions(-)
>> 
>> diff --git a/docs/grub.texi b/docs/grub.texi
>> index 6e483298d..f71ce9ffc 100644
>> --- a/docs/grub.texi
>> +++ b/docs/grub.texi
>> @@ -3274,6 +3274,7 @@ These variables have special meaning to GRUB.
>>     @menu
>>   * biosnum::
>> +* check_appended_signatures::
>>   * check_signatures::
>>   * chosen::
>>   * cmdpath::
>> @@ -3336,12 +3337,16 @@ this.
>>   For an alternative approach which also changes BIOS drive mappings 
>> for the
>>   chain-loaded system, @pxref{drivemap}.
>>   +@node check_appended_signatures
>> +@subsection check_appended_signatures
>> +This variable controls whether GRUB enforces appended signature 
>> validation on
>> +certain loaded files. @xref{Using appended signatures}.
>>     @node check_signatures
>>   @subsection check_signatures
>>   -This variable controls whether GRUB enforces digital signature
>> -validation on loaded files. @xref{Using digital signatures}.
>> +This variable controls whether GRUB enforces GPG-style digital 
>> signature
>> +validation on loaded files. @xref{Using GPG-style digital 
>> signatures}.
> 
> I am not sure whether everybody knows what GPG-style digitiabl
> signatures are. Maybe mention here once that those are in a separate
> file.
> 
>>     @node chosen
>>   @subsection chosen
>> @@ -6377,6 +6382,7 @@ 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
>>   * drivemap::                    Map a drive to another
>>   * echo::                        Display a line of text
>>   * efitextmode::                 Set/Get text output mode resolution
>> @@ -6395,6 +6401,7 @@ you forget a command, you can run the command 
>> @command{help}
>>   * hexdump::                     Show raw contents of a file or 
>> memory
>>   * insmod::                      Insert a module
>>   * keystatus::                   Check key modifier status
>> +* 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
>> @@ -6435,8 +6442,10 @@ you forget a command, you can run the command 
>> @command{help}
>>   * tpm2_key_protector_clear::    Clear the TPM2 key protector
>>   * 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
>>   * unset::                       Unset an environment variable
>>   @comment * vbeinfo::                     List available video modes
>> +* verify_appended::             Verify appended digital signature
>>   * verify_detached::             Verify detached digital signature
>>   * videoinfo::                   List available video modes
>>   * wrmsr::                       Write values to model-specific 
>> registers
>> @@ -6778,7 +6787,24 @@ These keys are used to validate signatures when 
>> environment variable
>>   @code{check_signatures} is set to @code{enforce}
>>   (@pxref{check_signatures}), and by some invocations of
>>   @command{verify_detached} (@pxref{verify_detached}).  @xref{Using
>> -digital signatures}, for more information.
>> +GPG-style digital signatures}, for more information.
>> +@end deffn
>> +
>> +@node distrust_certificate
>> +@subsection distrust_certificate
>> +
>> +@deffn Command distrust_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}).
>> +
>> +These certificates are used to validate appended signatures when 
>> environment
>> +variable @code{check_appended_signatures} is set to @code{enforce}
>> +(@pxref{check_appended_signatures}), and by @command{verify_appended}
>> +(@pxref{verify_appended}). See @xref{Using appended signatures} for 
>> more
>> +information.
>>   @end deffn
>>     @node drivemap
>> @@ -7169,6 +7195,19 @@ without any options, the @command{keystatus} 
>> command returns true if and
>>   only if checking key modifier status is supported.
>>   @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
>> @@ -7189,7 +7228,7 @@ The output is in GPG's v4 key fingerprint format 
>> (i.e., the output of
>>   @code{gpg --fingerprint}).  The least significant four bytes (last
>>   eight hexadecimal digits) can be used as an argument to
>>   @command{distrust} (@pxref{distrust}).
>> -@xref{Using digital signatures}, for more information about uses for
>> +@xref{Using GPG-style digital signatures}, for more information about 
>> uses for
>>   these keys.
>>   @end deffn
>>   @@ -7224,8 +7263,11 @@ When used with care, @option{--skip-sig} and 
>> the whitelist enable an
>>   administrator to configure a system to boot only signed
>>   configurations, but to allow the user to select from among multiple
>>   configurations, and to enable ``one-shot'' boot attempts and
>> -``savedefault'' behavior.  @xref{Using digital signatures}, for more
>> +``savedefault'' behavior.  @xref{Using GPG-style digital signatures}, 
>> for more
>>   information.
>> +Extra care should be taken when combining this command with appended 
>> signatures
>> +(@pxref{Using appended signatures}), as this file is not validated by 
>> an
>> +appended signature and could set @code{check_appended_signatures=no}.
>>   @end deffn
>>     @@ -7596,7 +7638,7 @@ read.  It is possible to modify a digitally 
>> signed environment block
>>   file from within GRUB using this command, such that its signature 
>> will
>>   no longer be valid on subsequent boots.  Care should be taken in 
>> such
>>   advanced configurations to avoid rendering the system
>> -unbootable. @xref{Using digital signatures}, for more information.
>> +unbootable. @xref{Using GPG-style digital signatures}, for more 
>> information.
>>   @end deffn
>>     @@ -8064,11 +8106,30 @@ signatures when environment variable 
>> @code{check_signatures} is set to
>>   must itself be properly signed.  The @option{--skip-sig} option can 
>> be
>>   used to disable signature-checking when reading @var{pubkey_file}
>>   itself. It is expected that @option{--skip-sig} is useful for 
>> testing
>> -and manual booting. @xref{Using digital signatures}, for more
>> +and manual booting. @xref{Using GPG-style digital signatures}, for 
>> more
>>   information.
>>   @end deffn
>>     +@node trust_certificate
>> +@subsection trust_certificate
>> +
>> +@deffn Command trust_certificate x509_certificate
>> +Read a 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
>> +variable @code{check_appended_signatures} is set to @code{enforce}.
>> +
>> +Note that if @code{check_appended_signatures} is set to 
>> @code{enforce}
>> +when @command{trust_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 signatures 
>> within x509
> 
> s/grub/GRUB
> 
>> +certificates themselves.)
>> +
>> +See @xref{Using appended signatures} for more information.
>> +@end deffn
>> +
>>   @node unset
>>   @subsection unset
>>   @@ -8087,6 +8148,18 @@ only on PC BIOS platforms.
>>   @end deffn
>>   @end ignore
>>   +@node verify_appended
>> +@subsection verify_appended
>> +
>> +@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}).
>> +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.
>> +@end deffn
>>     @node verify_detached
>>   @subsection verify_detached
>> @@ -8105,7 +8178,7 @@ tried.
>>     Exit code @code{$?} is set to 0 if the signature validates
>>   successfully.  If validation fails, it is set to a non-zero value.
>> -@xref{Using digital signatures}, for more information.
>> +@xref{Using GPG-style digital signatures}, for more information.
>>   @end deffn
>>     @node videoinfo
>> @@ -8565,14 +8638,15 @@ environment variables and commands are listed 
>> in the same order.
>>   @chapter Security
>>     @menu
>> -* Authentication and authorisation:: Users and access control
>> -* Using digital signatures::         Booting digitally signed code
>> -* UEFI secure boot and shim::        Booting digitally signed PE 
>> files
>> -* Secure Boot Advanced Targeting::   Embedded information for 
>> generation number based revocation
>> -* Measured Boot::                    Measuring boot components
>> -* Lockdown::                         Lockdown when booting on a 
>> secure setup
>> -* TPM2 key protector::               Managing disk key with TPM2 key 
>> protector
>> -* Signing GRUB itself::              Ensuring the integrity of the 
>> GRUB core image
>> +* Authentication and authorisation::   Users and access control
>> +* Using GPG-style digital signatures:: Booting digitally signed code
>> +* Using appended signatures::          An alternative approach to 
>> booting digitally signed code
>> +* UEFI secure boot and shim::          Booting digitally signed PE 
>> files
>> +* Secure Boot Advanced Targeting::     Embedded information for 
>> generation number based revocation
>> +* Measured Boot::                      Measuring boot components
>> +* Lockdown::                           Lockdown when booting on a 
>> secure setup
>> +* TPM2 key protector::                 Managing disk key with TPM2 
>> key protector
>> +* Signing GRUB itself::                Ensuring the integrity of the 
>> GRUB core image
>>   @end menu
>>     @node Authentication and authorisation
>> @@ -8648,8 +8722,8 @@ generating configuration files with 
>> authentication.  You can use
>>   adding @kbd{set superusers=} and @kbd{password} or 
>> @kbd{password_pbkdf2}
>>   commands.
>>   -@node Using digital signatures
>> -@section Using digital signatures in GRUB
>> +@node Using GPG-style digital signatures
>> +@section Using GPG-style digital signatures in GRUB
>>     GRUB's @file{core.img} can optionally provide enforcement that all 
>> files
>>   subsequently read from disk are covered by a valid digital 
>> signature.
>> @@ -8732,6 +8806,81 @@ or BIOS) configuration to cause the machine to 
>> boot from a different
>>   (attacker-controlled) device.  GRUB is at best only one link in a
>>   secure boot chain.
>>   +@node Using appended signatures
>> +@section Using appended signatures in GRUB
>> +
>> +GRUB supports verifying Linux-style 'appended signatures' for secure 
>> boot.
>> +Appended signatures are PKCS#7 messages containing a signature over 
>> the
>> +contents of a file, plus some metadata, appended to the end of a 
>> file. A file
>> +with an appended signature ends with the magic string:
>> +
>> +@example
>> +~Module signature appended~\n
>> +@end example
>> +
>> +where @code{\n} represents the carriage-return character, 
>> @code{0x0a}.
> 
> \n is the newline parameter, \r is carriage-return
> 
>> +
>> +To enable appended signature verification, load the appendedsig 
>> module and an
>> +x509 certificate for verification. Building the appendedsig module 
>> into the
>> +core grub image is recommended.
>> +
>> +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}.
>> +A file can be explictly verified using the @pxref{verify_appended} 
>> command.
> 
> explicitly
> 
>> +
>> +Only signatures made with the SHA-256 or SHA-512 hash algorithm are 
>> supported,
>> +and only RSA signatures are supported.
>> +
>> +A file can be signed with the @command{sign-file} utility supplied 
>> with the
>> +Linux kernel source. For example, if you have @code{signing.key} as 
>> the private
>> +key and @code{certificate.der} as the x509 certificate containing the 
>> public key:
>> +
>> +@example
>> +sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
>> +@end example
>> +
>> +Enforcement of signature verification is controlled by the
>> +@code{check_appended_signatures} variable. Verification will only 
>> take place
>> +when files are loaded if the variable is set to @code{enforce}. If a
>> +certificate is built into the grub core image with the @code{--x509} 
>> parameter,
>> +the variable will be automatically set to @code{enforce} when the 
>> appendedsig
>> +module is loaded.
>> +
>> +Unlike GPG-style signatures, not all files loaded by GRUB are 
>> required to be
>> +signed. Once verification is turned on, the following file types must 
>> carry
>> +appended signatures:
>> +
>> +@enumerate
>> +@item Linux, Multiboot, BSD, XNU and Plan9 kernels
>> +@item Grub modules, except those built in to the core image
>> +@item Any new certificate files to be trusted
>> +@end enumerate
>> +
>> +ACPI tables and Device Tree images will not be checked for appended 
>> signatures
>> +but must be verified by another mechanism such as GPG-style 
>> signatures before
>> +they will be loaded.
>> +
>> +No attempt is made to validate any other file type. In particular,
>> +chain-loaded binaries are not verified - if your platform supports
>> +chain-loading and this cannot be disabled, consider an alternative 
>> secure
>> +boot mechanism.
>> +
>> +As with GPG-style appended signatures, signature checking does 
>> @strong{not}
>> +stop an attacker with console access from dropping manually to the 
>> GRUB
>> +console and executing:
>> +
>> +@example
>> +set check_appended_signatures=no
>> +@end example
>> +
>> +Refer to the section on password-protecting GRUB 
>> (@pxref{Authentication
>> +and authorisation}) for more information on preventing this.
>> +
>> +Additionally, special care must be taken around the @command{loadenv} 
>> command,
>> +which can be used to turn off @code{check_appended_signature}.
>> +
>>   @node UEFI secure boot and shim
>>   @section UEFI secure boot and shim support
>> 
> 
> With nits fixed:
> 
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>

Thank you Stefan. Fixed it.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support
  2024-12-30 22:14   ` Stefan Berger
@ 2025-02-26  4:33     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-26  4:33 UTC (permalink / raw)
  To: Stefan Berger
  Cc: The development of GNU GRUB, dja, jan.setjeeilers, julian.klode,
	mate.kukri, pjones, avnish, nayna, ssrish

On 2024-12-31 03:44, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> 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>
>> ---
>>   grub-core/kern/ieee1275/ieee1275.c | 117 
>> +++++++++++++++++++++++++++++
> 
> Since this is pSeries-specific stuff I wonder whether this should not
> rather go into include/grub/powerpc/ieee1275/ieee1275.h and
> grub-core/kern/powerpc/ieee1275/ieee1275.c ?

Thank you Stefan.
yes. This should go into pSeries-specific. moved it to pSeries-specific.


> 
>>   include/grub/ieee1275/ieee1275.h   |  14 ++++
>>   2 files changed, 131 insertions(+)
>> 
>> diff --git a/grub-core/kern/ieee1275/ieee1275.c 
>> b/grub-core/kern/ieee1275/ieee1275.c
>> index 36ca2dbfc..8d0048844 100644
>> --- a/grub-core/kern/ieee1275/ieee1275.c
>> +++ b/grub-core/kern/ieee1275/ieee1275.c
>> @@ -807,3 +807,120 @@ grub_ieee1275_get_block_size 
>> (grub_ieee1275_ihandle_t ihandle)
>>       return args.size;
>>   }
>> +
>> +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/ieee1275/ieee1275.h 
>> b/include/grub/ieee1275/ieee1275.h
>> index c445d0499..edd8cd0eb 100644
>> --- a/include/grub/ieee1275/ieee1275.h
>> +++ b/include/grub/ieee1275/ieee1275.h
>> @@ -230,6 +230,20 @@ char *EXPORT_FUNC(grub_ieee1275_encode_uint4) 
>> (grub_ieee1275_ihandle_t ihandle,
>>                                                grub_size_t *size);
>>   int EXPORT_FUNC(grub_ieee1275_get_block_size) 
>> (grub_ieee1275_ihandle_t ihandle);
>>   +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);
>> +
>>   grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t 
>> size);
>>     int


Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables
  2024-12-30 23:01   ` Stefan Berger
@ 2025-02-26  4:43     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-26  4:43 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2024-12-31 04:31, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> 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>
>> ---
>>   grub-core/Makefile.am                       |   1 +
>>   grub-core/Makefile.core.def                 |   1 +
>>   grub-core/kern/ieee1275/init.c              |  14 +-
>>   grub-core/kern/ieee1275/platform_keystore.c | 337 
>> ++++++++++++++++++++
>>   include/grub/platform_keystore.h            | 233 ++++++++++++++
>>   5 files changed, 584 insertions(+), 2 deletions(-)
>>   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 e50db8106..afb25dc4f 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 1ed55b0e3..2fd060123 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;
> 
> This now becomes a file shared with other ieee1275 platforms, such as
> sparc64, as well. Also here maybe it should be
> 
>  powerpc_ieee1275 = kern/ieee1275/platform_keystore.c
> 
> or
> 
>  powerpc_ieee1275 = kern/powerpc/ieee1275/platform_keystore.c ?
> 

Yes. You are correct. moved it to pSeries-specific.


>>       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 59984b605..7d96c38f3 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__
>> @@ -959,7 +960,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);
>>   @@ -976,7 +977,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..1c564d5da
>> --- /dev/null
>> +++ b/grub-core/kern/ieee1275/platform_keystore.c
>> @@ -0,0 +1,337 @@
>> +/*
>> + *  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/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 ((grub_err_t) -7)
>> +
>> +/* Platform Keystore */
>> +static grub_size_t pks_max_object_size;
>> +grub_uint8_t grub_use_platform_keystore = 0;
>> +grub_pks_t grub_platform_keystore = { .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));
> 
> grub_realloc knows how to handle the case when first parameter is NULL.
> 
fixed it.

>> +
>> +      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;
>> +}
>> +
>> +/*
>> + * reads the secure boot version from PKS as an object.
>> + * caller must free result
>> + */
>> +static grub_err_t
>> +grub_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
>> +grub_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
>> +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");
> 
> Firmware doesn't have ...  ?
> 

fixed it.

>> +  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_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 = grub_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 = grub_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) */
>> +static grub_err_t
>> +grub_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 = grub_read_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))
> 
> same as (*data >= 2) ?
> 

I think here not needed to check (*data >= 2) because we supports 
following SB Version only
SB Version:
1 - PKS
0 - static key (embeded key)

>> +    {
>> +      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));
> 
> s/0x00/0
> 
Fixed it.
>> +}
>> +
>> +/* 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_get_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));
> 
> s/0x00/0
> 

Fixed it.

>> +      /* DB */
>> +      rc = grub_read_secure_boot_variables (0, DB, 
>> &grub_platform_keystore.db,
>> +                                            
>> &grub_platform_keystore.db_entries);
>> +      if (rc == GRUB_ERR_NONE)
>> +        {
>> +          /* DBX */
>> +          rc = grub_read_secure_boot_variables (0, DBX, 
>> &grub_platform_keystore.dbx,
>> +                                                
>> &grub_platform_keystore.dbx_entries);
>> +          if (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..7a7378926
>> --- /dev/null
>> +++ b/include/grub/platform_keystore.h
>> @@ -0,0 +1,233 @@
>> +/*
>> + * 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_UUID_SIZE 16
> 
> grub/types.h ?
> 
>> +#define GRUB_MAX_HASH_SIZE 64
>> +
>> +typedef struct grub_uuid grub_uuid_t;
> 
> grub/types.h ?
> 
>> +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];
>> +};
> 
> grub/types.h ?
> 

moved it to 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_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_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 = {NULL, NULL, 0, 0};
>> +void grub_release_platform_keystore (void);
>> +
>> +#endif
>> +
>> +#endif


Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables
  2024-12-30 23:04   ` Stefan Berger
@ 2025-02-26  4:44     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-26  4:44 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2024-12-31 04:34, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> 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
> 
> What is 'it'. The certificates would be saved ... ?
> 
>> the appendedsig (module) would read it later to extract
>> the certificate's details.
> 
> certifcates' ?
> 
>> 
>> In the following scenarios, static key mode will be activated:
>>   1. When secure boot is enabled with static
> 
> static keys ?
> 
>>   2. When SB Version is unavailable but Secure Boot is enabled
>>   3. When PKS support is unavailable but secure boot is enabled
> 
> Secure Boot
> 
>> 
>> Note:-
>> 
>> SB Version - secure boot mode
> 
> Secure Boot
> 
>> 1 - PKS
>> 0 - static key (embeded key)

Thank you Stefan. Fixed it.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists
  2024-12-31 17:21   ` Stefan Berger
@ 2025-02-27 15:21     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:21 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2024-12-31 22:51, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> 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 integerity of the kernel, the extracted data
> 
> integrity
> 
>> would be stored in the buffer db and dbx.
> 
> needs to be stored?
> 
>> 
>> 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,
> 
> integrity
> 
>> the extracted data would be stored in the buffer db.
> 
> needs to be stored?
> 
>> 
>> Note:-
>> 
>> if the trusted certificate nor binary hash exists in the distrusted 
>> list (DBX),
> 
> If neither the ... nor ...
> 
>> rejected it while extracting it from the platform keystore buffer.
> 
> what is 'it' in this context
> 
>> 
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   grub-core/commands/appendedsig/appendedsig.c | 636 
>> +++++++++++++++++--
>>   1 file changed, 592 insertions(+), 44 deletions(-)
>> 
>> diff --git a/grub-core/commands/appendedsig/appendedsig.c 
>> b/grub-core/commands/appendedsig/appendedsig.c
>> index 5c82b96a4..31649e800 100644
>> --- a/grub-core/commands/appendedsig/appendedsig.c
>> +++ b/grub-core/commands/appendedsig/appendedsig.c
>> @@ -34,7 +34,7 @@
>>   #include <libtasn1.h>
>>   #include <grub/env.h>
>>   #include <grub/lockdown.h>
>> -
>> +#include <grub/platform_keystore.h>
>>   #include "appendedsig.h"
>>     GRUB_MOD_LICENSE ("GPLv3+");
>> @@ -64,9 +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 grub_db = {.keys = NULL, .key_entries = 0, 
>> .signatures = NULL,
>> +                                .signature_size = NULL, 
>> .signature_entries = 0};
>>   +/* Distrusted list */
>> +struct grub_database grub_dbx = {.signatures = NULL, .signature_size 
>> = NULL,
>> +                                 .signature_entries = 0};
>>   /*
>>    * Force gcry_rsa to be a module dependency.
>>    *
>> @@ -87,6 +101,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;
>> +
>> +/* releasing trusted list memory */
> 
> Typically these functions start with 'free'. Free trusted list memory.
> 
>> +static void grub_release_trusted_list (void);
>> +/* releasing distrusted list memory */
>> +static void grub_release_distrusted_list (void);
> 
> I am not sure whether local functions and variables should be prefixed
> with grub_ since typically those prefixed wit grub_ are global
> functions. This comment applies to all functions in this patch and
> series.
> 
>>     static enum
>>   {
>> @@ -95,6 +116,248 @@ 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
>> +grub_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_ERR_UNKNOWN_COMMAND;
> 
> return grub_error (GRUB_ERR_OUT_OF_RANGE, "Unsupported GUID for hash")
> 
>> +
>> +  grub_memset (hash, 0x00, GRUB_MAX_HASH_SIZE);
>> +  grub_crypto_hash (hash_func, hash, data, data_size);
>> +  *hash_size =  hash_func->mdlen;
> 
> grub_memset(hash, 0, *hash_size);
> 
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/* adding the certificate/binary hash into the trusted/distrusted 
>> list */
> 
> Add the ...
> 
>> +static grub_err_t
>> +grub_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");
>> +
>> +  if (signatures == NULL && signature_size == NULL)
>> +    {
>> +      signatures = grub_zalloc (sizeof (grub_uint8_t *));
>> +      signature_size = grub_zalloc (sizeof (grub_size_t));
>> +    }
>> +  else
>> +    {
>> +      signatures = grub_realloc (signatures, sizeof (grub_uint8_t *) 
>> * (signature_entries + 1));
>> +      signature_size = grub_realloc (signature_size,
>> +                                     sizeof (grub_size_t) * 
>> (signature_entries + 1));
>> +    }
> 
> Also in this case grub_realloc can be used for first parameter being
> NULL but may need a 2nd variable to handle allocation failures.
> 

I hope no need one more variable here because we used reference of 
signature_list and signature_size_list
so, it won't make any impact here.

>> +
>> +  if (signatures == NULL || signature_size == NULL)
>> +    {
>> +      /*
>> +       * allocated memory will be freed by
>> +       * grub_release_trusted_list/grub_release_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 grub_err_t
>> +grub_is_x509 (const grub_uuid_t *guid)
> 
> Return int like many other *_is_xyz functions do ?
> 
>> +{
>> +  if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_UUID_SIZE) == 
>> 0)
>> +    return GRUB_ERR_NONE;
>> +
>> +  return GRUB_ERR_UNKNOWN_COMMAND;
>> +}
>> +
>> +static grub_err_t
>> +grub_is_cert_match (const struct x509_certificate *distrusted_cert,
>> +                    const struct x509_certificate *db_cert)
> 
> Return int ?
> 
>> +{
>> +
>> +  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
> 
> Verify -- capitalize everywhere.
> 
>> + * distrusted list, if it is present, return a bad signature.
> 
> You won't construct a bad signture but you return 
> GRUB_ERR_BAD_SIGNATURE.
> 
>> + * else, no errors.
> 
> Otherwise no error is returned. -- or omit entirely. Also in other 
> cases.
> 
> It looks like it can return GRUB_ERR_OUT_OF_MEMORY as well.
> 
> 
>> + */
>> +static grub_err_t
>> +grub_is_distrusted_cert (const struct x509_certificate *db_cert)
> 
> So this one here can have allocation failures and should return
> grub_err_t but calls the other two without propagating their errors.
> 
>> +{
>> +  grub_err_t rc = GRUB_ERR_NONE;
>> +  grub_size_t i = 0;
>> +  struct x509_certificate *distrusted_cert = NULL;
>> +
>> +  for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
>> +    {
>> +      if (grub_platform_keystore.dbx[i].data == NULL &&
> 
> 
> should be a '||' or simply remove data_size == 0 check?
> 
>> +          grub_platform_keystore.dbx[i].data_size == 0)
>> +        continue;
>> +
>> +      if (grub_is_x509 (&grub_platform_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_platform_keystore.dbx[i].data,
>> +                                       
>> grub_platform_keystore.dbx[i].data_size, distrusted_cert);
>> +          if (rc != GRUB_ERR_NONE)
>> +            {
>> +              grub_free (distrusted_cert);
>> +              continue;
>> +            }
>> +
>> +          if (grub_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_platform_keystore.dbx[i].data);
>> +              grub_memset (&grub_platform_keystore.dbx[i], 0x00, 
>> sizeof (grub_pks_sd_t));
> 
> s/0x00/0
> 
>> +              certificate_release (distrusted_cert);
>> +              grub_free (distrusted_cert);
>> +              return GRUB_ERR_BAD_SIGNATURE;
>> +            }
>> +
>> +          certificate_release (distrusted_cert);
>> +          grub_free (distrusted_cert);
>> +        }
>> +    }
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/* adding the certificate into the trusted/distrusted list */
> 
> Add the ..
> 
>> +static grub_err_t
>> +grub_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_printf ("Warning: skipping %s certificate (%d)\n",
>> +                   (is_db ? "trusted":"distrused"), rc);
>> +      grub_free (cert);
>> +      return rc;
>> +    }
>> +
>> +  if (is_db)
>> +    {
>> +      rc = grub_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":"distrused"), cert->subject);
> 
> distrusted
> 
>> +
>> +  key_entries++;
>> +  cert->next = database->keys;
>> +  database->keys = cert;
>> +  database->key_entries = key_entries;
>> +
>> +  return rc;
>> +}
>> +
>> +static grub_err_t
>> +grub_read_file (const grub_file_t file, grub_uint8_t **data, 
>> grub_ssize_t *data_size)
> 
> This function sounds so generic that it could be used in other places
> as well. It would we goood to move it to the same file as
> grub_file_read.
> 
>> +{
>> +  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 parse the unknown size of the 
>> file."));
> 
> 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;
>> +}
>> +
>>   static const char *
>>   grub_env_read_sec (struct grub_env_var *var __attribute__ 
>> ((unused)),
>>                      const char *val __attribute__ ((unused)))
>> @@ -248,7 +511,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 (!grub_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 +542,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 = grub_db.keys; pk; pk = pk->next)
>>           {
>>             rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, 
>> pk->mpis[0]);
>>             if (rc)
>> @@ -376,16 +639,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 = grub_db.keys;
>> +      grub_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 = grub_db.keys;
>> +  cert = grub_db.keys->next;
>>     while (cert)
>>       {
>>         if (i == cert_num)
>> @@ -432,8 +695,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 = grub_db.keys;
>> +  grub_db.keys = cert;
>>       return GRUB_ERR_NONE;
>>   }
>> @@ -446,7 +709,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 = grub_db.keys; cert; cert = cert->next)
>>       {
>>         grub_printf (N_("Certificate %d:\n"), cert_num);
>>   @@ -539,6 +802,280 @@ 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
> 
> Verify
> 
>> + * distrusted list, if it is present, return a bad signature.
> 
> Same comments as above.
> 
>> + * else, no errors.
> 
> 
>> + */
>> +static grub_err_t
>> +grub_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_platform_keystore.dbx_entries; i++)
>> +    {
>> +      if (grub_platform_keystore.dbx[i].data == NULL &&
> 
> '||' ?
> 
>> +          grub_platform_keystore.dbx[i].data_size == 0)
>> +        continue;
>> +
>> +      rc = grub_get_hash (&grub_platform_keystore.dbx[i].guid, data, 
>> data_size,
>> +                          cert_hash, &cert_hash_size);
>> +      if (rc != GRUB_ERR_NONE)
>> +        continue;
>> +
>> +      if (cert_hash_size == grub_platform_keystore.dbx[i].data_size 
>> &&
>> +          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
>> +          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof 
>> (grub_pks_sd_t));
> 
> s/0x00/0
> 
> sizeof(grub_platform_keystore.dbx[i]) -- so we don't need to know the
> type of this array
> 
>> +          return GRUB_ERR_BAD_SIGNATURE;
>> +        }
>> +    }
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/*
>> + * verify the trusted binary hash against the platform keystore 
>> buffer's
> 
> Verify.
> 
>> + * distrusted list, if it is present, return a bad signature.
> 
> Same comments as above.
> 
>> + * else, no errors.
>> + */
>> +static grub_err_t
>> +grub_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_platform_keystore.dbx_entries; i++)
>> +    {
>> +      if (grub_platform_keystore.dbx[i].data == NULL &&
> 
> '||' ?
> 
>> +          grub_platform_keystore.dbx[i].data_size == 0)
>> +        continue;
>> +
>> +      if (binary_hash_size == grub_platform_keystore.dbx[i].data_size 
>> &&
>> +          grub_memcmp (grub_platform_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_platform_keystore.dbx[i].data);
>> +          grub_memset (&grub_platform_keystore.dbx[i], 0x00, sizeof 
>> (grub_pks_sd_t));
> 
> same comments as above
> 
>> +          return GRUB_ERR_BAD_SIGNATURE;
>> +        }
>> +    }
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/*
>> + * extracts the binary hashes from the platform keystore buffer,
> 
> Extract the ...
> 
>> + * and adds it to the trusted list if not exists in distrusted list.
> 
> and add it .. if it does not exist in the distrusted list.
> 
>> + */
>> +static grub_err_t
>> +grub_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)
> 
> Here you have the '||'...
> 
>> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted binary hash 
>> data/size is null");
>> +
>> +  rc = grub_is_distrusted_binary_hash (*data, data_size);
>> +  if (rc != GRUB_ERR_NONE)
>> +    return rc;
>> +
>> +  rc = grub_add_hash (data, data_size, &grub_db.signatures, 
>> &grub_db.signature_size,
>> +                      &grub_db.signature_entries);
>> +  return rc;
>> +}
>> +
>> +static grub_err_t
>> +grub_is_hash (const grub_uuid_t *guid)
> 
> Same comments as with other functions as above.
> 
>> +{
>> +  /* 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;
>> +}
>> +
>> +/*> + * extracts the x509 certificates/binary hashes from the 
>> platform keystore buffer,
> 
> Extract the x509...
> 
>> + * parses it, and adds it to the trusted list.
> 
> parse it, and add it to the trusted list.
> 
>> + */
>> +static grub_err_t
>> +grub_create_trusted_list (void)
>> +{
>> +  grub_err_t rc = GRUB_ERR_NONE;
>> +  grub_size_t i = 0;
>> +
>> +  for (i = 0; i < grub_platform_keystore.db_entries; i++)
>> +    {
>> +      if (grub_is_hash (&grub_platform_keystore.db[i].guid) == 
>> GRUB_ERR_NONE)
>> +        {
>> +          rc = grub_add_trusted_binary_hash ((const grub_uint8_t **)
>> +                                             
>> &grub_platform_keystore.db[i].data,
>> +                                             
>> grub_platform_keystore.db[i].data_size);
>> +          if (rc == GRUB_ERR_OUT_OF_MEMORY)
>> +            return rc;
>> +
>> +          continue;
> 
> 'continue' not needed
> 
>> +        }
>> +      else if (grub_is_x509 (&grub_platform_keystore.db[i].guid) == 
>> GRUB_ERR_NONE)
>> +        {
>> +
> 
> stray empty line
> 
>> +          rc = grub_is_distrusted_cert_hash 
>> (grub_platform_keystore.db[i].data,
>> +                                             
>> grub_platform_keystore.db[i].data_size);
>> +          if (rc != GRUB_ERR_NONE)> +            continue;
>> +
>> +          rc = grub_add_certificate 
>> (grub_platform_keystore.db[i].data,
>> +                                     
>> grub_platform_keystore.db[i].data_size, &grub_db, 1);
>> +          if (rc == GRUB_ERR_OUT_OF_MEMORY)
>> +            return rc;
>> +          else if (rc != GRUB_ERR_NONE)
>> +            continue;
>> +        }
>> +      else
>> +        grub_printf ("Warning: unsupported signature data type and "
>> +                     "skipping trusted data (%" PRIuGRUB_SIZE ")\n", 
>> i + 1);
>> +    }
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/*
>> + * extracts the certificates, certificate/binary hashes out of the 
>> platform keystore buffer,
>> + * and adds it to the distrusted list.
>> + */
>> +static grub_err_t
>> +grub_create_distrusted_list (void)
>> +{
>> +  grub_err_t rc = GRUB_ERR_NONE;
>> +  grub_size_t i = 0;
>> +
>> +  for (i = 0; i < grub_platform_keystore.dbx_entries; i++)
>> +    {
>> +      if (grub_platform_keystore.dbx[i].data != NULL &&
> 
> '||'?
> 
>> +          grub_platform_keystore.dbx[i].data_size > 0)
>> +        {
>> +          if (grub_is_x509 (&grub_platform_keystore.dbx[i].guid) == 
>> GRUB_ERR_NONE)
>> +            {
>> +              rc = grub_add_certificate 
>> (grub_platform_keystore.dbx[i].data,
>> +                                         
>> grub_platform_keystore.dbx[i].data_size, &grub_dbx, 0);
>> +              if (rc == GRUB_ERR_OUT_OF_MEMORY)
>> +                return rc;
>> +            }
>> +          else if (grub_is_hash (&grub_platform_keystore.dbx[i].guid) 
>> == GRUB_ERR_NONE)
>> +            {
>> +              rc = grub_add_hash ((const grub_uint8_t **) 
>> &grub_platform_keystore.dbx[i].data,
>> +                                  
>> grub_platform_keystore.dbx[i].data_size,
>> +                                  &grub_dbx.signatures, 
>> &grub_dbx.signature_size,
>> +                                  &grub_dbx.signature_entries);
>> +              if (rc != GRUB_ERR_NONE)
>> +                return rc;
>> +            }
>> +          else
>> +            grub_printf ("Warning: unsupported signature data type 
>> and "
>> +                         "skipping distrusted data (%" PRIuGRUB_SIZE 
>> ")\n", i + 1);
>> +        }
>> +    }
>> +
>> +  return rc;
>> +}
>> +
>> +/*
>> + * extracts the x509 certificates from the ELF note header,
>> + * parses it, and adds it to the trusted list.
>> + */
>> +static grub_err_t
>> +grub_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));
> 
> ah, '0'
> 
>> +  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 = grub_add_certificate (cert_data, cert_data_size, &grub_db, 
>> 1);
>> +  if (cert_data != NULL)
>> +    grub_free (cert_data);
> 
> no need to check for cert_data != NULL
>> +
>> +  return err;
>> +}
>> +
>> +/* releasing memory */
>> +static void
>> +grub_release_trusted_list (void)
>> +{
>> +  struct x509_certificate *cert;
>> +  grub_size_t i = 0;
>> +
>> +  while (grub_db.keys != NULL)
>> +    {
>> +      cert = grub_db.keys;
>> +      grub_db.keys = grub_db.keys->next;
>> +      certificate_release (cert);
>> +      grub_free (cert);
>> +    }
>> +
>> +  for (i = 0; i < grub_db.signature_entries; i++)
>> +    grub_free (grub_db.signatures[i]);
>> +
>> +  grub_free (grub_db.signatures);
>> +  grub_free (grub_db.signature_size);
>> +  grub_memset (&grub_db, 0x00, sizeof (grub_db));
> 
> s/0x00/0
> 
>> +}
>> +
>> +/* releasing memory */
>> +static void
>> +grub_release_distrusted_list (void)
>> +{
>> +  struct x509_certificate *cert;
>> +  grub_size_t i = 0;
>> +
>> +  while (grub_dbx.keys != NULL)
>> +    {
>> +      cert = grub_dbx.keys;
>> +      grub_dbx.keys = grub_dbx.keys->next;
>> +      certificate_release (cert);
>> +      grub_free (cert);
>> +    }
>> +
>> +  for (i = 0; i < grub_dbx.signature_entries; i++)
>> +    grub_free (grub_dbx.signatures[i]);
>> +
>> +  grub_free (grub_dbx.signatures);
>> +  grub_free (grub_dbx.signature_size);
>> +  grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
> 
> s/0x00.0
> 
>> +}
>> +
>>   GRUB_MOD_INIT (appendedsig)
>>   {
>>     int rc;
>> @@ -548,7 +1085,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,39 +1092,51 @@ 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;
>> -
>> -    /* Not an X.509 certificate, skip. */
>> -    if (header->type != OBJ_TYPE_X509_PUBKEY)
>> -      continue;
>> -
>> -    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);
>> +  if (!grub_use_platform_keystore && check_sigs == check_sigs_forced)
>> +    {
>> +      FOR_MODULES (header)
>> +        {
>> +          /* Not an ELF module, skip.  */
>> +          if (header->type != OBJ_TYPE_X509_PUBKEY)
>> +            continue;
>>   -    grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", 
>> pk->subject);
>> +          rc = grub_build_static_trusted_list (header);
>> +          if (rc != GRUB_ERR_NONE)
>> +            {
>> +              grub_release_trusted_list ();
>> +              grub_error (rc, "static trusted list creation failed");
>> +            }
>> +          else
>> +            grub_printf ("appendedsig: the trusted list now has %" 
>> PRIuGRUB_SIZE " static keys\n",
>> +                         grub_db.key_entries);
>> +        }
>> +    }
>> +  else if (grub_use_platform_keystore && check_sigs == 
>> check_sigs_forced)
>> +    {
>> +      rc = grub_create_trusted_list ();
>> +      if (rc != GRUB_ERR_NONE)
>> +        {
>> +          grub_release_trusted_list ();
>> +          grub_error (rc, "trusted list creation failed");
>> +        }
>> +      else
>> +        {
>> +          rc = grub_create_distrusted_list ();
>> +          if (rc != GRUB_ERR_NONE)
>> +            {
>> +              grub_release_trusted_list ();
>> +              grub_release_distrusted_list ();
>> +              grub_error (rc, "distrusted list creation failed");
>> +            }
>> +          else
>> +            grub_printf ("appendedsig: the trusted list now has %" 
>> PRIuGRUB_SIZE " keys.\n"
>> +                         "appendedsig: the distrusted list now has %" 
>> PRIuGRUB_SIZE " keys.\n",
>> +                         grub_db.signature_entries + 
>> grub_db.key_entries,
>> +                         grub_dbx.signature_entries);
>> +        }
>>   -    pk->next = grub_trusted_key;
>> -    grub_trusted_key = pk;
>> -  }
>> +      grub_release_platform_keystore ();
>> +    }
>>       cmd_trust = grub_register_command ("trust_certificate", 
>> grub_cmd_trust, N_("X509_CERTIFICATE"),
>>                                        N_("Add X509_CERTIFICATE to 
>> trusted certificates."));

addressed all the comments. Thank you stefan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 17/21] appendedsig: While verifying the kernel, use trusted and distrusted lists
  2024-12-31 17:37   ` Stefan Berger
@ 2025-02-27 15:22     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:22 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2024-12-31 23:07, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> To verify the kernel's: verify the kernel binary against list of 
>> binary hashes
> 
> To verify the kernel's signature?
> 
> against lists of binary hashes
> 
>> that are distrusted and trusted. If it is not listed in both trusted 
>> and distrusted,
> 
> 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.
> 
>> the trusted keys from trusted key list used to verify the signature.
>> 
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   grub-core/commands/appendedsig/appendedsig.c | 188 
>> +++++++++++++------
>>   1 file changed, 133 insertions(+), 55 deletions(-)
>> 
>> diff --git a/grub-core/commands/appendedsig/appendedsig.c 
>> b/grub-core/commands/appendedsig/appendedsig.c
>> index 31649e800..8b084087e 100644
>> --- a/grub-core/commands/appendedsig/appendedsig.c
>> +++ b/grub-core/commands/appendedsig/appendedsig.c
>> @@ -497,6 +497,81 @@ 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
>> +grub_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 grub_get_hash (&guid, data, data_size, hash, hash_size);
>> +}
>> +
>> +/*
>> + * verify binary hash against the list of binary hashes that are 
>> distrusted
> Verify a binary hash
>> + * 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
>> +grub_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 < grub_dbx.signature_entries; i++)
>> +    {
>> +      rc = grub_get_binary_hash (grub_dbx.signature_size[i], data, 
>> data_size,
>> +                                 hash, &hash_size);
>> +      if (rc != GRUB_ERR_NONE)
>> +        continue;
>> +
>> +      if (hash_size == grub_dbx.signature_size[i] &&
>> +          grub_memcmp (grub_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]);
> 
> merge the error string into one
> 
>> +          return GRUB_ERR_BAD_SIGNATURE;
>> +        }
>> +    }
>> +
>> +  for (i = 0; i < grub_db.signature_entries; i++)
>> +    {
>> +      rc = grub_get_binary_hash (grub_db.signature_size[i], data, 
>> data_size,
>> +                                 hash, &hash_size);
>> +      if (rc != GRUB_ERR_NONE)
>> +        continue;
>> +
>> +      if (hash_size == grub_db.signature_size[i] &&
>> +          grub_memcmp (grub_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)
>>   {
>> @@ -506,12 +581,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 (!grub_db.key_entries)
>> +  if (!grub_db.key_entries && !grub_db.signature_entries)
>>       return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys 
>> to verify against"));
>>       err = extract_appended_signature (buf, bufsize, &sig);
>> @@ -520,68 +595,71 @@ grub_verify_appended_signature (const 
>> grub_uint8_t *buf, grub_size_t bufsize)
>>       datasize = bufsize - sig.signature_len;
>>   -  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
>> +  err = grub_verify_binary_hash (buf, datasize);
>> +  if (err == GRUB_ERR_EOF)
>>       {
>> -      /*
>> -       * 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 = grub_db.keys; pk; pk = pk->next)
> 
> /* 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)
>> +          /*
>> +           * 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(grub_db.keys * pkcs7 signers) 
>> approach.
>> +           */
>> +          si = &sig.pkcs7.signerInfos[i];
>> +          context = grub_zalloc (si->hash->contextsize);
>> +          if (context == NULL)
>> +            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 (cert = grub_db.keys; cert; cert = cert->next)
>>               {
>> -              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> -                                N_("Error padding hash for RSA 
>> verification: %d"), rc);
>> -              grub_free (context);
>> -              goto cleanup;
>> +              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;
>> +                }
>> +
>> +              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;
>> +                }
>> +
>> +              grub_dprintf ("appendedsig", "verify signer %d with key 
>> '%s' failed with %d\n",
>> +                            i, cert->subject, rc);
>>               }
>>   -          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, 
>> &si->sig_mpi, pk->mpis, NULL, NULL);
>> -          gcry_mpi_release (hashmpi);
>> -
>> -          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", "verify signer %d with key 
>> '%s' failed with %d\n",
>> -                        i, pk->subject, rc);
>> -        }
>> -
>> -      grub_free (context);
>> -
>> -      if (err == GRUB_ERR_NONE)
>> -        break;
>> +          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"));
> 
> You may need a special case to jump to from after the hash list test
> to indicate that the hash was found in the distrusted hashes list.
> 
>> +  else
>> +    grub_printf ("appendedsig: successfully verified the signature 
>> with a trusted key\n");
>> +
>>     return err;
>>   }
>> 


addressed all the comments. thank you stefan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note
  2025-01-02 13:19   ` Stefan Berger
@ 2025-02-27 15:23     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:23 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2025-01-02 18:49, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> if secure boot enabled with PKS and set use_static_keys flag, it
> 
> 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.
> 
>> reads the DB default keys from ELF Note and store it in trusted list 
>> buffer.
>> 
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   grub-core/commands/appendedsig/appendedsig.c | 58 
>> ++++++++++++++------
>>   1 file changed, 41 insertions(+), 17 deletions(-)
>> 
>> diff --git a/grub-core/commands/appendedsig/appendedsig.c 
>> b/grub-core/commands/appendedsig/appendedsig.c
>> index 8b084087e..9a9f4ef1c 100644
>> --- a/grub-core/commands/appendedsig/appendedsig.c
>> +++ b/grub-core/commands/appendedsig/appendedsig.c
>> @@ -1082,7 +1082,7 @@ grub_create_distrusted_list (void)
>>    * parses it, and adds it to the trusted list.
>>    */
>>   static grub_err_t
>> -grub_build_static_trusted_list (const struct grub_module_header 
>> *header)
>> +grub_build_static_trusted_list (const struct grub_module_header 
>> *header, const grub_bool_t mode)
> 
> A more meaningful variable name than 'mode' would be good. mode = true
> or false doesn't mean much.
> 
>>   {
>>     grub_err_t err = GRUB_ERR_NONE;
>>     struct grub_file pseudo_file;
>> @@ -1101,7 +1101,14 @@ grub_build_static_trusted_list (const struct 
>> grub_module_header *header)
>>     if (err != GRUB_ERR_NONE)
>>       return err;
>>   -  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 
>> 1);
>> +  if (mode)
>> +    {
>> +      err = grub_is_distrusted_cert_hash (cert_data, cert_data_size);
>> +      if (err != GRUB_ERR_NONE)
>> +        return err;
>> +    }
>> +
>> +  err = grub_add_certificate (cert_data, cert_data_size, &grub_db, 
>> mode);
>>     if (cert_data != NULL)
>>       grub_free (cert_data);
>>   @@ -1154,6 +1161,20 @@ grub_release_distrusted_list (void)
>>     grub_memset (&grub_dbx, 0x00, sizeof (grub_dbx));
>>   }
>>   +static grub_err_t
>> +grub_load_static_keys (const struct grub_module_header *header, const 
>> grub_bool_t mode)
>> +{
>> +  int rc = GRUB_ERR_NONE;
>> +  FOR_MODULES (header)
>> +    {
>> +      /* Not an ELF module, skip.  */
>> +      if (header->type != OBJ_TYPE_X509_PUBKEY)
>> +        continue;
>> +      rc = grub_build_static_trusted_list (header, mode);
> 
> Do you have to check rc at this point?
> 
>> +    }
>> +  return rc;
>> +}
>> +
>>   GRUB_MOD_INIT (appendedsig)
>>   {
>>     int rc;
>> @@ -1172,26 +1193,29 @@ GRUB_MOD_INIT (appendedsig)
>>       if (!grub_use_platform_keystore && check_sigs == 
>> check_sigs_forced)
>>       {
>> -      FOR_MODULES (header)
>> +      rc = grub_load_static_keys (header, 0);
>> +      if (rc != GRUB_ERR_NONE)
>>           {
>> -          /* Not an ELF module, skip.  */
>> -          if (header->type != OBJ_TYPE_X509_PUBKEY)
>> -            continue;
>> -
>> -          rc = grub_build_static_trusted_list (header);
>> -          if (rc != GRUB_ERR_NONE)
>> -            {
>> -              grub_release_trusted_list ();
>> -              grub_error (rc, "static trusted list creation failed");
>> -            }
>> -          else
>> -            grub_printf ("appendedsig: the trusted list now has %" 
>> PRIuGRUB_SIZE " static keys\n",
>> -                         grub_db.key_entries);
>> +          grub_release_trusted_list ();
>> +          grub_error (rc, "static trusted list creation failed");
>>           }
>> +      else
>> +        grub_printf ("appendedsig: the trusted list now has %" 
>> PRIuGRUB_SIZE " static keys\n",
>> +                     grub_db.key_entries);
>> +
>>       }
>>     else if (grub_use_platform_keystore && check_sigs == 
>> check_sigs_forced)
>>       {
>> -      rc = grub_create_trusted_list ();
>> +
>> +      if (grub_platform_keystore.use_static_keys == 1)
> 
> if (grub_platform_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 = grub_load_static_keys (header, 1);
>> +        }
>> +      else
>> +        rc = grub_create_trusted_list ();
>> +
>>         if (rc != GRUB_ERR_NONE)
>>           {
>>             grub_release_trusted_list ();


addressed all the comments. thank you Stefan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 18/21] ieee1275: set use_static_keys flag
  2025-01-02 13:22   ` Stefan Berger
@ 2025-02-27 15:24     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:24 UTC (permalink / raw)
  To: Stefan Berger
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, avnish, nayna, ssrish

On 2025-01-02 18:52, Stefan Berger wrote:
> On 12/18/24 9:56 AM, Sudhakar Kuppusamy wrote:
>> if secure boot enabled with PKS, it set the use_static_keys flag
> 
> I was not sure at this point what the patch actually does so I
> reformulated it a bit. I would start the patch description with the
> reason why you are introducing the use_static_key:
> 
> 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... or something
> like this.
> 
> 
>> when DB variable is not present in PKS storage and the appendedsig 
>> (module)
>> would use it later to extract the default DB key's from ELF Note and
>> store it in trustedlist.
>> 
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>   grub-core/kern/ieee1275/platform_keystore.c | 15 ++++++++++++++-
>>   include/grub/platform_keystore.h            | 12 +++++++-----
>>   2 files changed, 21 insertions(+), 6 deletions(-)
>> 
>> diff --git a/grub-core/kern/ieee1275/platform_keystore.c 
>> b/grub-core/kern/ieee1275/platform_keystore.c
>> index 1c564d5da..ddc11afd9 100644
>> --- a/grub-core/kern/ieee1275/platform_keystore.c
>> +++ b/grub-core/kern/ieee1275/platform_keystore.c
>> @@ -34,7 +34,11 @@
>>   /* Platform Keystore */
>>   static grub_size_t pks_max_object_size;
>>   grub_uint8_t grub_use_platform_keystore = 0;
>> -grub_pks_t grub_platform_keystore = { .db = NULL, .dbx = NULL, 
>> .db_entries = 0, .dbx_entries = 0 };
>> +grub_pks_t grub_platform_keystore = { .db = NULL,
>> +                                      .dbx = NULL,
>> +                                      .db_entries = 0,
>> +                                      .dbx_entries = 0,
>> +                                      .use_static_keys = 0 };
> 
> Use false
> 
>>     /* converts the esl data into the ESL */
>>   static grub_esl_t *
>> @@ -316,6 +320,15 @@ grub_platform_keystore_init (void)
>>         /* DB */
>>         rc = grub_read_secure_boot_variables (0, DB, 
>> &grub_platform_keystore.db,
>>                                               
>> &grub_platform_keystore.db_entries);
>> +      if (rc == PKS_OBJECT_NOT_FOUND)
>> +        {
>> +          rc = GRUB_ERR_NONE;
>> +          /*
>> +           * DB variable won't be available by default in PKS.
> 
> The DB variable.
> 
>> +           * So, it will loads the Default Keys from ELF Note */
> 
> s/loads/load
> -> If it is not available load the default keys from the ELF node (?)
> 
> 
>> +          grub_platform_keystore.use_static_keys = 1;
>> +        }
>> +
>>         if (rc == GRUB_ERR_NONE)
>>           {
>>             /* DBX */
>> diff --git a/include/grub/platform_keystore.h 
>> b/include/grub/platform_keystore.h
>> index 7a7378926..b333db7fd 100644
>> --- a/include/grub/platform_keystore.h
>> +++ b/include/grub/platform_keystore.h
>> @@ -49,6 +49,7 @@
>>   #define GRUB_UUID_SIZE 16
>>   #define GRUB_MAX_HASH_SIZE 64
>>   +typedef grub_uint8_t grub_bool_t;
> 
> This would be a candidate for types.h. term/tparam.c already defines
> it as char. bool also already exists and is also used in some places.
> 
>>   typedef struct grub_uuid grub_uuid_t;
>>   typedef struct grub_esd grub_esd_t;
>>   typedef struct grub_esl grub_esl_t;
>> @@ -207,10 +208,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__
>> @@ -225,7 +227,7 @@ extern grub_pks_t 
>> EXPORT_VAR(grub_platform_keystore);
>>   #else
>>     #define grub_use_platform_keystore	0
>> -grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0};
>> +grub_pks_t grub_platform_keystore = {NULL, NULL, 0, 0, 0};
> 
> Use false
> 
>>   void grub_release_platform_keystore (void);
>>     #endif


Addressed all the comments. Thank you Stefan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 05/21] pgp: factor out rsa_pad
  2025-01-04 18:40   ` Vladimir 'phcoder' Serbinenko
@ 2025-02-27 15:26     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:26 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko
  Cc: The development of GNU GRUB, dja, jan.setjeeilers, julian.klode,
	mate.kukri, pjones, stefanb, avnish, nayna, ssrish

On 2025-01-05 00:10, Vladimir 'phcoder' Serbinenko wrote:
> rsa_pad will be removed when we update libgcrypt (see pending patch).
> Can we accommodate for this?
> 
> On Wed, Dec 18, 2024 at 5:58 PM Sudhakar Kuppusamy
> <sudhakar@linux.ibm.com> wrote:
>> 
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
>> We want to use it in other RSA signature verification applications.
>> 
>> I considered and rejected putting it in lib/crypto.c. That file 
>> doesn't
>> currently require any MPI functions, but rsa_pad does. That's not so
>> much of a problem for the grub kernel and modules, but crypto.c also
>> gets built into all the grub utilities. So - despite the utils not
>> using any asymmetric ciphers -  we would need to built the entire MPI
>> infrastructure in to them.
>> 
>> A better and simpler solution is just to spin rsa_pad out into its own
>> PKCS#1 v1.5 module.
>> 
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>  grub-core/Makefile.core.def |  8 +++++
>>  grub-core/commands/pgp.c    | 28 ++----------------
>>  grub-core/lib/pkcs1_v15.c   | 59 
>> +++++++++++++++++++++++++++++++++++++
>>  include/grub/pkcs1_v15.h    | 27 +++++++++++++++++
>>  4 files changed, 96 insertions(+), 26 deletions(-)
>>  create mode 100644 grub-core/lib/pkcs1_v15.c
>>  create mode 100644 include/grub/pkcs1_v15.h
>> 
>> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
>> index f70e02e69..60db2adc5 100644
>> --- a/grub-core/Makefile.core.def
>> +++ b/grub-core/Makefile.core.def
>> @@ -2540,6 +2540,14 @@ module = {
>>    cppflags = '$(CPPFLAGS_GCRY)';
>>  };
>> 
>> +module = {
>> +  name = pkcs1_v15;
>> +  common = lib/pkcs1_v15.c;
>> +
>> +  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
>> +  cppflags = '$(CPPFLAGS_GCRY)';
>> +};
>> +
>>  module = {
>>    name = all_video;
>>    common = lib/fake_module.c;
>> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
>> index c6766f044..b084dc9a2 100644
>> --- a/grub-core/commands/pgp.c
>> +++ b/grub-core/commands/pgp.c
>> @@ -24,6 +24,7 @@
>>  #include <grub/file.h>
>>  #include <grub/command.h>
>>  #include <grub/crypto.h>
>> +#include <grub/pkcs1_v15.h>
>>  #include <grub/i18n.h>
>>  #include <grub/gcrypt/gcrypt.h>
>>  #include <grub/pubkey.h>
>> @@ -411,32 +412,7 @@ static int
>>  rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>>          const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
>>  {
>> -  grub_size_t tlen, emlen, fflen;
>> -  grub_uint8_t *em, *emptr;
>> -  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
>> -  int ret;
>> -  tlen = hash->mdlen + hash->asnlen;
>> -  emlen = (nbits + 7) / 8;
>> -  if (emlen < tlen + 11)
>> -    return 1;
>> -
>> -  em = grub_malloc (emlen);
>> -  if (!em)
>> -    return 1;
>> -
>> -  em[0] = 0x00;
>> -  em[1] = 0x01;
>> -  fflen = emlen - tlen - 3;
>> -  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
>> -    *emptr = 0xff;
>> -  *emptr++ = 0x00;
>> -  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
>> -  emptr += hash->asnlen;
>> -  grub_memcpy (emptr, hval, hash->mdlen);
>> -
>> -  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
>> -  grub_free (em);
>> -  return ret;
>> +  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
>>  }
>> 
>>  struct grub_pubkey_context
>> diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
>> new file mode 100644
>> index 000000000..dbacd563d
>> --- /dev/null
>> +++ b/grub-core/lib/pkcs1_v15.c
>> @@ -0,0 +1,59 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2013  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/dl.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +
>> +GRUB_MOD_LICENSE ("GPLv3+");
>> +
>> +/*
>> + * Given a hash value 'hval', of hash specification 'hash', perform
>> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
>> + * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
>> + */
>> +gcry_err_code_t
>> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
>> +                    const gcry_md_spec_t * hash, gcry_mpi_t mod)
>> +{
>> +  grub_size_t tlen, emlen, fflen;
>> +  grub_uint8_t *em, *emptr;
>> +  unsigned nbits = gcry_mpi_get_nbits (mod);
>> +  int ret;
>> +  tlen = hash->mdlen + hash->asnlen;
>> +  emlen = (nbits + 7) / 8;
>> +  if (emlen < tlen + 11)
>> +    return GPG_ERR_TOO_SHORT;
>> +
>> +  em = grub_malloc (emlen);
>> +  if (!em)
>> +    return 1;
>> +
>> +  em[0] = 0x00;
>> +  em[1] = 0x01;
>> +  fflen = emlen - tlen - 3;
>> +  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
>> +    *emptr = 0xff;
>> +  *emptr++ = 0x00;
>> +  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
>> +  emptr += hash->asnlen;
>> +  grub_memcpy (emptr, hval, hash->mdlen);
>> +
>> +  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
>> +  grub_free (em);
>> +  return ret;
>> +}
>> diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
>> new file mode 100644
>> index 000000000..5c338c84a
>> --- /dev/null
>> +++ b/include/grub/pkcs1_v15.h
>> @@ -0,0 +1,27 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2013  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/>.
>> + */
>> +
>> +/*
>> + * Given a hash value 'hval', of hash specification 'hash', perform
>> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
>> + * (See RFC 8017 s 9.2)
>> + */
>> +gcry_err_code_t
>> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
>> +                    const gcry_md_spec_t * hash, gcry_mpi_t mod);
>> +
>> --
>> 2.43.5
>> 
>> 
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> https://lists.gnu.org/mailman/listinfo/grub-devel


Sure. we can accommodate for this. Thank you Vladimir for the 
information.


Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 05/21] pgp: factor out rsa_pad
  2025-01-24 10:40   ` Avnish Chouhan
@ 2025-02-27 15:28     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:28 UTC (permalink / raw)
  To: Avnish Chouhan
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper

On 2025-01-24 16:10, Avnish Chouhan wrote:
> Indentation looks off in couple of places. Please fix it.
> 
> Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
> 
> On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
>> We want to use it in other RSA signature verification applications.
>> 
>> I considered and rejected putting it in lib/crypto.c. That file 
>> doesn't
>> currently require any MPI functions, but rsa_pad does. That's not so
>> much of a problem for the grub kernel and modules, but crypto.c also
>> gets built into all the grub utilities. So - despite the utils not
>> using any asymmetric ciphers -  we would need to built the entire MPI
>> infrastructure in to them.
>> 
>> A better and simpler solution is just to spin rsa_pad out into its own
>> PKCS#1 v1.5 module.
>> 
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>  grub-core/Makefile.core.def |  8 +++++
>>  grub-core/commands/pgp.c    | 28 ++----------------
>>  grub-core/lib/pkcs1_v15.c   | 59 
>> +++++++++++++++++++++++++++++++++++++
>>  include/grub/pkcs1_v15.h    | 27 +++++++++++++++++
>>  4 files changed, 96 insertions(+), 26 deletions(-)
>>  create mode 100644 grub-core/lib/pkcs1_v15.c
>>  create mode 100644 include/grub/pkcs1_v15.h
>> 
>> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
>> index f70e02e69..60db2adc5 100644
>> --- a/grub-core/Makefile.core.def
>> +++ b/grub-core/Makefile.core.def
>> @@ -2540,6 +2540,14 @@ module = {
>>    cppflags = '$(CPPFLAGS_GCRY)';
>>  };
>> 
>> +module = {
>> +  name = pkcs1_v15;
>> +  common = lib/pkcs1_v15.c;
>> +
>> +  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
>> +  cppflags = '$(CPPFLAGS_GCRY)';
>> +};
>> +
>>  module = {
>>    name = all_video;
>>    common = lib/fake_module.c;
>> diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
>> index c6766f044..b084dc9a2 100644
>> --- a/grub-core/commands/pgp.c
>> +++ b/grub-core/commands/pgp.c
>> @@ -24,6 +24,7 @@
>>  #include <grub/file.h>
>>  #include <grub/command.h>
>>  #include <grub/crypto.h>
>> +#include <grub/pkcs1_v15.h>
>>  #include <grub/i18n.h>
>>  #include <grub/gcrypt/gcrypt.h>
>>  #include <grub/pubkey.h>
>> @@ -411,32 +412,7 @@ static int
>>  rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
>>  	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
>>  {
>> -  grub_size_t tlen, emlen, fflen;
>> -  grub_uint8_t *em, *emptr;
>> -  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
>> -  int ret;
>> -  tlen = hash->mdlen + hash->asnlen;
>> -  emlen = (nbits + 7) / 8;
>> -  if (emlen < tlen + 11)
>> -    return 1;
>> -
>> -  em = grub_malloc (emlen);
>> -  if (!em)
>> -    return 1;
>> -
>> -  em[0] = 0x00;
>> -  em[1] = 0x01;
>> -  fflen = emlen - tlen - 3;
>> -  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
>> -    *emptr = 0xff;
>> -  *emptr++ = 0x00;
>> -  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
>> -  emptr += hash->asnlen;
>> -  grub_memcpy (emptr, hval, hash->mdlen);
>> -
>> -  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
>> -  grub_free (em);
>> -  return ret;
>> +  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
>>  }
>> 
>>  struct grub_pubkey_context
>> diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
>> new file mode 100644
>> index 000000000..dbacd563d
>> --- /dev/null
>> +++ b/grub-core/lib/pkcs1_v15.c
>> @@ -0,0 +1,59 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2013  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/dl.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +
>> +GRUB_MOD_LICENSE ("GPLv3+");
>> +
>> +/*
>> + * Given a hash value 'hval', of hash specification 'hash', perform
>> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
>> + * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
>> + */
>> +gcry_err_code_t
>> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
>> +		     const gcry_md_spec_t * hash, gcry_mpi_t mod)
>> +{
>> +  grub_size_t tlen, emlen, fflen;
>> +  grub_uint8_t *em, *emptr;
>> +  unsigned nbits = gcry_mpi_get_nbits (mod);
>> +  int ret;
>> +  tlen = hash->mdlen + hash->asnlen;
>> +  emlen = (nbits + 7) / 8;
>> +  if (emlen < tlen + 11)
>> +    return GPG_ERR_TOO_SHORT;
>> +
>> +  em = grub_malloc (emlen);
>> +  if (!em)
>> +    return 1;
>> +
>> +  em[0] = 0x00;
>> +  em[1] = 0x01;
>> +  fflen = emlen - tlen - 3;
>> +  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
>> +    *emptr = 0xff;
>> +  *emptr++ = 0x00;
>> +  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
>> +  emptr += hash->asnlen;
>> +  grub_memcpy (emptr, hval, hash->mdlen);
>> +
>> +  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
>> +  grub_free (em);
>> +  return ret;
>> +}
>> diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
>> new file mode 100644
>> index 000000000..5c338c84a
>> --- /dev/null
>> +++ b/include/grub/pkcs1_v15.h
>> @@ -0,0 +1,27 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2013  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/>.
>> + */
>> +
>> +/*
>> + * Given a hash value 'hval', of hash specification 'hash', perform
>> + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
>> + * (See RFC 8017 s 9.2)
>> + */
>> +gcry_err_code_t
>> +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
>> +		     const gcry_md_spec_t * hash, gcry_mpi_t mod);
>> +


Addressed the above comments. thank you Avnish Chouhan

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates
  2025-01-24 11:10   ` Avnish Chouhan
@ 2025-02-27 15:31     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:31 UTC (permalink / raw)
  To: Avnish Chouhan
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, Javier Martinez Canillas,
	Michal Suchanek, daniel.kiper

On 2025-01-24 16:40, Avnish Chouhan wrote:
> Suggestion : It will be good if we can remove the brackets in one
> liner if conditions and loops!
> 
> Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
> 
> On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> This code allows us to parse:
>> 
>>  - PKCS#7 signedData messages. Only a single signerInfo is supported,
>>    which is all that the Linux sign-file utility supports creating
>>    out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
>>    Any certificate embedded in the PKCS#7 message will be ignored.
>> 
>>  - X.509 certificates: at least enough to verify the signatures on the
>>    PKCS#7 messages. We expect that the certificates embedded in grub 
>> will
>>    be leaf certificates, not CA certificates. The parser enforces 
>> this.
>> 
>>  - X.509 certificates support the Extended Key Usage extension and 
>> handle
>>    it by verifying that the certificate has a single purpose, that is 
>> code
>>    signing. This is required because Red Hat certificates have both 
>> Key
>>    Usage and Extended Key Usage extensions present.
>> 
>> Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> # EKU 
>> support
>> Reported-by: Michal Suchanek <msuchanek@suse.com> # key usage issue
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>  grub-core/commands/appendedsig/appendedsig.h | 110 +++
>>  grub-core/commands/appendedsig/asn1util.c    |  99 ++
>>  grub-core/commands/appendedsig/pkcs7.c       | 473 +++++++++
>>  grub-core/commands/appendedsig/x509.c        | 981 
>> +++++++++++++++++++
>>  4 files changed, 1663 insertions(+)
>>  create mode 100644 grub-core/commands/appendedsig/appendedsig.h
>>  create mode 100644 grub-core/commands/appendedsig/asn1util.c
>>  create mode 100644 grub-core/commands/appendedsig/pkcs7.c
>>  create mode 100644 grub-core/commands/appendedsig/x509.c
>> 
>> diff --git a/grub-core/commands/appendedsig/appendedsig.h
>> b/grub-core/commands/appendedsig/appendedsig.h
>> new file mode 100644
>> index 000000000..fa59302c8
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/appendedsig.h
>> @@ -0,0 +1,110 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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/crypto.h>
>> +#include <grub/libtasn1.h>
>> +
>> +extern asn1_node _gnutls_gnutls_asn;
>> +extern asn1_node _gnutls_pkix_asn;
>> +
>> +#define MAX_OID_LEN 32
>> +
>> +/*
>> + * One or more x509 certificates.
>> + * We do limited parsing: extracting only the serial, CN and RSA 
>> public key.
>> + */
>> +struct x509_certificate
>> +{
>> +  struct x509_certificate *next;
>> +  grub_uint8_t *serial;
>> +  grub_size_t serial_len;
>> +  char *subject;
>> +  grub_size_t subject_len;
>> +  /* We only support RSA public keys. This encodes [modulus, 
>> publicExponent] */
>> +  gcry_mpi_t mpis[2];
>> +};
>> +
>> +/*
>> + * A PKCS#7 signedData signerInfo.
>> + */
>> +struct pkcs7_signerInfo
>> +{
>> +  const gcry_md_spec_t *hash;
>> +  gcry_mpi_t sig_mpi;
>> +};
>> +
>> +/*
>> + * A PKCS#7 signedData message.
>> + * We make no attempt to match intelligently, so we don't save any 
>> info about
>> + * the signer.
>> + */
>> +struct pkcs7_signedData
>> +{
>> +  int signerInfo_count;
>> +  struct pkcs7_signerInfo *signerInfos;
>> +};
>> +
>> +/* Do libtasn1 init */
>> +int
>> +asn1_init (void);
>> +
>> +/*
>> + * Import a DER-encoded certificate at 'data', of size 'size'.
>> + * Place the results into 'results', which must be already allocated.
>> + */
>> +grub_err_t
>> +parse_x509_certificate (const void *data, grub_size_t size, struct
>> x509_certificate *results);
>> +
>> +/*
>> + * Release all the storage associated with the x509 certificate.
>> + * If the caller dynamically allocated the certificate, it must free 
>> it.
>> + * The caller is also responsible for maintenance of the linked list.
>> + */
>> +void
>> +certificate_release (struct x509_certificate *cert);
>> +
>> +/*
>> + * Parse a PKCS#7 message, which must be a signedData message.
>> + * The message must be in 'sigbuf' and of size 'data_size'. The 
>> result is
>> + * placed in 'msg', which must already be allocated.
>> + */
>> +grub_err_t
>> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size,
>> struct pkcs7_signedData *msg);
>> +
>> +/*
>> + * Release all the storage associated with the PKCS#7 message.
>> + * If the caller dynamically allocated the message, it must free it.
>> + */
>> +void
>> +pkcs7_signedData_release (struct pkcs7_signedData *msg);
>> +
>> +/*
>> + * Read a value from an ASN1 node, allocating memory to store it.
>> + * It will work for anything where the size libtasn1 returns is 
>> right:
>> + *  - Integers
>> + *  - Octet strings
>> + *  - DER encoding of other structures
>> + * It will _not_ work for things where libtasn1 size requires 
>> adjustment:
>> + *  - Strings that require an extra NULL byte at the end
>> + *  - Bit strings because libtasn1 returns the length in bits, not 
>> bytes.
>> + *
>> + * If the function returns a non-NULL value, the caller must free it.
>> + */
>> +void *
>> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const
>> char *friendly_name, int *content_size);
>> diff --git a/grub-core/commands/appendedsig/asn1util.c
>> b/grub-core/commands/appendedsig/asn1util.c
>> new file mode 100644
>> index 000000000..609d0ecf2
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/asn1util.c
>> @@ -0,0 +1,99 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
>> +#include <grub/types.h>
>> +#include <grub/err.h>
>> +#include <grub/mm.h>
>> +#include <grub/crypto.h>
>> +#include <grub/misc.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +
>> +#include "appendedsig.h"
>> +
>> +asn1_node _gnutls_gnutls_asn = NULL;
>> +asn1_node _gnutls_pkix_asn = NULL;
>> +
>> +extern const asn1_static_node gnutls_asn1_tab[];
>> +extern const asn1_static_node pkix_asn1_tab[];
>> +
>> +/*
>> + * Read a value from an ASN1 node, allocating memory to store it.
>> + * It will work for anything where the size libtasn1 returns is 
>> right:
>> + *  - Integers
>> + *  - Octet strings
>> + *  - DER encoding of other structures
>> + * It will _not_ work for things where libtasn1 size requires 
>> adjustment:
>> + *  - Strings that require an extra NULL byte at the end
>> + *  - Bit strings because libtasn1 returns the length in bits, not 
>> bytes.
>> + * If the function returns a non-NULL value, the caller must free it.
>> + */
>> +void *
>> +grub_asn1_allocate_and_read (asn1_node node, const char *name, const
>> char *friendly_name, int *content_size)
>> +{
>> +  int result;
>> +  grub_uint8_t *tmpstr = NULL;
>> +  int tmpstr_size = 0;
>> +
>> +  result = asn1_read_value (node, name, NULL, &tmpstr_size);
>> +  if (result != ASN1_MEM_ERROR)
>> +    {
>> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
>> +                     _("Reading size of %s did not return expected
>> status: %s"),
>> +                     friendly_name, asn1_strerror (result));
>> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
>> +      return NULL;
>> +    }
>> +
>> +  tmpstr = grub_malloc (tmpstr_size);
>> +  if (tmpstr == NULL)
>> +    {
>> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
>> +                     "Could not allocate memory to store %s", 
>> friendly_name);
>> +      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
>> +      return NULL;
>> +    }
>> +
>> +  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      grub_free (tmpstr);
>> +      grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error 
>> reading %s: %s",
>> +                     friendly_name, asn1_strerror (result));
>> +      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
>> +      return NULL;
>> +    }
>> +
>> +  *content_size = tmpstr_size;
>> +
>> +  return tmpstr;
>> +}
>> +
>> +int
>> +asn1_init (void)
>> +{
>> +  int res;
>> +  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      return res;
>> +    }
>> +  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
>> +  return res;
>> +}
>> diff --git a/grub-core/commands/appendedsig/pkcs7.c
>> b/grub-core/commands/appendedsig/pkcs7.c
>> new file mode 100644
>> index 000000000..61e560854
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/pkcs7.c
>> @@ -0,0 +1,473 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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 "appendedsig.h"
>> +#include <grub/misc.h>
>> +#include <grub/crypto.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +#include <sys/types.h>
>> +
>> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
>> +
>> +/*
>> + * RFC 5652 s 5.1
>> + */
>> +static const char *signedData_oid = "1.2.840.113549.1.7.2";
>> +
>> +/*
>> + * RFC 4055 s 2.1
>> + */
>> +static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
>> +static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
>> +
>> +static grub_err_t
>> +process_content (grub_uint8_t *content, int size, struct 
>> pkcs7_signedData *msg)
>> +{
>> +  int res;
>> +  asn1_node signed_part;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char algo_oid[MAX_OID_LEN];
>> +  int algo_oid_size = sizeof (algo_oid);
>> +  int algo_count;
>> +  int signer_count;
>> +  int i;
>> +  char version;
>> +  int version_size = sizeof (version);
>> +  grub_uint8_t *result_buf;
>> +  int result_size = 0;
>> +  int crls_size = 0;
>> +  gcry_error_t gcry_err;
>> +  bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
>> +  char *da_path;
>> +  char *si_sig_path;
>> +  char *si_da_path;
>> +
>> +  res = asn1_create_element (_gnutls_pkix_asn,
>> "PKIX1.pkcs-7-SignedData", &signed_part);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for PKCS#7 
>> signed "
>> +                         "part.");
>> +    }
>> +
>> +  res = asn1_der_decoding2 (&signed_part, content, &size,
>> +                            ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Error reading PKCS#7 signed data: %s", 
>> asn1_error);
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  /*
>> +   * SignedData ::= SEQUENCE {
>> +   *     version CMSVersion,
>> +   *     digestAlgorithms DigestAlgorithmIdentifiers,
>> +   *     encapContentInfo EncapsulatedContentInfo,
>> +   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
>> +   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
>> +   *     signerInfos SignerInfos }
>> +   */
>> +
>> +  /* version per the algo in 5.1, must be 1 */
>> +  res = asn1_read_value (signed_part, "version", &version, 
>> &version_size);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading
>> signedData version: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (version != 1)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Unexpected signature version v%d, only v1
>> supported", version);
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  /*
>> +   * digestAlgorithms DigestAlgorithmIdentifiers
>> +   *
>> +   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
>> +   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier 
>> (10.1.1)
>> +   *
>> +   * RFC 4055 s 2.1:
>> +   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
>> +   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
>> +   *
>> +   * We only support 1 element in the set, and we do not check 
>> parameters atm.
>> +   */
>> +  res = asn1_number_of_elements (signed_part, "digestAlgorithms", 
>> &algo_count);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting
>> number of digest algorithms: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (algo_count <= 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "A minimum of 1 digest algorithm is 
>> required");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (algo_count > 2)
>> +    {
>> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                        "A maximum of 2 digest algorithms are 
>> supported");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  sha256_in_da = false;
>> +  sha512_in_da = false;
>> +
>> +  for (i = 0; i < algo_count; i++)
>> +    {
>> +      da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 
>> 1);
>> +      if (!da_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                            "Could not allocate path for digest 
>> algorithm "
>> +                            "parsing path");
>> +          goto cleanup_signed_part;
>> +        }
>> +
>> +      algo_oid_size = sizeof (algo_oid);
>> +      res = asn1_read_value (signed_part, da_path, algo_oid, 
>> &algo_oid_size);
>> +      if (res != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading
>> digest algorithm: %s",
>> +                            asn1_strerror (res));
>> +          grub_free (da_path);
>> +          goto cleanup_signed_part;
>> +        }
>> +
>> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
>> +        {
>> +          if (!sha512_in_da)
>> +            {
>> +              sha512_in_da = true;
>> +            }
>> +          else
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                                "SHA-512 specified twice in digest 
>> algorithm "
>> +                                "list");
>> +              grub_free (da_path);
>> +              goto cleanup_signed_part;
>> +            }
>> +        }
>> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 
>> 0)
>> +        {
>> +          if (!sha256_in_da)
>> +            {
>> +              sha256_in_da = true;
>> +            }
>> +          else
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                                "SHA-256 specified twice in digest 
>> algorithm "
>> +                                "list");
>> +              grub_free (da_path);
>> +              goto cleanup_signed_part;
>> +            }
>> +        }
>> +      else
>> +        {
>> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only
>> SHA-256 and SHA-512 hashes are supported, found OID %s",
>> +                            algo_oid);
>> +          grub_free (da_path);
>> +          goto cleanup_signed_part;
>> +        }
>> +
>> +      grub_free (da_path);
>> +    }
>> +
>> +  /* at this point, at least one of sha{256,512}_in_da must be true 
>> */
>> +
>> +  /*
>> +   * We ignore the certificates, but we don't permit CRLs.
>> +   * A CRL entry might be revoking the certificate we're using, and 
>> we have
>> +   * no way of dealing with that at the moment.
>> +   */
>> +  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
>> +  if (res != ASN1_ELEMENT_NOT_FOUND)
>> +    {
>> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                        "PKCS#7 messages with embedded CRLs are not
>> supported");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  /* read the signatures */
>> +
>> +  res = asn1_number_of_elements (signed_part, "signerInfos", 
>> &signer_count);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting
>> number of signers: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  if (signer_count <= 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "A minimum of 1 signer is required");
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  msg->signerInfos = grub_calloc (signer_count, sizeof (struct
>> pkcs7_signerInfo));
>> +  if (!msg->signerInfos)
>> +    {
>> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                        "Could not allocate space for %d signers",
>> signer_count);
>> +      goto cleanup_signed_part;
>> +    }
>> +
>> +  msg->signerInfo_count = 0;
>> +  for (i = 0; i < signer_count; i++)
>> +    {
>> +      si_da_path = grub_xasprintf
>> ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
>> +      if (!si_da_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
>> allocate path for signer %d's digest algorithm parsing path",
>> +                            i);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      algo_oid_size = sizeof (algo_oid);
>> +      res = asn1_read_value (signed_part, si_da_path, algo_oid,
>> &algo_oid_size);
>> +      if (res != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                            "Error reading signer %d's digest
>> algorithm: %s", i,
>> +                            asn1_strerror (res));
>> +          grub_free (si_da_path);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      grub_free (si_da_path);
>> +
>> +      if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
>> +        {
>> +          if (!sha512_in_da)
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d
>> claims a SHA-512 signature "
>> +                                "which was not specified in the outer
>> DigestAlgorithms", i);
>> +              goto cleanup_signerInfos;
>> +            }
>> +          else
>> +            {
>> +              sha512_in_si = true;
>> +              msg->signerInfos[i].hash =
>> +                      grub_crypto_lookup_md_by_name ("sha512");
>> +            }
>> +        }
>> +      else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 
>> 0)
>> +        {
>> +          if (!sha256_in_da)
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Signer %d
>> claims a SHA-256 signature "
>> +                                "which was not specified in the outer
>> DigestAlgorithms", i);
>> +              goto cleanup_signerInfos;
>> +            }
>> +          else
>> +            {
>> +              sha256_in_si = true;
>> +              msg->signerInfos[i].hash =
>> +                      grub_crypto_lookup_md_by_name ("sha256");
>> +            }
>> +        }
>> +      else
>> +        {
>> +          err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                            "Only SHA-256 and SHA-512 hashes are
>> supported, found OID %s",
>> +                            algo_oid);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      if (!msg->signerInfos[i].hash)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                            "Hash algorithm for signer %d (OID %s)
>> not loaded", i, algo_oid);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 
>> 1);
>> +      if (!si_sig_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                            "Could not allocate path for signer %d's
>> signature parsing path", i);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      result_buf = grub_asn1_allocate_and_read (signed_part, 
>> si_sig_path,
>> +                                                "signature data",
>> &result_size);
>> +      grub_free (si_sig_path);
>> +
>> +      if (!result_buf)
>> +        {
>> +          err = grub_errno;
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi),
>> GCRYMPI_FMT_USG,
>> +                                result_buf, result_size, NULL);
>> +
>> +      grub_free (result_buf);
>> +
>> +      if (gcry_err != GPG_ERR_NO_ERROR)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                            "Error loading signature %d into MPI
>> structure: %d",
>> +                            i, gcry_err);
>> +          goto cleanup_signerInfos;
>> +        }
>> +
>> +      /*
>> +       * use msg->signerInfo_count to track fully populated 
>> signerInfos so we
>> +       * know how many we need to clean up
>> +       */
>> +      msg->signerInfo_count++;
>> +    }
>> +
>> +  /*
>> +   * Final consistency check of signerInfo.*.digestAlgorithm vs
>> +   * digestAlgorithms.*.algorithm. An algorithm must be present in 
>> both
>> +   * digestAlgorithms and signerInfo or in neither. We have already 
>> checked
>> +   * for an algorithm in signerInfo that is not in digestAlgorithms, 
>> here we
>> +   * check for algorithms in digestAlgorithms but not in signerInfos.
>> +   */
>> +  if (sha512_in_da && !sha512_in_si)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "SHA-512 specified in DigestAlgorithms but 
>> did not "
>> +                        "appear in SignerInfos");
>> +      goto cleanup_signerInfos;
>> +    }
>> +
>> +  if (sha256_in_da && !sha256_in_si)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "SHA-256 specified in DigestAlgorithms but 
>> did not "
>> +                        "appear in SignerInfos");
>> +      goto cleanup_signerInfos;
>> +    }
>> +
>> +  asn1_delete_structure (&signed_part);
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_signerInfos:
>> +  for (i = 0; i < msg->signerInfo_count; i++)
>> +    gcry_mpi_release (msg->signerInfos[i].sig_mpi);
>> +  grub_free (msg->signerInfos);
>> +cleanup_signed_part:
>> +  asn1_delete_structure (&signed_part);
>> +  return err;
>> +}
>> +
>> +grub_err_t
>> +parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size,
>> struct pkcs7_signedData *msg)
>> +{
>> +  int res;
>> +  asn1_node content_info;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char content_oid[MAX_OID_LEN];
>> +  grub_uint8_t *content;
>> +  int content_size;
>> +  int content_oid_size = sizeof (content_oid);
>> +  int size;
>> +
>> +  if (data_size > GRUB_INT_MAX)
>> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 
>> message "
>> +                                              "where data size > 
>> INT_MAX");
>> +  size = (int) data_size;
>> +
>> +  res = asn1_create_element (_gnutls_pkix_asn,
>> "PKIX1.pkcs-7-ContentInfo", &content_info);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for PKCS#7
>> data: %s",
>> +                         asn1_strerror (res));
>> +    }
>> +
>> +  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
>> +                            ASN1_DECODE_FLAG_STRICT_DER |
>> ASN1_DECODE_FLAG_ALLOW_PADDING,
>> +                            asn1_error);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Error decoding PKCS#7 message DER: %s", 
>> asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * ContentInfo ::= SEQUENCE {
>> +   *     contentType ContentType,
>> +   *     content [0] EXPLICIT ANY DEFINED BY contentType }
>> +   *
>> +   * ContentType ::= OBJECT IDENTIFIER
>> +   */
>> +  res = asn1_read_value (content_info, "contentType", content_oid,
>> &content_oid_size);
>> +  if (res != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7
>> content type: %s",
>> +                        asn1_strerror (res));
>> +      goto cleanup;
>> +    }
>> +
>> +  /* OID for SignedData defined in 5.1 */
>> +  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 
>> 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
>> +                        "Unexpected content type in PKCS#7 message:
>> OID %s", content_oid);
>> +      goto cleanup;
>> +    }
>> +
>> +  content = grub_asn1_allocate_and_read (content_info, "content",
>> +                                         "PKCS#7 message content",
>> &content_size);
>> +  if (!content)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  err = process_content (content, content_size, msg);
>> +  grub_free (content);
>> +
>> +cleanup:
>> +  asn1_delete_structure (&content_info);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Release all the storage associated with the PKCS#7 message.
>> + * If the caller dynamically allocated the message, it must free it.
>> + */
>> +void
>> +pkcs7_signedData_release (struct pkcs7_signedData *msg)
>> +{
>> +  grub_ssize_t i;
>> +
>> +  for (i = 0; i < msg->signerInfo_count; i++)
>> +    {
>> +      gcry_mpi_release (msg->signerInfos[i].sig_mpi);
>> +    }
>> +  grub_free (msg->signerInfos);
>> +}
>> diff --git a/grub-core/commands/appendedsig/x509.c
>> b/grub-core/commands/appendedsig/x509.c
>> new file mode 100644
>> index 000000000..eb9a1ca0f
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/x509.c
>> @@ -0,0 +1,981 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2022 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/libtasn1.h>
>> +#include <grub/types.h>
>> +#include <grub/err.h>
>> +#include <grub/mm.h>
>> +#include <grub/crypto.h>
>> +#include <grub/misc.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +
>> +#include "appendedsig.h"
>> +
>> +static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
>> +
>> +/*
>> + * RFC 3279 2.3.1  RSA Keys
>> + */
>> +static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
>> +
>> +/*
>> + * RFC 5280 Appendix A
>> + */
>> +static const char *commonName_oid = "2.5.4.3";
>> +
>> +/*
>> + * RFC 5280 4.2.1.3 Key Usage
>> + */
>> +static const char *keyUsage_oid = "2.5.29.15";
>> +
>> +static const grub_uint8_t digitalSignatureUsage = 0x80;
>> +
>> +/*
>> + * RFC 5280 4.2.1.9 Basic Constraints
>> + */
>> +static const char *basicConstraints_oid = "2.5.29.19";
>> +
>> +/*
>> + * RFC 5280 4.2.1.12 Extended Key Usage
>> + */
>> +static const char *extendedKeyUsage_oid = "2.5.29.37";
>> +static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
>> +
>> +/*
>> + * RFC 3279 2.3.1
>> + *
>> + *  The RSA public key MUST be encoded using the ASN.1 type 
>> RSAPublicKey:
>> + *
>> + *     RSAPublicKey ::= SEQUENCE {
>> + *        modulus            INTEGER,    -- n
>> + *        publicExponent     INTEGER  }  -- e
>> + *
>> + *  where modulus is the modulus n, and publicExponent is the public
>> + *  exponent e.
>> + */
>> +static grub_err_t
>> +grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct
>> x509_certificate *certificate)
>> +{
>> +  int result;
>> +  asn1_node spk = NULL;
>> +  grub_uint8_t *m_data, *e_data;
>> +  int m_size, e_size;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  gcry_error_t gcry_err;
>> +
>> +  result = asn1_create_element (_gnutls_gnutls_asn,
>> "GNUTLS.RSAPublicKey", &spk);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Cannot create storage for public key ASN.1 
>> data");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&spk, der, &dersize,
>> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Cannot decode certificate public key DER:
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA
>> modulus", &m_size);
>> +  if (!m_data)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  e_data = grub_asn1_allocate_and_read (spk, "publicExponent",
>> +                                        "RSA public exponent", 
>> &e_size);
>> +  if (!e_data)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup_m_data;
>> +    }
>> +
>> +  /*
>> +   * convert m, e to mpi
>> +   *
>> +   * nscanned is not set for FMT_USG, it's only set for FMT_PGP,
>> +   * so we can't verify it
>> +   */
>> +  gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG,
>> m_data, m_size, NULL);
>> +  if (gcry_err != GPG_ERR_NO_ERROR)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error loading RSA modulus into MPI
>> structure: %d", gcry_err);
>> +      goto cleanup_e_data;
>> +    }
>> +
>> +  gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG,
>> e_data, e_size, NULL);
>> +  if (gcry_err != GPG_ERR_NO_ERROR)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error loading RSA exponent into MPI
>> structure: %d", gcry_err);
>> +      goto cleanup_m_mpi;
>> +    }
>> +
>> +  grub_free (e_data);
>> +  grub_free (m_data);
>> +  asn1_delete_structure (&spk);
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_m_mpi:
>> +  gcry_mpi_release (certificate->mpis[0]);
>> +cleanup_e_data:
>> +  grub_free (e_data);
>> +cleanup_m_data:
>> +  grub_free (m_data);
>> +cleanup:
>> +  asn1_delete_structure (&spk);
>> +  return err;
>> +}
>> +
>> +/*
>> + * RFC 5280:
>> + *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
>> + *       algorithm            AlgorithmIdentifier,
>> + *       subjectPublicKey     BIT STRING  }
>> + *
>> + * AlgorithmIdentifiers come from RFC 3279, we are not strictly 
>> compilant as we
>> + * only support RSA Encryption.
>> + */
>> +
>> +static grub_err_t
>> +grub_x509_read_subject_public_key (asn1_node asn, struct
>> x509_certificate *results)
>> +{
>> +  int result;
>> +  grub_err_t err;
>> +  const char *algo_name =
>> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
>> +  const char *params_name =
>> +          "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
>> +  const char *pk_name = 
>> "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
>> +  char algo_oid[MAX_OID_LEN];
>> +  int algo_size = sizeof (algo_oid);
>> +  char params_value[2];
>> +  int params_size = sizeof (params_value);
>> +  grub_uint8_t *key_data = NULL;
>> +  int key_size = 0;
>> +  unsigned int key_type;
>> +
>> +  /* algorithm: see notes for rsaEncryption_oid */
>> +  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509
>> public key algorithm: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof
>> (rsaEncryption_oid)) != 0)
>> +    {
>> +      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
>> +                         "Unsupported x509 public key algorithm: %s",
>> algo_oid);
>> +    }
>> +
>> +  /*
>> +   * RFC 3279 2.3.1
>> +   * The rsaEncryption OID is intended to be used in the algorithm 
>> field
>> +   * of a value of type AlgorithmIdentifier.  The parameters field 
>> MUST
>> +   * have ASN.1 type NULL for this algorithm identifier.
>> +   */
>> +  result = asn1_read_value (asn, params_name, params_value, 
>> &params_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509
>> public key parameters: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  if (params_value[0] != ASN1_TAG_NULL)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                         "Invalid x509 public key parameters: 
>> expected NULL");
>> +    }
>> +
>> +  /*
>> +   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of 
>> the BIT
>> +   * STRING subjectPublicKey.
>> +   */
>> +  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, 
>> &key_type);
>> +  if (result != ASN1_MEM_ERROR)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size
>> of x509 public key: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +  if (key_type != ASN1_ETYPE_BIT_STRING)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1
>> type when reading x509 public key: %x",
>> +                         key_type);
>> +    }
>> +
>> +  /* length is in bits */
>> +  key_size = (key_size + 7) / 8;
>> +
>> +  key_data = grub_malloc (key_size);
>> +  if (!key_data)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Out of memory for x509 public key");
>> +    }
>> +
>> +  result = asn1_read_value (asn, pk_name, key_data, &key_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      grub_free (key_data);
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                         "Error reading public key data");
>> +    }
>> +  key_size = (key_size + 7) / 8;
>> +
>> +  err = grub_parse_rsa_pubkey (key_data, key_size, results);
>> +  grub_free (key_data);
>> +
>> +  return err;
>> +}
>> +
>> +/* Decode a string as defined in Appendix A */
>> +static grub_err_t
>> +decode_string (char *der, int der_size, char **string, grub_size_t
>> *string_size)
>> +{
>> +  asn1_node strasn;
>> +  int result;
>> +  char *choice;
>> +  int choice_size = 0;
>> +  int tmp_size = 0;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn,
>> "PKIX1.DirectoryString", &strasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for
>> certificate: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&strasn, der, &der_size,
>> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Could not parse DER for DirectoryString:
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString
>> choice", &choice_size);
>> +  if (!choice)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  if (grub_strncmp ("utf8String", choice, choice_size) == 0)
>> +    {
>> +      result = asn1_read_value (strasn, "utf8String", NULL, 
>> &tmp_size);
>> +      if (result != ASN1_MEM_ERROR)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
>> size of UTF-8 string: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_choice;
>> +        }
>> +    }
>> +  else if (grub_strncmp ("printableString", choice, choice_size) == 
>> 0)
>> +    {
>> +      result = asn1_read_value (strasn, "printableString", NULL, 
>> &tmp_size);
>> +      if (result != ASN1_MEM_ERROR)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
>> size of UTF-8 string: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_choice;
>> +        }
>> +    }
>> +  else
>> +    {
>> +      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and
>> printable DirectoryStrings are supported, got %s",
>> +                        choice);
>> +      goto cleanup_choice;
>> +    }
>> +
>> +  /* read size does not include trailing null */
>> +  tmp_size++;
>> +
>> +  *string = grub_malloc (tmp_size);
>> +  if (!*string)
>> +    {
>> +      err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                        "Cannot allocate memory for DirectoryString 
>> contents");
>> +      goto cleanup_choice;
>> +    }
>> +
>> +  result = asn1_read_value (strasn, choice, *string, &tmp_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s
>> in DirectoryString: %s",
>> +                        choice, asn1_strerror (result));
>> +      grub_free (*string);
>> +      goto cleanup_choice;
>> +    }
>> +  *string_size = tmp_size + 1;
>> +  (*string)[tmp_size] = '\0';
>> +
>> +cleanup_choice:
>> +  grub_free (choice);
>> +cleanup:
>> +  asn1_delete_structure (&strasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * TBSCertificate  ::=  SEQUENCE  {
>> + *       version         [0]  EXPLICIT Version DEFAULT v1,
>> + * ...
>> + *
>> + * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
>> + */
>> +static grub_err_t
>> +check_version (asn1_node certificate)
>> +{
>> +  int rc;
>> +  const char *name = "tbsCertificate.version";
>> +  grub_uint8_t version;
>> +  int len = sizeof (version);
>> +
>> +  rc = asn1_read_value (certificate, name, &version, &len);
>> +
>> +  /* require version 3 */
>> +  if (rc != ASN1_SUCCESS || len != 1)
>> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                       "Error reading certificate version");
>> +
>> +  if (version != 0x02)
>> +    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509
>> certificate version, expected v3 (0x02), got 0x%02x",
>> +                       version);
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +/*
>> + * This is an X.501 Name, which is complex.
>> + *
>> + * For simplicity, we extract only the CN.
>> + */
>> +static grub_err_t
>> +read_name (asn1_node asn, const char *name_path, char **name,
>> grub_size_t *name_size)
>> +{
>> +  int seq_components, set_components;
>> +  int result;
>> +  int i, j;
>> +  char *top_path, *set_path, *type_path, *val_path;
>> +  char type[MAX_OID_LEN];
>> +  int type_len = sizeof (type);
>> +  int string_size = 0;
>> +  char *string_der;
>> +  grub_err_t err;
>> +
>> +  *name = NULL;
>> +
>> +  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
>> +  if (!top_path)
>> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                       "Could not allocate memory for %s name parsing
>> path", name_path);
>> +
>> +  result = asn1_number_of_elements (asn, top_path, &seq_components);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name
>> components: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  for (i = 1; i <= seq_components; i++)
>> +    {
>> +      set_path = grub_xasprintf ("%s.?%d", top_path, i);
>> +      if (!set_path)
>> +        {
>> +          err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
>> allocate memory for %s name set parsing path",
>> +                            name_path);
>> +          goto cleanup_set;
>> +        }
>> +      /* this brings us, hopefully, to a set */
>> +      result = asn1_number_of_elements (asn, set_path, 
>> &set_components);
>> +      if (result != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting
>> name sub-components components (element %d): %s",
>> +                            i, asn1_strerror (result));
>> +          goto cleanup_set;
>> +        }
>> +      for (j = 1; j <= set_components; j++)
>> +        {
>> +          type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, 
>> j);
>> +          if (!type_path)
>> +            {
>> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
>> allocate memory for %s name component type path",
>> +                                name_path);
>> +              goto cleanup_set;
>> +            }
>> +          type_len = sizeof (type);
>> +          result = asn1_read_value (asn, type_path, type, &type_len);
>> +          if (result != ASN1_SUCCESS)
>> +            {
>> +              err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error
>> reading %s name component type: %s",
>> +                                name_path, asn1_strerror (result));
>> +              goto cleanup_type;
>> +            }
>> +
>> +          if (grub_strncmp (type, commonName_oid, type_len) != 0)
>> +            {
>> +              grub_free (type_path);
>> +              continue;
>> +            }
>> +
>> +          val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, 
>> j);
>> +          if (!val_path)
>> +            {
>> +              err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not
>> allocate memory for %s name component value path",
>> +                                name_path);
>> +              goto cleanup_set;
>> +            }
>> +
>> +          string_der = grub_asn1_allocate_and_read (asn, val_path,
>> name_path, &string_size);
>> +          if (!string_der)
>> +            {
>> +              err = grub_errno;
>> +              goto cleanup_val_path;
>> +            }
>> +
>> +          err = decode_string (string_der, string_size, name, 
>> name_size);
>> +          if (err)
>> +            goto cleanup_string;
>> +
>> +          grub_free (string_der);
>> +          grub_free (type_path);
>> +          grub_free (val_path);
>> +          break;
>> +        }
>> +      grub_free (set_path);
>> +
>> +      if (*name)
>> +        break;
>> +    }
>> +
>> +  grub_free (top_path);
>> +
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_string:
>> +  grub_free (string_der);
>> +cleanup_val_path:
>> +  grub_free (val_path);
>> +cleanup_type:
>> +  grub_free (type_path);
>> +cleanup_set:
>> +  grub_free (set_path);
>> +cleanup:
>> +  grub_free (top_path);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Verify the Key Usage extension.
>> + * We require the Digital signature usage.
>> + */
>> +static grub_err_t
>> +verify_key_usage (grub_uint8_t *value, int value_size)
>> +{
>> +  asn1_node usageasn;
>> +  int result;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  grub_uint8_t usage = 0xff;
>> +  int usage_size = sizeof (usage_size);
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", 
>> &usageasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for key 
>> usage");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&usageasn, value, &value_size,
>> +                               ASN1_DECODE_FLAG_STRICT_DER, 
>> asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error parsing DER for Key Usage: %s", 
>> asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  result = asn1_read_value (usageasn, "", &usage, &usage_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key
>> Usage value: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  if (!(usage & digitalSignatureUsage))
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Key Usage (0x%x) missing Digital Signature
>> usage", usage);
>> +      goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +  asn1_delete_structure (&usageasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * BasicConstraints ::= SEQUENCE {
>> + *       cA                      BOOLEAN DEFAULT FALSE,
>> + *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
>> + */
>> +static grub_err_t
>> +verify_basic_constraints (grub_uint8_t *value, int value_size)
>> +{
>> +  asn1_node basicasn;
>> +  int result;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char cA[6]; /* FALSE or TRUE */
>> +  int cA_size = sizeof (cA);
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn,
>> "PKIX1.BasicConstraints", &basicasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for Basic 
>> "
>> +                         "Constraints");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&basicasn, value, &value_size,
>> +                               ASN1_DECODE_FLAG_STRICT_DER, 
>> asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error parsing DER for Basic Constraints:
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
>> +  if (result == ASN1_ELEMENT_NOT_FOUND)
>> +    {
>> +      /* Not present, default is False, so this is OK */
>> +      err = GRUB_ERR_NONE;
>> +      goto cleanup;
>> +    }
>> +  else if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic
>> Constraints cA value: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  /* The certificate must not be a CA certificate */
>> +  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: 
>> %s", cA);
>> +      goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +  asn1_delete_structure (&basicasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
>> + *
>> + * KeyPurposeId ::= OBJECT IDENTIFIER
>> + */
>> +static grub_err_t
>> +verify_extended_key_usage (grub_uint8_t *value, int value_size)
>> +{
>> +  asn1_node extendedasn;
>> +  int result, count;
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  char usage[MAX_OID_LEN];
>> +  int usage_size = sizeof (usage);
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn,
>> "PKIX1.ExtKeyUsageSyntax", &extendedasn);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for 
>> Extended Key "
>> +                         "Usage");
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
>> +                               ASN1_DECODE_FLAG_STRICT_DER, 
>> asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Error parsing DER for Extended Key Usage:
>> %s", asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * If EKUs are present, there must be exactly 1 usage and it must 
>> be a
>> +   * codeSigning usage. (If we get to this point, we are parsing an 
>> EKU
>> +   * extension and therefore must have a usage. The code that makes 
>> having an
>> +   * EKU extension optional is in verify_extensions.)
>> +   */
>> +  result = asn1_number_of_elements (extendedasn, "", &count);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting
>> number of Extended Key Usages: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  if (count != 1)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of
>> Extended Key Usages: %d, 1 expected",
>> +                        count);
>> +      goto cleanup;
>> +    }
>> +
>> +  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
>> Extended Key Usage: %s",
>> +                        asn1_strerror (result));
>> +      goto cleanup;
>> +    }
>> +
>> +  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Unexpected Extended Key Usage OID, got: %s", 
>> usage);
>> +      goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +  asn1_delete_structure (&extendedasn);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
>> + *
>> + * Extension  ::=  SEQUENCE  {
>> + *      extnID      OBJECT IDENTIFIER,
>> + *      critical    BOOLEAN DEFAULT FALSE,
>> + *      extnValue   OCTET STRING
>> + *                  -- contains the DER encoding of an ASN.1 value
>> + *                  -- corresponding to the extension type identified
>> + *                  -- by extnID
>> + * }
>> + *
>> + * A certificate must:
>> + *  - contain the Digital Signature usage only
>> + *  - not be a CA
>> + *  - contain no extended usages, or only a code signing extended 
>> usage
>> + *  - not contain any other critical extensions (RFC 5280 s 4.2)
>> + */
>> +static grub_err_t
>> +verify_extensions (asn1_node cert)
>> +{
>> +  int result;
>> +  int ext, num_extensions = 0;
>> +  int usage_present = 0, constraints_present = 0, 
>> extended_usage_present = 0;
>> +  char *oid_path, *critical_path, *value_path;
>> +  char extnID[MAX_OID_LEN];
>> +  int extnID_size;
>> +  grub_err_t err;
>> +  char critical[6]; /* we get either "TRUE" or "FALSE" */
>> +  int critical_size;
>> +  grub_uint8_t *value;
>> +  int value_size;
>> +
>> +  result = asn1_number_of_elements (cert,
>> "tbsCertificate.extensions", &num_extensions);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting
>> number of extensions: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  if (num_extensions < 2)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Insufficient number
>> of extensions for "
>> +                         "certificate, need at least 2, got %d",
>> +                         num_extensions);
>> +    }
>> +
>> +  for (ext = 1; ext <= num_extensions; ext++)
>> +    {
>> +      oid_path = grub_xasprintf 
>> ("tbsCertificate.extensions.?%d.extnID", ext);
>> +
>> +      extnID_size = sizeof (extnID);
>> +      result = asn1_read_value (cert, oid_path, extnID, 
>> &extnID_size);
>> +      if (result != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
>> extension OID: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_oid_path;
>> +        }
>> +
>> +      critical_path = grub_xasprintf
>> ("tbsCertificate.extensions.?%d.critical", ext);
>> +      critical_size = sizeof (critical);
>> +      result = asn1_read_value (cert, critical_path, critical, 
>> &critical_size);
>> +      if (result == ASN1_ELEMENT_NOT_FOUND)
>> +        {
>> +          critical[0] = '\0';
>> +        }
>> +      else if (result != ASN1_SUCCESS)
>> +        {
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading
>> extension criticality: %s",
>> +                            asn1_strerror (result));
>> +          goto cleanup_critical_path;
>> +        }
>> +
>> +      value_path = grub_xasprintf
>> ("tbsCertificate.extensions.?%d.extnValue", ext);
>> +      value = grub_asn1_allocate_and_read (cert, value_path,
>> +                                           "certificate extension
>> value", &value_size);
>> +      if (!value)
>> +        {
>> +          err = grub_errno;
>> +          goto cleanup_value_path;
>> +        }
>> +
>> +      /*
>> +       * Now we must see if we recognise the OID.
>> +       * If we have an unrecognised critical extension we MUST bail.
>> +       */
>> +      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
>> +        {
>> +          err = verify_key_usage (value, value_size);
>> +          if (err != GRUB_ERR_NONE)
>> +            {
>> +              goto cleanup_value;
>> +            }
>> +          usage_present++;
>> +        }
>> +      else if (grub_strncmp (basicConstraints_oid, extnID, 
>> extnID_size) == 0)
>> +        {
>> +          err = verify_basic_constraints (value, value_size);
>> +          if (err != GRUB_ERR_NONE)
>> +            {
>> +              goto cleanup_value;
>> +            }
>> +          constraints_present++;
>> +        }
>> +      else if (grub_strncmp (extendedKeyUsage_oid, extnID, 
>> extnID_size) == 0)
>> +        {
>> +          err = verify_extended_key_usage (value, value_size);
>> +          if (err != GRUB_ERR_NONE)
>> +            {
>> +              goto cleanup_value;
>> +            }
>> +          extended_usage_present++;
>> +        }
>> +      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
>> +        {
>> +          /*
>> +           * per the RFC, we must not process a certificate with
>> +           * a critical extension we do not understand.
>> +           */
>> +          err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                            "Unhandled critical x509 extension with
>> OID %s", extnID);
>> +          goto cleanup_value;
>> +        }
>> +
>> +      grub_free (value);
>> +      grub_free (value_path);
>> +      grub_free (critical_path);
>> +      grub_free (oid_path);
>> +    }
>> +
>> +  if (usage_present != 1)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number
>> of Key Usage extensions "
>> +                         "- expected 1, got %d", usage_present);
>> +    }
>> +  if (constraints_present != 1)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number
>> of basic constraints extensions "
>> +                         "- expected 1, got %d", 
>> constraints_present);
>> +    }
>> +  if (extended_usage_present > 1)
>> +    {
>> +      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number
>> of Extended Key Usage extensions "
>> +                         "- expected 0 or 1, got %d", 
>> extended_usage_present);
>> +    }
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_value:
>> +  grub_free (value);
>> +cleanup_value_path:
>> +  grub_free (value_path);
>> +cleanup_critical_path:
>> +  grub_free (critical_path);
>> +cleanup_oid_path:
>> +  grub_free (oid_path);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Parse a certificate whose DER-encoded form is in @data, of size 
>> @data_size.
>> + * Return the results in @results, which must point to an allocated
>> x509 certificate.
>> + */
>> +grub_err_t
>> +parse_x509_certificate (const void *data, grub_size_t data_size,
>> struct x509_certificate *results)
>> +{
>> +  int result = 0;
>> +  asn1_node cert;
>> +  grub_err_t err;
>> +  int size;
>> +  int tmp_size;
>> +
>> +  if (data_size > GRUB_INT_MAX)
>> +    return grub_error (GRUB_ERR_OUT_OF_RANGE,
>> +                       "Cannot parse a certificate where data size > 
>> INT_MAX");
>> +  size = (int) data_size;
>> +
>> +  result = asn1_create_element (_gnutls_pkix_asn, 
>> "PKIX1.Certificate", &cert);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
>> +                         "Could not create ASN.1 structure for
>> certificate: %s",
>> +                         asn1_strerror (result));
>> +    }
>> +
>> +  result = asn1_der_decoding2 (&cert, data, &size,
>> ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
>> +  if (result != ASN1_SUCCESS)
>> +    {
>> +      err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
>> +                        "Could not parse DER for certificate: %s", 
>> asn1_error);
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * TBSCertificate  ::=  SEQUENCE {
>> +   *     version         [0]  EXPLICIT Version DEFAULT v1
>> +   */
>> +  err = check_version (cert);
>> +  if (err != GRUB_ERR_NONE)
>> +    {
>> +      goto cleanup;
>> +    }
>> +
>> +  /*
>> +   * serialNumber         CertificateSerialNumber,
>> +   *
>> +   * CertificateSerialNumber  ::=  INTEGER
>> +   */
>> +  results->serial = grub_asn1_allocate_and_read (cert,
>> "tbsCertificate.serialNumber",
>> +                                                 "certificate serial
>> number", &tmp_size);
>> +  if (!results->serial)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +  /*
>> +   * It's safe to cast the signed int to an unsigned here, we know
>> +   * length is non-negative
>> +   */
>> +  results->serial_len = tmp_size;
>> +
>> +  /*
>> +   * signature            AlgorithmIdentifier,
>> +   *
>> +   * We don't load the signature or issuer at the moment,
>> +   * as we don't attempt x509 verification.
>> +   */
>> +
>> +  /*
>> +   * issuer               Name,
>> +   *
>> +   * The RFC only requires the serial number to be unique within
>> +   * issuers, so to avoid ambiguity we _technically_ ought to make
>> +   * this available.
>> +   */
>> +
>> +  /*
>> +   * validity             Validity,
>> +   *
>> +   * Validity ::= SEQUENCE {
>> +   *     notBefore      Time,
>> +   *     notAfter       Time }
>> +   *
>> +   * We can't validate this reasonably, we have no true time source 
>> on several
>> +   * platforms. For now we do not parse them.
>> +   */
>> +
>> +  /*
>> +   * subject              Name,
>> +   *
>> +   * This is an X501 name, we parse out just the CN.
>> +   */
>> +  err = read_name (cert, "tbsCertificate.subject", &results->subject,
>> &results->subject_len);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup_serial;
>> +
>> +  /*
>> +   * TBSCertificate  ::=  SEQUENCE  {
>> +   *    ...
>> +   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
>> +   *    ...
>> +   */
>> +  err = grub_x509_read_subject_public_key (cert, results);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup_name;
>> +
>> +  /*
>> +   * TBSCertificate  ::=  SEQUENCE  {
>> +   *    ...
>> +   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
>> +   *                         -- If present, version MUST be v3
>> +   * }
>> +   */
>> +
>> +  err = verify_extensions (cert);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup_mpis;
>> +
>> +  /*
>> +   * We do not read or check the signature on the certificate:
>> +   * as discussed we do not try to validate the certificate but trust
>> +   * it implictly.
>> +   */
>> +
>> +  asn1_delete_structure (&cert);
>> +  return GRUB_ERR_NONE;
>> +
>> +cleanup_mpis:
>> +  gcry_mpi_release (results->mpis[0]);
>> +  gcry_mpi_release (results->mpis[1]);
>> +cleanup_name:
>> +  grub_free (results->subject);
>> +cleanup_serial:
>> +  grub_free (results->serial);
>> +cleanup:
>> +  asn1_delete_structure (&cert);
>> +  return err;
>> +}
>> +
>> +/*
>> + * Release all the storage associated with the x509 certificate.
>> + * If the caller dynamically allocated the certificate, it must free 
>> it.
>> + * The caller is also responsible for maintenance of the linked list.
>> + */
>> +void
>> +certificate_release (struct x509_certificate *cert)
>> +{
>> +  grub_free (cert->subject);
>> +  grub_free (cert->serial);
>> +  gcry_mpi_release (cert->mpis[0]);
>> +  gcry_mpi_release (cert->mpis[1]);
>> +}


Addressed your suggestion. thank you  Avnish Chouhan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 10/21] appended signatures: support verifying appended signatures
  2025-02-06  6:10   ` Avnish Chouhan
@ 2025-02-27 15:33     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:33 UTC (permalink / raw)
  To: Avnish Chouhan
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper

On 2025-02-06 11:40, Avnish Chouhan wrote:
> On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> Building on the parsers and the ability to embed x509 certificates, as
>> well as the existing gcrypt functionality, add a module for verifying
>> appended signatures.
>> 
>> This includes a verifier that requires that Linux kernels and grub 
>> modules
>> have appended signatures, and commands to manage the list of trusted
>> certificates for verification.
>> 
>> Verification must be enabled by setting check_appended_signatures. If
>> GRUB is locked down when the module is loaded, verification will be
>> enabled and locked automatically.
>> 
>> As with the PGP verifier, it is not a complete secure-boot solution:
>> other mechanisms, such as a password or lockdown, must be used to 
>> ensure
>> that a user cannot drop to the grub shell and disable verification.
>> 
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>  grub-core/Makefile.core.def                   |  14 +
>>  grub-core/commands/appendedsig/appendedsig.c  | 620 
>> ++++++++++++++++++
>>  grub-core/commands/appendedsig/appendedsig.h  |   2 +-
>>  grub-core/commands/appendedsig/asn1util.c     |   2 +-
>>  .../commands/appendedsig/gnutls_asn1_tab.c    |   2 +-
>>  .../commands/appendedsig/pkix_asn1_tab.c      |   2 +-
>>  grub-core/commands/appendedsig/x509.c         |   2 +-
>>  include/grub/file.h                           |   2 +
>>  8 files changed, 641 insertions(+), 5 deletions(-)
>>  create mode 100644 grub-core/commands/appendedsig/appendedsig.c
>> 
>> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
>> index 60db2adc5..d693986c6 100644
>> --- a/grub-core/Makefile.core.def
>> +++ b/grub-core/Makefile.core.def
>> @@ -979,6 +979,20 @@ module = {
>>    cppflags = '-I$(srcdir)/lib/posix_wrap';
>>  };
>> 
>> +module = {
>> +  name = appendedsig;
>> +  common = commands/appendedsig/appendedsig.c;
>> +  common = commands/appendedsig/x509.c;
>> +  common = commands/appendedsig/pkcs7.c;
>> +  common = commands/appendedsig/asn1util.c;
>> +  common = commands/appendedsig/gnutls_asn1_tab.c;
>> +  common = commands/appendedsig/pkix_asn1_tab.c;
>> +
>> +  // posix wrapper required for gcry to get sys/types.h
>> +  cflags = '$(CFLAGS_POSIX)';
>> +  cppflags = '-I$(srcdir)/lib/posix_wrap 
>> -I$(srcdir)/lib/libtasn1-grub';
>> +};
>> +
>>  module = {
>>    name = hdparm;
>>    common = commands/hdparm.c;
>> diff --git a/grub-core/commands/appendedsig/appendedsig.c
>> b/grub-core/commands/appendedsig/appendedsig.c
>> new file mode 100644
>> index 000000000..5c82b96a4
>> --- /dev/null
>> +++ b/grub-core/commands/appendedsig/appendedsig.c
>> @@ -0,0 +1,620 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc.
>> + *  Copyright (C) 2020, 2021, 2022 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/types.h>
>> +#include <grub/misc.h>
>> +#include <grub/mm.h>
>> +#include <grub/err.h>
>> +#include <grub/dl.h>
>> +#include <grub/file.h>
>> +#include <grub/command.h>
>> +#include <grub/crypto.h>
>> +#include <grub/pkcs1_v15.h>
>> +#include <grub/i18n.h>
>> +#include <grub/gcrypt/gcrypt.h>
>> +#include <grub/kernel.h>
>> +#include <grub/extcmd.h>
>> +#include <grub/verify.h>
>> +#include <libtasn1.h>
>> +#include <grub/env.h>
>> +#include <grub/lockdown.h>
>> +
>> +#include "appendedsig.h"
>> +
>> +GRUB_MOD_LICENSE ("GPLv3+");
>> +
>> +const char magic[] = "~Module signature appended~\n";
>> +
>> +/*
>> + * This structure is extracted from scripts/sign-file.c in the linux 
>> kernel
>> + * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
>> + */
>> +struct module_signature
>> +{
>> +  grub_uint8_t algo;       /* Public-key crypto algorithm [0] */
>> +  grub_uint8_t hash;       /* Digest algorithm [0] */
>> +  grub_uint8_t id_type;    /* Key identifier type [PKEY_ID_PKCS7] */
>> +  grub_uint8_t signer_len; /* Length of signer's name [0] */
>> +  grub_uint8_t key_id_len; /* Length of key identifier [0] */
>> +  grub_uint8_t __pad[3];
>> +  grub_uint32_t sig_len;   /* Length of signature data */
>> +} GRUB_PACKED;
>> +
>> +/* This represents an entire, parsed, appended signature */
>> +struct grub_appended_signature
>> +{
>> +  grub_size_t signature_len;            /* Length of PKCS#7 data +
>> metadata + magic */
>> +  struct module_signature sig_metadata; /* Module signature metadata 
>> */
>> +  struct pkcs7_signedData pkcs7;        /* Parsed PKCS#7 data */
>> +};
>> +
>> +/* Trusted certificates for verifying appended signatures */
>> +struct x509_certificate *grub_trusted_key;
>> +
>> +/*
>> + * Force gcry_rsa to be a module dependency.
>> + *
>> + * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't 
>> be built
>> + * in if you add 'appendedsig' to grub-install --modules. You would 
>> need to
>> + * add 'gcry_rsa' too. That's confusing and seems suboptimal, 
>> especially when
>> + * we only support RSA.
>> + *
>> + * Dynamic loading also causes some concerns. We can't load gcry_rsa 
>> from the
>> + * the filesystem after we install the verifier - we won't be able to 
>> verify
>> + * it without having it already present. We also shouldn't load it 
>> before we
>> + * install the verifier, because that would mean it wouldn't be 
>> verified - an
>> + * attacker could insert any code they wanted into the module.
>> + *
>> + * So instead, reference the internal symbol from gcry_rsa. That 
>> creates a
>> + * direct dependency on gcry_rsa, so it will be built in when this 
>> module
>> + * is built in. Being built in (assuming the core image is itself 
>> signed!)
>> + * also resolves our concerns about loading from the filesystem.
>> + */
>> +extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
>> +
>> +static enum
>> +{
>> +  check_sigs_no = 0,
>> +  check_sigs_enforce = 1,
>> +  check_sigs_forced = 2
>> +} check_sigs = check_sigs_no;
>> +
>> +static const char *
>> +grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
>> +                   const char *val __attribute__ ((unused)))
>> +{
>> +  if (check_sigs == check_sigs_forced)
>> +    return "forced";
>> +  else if (check_sigs == check_sigs_enforce)
>> +    return "enforce";
>> +  else
>> +    return "no";
>> +}
>> +
>> +static char *
>> +grub_env_write_sec (struct grub_env_var *var __attribute__
>> ((unused)), const char *val)
>> +{
>> +  /* Do not allow the value to be changed if set to forced */
>> +  if (check_sigs == check_sigs_forced)
>> +    return grub_strdup ("forced");
>> +
>> +  if ((*val == '2') || (*val == 'f'))
>> +    check_sigs = check_sigs_forced;
>> +  else if ((*val == '1') || (*val == 'e'))
>> +    check_sigs = check_sigs_enforce;
>> +  else if ((*val == '0') || (*val == 'n'))
>> +    check_sigs = check_sigs_no;
>> +
>> +  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"),
> 
> Hi,
> 
> Indentation seems off here!
> 
>> +                             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)
>> +{
>> +  grub_size_t pkcs7_size;
>> +  grub_size_t remaining_len;
>> +  const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen 
>> (magic);
>> +
>> +  if (bufsize < grub_strlen (magic))
>> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for
>> signature magic"));
>> +
>> +  if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen 
>> (magic)))
>> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Missing or invalid
>> signature magic"));
>> +
>> +  remaining_len = bufsize - grub_strlen (magic);
>> +
>> +  if (remaining_len < sizeof (struct module_signature))
>> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for
>> signature metadata"));
>> +
>> +  appsigdata -= sizeof (struct module_signature);
>> +
>> +  /* extract the metadata */
>> +  grub_memcpy (&(sig->sig_metadata), appsigdata, sizeof (struct
>> module_signature));
>> +
>> +  remaining_len -= sizeof (struct module_signature);
>> +
>> +  if (sig->sig_metadata.id_type != 2)
>> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature 
>> type"));
>> +
>> +  pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len);
>> +
>> +  if (pkcs7_size > remaining_len)
>> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for
>> PKCS#7 message"));
>> +
>> +  grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", 
>> pkcs7_size);
>> +
>> +  sig->signature_len = grub_strlen (magic) + sizeof (struct
>> module_signature) + pkcs7_size;
>> +
>> +  /* rewind pointer and parse pkcs7 data */
>> +  appsigdata -= pkcs7_size;
>> +
>> +  return parse_pkcs7_signedData (appsigdata, pkcs7_size, 
>> &sig->pkcs7);
>> +}
>> +
>> +static grub_err_t
>> +grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t 
>> bufsize)
>> +{
>> +  grub_err_t err = GRUB_ERR_NONE;
>> +  grub_size_t datasize;
>> +  void *context;
>> +  unsigned char *hash;
>> +  gcry_mpi_t hashmpi;
>> +  gcry_err_code_t rc;
>> +  struct x509_certificate *pk;
>> +  struct grub_appended_signature sig;
>> +  struct pkcs7_signerInfo *si;
>> +  int i;
>> +
>> +  if (!grub_trusted_key)
>> +    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to
>> verify against"));
>> +
>> +  err = extract_appended_signature (buf, bufsize, &sig);
>> +  if (err != GRUB_ERR_NONE)
>> +    return err;
>> +
>> +  datasize = bufsize - sig.signature_len;
>> +
>> +  for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
>> +    {
>> +      /*
>> +       * 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 = grub_trusted_key; pk; pk = pk->next)
>> +        {
>> +          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;
>> +            }
>> +
>> +          rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi,
>> &si->sig_mpi, pk->mpis, NULL, NULL);
>> +          gcry_mpi_release (hashmpi);
>> +
>> +          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", "verify signer %d with key
>> '%s' failed with %d\n",
>> +                        i, pk->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);
>> +
>> +  return err;
>> +}
>> +
>> +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;
>> +
>> +  if (argc < 1)
>> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument 
>> expected"));
>> +
>> +  grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
>> +
>> +  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
>> +  if (!f)
>> +    {
>> +      err = grub_errno;
>> +      goto cleanup;
>> +    }
>> +
>> +  err = file_read_all (f, &data, &file_size);
>> +  if (err != GRUB_ERR_NONE)
>> +    goto cleanup;
>> +
>> +  err = grub_verify_appended_signature (data, file_size);
>> +
>> +  grub_free (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)
>> +{
>> +  unsigned long cert_num, i;
>> +  struct x509_certificate *cert, *prev;
>> +
>> +  if (argc != 1)
>> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument 
>> expected"));
>> +
>> +  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"));
>> +
>> +  if (cert_num == 1)
>> +    {
>> +      cert = grub_trusted_key;
>> +      grub_trusted_key = cert->next;
>> +
>> +      certificate_release (cert);
>> +      grub_free (cert);
>> +      return GRUB_ERR_NONE;
>> +    }
>> +  i = 2;
>> +  prev = grub_trusted_key;
>> +  cert = grub_trusted_key->next;
>> +  while (cert)
>> +    {
>> +      if (i == cert_num)
>> +        {
>> +          prev->next = cert->next;
>> +          certificate_release (cert);
>> +          grub_free (cert);
>> +          return GRUB_ERR_NONE;
>> +        }
>> +      i++;
>> +      prev = cert;
>> +      cert = 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);
>> +}
>> +
>> +static grub_err_t
>> +grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int
>> argc, char **args)
>> +{
>> +  grub_file_t certf;
>> +  struct x509_certificate *cert = NULL;
>> +  grub_err_t err;
>> +
>> +  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"));
>> +
>> +  err = read_cert_from_file (certf, cert);
>> +  grub_file_close (certf);
>> +  if (err != GRUB_ERR_NONE)
>> +    {
>> +      grub_free (cert);
>> +      return err;
>> +    }
>> +  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
>> cert->subject);
>> +
>> +  cert->next = grub_trusted_key;
>> +  grub_trusted_key = cert;
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +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;
>> +
>> +  for (cert = grub_trusted_key; cert; cert = cert->next)
>> +    {
>> +      grub_printf (N_("Certificate %d:\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++;
>> +    }
>> +
>> +  return GRUB_ERR_NONE;
>> +}
>> +
>> +static grub_err_t
>> +appendedsig_init (grub_file_t io __attribute__ ((unused)), enum
>> grub_file_type type,
>> +                  void **context __attribute__ ((unused)), enum
>> grub_verify_flags *flags)
>> +{
>> +  if (check_sigs == check_sigs_no)
>> +    {
>> +      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
>> +      return GRUB_ERR_NONE;
>> +    }
>> +
>> +  switch (type & GRUB_FILE_TYPE_MASK)
>> +    {
>> +      case GRUB_FILE_TYPE_CERTIFICATE_TRUST:
>> +        /*
>> +         * This is a certificate to add to trusted keychain.
>> +         *
>> +         * This needs to be verified or blocked. Ideally we'd write 
>> an x509
>> +         * verifier, but we lack the hubris required to take this on. 
>> Instead,
>> +         * require that it have an appended signature.
>> +         */
>> +
>> +        /* Fall through */
>> +
>> +      case GRUB_FILE_TYPE_LINUX_KERNEL:
>> +      case GRUB_FILE_TYPE_GRUB_MODULE:
>> +        /*
>> +         * Appended signatures are only defined for ELF binaries.
>> +         * Out of an abundance of caution, we only verify Linux 
>> kernels and
>> +         * GRUB modules at this point.
>> +         */
>> +        *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
>> +        return GRUB_ERR_NONE;
>> +
>> +      case GRUB_FILE_TYPE_ACPI_TABLE:
>> +      case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
>> +        /*
>> +         * It is possible to use appended signature verification 
>> without
>> +         * lockdown - like the PGP verifier. When combined with an 
>> embedded
>> +         * config file in a signed grub binary, this could still be a
>> meaningful
>> +         * secure-boot chain - so long as it isn't subverted by
>> something like a
>> +         * rouge ACPI table or DT image. Defer them explicitly.
>> +         */
>> +        *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
>> +        return GRUB_ERR_NONE;
>> +
>> +      default:
>> +        *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
>> +        return GRUB_ERR_NONE;
>> +    }
>> +}
>> +
>> +static grub_err_t
>> +appendedsig_write (void *ctxt __attribute__ ((unused)), void *buf,
>> grub_size_t size)
>> +{
>> +  return grub_verify_appended_signature (buf, size);
>> +}
>> +
>> +struct grub_file_verifier grub_appendedsig_verifier = {
>> +  .name = "appendedsig",
>> +  .init = appendedsig_init,
>> +  .write = appendedsig_write,
>> +};
>> +
>> +static grub_ssize_t
>> +pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
>> +{
>> +  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
>> +  return 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;
>> +
>> +GRUB_MOD_INIT (appendedsig)
>> +{
>> +  int rc;
>> +  struct grub_module_header *header;
>> +
>> +  /* If in lockdown, immediately enter forced mode */
>> +  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");
>> +
>> +  rc = asn1_init ();
>> +  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;
>> +
>> +    /* Not an X.509 certificate, skip. */
>> +    if (header->type != OBJ_TYPE_X509_PUBKEY)
>> +      continue;
>> +
>> +    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");
>> +      }
> 
> Suggestion : Good to have without brackets if just one line condition!
> Thank you!
> 
> Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
> 
>> +
>> +    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;
>> +  }
>> +
>> +  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_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."));
>> +
>> +  grub_verifier_register (&grub_appendedsig_verifier);
>> +  grub_dl_set_persistent (mod);
>> +}
>> +
>> +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);
>> +}
>> diff --git a/grub-core/commands/appendedsig/appendedsig.h
>> b/grub-core/commands/appendedsig/appendedsig.h
>> index fa59302c8..60ee0f2fa 100644
>> --- a/grub-core/commands/appendedsig/appendedsig.h
>> +++ b/grub-core/commands/appendedsig/appendedsig.h
>> @@ -18,7 +18,7 @@
>>   */
>> 
>>  #include <grub/crypto.h>
>> -#include <grub/libtasn1.h>
>> +#include <libtasn1.h>
>> 
>>  extern asn1_node _gnutls_gnutls_asn;
>>  extern asn1_node _gnutls_pkix_asn;
>> diff --git a/grub-core/commands/appendedsig/asn1util.c
>> b/grub-core/commands/appendedsig/asn1util.c
>> index 609d0ecf2..a2c46724a 100644
>> --- a/grub-core/commands/appendedsig/asn1util.c
>> +++ b/grub-core/commands/appendedsig/asn1util.c
>> @@ -17,7 +17,7 @@
>>   *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>> 
>> -#include <grub/libtasn1.h>
>> +#include <libtasn1.h>
>>  #include <grub/types.h>
>>  #include <grub/err.h>
>>  #include <grub/mm.h>
>> diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
>> b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
>> index ddd1314e6..8c4eb81d7 100644
>> --- a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
>> +++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
>> @@ -1,5 +1,5 @@
>>  #include <grub/mm.h>
>> -#include <grub/libtasn1.h>
>> +#include <libtasn1.h>
>> 
>>  const asn1_static_node gnutls_asn1_tab[] = {
>>    { "GNUTLS", 536872976, NULL },
>> diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c
>> b/grub-core/commands/appendedsig/pkix_asn1_tab.c
>> index adef69d95..8eeeac047 100644
>> --- a/grub-core/commands/appendedsig/pkix_asn1_tab.c
>> +++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
>> @@ -1,5 +1,5 @@
>>  #include <grub/mm.h>
>> -#include <grub/libtasn1.h>
>> +#include <libtasn1.h>
>> 
>>  const asn1_static_node pkix_asn1_tab[] = {
>>    { "PKIX1", 536875024, NULL },
>> diff --git a/grub-core/commands/appendedsig/x509.c
>> b/grub-core/commands/appendedsig/x509.c
>> index eb9a1ca0f..b113ac38b 100644
>> --- a/grub-core/commands/appendedsig/x509.c
>> +++ b/grub-core/commands/appendedsig/x509.c
>> @@ -17,7 +17,7 @@
>>   *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>> 
>> -#include <grub/libtasn1.h>
>> +#include <libtasn1.h>
>>  #include <grub/types.h>
>>  #include <grub/err.h>
>>  #include <grub/mm.h>
>> diff --git a/include/grub/file.h b/include/grub/file.h
>> index a5bf3a792..d678de063 100644
>> --- a/include/grub/file.h
>> +++ b/include/grub/file.h
>> @@ -80,6 +80,8 @@ enum grub_file_type
>>      GRUB_FILE_TYPE_PUBLIC_KEY,
>>      /* File holding public key to add to trused keys.  */
>>      GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
>> +    /* File holding x509 certificiate to add to trusted keys.  */
>> +    GRUB_FILE_TYPE_CERTIFICATE_TRUST,
>>      /* File of which we intend to print a blocklist to the user.  */
>>      GRUB_FILE_TYPE_PRINT_BLOCKLIST,
>>      /* File we intend to use for test loading or testing speed.  */


Addressed above comments. Thank you Avnish Chouhan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot
  2025-02-06  6:23   ` Avnish Chouhan
@ 2025-02-27 15:34     ` sudhakar
  0 siblings, 0 replies; 83+ messages in thread
From: sudhakar @ 2025-02-27 15:34 UTC (permalink / raw)
  To: Avnish Chouhan
  Cc: grub-devel, dja, jan.setjeeilers, julian.klode, mate.kukri,
	pjones, stefanb, nayna, ssrish, daniel.kiper

On 2025-02-06 11:53, Avnish Chouhan wrote:
> On 2024-12-18 20:26, Sudhakar Kuppusamy wrote:
>> From: Daniel Axtens <dja@axtens.net>
>> 
>> If the 'ibm,secure-boot' property of the root node is 2 or greater,
>> enter lockdown.
>> 
>> Signed-off-by: Daniel Axtens <dja@axtens.net>
>> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
>> ---
>>  docs/grub.texi                 |  4 ++--
>>  grub-core/Makefile.core.def    |  1 +
>>  grub-core/kern/ieee1275/init.c | 28 ++++++++++++++++++++++++++++
>>  include/grub/lockdown.h        |  3 ++-
>>  4 files changed, 33 insertions(+), 3 deletions(-)
>> 
>> diff --git a/docs/grub.texi b/docs/grub.texi
>> index f71ce9ffc..6b634f111 100644
>> --- a/docs/grub.texi
>> +++ b/docs/grub.texi
>> @@ -8959,8 +8959,8 @@ platforms.
>>  @section Lockdown when booting on a secure setup
>> 
>>  The GRUB can be locked down when booted on a secure boot environment,
>> for example
>> -if the UEFI secure boot is enabled. On a locked down configuration,
>> the GRUB will
>> -be restricted and some operations/commands cannot be executed.
>> +if UEFI or Power secure boot is enabled. On a locked down 
>> configuration, the
>> +GRUB will be restricted and some operations/commands cannot be 
>> executed.
>> 
>>  The @samp{lockdown} variable is set to @samp{y} when the GRUB is 
>> locked down.
>>  Otherwise it does not exit.
>> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
>> index 9cf4a6009..1ed55b0e3 100644
>> --- a/grub-core/Makefile.core.def
>> +++ b/grub-core/Makefile.core.def
>> @@ -331,6 +331,7 @@ kernel = {
>>    powerpc_ieee1275 = kern/powerpc/cache.S;
>>    powerpc_ieee1275 = kern/powerpc/dl.c;
>>    powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
>> +  powerpc_ieee1275 = kern/lockdown.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 dfbd0b899..59984b605 100644
>> --- a/grub-core/kern/ieee1275/init.c
>> +++ b/grub-core/kern/ieee1275/init.c
>> @@ -49,6 +49,7 @@
>>  #if defined(__powerpc__) || defined(__i386__)
>>  #include <grub/ieee1275/alloc.h>
>>  #endif
>> +#include <grub/lockdown.h>
>> 
>>  /* The maximum heap size we're going to claim at boot. Not used by 
>> sparc. */
>>  #ifdef __i386__
>> @@ -953,6 +954,31 @@ grub_parse_cmdline (void)
>>      }
>>  }
>> 
>> +static void
>> +grub_get_ieee1275_secure_boot (void)
>> +{
>> +  grub_ieee1275_phandle_t root;
>> +  int rc;
>> +  grub_uint32_t is_sb;
>> +
>> +  grub_ieee1275_finddevice ("/", &root);
> 
> Hi,
> 
> Failure check condition is missing!
> 
> Thank you,
> Avnish Chouhan
> 
>> +
>> +  rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", 
>> &is_sb,
>> +                                           sizeof (is_sb), 0);
>> +
>> +  /*
>> +   * ibm,secure-boot:
>> +   * 0 - disabled
>> +   * 1 - audit
>> +   * 2 - enforce
>> +   * 3 - enforce + OS-specific behaviour
>> +   *
>> +   * We only support enforce.
>> +   */
>> +  if (rc >= 0 && is_sb >= 2)
>> +    grub_lockdown ();
>> +}
>> +
>>  grub_addr_t grub_modbase;
>> 
>>  void
>> @@ -978,6 +1004,8 @@ grub_machine_init (void)
>>  #else
>>    grub_install_get_time_ms (grub_rtc_get_time_ms);
>>  #endif
>> +
>> +  grub_get_ieee1275_secure_boot ();
>>  }
>> 
>>  void
>> diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
>> index 40531fa82..ebfee4bf0 100644
>> --- a/include/grub/lockdown.h
>> +++ b/include/grub/lockdown.h
>> @@ -24,7 +24,8 @@
>>  #define GRUB_LOCKDOWN_DISABLED       0
>>  #define GRUB_LOCKDOWN_ENABLED        1
>> 
>> -#ifdef GRUB_MACHINE_EFI
>> +#if defined(GRUB_MACHINE_EFI) || \
>> +    (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
>>  extern void
>>  EXPORT_FUNC (grub_lockdown) (void);
>>  extern int


Addressed above comments. Thank you Avnish Chouhan.

Thanks,
Sudhakar Kuppusamy

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 83+ messages in thread

end of thread, other threads:[~2025-02-27 15:35 UTC | newest]

Thread overview: 83+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-18 14:56 [PATCH v1 00/21] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
2024-12-18 14:56 ` [PATCH v1 01/21] powerpc-ieee1275: Add support for signing grub with an appended signature Sudhakar Kuppusamy
2024-12-27 14:58   ` Stefan Berger
2025-02-26  4:24     ` sudhakar
2025-01-04 18:30   ` Vladimir 'phcoder' Serbinenko
2025-01-06  6:25   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 02/21] docs/grub: Document signing grub under UEFI Sudhakar Kuppusamy
2024-12-27 15:00   ` Stefan Berger
2024-12-18 14:56 ` [PATCH v1 03/21] docs/grub: Document signing grub with an appended signature Sudhakar Kuppusamy
2024-12-27 15:04   ` Stefan Berger
2025-01-04 18:32   ` Vladimir 'phcoder' Serbinenko
2025-01-24  9:44   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 04/21] dl: provide a fake grub_dl_set_persistent for the emu target Sudhakar Kuppusamy
2024-12-27 15:06   ` Stefan Berger
2025-01-04 18:36   ` Vladimir 'phcoder' Serbinenko
2025-01-24  9:47   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 05/21] pgp: factor out rsa_pad Sudhakar Kuppusamy
2024-12-27 15:11   ` Stefan Berger
2025-01-04 18:40   ` Vladimir 'phcoder' Serbinenko
2025-02-27 15:26     ` sudhakar
2025-01-24 10:40   ` Avnish Chouhan
2025-02-27 15:28     ` sudhakar
2024-12-18 14:56 ` [PATCH v1 06/21] crypto: move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
2024-12-27 15:13   ` Stefan Berger
2025-01-04 18:41   ` Vladimir 'phcoder' Serbinenko
2025-01-24 10:42   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 07/21] grub-install: support embedding x509 certificates Sudhakar Kuppusamy
2024-12-27 16:08   ` Stefan Berger
2025-01-24 10:45   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 08/21] appended signatures: import GNUTLS's ASN.1 description files Sudhakar Kuppusamy
2024-12-28 19:02   ` Stefan Berger
2025-01-24 10:47   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 09/21] appended signatures: parse PKCS#7 signedData and X.509 certificates Sudhakar Kuppusamy
2024-12-28 19:46   ` Stefan Berger
2025-02-26  4:26     ` sudhakar
2025-01-24 11:10   ` Avnish Chouhan
2025-02-27 15:31     ` sudhakar
2025-01-24 11:23   ` Michal Suchánek
2024-12-18 14:56 ` [PATCH v1 10/21] appended signatures: support verifying appended signatures Sudhakar Kuppusamy
2024-12-29 16:37   ` Stefan Berger
2025-02-06  6:10   ` Avnish Chouhan
2025-02-27 15:33     ` sudhakar
2024-12-18 14:56 ` [PATCH v1 11/21] appended signatures: verification tests Sudhakar Kuppusamy
2024-12-30 15:39   ` Stefan Berger
2025-02-14 10:27   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 12/21] appended signatures: documentation Sudhakar Kuppusamy
2024-12-30 15:50   ` Stefan Berger
2025-02-26  4:28     ` sudhakar
2025-02-14 10:39   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 13/21] ieee1275: enter lockdown based on /ibm,secure-boot Sudhakar Kuppusamy
2024-12-30 22:02   ` Stefan Berger
2025-02-06  6:23   ` Avnish Chouhan
2025-02-27 15:34     ` sudhakar
2024-12-18 14:56 ` [PATCH v1 14/21] ieee1275: Platform Keystore (PKS) Support Sudhakar Kuppusamy
2024-12-30 22:14   ` Stefan Berger
2025-02-26  4:33     ` sudhakar
2025-02-06  9:09   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 15/21] ieee1275: Read the DB and DBX secure boot variables Sudhakar Kuppusamy
2024-12-30 23:01   ` Stefan Berger
2025-02-26  4:43     ` sudhakar
2024-12-30 23:04   ` Stefan Berger
2025-02-26  4:44     ` sudhakar
2025-02-07  5:57   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 16/21] appendedsig: The creation of trusted and distrusted lists Sudhakar Kuppusamy
2024-12-31 17:21   ` Stefan Berger
2025-02-27 15:21     ` sudhakar
2025-02-07  6:39   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 17/21] appendedsig: While verifying the kernel, use " Sudhakar Kuppusamy
2024-12-31 17:37   ` Stefan Berger
2025-02-27 15:22     ` sudhakar
2025-02-07  6:44   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 18/21] ieee1275: set use_static_keys flag Sudhakar Kuppusamy
2025-01-02 13:22   ` Stefan Berger
2025-02-27 15:24     ` sudhakar
2025-02-07  6:46   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 19/21] appendedsig: Reads the default DB keys from ELF Note Sudhakar Kuppusamy
2025-01-02 13:19   ` Stefan Berger
2025-02-27 15:23     ` sudhakar
2025-02-07  6:54   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 20/21] appendedsig: The grub command's trusted and distrusted support Sudhakar Kuppusamy
2025-02-07 10:16   ` Avnish Chouhan
2024-12-18 14:56 ` [PATCH v1 21/21] appendedsig: documentation Sudhakar Kuppusamy
2025-02-07 10:00   ` Avnish Chouhan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.