All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Add support for signing grub with an appended signature
@ 2020-08-21  2:37 Daniel Axtens
  2020-08-21  2:37 ` [PATCH 1/3] Add suport " Daniel Axtens
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Daniel Axtens @ 2020-08-21  2:37 UTC (permalink / raw)
  To: grub-devel; +Cc: rashmica.g, alastair, Daniel Axtens

Part of a secure boot chain is allowing boot firmware to verify the
grub core.img. For UEFI platforms, this is done by signing the PE
binary with a tool like pesign or sb-sign. However, for platforms that
don't implement UEFI, an alternative scheme is required.

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

Because some platforms, such as powerpc-ieee1275, 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.

More details are in patch 1, including a link to an open-source firmware
capable of verifying a grub image signed this way.

Daniel Axtens (2):
  docs/grub: Document signing grub under UEFI
  docs/grub: Document signing grub with an appended signature

Rashmica Gupta (1):
  Add suport for signing grub with an appended signature

 docs/grub.texi              | 64 ++++++++++++++++++++++++++++++++++++-
 include/grub/util/install.h |  8 +++--
 include/grub/util/mkimage.h |  4 +--
 util/grub-install-common.c  | 16 ++++++++--
 util/grub-mkimage.c         | 11 +++++++
 util/grub-mkimagexx.c       | 39 +++++++++++++++++++++-
 util/mkimage.c              | 10 +++---
 7 files changed, 138 insertions(+), 14 deletions(-)

-- 
2.25.1



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

* [PATCH 1/3] Add suport for signing grub with an appended signature
  2020-08-21  2:37 [PATCH 0/3] Add support for signing grub with an appended signature Daniel Axtens
@ 2020-08-21  2:37 ` Daniel Axtens
  2020-08-21  2:37 ` [PATCH 2/3] docs/grub: Document signing grub under UEFI Daniel Axtens
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 14+ messages in thread
From: Daniel Axtens @ 2020-08-21  2:37 UTC (permalink / raw)
  To: grub-devel; +Cc: rashmica.g, alastair, Daniel Axtens

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: Daniel Axtens <dja@axtens.net>
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>

---

You can experiment with this code with a patched version of SLOF
that verifies these signatures. You can find one at:
   https://github.com/daxtens/SLOF

I will be proposing the ELF note details for inclusion in a future
Power Architecture Platform Reference (PAPR).

---
 include/grub/util/install.h |  8 ++++++--
 include/grub/util/mkimage.h |  4 ++--
 util/grub-install-common.c  | 16 ++++++++++++---
 util/grub-mkimage.c         | 11 +++++++++++
 util/grub-mkimagexx.c       | 39 ++++++++++++++++++++++++++++++++++++-
 util/mkimage.c              | 10 +++++-----
 6 files changed, 75 insertions(+), 13 deletions(-)

diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 2631b1074513..eb1b83b6d946 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -63,6 +63,9 @@
     /* TRANSLATORS: "embed" is a verb (command description).  "*/	\
   { "pubkey",   'k', N_("FILE"), 0,					\
       N_("embed FILE as public key 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,						\
     N_("print verbose messages."), 1 }
 
@@ -122,7 +125,8 @@ enum grub_install_options {
   GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY,
   GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE,
   GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
-  GRUB_INSTALL_OPTIONS_DTB
+  GRUB_INSTALL_OPTIONS_DTB,
+  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
 };
 
 extern char *grub_install_source_directory;
@@ -182,7 +186,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 struct grub_install_image_target_desc *
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
index ba9f568f6926..2000d6fbdf1e 100644
--- a/include/grub/util/mkimage.h
+++ b/include/grub/util/mkimage.h
@@ -50,12 +50,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 **core_img, size_t *core_size,
+			     int note, 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 **core_img, size_t *core_size,
+			     int note, 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 ca0ac612ac51..e9b75d6f1fcf 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -308,10 +308,12 @@ handle_install_list (struct install_list *il, const char *val,
 static char **pubkeys;
 static size_t npubkeys;
 static grub_compression_t compression;
+static size_t appsig_size;
 
 int
 grub_install_parse (int key, char *arg)
 {
+  const char *end;
   switch (key)
     {
     case 'C':
@@ -400,6 +402,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;
     }
@@ -498,10 +506,12 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
   grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'"
 		  " --output '%s' "
 		  " --dtb '%s' "
-		  "--format '%s' --compression '%s' %s %s\n",
+		  "--format '%s' --compression '%s' "
+		  "--appended-signature-size %zu %s %s\n",
 		  dir, prefix,
 		  outname, dtb ? : "", mkimage_target,
-		  compnames[compression], note ? "--note" : "", s);
+		  compnames[compression], appsig_size,
+		  note ? "--note" : "", s);
   free (s);
 
   tgt = grub_install_get_image_target (mkimage_target);
@@ -511,7 +521,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);
+			       note, appsig_size, compression, dtb);
   while (dc--)
     grub_install_pop_module ();
 }
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index 912564e3622f..c1e07c70dc7e 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -82,6 +82,7 @@ static struct argp_option options[] = {
   {"format",  'O', N_("FORMAT"), 0, 0, 0},
   {"compression",  'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0},
   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
+  {"appended-signature-size", 's', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
   { 0, 0, 0, 0, 0, 0 }
 };
 
@@ -124,6 +125,7 @@ struct arguments
   char *font;
   char *config;
   int note;
+  size_t appsig_size;
   const struct grub_install_image_target_desc *image_target;
   grub_compression_t comp;
 };
@@ -134,6 +136,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)
     {
@@ -166,6 +169,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);
@@ -309,6 +319,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);
 
   if (grub_util_file_sync (fp) < 0)
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index ab6dfab79242..3bfed4369fd3 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -84,6 +84,15 @@ struct grub_ieee1275_note
   struct grub_ieee1275_note_desc descriptor;
 };
 
+#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)];
+};
+
 #define GRUB_XEN_NOTE_NAME "Xen"
 
 struct fixup_block_list
@@ -207,7 +216,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 **core_img, size_t *core_size,
+				    int note, size_t appsig_size, char **core_img, size_t *core_size,
 				    Elf_Addr target_addr,
 				    struct grub_mkimage_layout *layout)
 {
@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
   int shnum = 4;
   int string_size = sizeof (".text") + sizeof ("mods") + 1;
 
+  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;
 
@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
       phdr->p_offset = grub_host_to_target32 (header_size + program_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 *)
+      (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
+
+    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 + (note ? sizeof (struct grub_ieee1275_note) : 0));
+  }
+
   {
     char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
 		       + shnum * sizeof (*shdr));
diff --git a/util/mkimage.c b/util/mkimage.c
index 37d6249f16b3..bd06968deccb 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -822,7 +822,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)
 {
   char *kernel_img, *core_img;
   size_t total_module_size, core_size;
@@ -1742,11 +1742,11 @@ 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, &core_img, &core_size,
-				       target_addr, &layout);
+	  grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
+				       &core_size, target_addr, &layout);
 	else
-	  grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size,
-				       target_addr, &layout);
+	  grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
+				       &core_size, target_addr, &layout);
       }
       break;
     }
-- 
2.25.1



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

* [PATCH 2/3] docs/grub: Document signing grub under UEFI
  2020-08-21  2:37 [PATCH 0/3] Add support for signing grub with an appended signature Daniel Axtens
  2020-08-21  2:37 ` [PATCH 1/3] Add suport " Daniel Axtens
@ 2020-08-21  2:37 ` Daniel Axtens
  2020-08-21  2:37 ` [PATCH 3/3] docs/grub: Document signing grub with an appended signature Daniel Axtens
  2020-09-23 15:11 ` [PATCH 0/3] Add support for " Daniel Axtens
  3 siblings, 0 replies; 14+ messages in thread
From: Daniel Axtens @ 2020-08-21  2:37 UTC (permalink / raw)
  To: grub-devel; +Cc: rashmica.g, alastair, Daniel Axtens

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>
---
 docs/grub.texi | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 1ce9993a53fc..35da48456d9e 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5736,6 +5736,7 @@ environment variables and commands are listed in the same order.
 * Using digital signatures::         Booting digitally signed code
 * UEFI secure boot and shim::        Booting digitally signed PE files
 * Measured Boot::                    Measuring boot components
+* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
 @end menu
 
 @node Authentication and authorisation
@@ -5814,7 +5815,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}
@@ -5950,6 +5951,25 @@ into @file{core.img} in order to avoid a potential gap in measurement between
 
 Measured boot is currently only supported on EFI platforms.
 
+@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.25.1



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

* [PATCH 3/3] docs/grub: Document signing grub with an appended signature
  2020-08-21  2:37 [PATCH 0/3] Add support for signing grub with an appended signature Daniel Axtens
  2020-08-21  2:37 ` [PATCH 1/3] Add suport " Daniel Axtens
  2020-08-21  2:37 ` [PATCH 2/3] docs/grub: Document signing grub under UEFI Daniel Axtens
@ 2020-08-21  2:37 ` Daniel Axtens
  2020-10-20  3:54   ` Michael Chang
  2020-09-23 15:11 ` [PATCH 0/3] Add support for " Daniel Axtens
  3 siblings, 1 reply; 14+ messages in thread
From: Daniel Axtens @ 2020-08-21  2:37 UTC (permalink / raw)
  To: grub-devel; +Cc: rashmica.g, alastair, Daniel Axtens

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

diff --git a/docs/grub.texi b/docs/grub.texi
index 35da48456d9e..bbbe6c7e07bf 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5970,6 +5970,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.25.1



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

* Re: [PATCH 0/3] Add support for signing grub with an appended signature
  2020-08-21  2:37 [PATCH 0/3] Add support for signing grub with an appended signature Daniel Axtens
                   ` (2 preceding siblings ...)
  2020-08-21  2:37 ` [PATCH 3/3] docs/grub: Document signing grub with an appended signature Daniel Axtens
@ 2020-09-23 15:11 ` Daniel Axtens
  3 siblings, 0 replies; 14+ messages in thread
From: Daniel Axtens @ 2020-09-23 15:11 UTC (permalink / raw)
  To: grub-devel, pjones, xnox; +Cc: rashmica.g, alastair

Hi,

> Part of a secure boot chain is allowing boot firmware to verify the
> grub core.img. For UEFI platforms, this is done by signing the PE
> binary with a tool like pesign or sb-sign. However, for platforms that
> don't implement UEFI, an alternative scheme is required.
>
> These patches provide some infrastructure and documentation for
> signing grub's core.img with a Linux-kernel-module style appended
> signature.
>
> Because some platforms, such as powerpc-ieee1275, 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.

This is following up on the discussion out of Linux Plumbers [1].
Hopefully I've got the main question-askers, apologies if I've missed
anyone or sent emails to the wrong people. I'm also emailing grub-devel@
in hopes of catching anyone else who is interested.

One of the big requirements I heard was a desire to support key
rotation, for example by being able to embed multiple signatures in a
single signed grub.

I checked, and this is possible with appended signatures as I have
proposed them, because the size of the full signature block is known
when grub-mkimage is called.

You do have to do a bit of magic with openssl and sign-file, but it's
not particuarly bad. This demonstrates the openssl side and it's easy
to integrate with grub-mkimage:

# sign data/hello-world with both signing1 and signing2, placing just the
# PKCS#7 message in out/double-sig.p7s
openssl cms -sign -binary -in data/hello-world \
    -signer signing1.pem -inkey signing1.key \
    -signer signing2.pem -inkey signing2.key \
    -out out/double-sig.p7s -outform DER -noattr -md sha512

# append it to data/hello-world using sign-file's -s option, creating
# out/hello-world-sha512-2keys
../tools/sign-file -s out/double-sig.p7s sha512 /dev/null data/hello-world out/hello-world-sha512-2keys

# to verify, extract the cryptographic message with
# extract-module-sig.pl from the kernel source

./extract-module-sig.pl -s out/hello-world-sha512-2keys > out/hello-world-sha512-2keys.sig 2> /dev/null
if ! cmp out/double-sig.p7s out/hello-world-sha512-2keys.sig ; then
	echo "Input signature and data from extract-module-sig.pl -s do not agree!"
	exit 1;
fi

# openssl's verify requires that _both_ signatures are made with
# embedded certs which validate against a trusted CA
openssl cms -verify -binary -in out/hello-world-sha512-2keys.sig -inform der \
            -content hello-world -CAfile ca.pem -out /dev/null
if [ $? -ne 0 ]; then
	echo "OpenSSL failed to verify with both keys"
	exit 1
fi

For our application, firmware will allow a grub binary to boot if any
of the signatures in the PKCS#7 message match a key that is trusted by
firmware. This should allow keys to be rotated with firmware releases
without breaking backwards compatibility.

I've updated https://github.com/daxtens/SLOF to demonstrate this: if
any signature can be validated by a built-in key, it will pass
verification.



Another thing that was raised was the ability to make multiple
signatures separated in time, where the second signer didn't have
access to the private keys for the first signer. The example given was
for someone to sign a distro binary with a second set of keys
(e.g. specific keys for a data center) - then the binary would be
bootable on machines with distro keys, and also on machines that have
only the second set of keys.

This is not so easy. For grub, with the elf note, the data over which
the signature is made contains the size of the signature. To add a
signature would be to change the size of the signature stored in the
signed data. That would either break the old signature, or we would need
to make it not a true appended signature any more: rather than being a
'dumb' signature over everything before the start of the appended
signature data, it'd be more complex. We'd need to teach the signer and
verifier how to deal with that, and then we've thrown away the
advantages of appended signatures and reinvented many of the
complexities of Authenticode.

One thing we could potentially do without going down that route is to
include a quantity of 'blank space' for signatures - we could for
example always allocate a few kilobytes for signatures. The distro
signatures would take up the first part of the buffer, leaving space
for some for 'user' signatures.

We can get this to work with the appended-signature format "as is": we
specify how big the PKCS#7 message is, and if the message happens to be
smaller than the size we give, both openssl and mbedtls will just ignore
any trailing data.

This does at least kinda-sorta work, but OpenSSL's 'cms -resign' command
only works if we include signed attributes and at the moment our mbedtls
implementation cannot handle that. I don't think the PKCS#7 standard
mandates that behaviour, so maybe we can hack around it with the OpenSSL
C API. Or maybe we can extend mbedtls to handle signed
attributes. (eek!)

The concern I have is that this approach creates a big block of
arbitrary unsigned data in the grub binary. An attacker under our threat
model (root on the host) could put any data they like into that space. I
worry that in combination with some other vulernability, this could be
used to more easily pass useful data in to grub. However, maybe that's
not that much of a win for the attacker: if they are root they also have
complete control of grub.cfg and can instruct grub to do quite a bit as
it is.

I'm also not sure that the use-case is quite as likely with Power
systems vs x86 systems. But if I'm overthinking the security
implications of a blank space in the binary, it seems like we could get
it to work and I'd be happy to chase it up further.

Thoughts? (on or off-list is fine.)

Kind regards,
Daniel

[1] https://linuxplumbersconf.org/event/7/contributions/738/
    https://youtu.be/IJUNxHnopH4?t=537

> More details are in patch 1, including a link to an open-source firmware
> capable of verifying a grub image signed this way.
>
> Daniel Axtens (2):
>   docs/grub: Document signing grub under UEFI
>   docs/grub: Document signing grub with an appended signature
>
> Rashmica Gupta (1):
>   Add suport for signing grub with an appended signature
>
>  docs/grub.texi              | 64 ++++++++++++++++++++++++++++++++++++-
>  include/grub/util/install.h |  8 +++--
>  include/grub/util/mkimage.h |  4 +--
>  util/grub-install-common.c  | 16 ++++++++--
>  util/grub-mkimage.c         | 11 +++++++
>  util/grub-mkimagexx.c       | 39 +++++++++++++++++++++-
>  util/mkimage.c              | 10 +++---
>  7 files changed, 138 insertions(+), 14 deletions(-)
>
> -- 
> 2.25.1


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

* Re: [PATCH 3/3] docs/grub: Document signing grub with an appended signature
  2020-08-21  2:37 ` [PATCH 3/3] docs/grub: Document signing grub with an appended signature Daniel Axtens
@ 2020-10-20  3:54   ` Michael Chang
  2020-10-20  4:51     ` Daniel Axtens
  0 siblings, 1 reply; 14+ messages in thread
From: Michael Chang @ 2020-10-20  3:54 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: rashmica.g, alastair, Daniel Axtens

On Fri, Aug 21, 2020 at 12:37:20PM +1000, Daniel Axtens wrote:
> 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>
> ---
>  docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 35da48456d9e..bbbe6c7e07bf 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -5970,6 +5970,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}

Maybe `core.elf` should be used for embedded image on ieee1275 platform?
The core.img is more pc bios specific IMHO, and hence would be edited
on-the-fly during the grub-install/grub-bios-setup process for keeping
or adding some records, making it not a good example to the proposed
procedure here as the image on filesysetm and partition may differ.

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

Could you please provide more indication on how to install the signed
image afterwards ? I suppose it is 'dd' for writing the core.elf.signed
to the PReP partition but not really sure that is correct.

It also looked to me that the entire process can be integrated to
grub-install so the user can get less hassle to setting it up. For that
matters we could work out new grub-install options to accept user's
private key and public key certicate to compose signed image with
appended signature and install it on the fly. Is there anything that
I could have missed here ?

Thanks,
Michael

> +@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.25.1
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



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

* Re: [PATCH 3/3] docs/grub: Document signing grub with an appended signature
  2020-10-20  3:54   ` Michael Chang
@ 2020-10-20  4:51     ` Daniel Axtens
  2020-10-20  5:58       ` Michael Chang
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Axtens @ 2020-10-20  4:51 UTC (permalink / raw)
  To: Michael Chang, The development of GNU GRUB; +Cc: rashmica.g, alastair

Hi Michael,

>> +@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}
>
> Maybe `core.elf` should be used for embedded image on ieee1275 platform?
> The core.img is more pc bios specific IMHO, and hence would be edited
> on-the-fly during the grub-install/grub-bios-setup process for keeping
> or adding some records, making it not a good example to the proposed
> procedure here as the image on filesysetm and partition may differ.

Sure, I will change this in v2.

>> +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)
>
> Could you please provide more indication on how to install the signed
> image afterwards ? I suppose it is 'dd' for writing the core.elf.signed
> to the PReP partition but not really sure that is correct.

At the moment, yes, dd.

Firmware loads raw bytes off the PReP partition and expects them to be a
32-bit BE ELF binary. Therefore any method that can put raw bytes on
disk will work, and dd is the classic tool for the job.

I'll improve this for v2 on the basis of how the discussions on Michal's
proposal to do away with the ELF note go.

> It also looked to me that the entire process can be integrated to
> grub-install so the user can get less hassle to setting it up. For that
> matters we could work out new grub-install options to accept user's
> private key and public key certicate to compose signed image with
> appended signature and install it on the fly. Is there anything that
> I could have missed here ?

We'd need to add a dependency on OpenSSL (or maybe GNUTLS) to grub-install,
as there's no support in grub to generate PKCS#7 messages. I don't know
if that's acceptable?

One of the reasons I didn't go down that road initially is that I
imagine that most signed images are going to be signed by distros prior
to installation. Maybe grub-mkimage would be a better place to add this
feature. I think this is something we'll need to revisit once we resolve
the discussion about the ELF note generally.

Kind regards,
Daniel

>
> Thanks,
> Michael
>
>> +@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.25.1
>> 
>> 
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> https://lists.gnu.org/mailman/listinfo/grub-devel


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

* Re: [PATCH 3/3] docs/grub: Document signing grub with an appended signature
  2020-10-20  4:51     ` Daniel Axtens
@ 2020-10-20  5:58       ` Michael Chang
  0 siblings, 0 replies; 14+ messages in thread
From: Michael Chang @ 2020-10-20  5:58 UTC (permalink / raw)
  To: Daniel Axtens; +Cc: The development of GNU GRUB, rashmica.g, alastair

On Tue, Oct 20, 2020 at 03:51:11PM +1100, Daniel Axtens wrote:
> Hi Michael,
> 
> >> +@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}
> >
> > Maybe `core.elf` should be used for embedded image on ieee1275 platform?
> > The core.img is more pc bios specific IMHO, and hence would be edited
> > on-the-fly during the grub-install/grub-bios-setup process for keeping
> > or adding some records, making it not a good example to the proposed
> > procedure here as the image on filesysetm and partition may differ.
> 
> Sure, I will change this in v2.
> 
> >> +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)
> >
> > Could you please provide more indication on how to install the signed
> > image afterwards ? I suppose it is 'dd' for writing the core.elf.signed
> > to the PReP partition but not really sure that is correct.
> 
> At the moment, yes, dd.
> 
> Firmware loads raw bytes off the PReP partition and expects them to be a
> 32-bit BE ELF binary. Therefore any method that can put raw bytes on
> disk will work, and dd is the classic tool for the job.
> 
> I'll improve this for v2 on the basis of how the discussions on Michal's
> proposal to do away with the ELF note go.
> 
> > It also looked to me that the entire process can be integrated to
> > grub-install so the user can get less hassle to setting it up. For that
> > matters we could work out new grub-install options to accept user's
> > private key and public key certicate to compose signed image with
> > appended signature and install it on the fly. Is there anything that
> > I could have missed here ?
> 
> We'd need to add a dependency on OpenSSL (or maybe GNUTLS) to grub-install,
> as there's no support in grub to generate PKCS#7 messages. I don't know
> if that's acceptable?

I think it is acceptable if we invoke utility like openssl in
grub-install as there has been some utilities got invoked for different
purpose. (Remember, grub-install used to be written as script :))

> One of the reasons I didn't go down that road initially is that I
> imagine that most signed images are going to be signed by distros prior
> to installation. Maybe grub-mkimage would be a better place to add this
> feature. I think this is something we'll need to revisit once we resolve
> the discussion about the ELF note generally.

Yes. That sounds reasonable as long as the distro would have to work out
the signed core.efi via grub-mkimage in a way that can handle different
installation setup without resorting to any setup work performed by the
user to the image itself (ie running grub-install). The `dd` should just
work and the right thing to do so.

Thanks,
Michael

> 
> Kind regards,
> Daniel
> 
> >
> > Thanks,
> > Michael
> >
> >> +@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.25.1
> >> 
> >> 
> >> _______________________________________________
> >> Grub-devel mailing list
> >> Grub-devel@gnu.org
> >> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



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

* Re: [PATCH 0/3] Add support for signing grub with an appended signature
  2020-10-23  5:33       ` Daniel Axtens
@ 2020-11-04 18:04         ` Michal Suchánek
  0 siblings, 0 replies; 14+ messages in thread
From: Michal Suchánek @ 2020-11-04 18:04 UTC (permalink / raw)
  To: Daniel Axtens; +Cc: grub-devel

On Fri, Oct 23, 2020 at 04:33:58PM +1100, Daniel Axtens wrote:
> Hi Michal,
> 
> >> So grub is usually loaded from the PReP partition if you are booting
> >> from disk. But, if you are booting from a CD/USB/etc, we first parse
> >> /ppc/boot-info.txt and then load whatever file it identifies. If you're
> >> netbooting we load the file we get from the network.
> >> 
> >> One strength of the ELF-note based scheme is that verification of the
> >> appended signature is exactly the same in all these scenarios, and in
> >> each case it can live entirely in the ELF parsing and loading code.
> >> 
> >> In contrast, if we don't have an elf note, we have to handle PReP
> >> partitions, CHRP boot-info.txt and netboot separately. At least in the
> >> PReP case we also have to do parse enough of the ELF header to determine
> >> how much data we need to be hashing for signature verification, and this
> >> crosses a couple of previously separate steps of the process.
> >> 
> >> To illustrate from SLOF, currently the ELF note stuff lives almost
> >> entirely in elf32.c, but for the scheme you describe we need to patch
> >> load-from-dos-boot-partition, load-from-gpt-prep-partition, whatever
> >> code we use for where we boot a file directly from disk for CHRP
> >> boot-info.txt loading, and something somewhere in the netboot code.
> >
> > Why do you have to handle different boot media separately, though?
> >
> > There is this bug, supposedly in 'old firmware' that when the PReP
> > partition is large (gigabytes in size) the firmware crashes trying to
> > load the whole thing to memory and hand it over to the elf parser. If
> > this is fixed today you need to parse the header anyway to know how much
> > to load, or you need to just hand over some handle to the partition and
> > let the elf parser do the reading.
> 
> Hmm, I will pass this on to the enterprise/proprietary Partiton Firmware
> (PFW) team to confirm that it's been fixed.
> 
> It won't affect (at least modern versions of) SLOF, as SLOF caps the
> amount of PReP partition that it reads at 32MB. It reads min(partition
> size, 32MB) and passes that to the ELF loader. (I suppose that will
> break if a bootloader ever grows to be > 32MB, but most distros only
> allocate something like 8MB to PReP today, so you'd hit partition size
> limits first anyway.)
> 
> > The appended signature format is exactly the same in each case: there is
> > a container such as a partition, a file, or a block of memory that has
> > an elf binary at the start, optional padding, and optinal signature at
> > the end. There is nothing stopping the elf parser from parsing both
> > the elf header and the signature footer when it gets the data.
> 
> Reflecting on it, the proposed new design is also pretty quirky.
> 
> The existing appended signature format is:
> 
>  data || pkcs7 || metadata || magic
> 
> If you strip off the signature, only the data remains, which you can
> immediately calculate the hash on and verify the signature. The ELF note
> format perserves this property.
> 
> Moving the signature to the end of the PReP partition gives you:
> 
>   data || [padding] || pkcs7 || metadata || magic
> 
> Once you've stripped off the signature, you now need an extra processing
> step to strip off the padding. And - unusually for appended signatures -
> you need to know about the format of the data to distinguish data from
> padding.

And you need to know about the format of the data to make use of it -
specifically to execute it as an ELF binary, anyway.

> 
> > In the case of the partition containing the elf binary it is expected
> > that the padding is non-zero, in the other cases having padding is
> > suspicious.
> >
> > In the case of a partition you have to read the data in some
> > device-specific sectors while files can be read at arbitrary sized
> > chunks.
> >
> > If you choose to write separate code to fetch the elf binary from
> > different media due to these differences then these separate code paths
> > must be adjusted. However, that is inherent to lack of suitable
> > abstraction in the code, and not the appended signature format.
> >
> > I think it is more productive to clean up the code to handle all media
> > the same way rather than inventing new unique quirky and deficient
> > signature format.
> 
> You would need to handle the new padding at some stage in the pipeline,
> and that pipeline stage needs to know how to read an ELF header. So I
> agree that it would be logical to put signature verification in the ELF
> parsing stage.
> 
> However, if you want to flag the existence of padding in non-PReP cases
> - either to reject it or warn about it - then the signature verifier
> needs to know if it's parsing a PReP partition. If the signature
> validation lives in the ELF parser, you now need to tell the ELF parser
> that you are parsing a PReP partion. This seems like an abstraction or
> layering problem - the ELF parser shouldn't need to know or care where
> the ELF binary comes from.
> 
> So I think that merely cleaning up the code wouldn't be sufficient.

Adding the flag is something optional, and otherwise the data passed is
the same.

If you read PReP either pass the whole thing if it is smaller than 32MB
or you pass the first 32MB and append the signature (if it exists), and
there is quirky case when the signature crosses the boundary of your
'maximum binary size'. This quirky case is caused by another layering
violation - the code is reading something it does not understand from
the partition.

Thanks

Michal

> 
> Kind regards,
> Daniel
> 
> >
> > Thanks
> >
> > Michal
> >
> >> 
> >> We can still support multiple signers disjoint in time with the scheme I
> >> suggest at
> >> https://lists.gnu.org/archive/html/grub-devel/2020-09/msg00081.html
> >> although I do agree it's ugly in its own separate way.
> >> 
> >> Kind regards,
> >> Daniel
> >> 
> >> >> The disadvantage is that for signed grub dd is no longer an alternative
> >> >> to grub-install.
> >> >>
> >> >> There was also concern about distinguishing signed and un-signed grub.
> >> >> That is that writing an un-signed grub might lease a stale signature
> >> >> leading to an error.
> >> >>
> >> >> However, secure boot is something that should be enabled or disabled in
> >> >> firmware settings, and not triggered by the PPeP partition containing a
> >> >> signature. 
> >> >>
> >> >> When secure boot is enabled checking the grub signature is required and
> >> >> un-signed grub is invalid. When secure boot is disabled the signature
> >> >> is irrelevant and stale signature should not cause any error.
> >> >
> >> > What I'm concerned about here - and it's possible I explained it poorly
> >> > at Plumbers - is how a systems administrator would distinguish between
> >> > having accidentally installed an unsigned grub, and having installed a
> >> > grub with a broken or untrusted signature.
> >> >
> >> > Having said that, ...
> >> >
> >> >> grub-install can also remove the signature magic when installing
> >> >> un-signed grub for consistency. Users using dd to install un-signed
> >> >> grub might still have an old signature at the end of the partition.
> >> >
> >> > if we make grub-install do the right thing, I think that sufficiently
> >> > mitigates my concern.
> >> >
> >> > Thanks again, and I'll let you know how I get on shortly.
> >> >
> >> > Kind regards,
> >> > Daniel


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

* Re: [PATCH 0/3] Add support for signing grub with an appended signature
  2020-10-22 11:14     ` Michal Suchánek
@ 2020-10-23  5:33       ` Daniel Axtens
  2020-11-04 18:04         ` Michal Suchánek
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Axtens @ 2020-10-23  5:33 UTC (permalink / raw)
  To: Michal Suchánek; +Cc: grub-devel

Hi Michal,

>> So grub is usually loaded from the PReP partition if you are booting
>> from disk. But, if you are booting from a CD/USB/etc, we first parse
>> /ppc/boot-info.txt and then load whatever file it identifies. If you're
>> netbooting we load the file we get from the network.
>> 
>> One strength of the ELF-note based scheme is that verification of the
>> appended signature is exactly the same in all these scenarios, and in
>> each case it can live entirely in the ELF parsing and loading code.
>> 
>> In contrast, if we don't have an elf note, we have to handle PReP
>> partitions, CHRP boot-info.txt and netboot separately. At least in the
>> PReP case we also have to do parse enough of the ELF header to determine
>> how much data we need to be hashing for signature verification, and this
>> crosses a couple of previously separate steps of the process.
>> 
>> To illustrate from SLOF, currently the ELF note stuff lives almost
>> entirely in elf32.c, but for the scheme you describe we need to patch
>> load-from-dos-boot-partition, load-from-gpt-prep-partition, whatever
>> code we use for where we boot a file directly from disk for CHRP
>> boot-info.txt loading, and something somewhere in the netboot code.
>
> Why do you have to handle different boot media separately, though?
>
> There is this bug, supposedly in 'old firmware' that when the PReP
> partition is large (gigabytes in size) the firmware crashes trying to
> load the whole thing to memory and hand it over to the elf parser. If
> this is fixed today you need to parse the header anyway to know how much
> to load, or you need to just hand over some handle to the partition and
> let the elf parser do the reading.

Hmm, I will pass this on to the enterprise/proprietary Partiton Firmware
(PFW) team to confirm that it's been fixed.

It won't affect (at least modern versions of) SLOF, as SLOF caps the
amount of PReP partition that it reads at 32MB. It reads min(partition
size, 32MB) and passes that to the ELF loader. (I suppose that will
break if a bootloader ever grows to be > 32MB, but most distros only
allocate something like 8MB to PReP today, so you'd hit partition size
limits first anyway.)

> The appended signature format is exactly the same in each case: there is
> a container such as a partition, a file, or a block of memory that has
> an elf binary at the start, optional padding, and optinal signature at
> the end. There is nothing stopping the elf parser from parsing both
> the elf header and the signature footer when it gets the data.

Reflecting on it, the proposed new design is also pretty quirky.

The existing appended signature format is:

 data || pkcs7 || metadata || magic

If you strip off the signature, only the data remains, which you can
immediately calculate the hash on and verify the signature. The ELF note
format perserves this property.

Moving the signature to the end of the PReP partition gives you:

  data || [padding] || pkcs7 || metadata || magic

Once you've stripped off the signature, you now need an extra processing
step to strip off the padding. And - unusually for appended signatures -
you need to know about the format of the data to distinguish data from
padding.

> In the case of the partition containing the elf binary it is expected
> that the padding is non-zero, in the other cases having padding is
> suspicious.
>
> In the case of a partition you have to read the data in some
> device-specific sectors while files can be read at arbitrary sized
> chunks.
>
> If you choose to write separate code to fetch the elf binary from
> different media due to these differences then these separate code paths
> must be adjusted. However, that is inherent to lack of suitable
> abstraction in the code, and not the appended signature format.
>
> I think it is more productive to clean up the code to handle all media
> the same way rather than inventing new unique quirky and deficient
> signature format.

You would need to handle the new padding at some stage in the pipeline,
and that pipeline stage needs to know how to read an ELF header. So I
agree that it would be logical to put signature verification in the ELF
parsing stage.

However, if you want to flag the existence of padding in non-PReP cases
- either to reject it or warn about it - then the signature verifier
needs to know if it's parsing a PReP partition. If the signature
validation lives in the ELF parser, you now need to tell the ELF parser
that you are parsing a PReP partion. This seems like an abstraction or
layering problem - the ELF parser shouldn't need to know or care where
the ELF binary comes from.

So I think that merely cleaning up the code wouldn't be sufficient.

Kind regards,
Daniel

>
> Thanks
>
> Michal
>
>> 
>> We can still support multiple signers disjoint in time with the scheme I
>> suggest at
>> https://lists.gnu.org/archive/html/grub-devel/2020-09/msg00081.html
>> although I do agree it's ugly in its own separate way.
>> 
>> Kind regards,
>> Daniel
>> 
>> >> The disadvantage is that for signed grub dd is no longer an alternative
>> >> to grub-install.
>> >>
>> >> There was also concern about distinguishing signed and un-signed grub.
>> >> That is that writing an un-signed grub might lease a stale signature
>> >> leading to an error.
>> >>
>> >> However, secure boot is something that should be enabled or disabled in
>> >> firmware settings, and not triggered by the PPeP partition containing a
>> >> signature. 
>> >>
>> >> When secure boot is enabled checking the grub signature is required and
>> >> un-signed grub is invalid. When secure boot is disabled the signature
>> >> is irrelevant and stale signature should not cause any error.
>> >
>> > What I'm concerned about here - and it's possible I explained it poorly
>> > at Plumbers - is how a systems administrator would distinguish between
>> > having accidentally installed an unsigned grub, and having installed a
>> > grub with a broken or untrusted signature.
>> >
>> > Having said that, ...
>> >
>> >> grub-install can also remove the signature magic when installing
>> >> un-signed grub for consistency. Users using dd to install un-signed
>> >> grub might still have an old signature at the end of the partition.
>> >
>> > if we make grub-install do the right thing, I think that sufficiently
>> > mitigates my concern.
>> >
>> > Thanks again, and I'll let you know how I get on shortly.
>> >
>> > Kind regards,
>> > Daniel


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

* Re: [PATCH 0/3] Add support for signing grub with an appended signature
  2020-10-22  4:25   ` Daniel Axtens
@ 2020-10-22 11:14     ` Michal Suchánek
  2020-10-23  5:33       ` Daniel Axtens
  0 siblings, 1 reply; 14+ messages in thread
From: Michal Suchánek @ 2020-10-22 11:14 UTC (permalink / raw)
  To: Daniel Axtens; +Cc: grub-devel

Hello,

thanks for looking into this

On Thu, Oct 22, 2020 at 03:25:33PM +1100, Daniel Axtens wrote:
> Hi Michal,
> 
> >> A simpler scheme would be for grub-install to parse the signature
> >> footer, split-off the signature, write the ELF binary at the start of
> >> the PReP partition, and the signature at the end. Then the grub
> >> signature can use exactly same format as the kernel and modules.
> >
> > I got part way through implementing this today in SLOF and realised that
> > it's not immediately clear what the size of the signed data is for
> > verifying the appended signature - that is, how much of the PReP
> > partition should I be hashing? As I said, the appended signature
> > metadata doesn't encode this particular size value.
> >
> > One thing that we might be able to do is to base the size of the
> > verified data on a size calculated from the ELF header: basically figure
> > out the maximum file offset + size for all the program headers, capped
> > at (partition size - appended signature size), and hash that many
> > bytes. If I understand correctly, and assuming grub-mkimage constructs
> > valid ELF files, this should be correct.
> >
> > I'll give this a go in SLOF tomorrow, and I'll also need to confer with
> > the team that develops the proprietary firmware used by PowerVM.
> >
> 
> I talked to the firmware team this morning.
> 
> So grub is usually loaded from the PReP partition if you are booting
> from disk. But, if you are booting from a CD/USB/etc, we first parse
> /ppc/boot-info.txt and then load whatever file it identifies. If you're
> netbooting we load the file we get from the network.
> 
> One strength of the ELF-note based scheme is that verification of the
> appended signature is exactly the same in all these scenarios, and in
> each case it can live entirely in the ELF parsing and loading code.
> 
> In contrast, if we don't have an elf note, we have to handle PReP
> partitions, CHRP boot-info.txt and netboot separately. At least in the
> PReP case we also have to do parse enough of the ELF header to determine
> how much data we need to be hashing for signature verification, and this
> crosses a couple of previously separate steps of the process.
> 
> To illustrate from SLOF, currently the ELF note stuff lives almost
> entirely in elf32.c, but for the scheme you describe we need to patch
> load-from-dos-boot-partition, load-from-gpt-prep-partition, whatever
> code we use for where we boot a file directly from disk for CHRP
> boot-info.txt loading, and something somewhere in the netboot code.

Why do you have to handle different boot media separately, though?

There is this bug, supposedly in 'old firmware' that when the PReP
partition is large (gigabytes in size) the firmware crashes trying to
load the whole thing to memory and hand it over to the elf parser. If
this is fixed today you need to parse the header anyway to know how much
to load, or you need to just hand over some handle to the partition and
let the elf parser do the reading.

The appended signature format is exactly the same in each case: there is
a container such as a partition, a file, or a block of memory that has
an elf binary at the start, optional padding, and optinal signature at
the end. There is nothing stopping the elf parser from parsing both
the elf header and the signature footer when it gets the data.

In the case of the partition containing the elf binary it is expected
that the padding is non-zero, in the other cases having padding is
suspicious.

In the case of a partition you have to read the data in some
device-specific sectors while files can be read at arbitrary sized
chunks.

If you choose to write separate code to fetch the elf binary from
different media due to these differences then these separate code paths
must be adjusted. However, that is inherent to lack of suitable
abstraction in the code, and not the appended signature format.

I think it is more productive to clean up the code to handle all media
the same way rather than inventing new unique quirky and deficient
signature format.

Thanks

Michal

> 
> We can still support multiple signers disjoint in time with the scheme I
> suggest at
> https://lists.gnu.org/archive/html/grub-devel/2020-09/msg00081.html
> although I do agree it's ugly in its own separate way.
> 
> Kind regards,
> Daniel
> 
> >> The disadvantage is that for signed grub dd is no longer an alternative
> >> to grub-install.
> >>
> >> There was also concern about distinguishing signed and un-signed grub.
> >> That is that writing an un-signed grub might lease a stale signature
> >> leading to an error.
> >>
> >> However, secure boot is something that should be enabled or disabled in
> >> firmware settings, and not triggered by the PPeP partition containing a
> >> signature. 
> >>
> >> When secure boot is enabled checking the grub signature is required and
> >> un-signed grub is invalid. When secure boot is disabled the signature
> >> is irrelevant and stale signature should not cause any error.
> >
> > What I'm concerned about here - and it's possible I explained it poorly
> > at Plumbers - is how a systems administrator would distinguish between
> > having accidentally installed an unsigned grub, and having installed a
> > grub with a broken or untrusted signature.
> >
> > Having said that, ...
> >
> >> grub-install can also remove the signature magic when installing
> >> un-signed grub for consistency. Users using dd to install un-signed
> >> grub might still have an old signature at the end of the partition.
> >
> > if we make grub-install do the right thing, I think that sufficiently
> > mitigates my concern.
> >
> > Thanks again, and I'll let you know how I get on shortly.
> >
> > Kind regards,
> > Daniel


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

* Re: [PATCH 0/3] Add support for signing grub with an appended signature
       [not found] ` <871rhuwi80.fsf@dja-thinkpad.axtens.net>
  2020-10-19 23:18   ` Daniel Axtens
@ 2020-10-22  4:25   ` Daniel Axtens
  2020-10-22 11:14     ` Michal Suchánek
  1 sibling, 1 reply; 14+ messages in thread
From: Daniel Axtens @ 2020-10-22  4:25 UTC (permalink / raw)
  To: Michal Suchánek, grub-devel

Hi Michal,

>> A simpler scheme would be for grub-install to parse the signature
>> footer, split-off the signature, write the ELF binary at the start of
>> the PReP partition, and the signature at the end. Then the grub
>> signature can use exactly same format as the kernel and modules.
>
> I got part way through implementing this today in SLOF and realised that
> it's not immediately clear what the size of the signed data is for
> verifying the appended signature - that is, how much of the PReP
> partition should I be hashing? As I said, the appended signature
> metadata doesn't encode this particular size value.
>
> One thing that we might be able to do is to base the size of the
> verified data on a size calculated from the ELF header: basically figure
> out the maximum file offset + size for all the program headers, capped
> at (partition size - appended signature size), and hash that many
> bytes. If I understand correctly, and assuming grub-mkimage constructs
> valid ELF files, this should be correct.
>
> I'll give this a go in SLOF tomorrow, and I'll also need to confer with
> the team that develops the proprietary firmware used by PowerVM.
>

I talked to the firmware team this morning.

So grub is usually loaded from the PReP partition if you are booting
from disk. But, if you are booting from a CD/USB/etc, we first parse
/ppc/boot-info.txt and then load whatever file it identifies. If you're
netbooting we load the file we get from the network.

One strength of the ELF-note based scheme is that verification of the
appended signature is exactly the same in all these scenarios, and in
each case it can live entirely in the ELF parsing and loading code.

In contrast, if we don't have an elf note, we have to handle PReP
partitions, CHRP boot-info.txt and netboot separately. At least in the
PReP case we also have to do parse enough of the ELF header to determine
how much data we need to be hashing for signature verification, and this
crosses a couple of previously separate steps of the process.

To illustrate from SLOF, currently the ELF note stuff lives almost
entirely in elf32.c, but for the scheme you describe we need to patch
load-from-dos-boot-partition, load-from-gpt-prep-partition, whatever
code we use for where we boot a file directly from disk for CHRP
boot-info.txt loading, and something somewhere in the netboot code.

We can still support multiple signers disjoint in time with the scheme I
suggest at
https://lists.gnu.org/archive/html/grub-devel/2020-09/msg00081.html
although I do agree it's ugly in its own separate way.

Kind regards,
Daniel

>> The disadvantage is that for signed grub dd is no longer an alternative
>> to grub-install.
>>
>> There was also concern about distinguishing signed and un-signed grub.
>> That is that writing an un-signed grub might lease a stale signature
>> leading to an error.
>>
>> However, secure boot is something that should be enabled or disabled in
>> firmware settings, and not triggered by the PPeP partition containing a
>> signature. 
>>
>> When secure boot is enabled checking the grub signature is required and
>> un-signed grub is invalid. When secure boot is disabled the signature
>> is irrelevant and stale signature should not cause any error.
>
> What I'm concerned about here - and it's possible I explained it poorly
> at Plumbers - is how a systems administrator would distinguish between
> having accidentally installed an unsigned grub, and having installed a
> grub with a broken or untrusted signature.
>
> Having said that, ...
>
>> grub-install can also remove the signature magic when installing
>> un-signed grub for consistency. Users using dd to install un-signed
>> grub might still have an old signature at the end of the partition.
>
> if we make grub-install do the right thing, I think that sufficiently
> mitigates my concern.
>
> Thanks again, and I'll let you know how I get on shortly.
>
> Kind regards,
> Daniel


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

* Re: [PATCH 0/3] Add support for signing grub with an appended signature
       [not found] ` <871rhuwi80.fsf@dja-thinkpad.axtens.net>
@ 2020-10-19 23:18   ` Daniel Axtens
  2020-10-22  4:25   ` Daniel Axtens
  1 sibling, 0 replies; 14+ messages in thread
From: Daniel Axtens @ 2020-10-19 23:18 UTC (permalink / raw)
  To: grub-devel

[This bounced from the list for some reason, so I'm trying again.]

Hi Michal,

That's a really interesting proposal - thank you. I'm still thinking
about it and experimenting with it in SLOF.

Some thoughts:

> It has been pointed out in the plumbers session that the ELF note will
> cause problems when user wants to add additional signature.
>
> The normal appended signature has only one size information - in the
> footer at the end of the binary, and that is not part of the signed
> data. So if you want to add additional signature it if possible to
> expand the room for the signature data.

The appended signature metadata doesn't contain information about the
size of the signed data. It contains the size of the PKCS#7/CMS
signature block - because that can change in size based on the hash
function and the identity of the signing certificate.

Normally this doesn't matter: you can get a size of the whole file from
the filesystem and then because you know the size of the appended
signature data, you can work out the size of the signed data.

> In contrast the ELF note size is present in the ELF header which is
> also signed. This does not allow adjusting the size of the signature
> data once the binary is signed.

Correct. We could potentially allocate lots of space, but you are
correct that the size of the ELF note is fixed by the signature.

> A simpler scheme would be for grub-install to parse the signature
> footer, split-off the signature, write the ELF binary at the start of
> the PReP partition, and the signature at the end. Then the grub
> signature can use exactly same format as the kernel and modules.

I got part way through implementing this today in SLOF and realised that
it's not immediately clear what the size of the signed data is for
verifying the appended signature - that is, how much of the PReP
partition should I be hashing? As I said, the appended signature
metadata doesn't encode this particular size value.

One thing that we might be able to do is to base the size of the
verified data on a size calculated from the ELF header: basically figure
out the maximum file offset + size for all the program headers, capped
at (partition size - appended signature size), and hash that many
bytes. If I understand correctly, and assuming grub-mkimage constructs
valid ELF files, this should be correct.

I'll give this a go in SLOF tomorrow, and I'll also need to confer with
the team that develops the proprietary firmware used by PowerVM.

> The disadvantage is that for signed grub dd is no longer an alternative
> to grub-install.
>
> There was also concern about distinguishing signed and un-signed grub.
> That is that writing an un-signed grub might lease a stale signature
> leading to an error.
>
> However, secure boot is something that should be enabled or disabled in
> firmware settings, and not triggered by the PPeP partition containing a
> signature. 
>
> When secure boot is enabled checking the grub signature is required and
> un-signed grub is invalid. When secure boot is disabled the signature
> is irrelevant and stale signature should not cause any error.

What I'm concerned about here - and it's possible I explained it poorly
at Plumbers - is how a systems administrator would distinguish between
having accidentally installed an unsigned grub, and having installed a
grub with a broken or untrusted signature.

Having said that, ...

> grub-install can also remove the signature magic when installing
> un-signed grub for consistency. Users using dd to install un-signed
> grub might still have an old signature at the end of the partition.

if we make grub-install do the right thing, I think that sufficiently
mitigates my concern.

Thanks again, and I'll let you know how I get on shortly.

Kind regards,
Daniel



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

* [PATCH 0/3] Add support for signing grub with an appended signature
@ 2020-10-16 11:20 Michal Suchánek
       [not found] ` <871rhuwi80.fsf@dja-thinkpad.axtens.net>
  0 siblings, 1 reply; 14+ messages in thread
From: Michal Suchánek @ 2020-10-16 11:20 UTC (permalink / raw)
  To: dja, grub-devel

Hello,

It has been pointed out in the plumbers session that the ELF note will
cause problems when user wants to add additional signature.

The normal appended signature has only one size information - in the
footer at the end of the binary, and that is not part of the signed
data. So if you want to add additional signature it if possible to
expand the room for the signature data.

In contrast the ELF note size is present in the ELF header which is
also signed. This does not allow adjusting the size of the signature
data once the binary is signed.

A simpler scheme would be for grub-install to parse the signature
footer, split-off the signature, write the ELF binary at the start of
the PReP partition, and the signature at the end. Then the grub
signature can use exactly same format as the kernel and modules.

The disadvantage is that for signed grub dd is no longer an alternative
to grub-install.

There was also concern about distinguishing signed and un-signed grub.
That is that writing an un-signed grub might lease a stale signature
leading to an error.

However, secure boot is something that should be enabled or disabled in
firmware settings, and not triggered by the PPeP partition containing a
signature. 

When secure boot is enabled checking the grub signature is required and
un-signed grub is invalid. When secure boot is disabled the signature
is irrelevant and stale signature should not cause any error.

grub-install can also remove the signature magic when installing
un-signed grub for consistency. Users using dd to install un-signed
grub might still have an old signature at the end of the partition.

Thanks

Michal


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

end of thread, other threads:[~2020-11-04 18:04 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-21  2:37 [PATCH 0/3] Add support for signing grub with an appended signature Daniel Axtens
2020-08-21  2:37 ` [PATCH 1/3] Add suport " Daniel Axtens
2020-08-21  2:37 ` [PATCH 2/3] docs/grub: Document signing grub under UEFI Daniel Axtens
2020-08-21  2:37 ` [PATCH 3/3] docs/grub: Document signing grub with an appended signature Daniel Axtens
2020-10-20  3:54   ` Michael Chang
2020-10-20  4:51     ` Daniel Axtens
2020-10-20  5:58       ` Michael Chang
2020-09-23 15:11 ` [PATCH 0/3] Add support for " Daniel Axtens
2020-10-16 11:20 Michal Suchánek
     [not found] ` <871rhuwi80.fsf@dja-thinkpad.axtens.net>
2020-10-19 23:18   ` Daniel Axtens
2020-10-22  4:25   ` Daniel Axtens
2020-10-22 11:14     ` Michal Suchánek
2020-10-23  5:33       ` Daniel Axtens
2020-11-04 18:04         ` Michal Suchánek

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.