46968b6
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
46968b6
From: Alastair D'Silva <alastair@d-silva.org>
46968b6
Date: Mon, 6 Jul 2020 13:33:04 +1000
46968b6
Subject: [PATCH] grub-install: support embedding x509 certificates
46968b6
46968b6
To support verification of appended signatures, we need a way to
46968b6
embed the necessary public keys. Existing appended signature schemes
46968b6
in the Linux kernel use X.509 certificates, so allow certificates to
46968b6
be embedded in the grub core image in the same way as PGP keys.
46968b6
46968b6
Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
46968b6
Signed-off-by: Daniel Axtens <dja@axtens.net>
46968b6
---
46968b6
 grub-core/commands/pgp.c    |  2 +-
2a0a68c
 util/grub-install-common.c  | 23 ++++++++++++++++++++++-
46968b6
 util/grub-mkimage.c         | 15 +++++++++++++--
46968b6
 util/mkimage.c              | 38 ++++++++++++++++++++++++++++++++++++--
46968b6
 include/grub/kernel.h       |  4 +++-
46968b6
 include/grub/util/install.h |  7 +++++--
2a0a68c
 6 files changed, 80 insertions(+), 9 deletions(-)
46968b6
46968b6
diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
e622855
index 355a43844a..b81ac0ae46 100644
46968b6
--- a/grub-core/commands/pgp.c
46968b6
+++ b/grub-core/commands/pgp.c
46968b6
@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
46968b6
     grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
46968b6
 
46968b6
     /* Not an ELF module, skip.  */
46968b6
-    if (header->type != OBJ_TYPE_PUBKEY)
46968b6
+    if (header->type != OBJ_TYPE_GPG_PUBKEY)
46968b6
       continue;
46968b6
 
46968b6
     pseudo_file.fs = &pseudo_fs;
46968b6
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
e622855
index a74fee16e2..c603f5b308 100644
46968b6
--- a/util/grub-install-common.c
46968b6
+++ b/util/grub-install-common.c
13985b0
@@ -460,6 +460,8 @@ static char **pubkeys;
46968b6
 static size_t npubkeys;
46968b6
 static char *sbat;
46968b6
 static int disable_shim_lock;
46968b6
+static char **x509keys;
46968b6
+static size_t nx509keys;
46968b6
 static grub_compression_t compression;
46968b6
 static size_t appsig_size;
46968b6
 
2a0a68c
@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg)
46968b6
     case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK:
46968b6
       disable_shim_lock = 1;
2a0a68c
       return 1;
46968b6
+    case 'x':
46968b6
+      x509keys = xrealloc (x509keys,
46968b6
+			  sizeof (x509keys[0])
46968b6
+			  * (nx509keys + 1));
46968b6
+      x509keys[nx509keys++] = xstrdup (arg);
2a0a68c
+      return 1;
46968b6
 
46968b6
     case GRUB_INSTALL_OPTIONS_VERBOSITY:
2a0a68c
       verbosity++;
2a0a68c
@@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
46968b6
   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
46968b6
     slen += 20 + grub_strlen (*pk);
46968b6
 
46968b6
+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
46968b6
+    slen += 10 + grub_strlen (*pk);
46968b6
+
46968b6
   for (md = modules.entries; *md; md++)
46968b6
     {
46968b6
       slen += 10 + grub_strlen (*md);
2a0a68c
@@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
46968b6
       *p++ = ' ';
46968b6
     }
46968b6
 
46968b6
+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
46968b6
+    {
46968b6
+      p = grub_stpcpy (p, "--x509 '");
46968b6
+      p = grub_stpcpy (p, *pk);
46968b6
+      *p++ = '\'';
46968b6
+      *p++ = ' ';
46968b6
+    }
46968b6
+
46968b6
   for (md = modules.entries; *md; md++)
46968b6
     {
46968b6
       *p++ = '\'';
2a0a68c
@@ -684,7 +703,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
46968b6
 
46968b6
   grub_install_generate_image (dir, prefix, fp, outname,
46968b6
 			       modules.entries, memdisk_path,
46968b6
-			       pubkeys, npubkeys, config_path, tgt,
46968b6
+			       pubkeys, npubkeys,
46968b6
+			       x509keys, nx509keys,
46968b6
+			       config_path, tgt,
46968b6
 			       note, appsig_size, compression, dtb, sbat,
46968b6
 			       disable_shim_lock);
46968b6
   while (dc--)
46968b6
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
e622855
index 8a53310548..e1f1112784 100644
46968b6
--- a/util/grub-mkimage.c
46968b6
+++ b/util/grub-mkimage.c
46968b6
@@ -75,7 +75,8 @@ static struct argp_option options[] = {
46968b6
    /* TRANSLATORS: "embed" is a verb (command description).  "*/
46968b6
   {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
46968b6
    /* TRANSLATORS: "embed" is a verb (command description).  "*/
46968b6
-  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0},
46968b6
+  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0},
46968b6
+  {"x509",     'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
46968b6
   /* TRANSLATORS: NOTE is a name of segment.  */
46968b6
   {"note",   'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
46968b6
   {"output",  'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
46968b6
@@ -124,6 +125,8 @@ struct arguments
46968b6
   char *dtb;
46968b6
   char **pubkeys;
46968b6
   size_t npubkeys;
46968b6
+  char **x509keys;
46968b6
+  size_t nx509keys;
46968b6
   char *font;
46968b6
   char *config;
46968b6
   char *sbat;
46968b6
@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
46968b6
       arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg);
46968b6
       break;
46968b6
 
46968b6
+    case 'x':
46968b6
+      arguments->x509keys = xrealloc (arguments->x509keys,
46968b6
+				      sizeof (arguments->x509keys[0])
46968b6
+				      * (arguments->nx509keys + 1));
46968b6
+      arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
46968b6
+      break;
46968b6
+
46968b6
     case 'c':
46968b6
       if (arguments->config)
46968b6
 	free (arguments->config);
46968b6
@@ -332,7 +342,8 @@ main (int argc, char *argv[])
46968b6
   grub_install_generate_image (arguments.dir, arguments.prefix, fp,
46968b6
 			       arguments.output, arguments.modules,
46968b6
 			       arguments.memdisk, arguments.pubkeys,
46968b6
-			       arguments.npubkeys, arguments.config,
46968b6
+			       arguments.npubkeys, arguments.x509keys,
46968b6
+			       arguments.nx509keys, arguments.config,
46968b6
 			       arguments.image_target, arguments.note,
9fdaa79
 			       arguments.appsig_size, arguments.comp,
9fdaa79
 			       arguments.dtb, arguments.sbat,
46968b6
diff --git a/util/mkimage.c b/util/mkimage.c
e622855
index bab1227601..8319e8dfbd 100644
46968b6
--- a/util/mkimage.c
46968b6
+++ b/util/mkimage.c
46968b6
@@ -867,7 +867,8 @@ void
46968b6
 grub_install_generate_image (const char *dir, const char *prefix,
46968b6
 			     FILE *out, const char *outname, char *mods[],
46968b6
 			     char *memdisk_path, char **pubkey_paths,
46968b6
-			     size_t npubkeys, char *config_path,
46968b6
+			     size_t npubkeys, char **x509key_paths,
46968b6
+			     size_t nx509keys, char *config_path,
46968b6
 			     const struct grub_install_image_target_desc *image_target,
46968b6
 			     int note, size_t appsig_size, grub_compression_t comp,
46968b6
 			     const char *dtb_path, const char *sbat_path,
46968b6
@@ -913,6 +914,19 @@ grub_install_generate_image (const char *dir, const char *prefix,
46968b6
       }
46968b6
   }
46968b6
 
46968b6
+  {
46968b6
+    size_t i;
46968b6
+    for (i = 0; i < nx509keys; i++)
46968b6
+      {
46968b6
+	size_t curs;
46968b6
+	curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
46968b6
+	grub_util_info ("the size of x509 public key %u is 0x%"
46968b6
+			GRUB_HOST_PRIxLONG_LONG,
46968b6
+			(unsigned) i, (unsigned long long) curs);
46968b6
+	total_module_size += curs + sizeof (struct grub_module_header);
46968b6
+      }
46968b6
+  }
46968b6
+
46968b6
   if (memdisk_path)
46968b6
     {
46968b6
       memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
46968b6
@@ -1034,7 +1048,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
46968b6
 	curs = grub_util_get_image_size (pubkey_paths[i]);
46968b6
 
46968b6
 	header = (struct grub_module_header *) (kernel_img + offset);
46968b6
-	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
46968b6
+	header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY);
46968b6
 	header->size = grub_host_to_target32 (curs + sizeof (*header));
46968b6
 	offset += sizeof (*header);
46968b6
 
46968b6
@@ -1043,6 +1057,26 @@ grub_install_generate_image (const char *dir, const char *prefix,
46968b6
       }
46968b6
   }
46968b6
 
46968b6
+  {
46968b6
+    size_t i;
46968b6
+    for (i = 0; i < nx509keys; i++)
46968b6
+      {
46968b6
+	size_t curs;
46968b6
+	struct grub_module_header *header;
46968b6
+
46968b6
+	curs = grub_util_get_image_size (x509key_paths[i]);
46968b6
+
46968b6
+	header = (struct grub_module_header *) (kernel_img + offset);
46968b6
+	header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
46968b6
+	header->size = grub_host_to_target32 (curs + sizeof (*header));
46968b6
+	offset += sizeof (*header);
46968b6
+
46968b6
+	grub_util_load_image (x509key_paths[i], kernel_img + offset);
46968b6
+	offset += ALIGN_ADDR (curs);
46968b6
+      }
46968b6
+  }
46968b6
+
46968b6
+
46968b6
   if (memdisk_path)
46968b6
     {
46968b6
       struct grub_module_header *header;
46968b6
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
e622855
index 55849777ea..98edc0863f 100644
46968b6
--- a/include/grub/kernel.h
46968b6
+++ b/include/grub/kernel.h
46968b6
@@ -30,7 +30,9 @@ enum
46968b6
   OBJ_TYPE_PREFIX,
46968b6
   OBJ_TYPE_PUBKEY,
46968b6
   OBJ_TYPE_DTB,
46968b6
-  OBJ_TYPE_DISABLE_SHIM_LOCK
46968b6
+  OBJ_TYPE_DISABLE_SHIM_LOCK,
46968b6
+  OBJ_TYPE_GPG_PUBKEY,
46968b6
+  OBJ_TYPE_X509_PUBKEY,
46968b6
 };
46968b6
 
46968b6
 /* The module header.  */
46968b6
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
e622855
index cf4531e02b..51f3b13ac1 100644
46968b6
--- a/include/grub/util/install.h
46968b6
+++ b/include/grub/util/install.h
46968b6
@@ -67,6 +67,8 @@
46968b6
       N_("SBAT metadata"), 0 },						\
46968b6
   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,	\
46968b6
       N_("disable shim_lock verifier"), 0 },				\
46968b6
+  { "x509key",   'x', N_("FILE"), 0,					\
46968b6
+      N_("embed FILE as an x509 certificate for signature checking"), 0}, \
46968b6
   { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
46968b6
     "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
46968b6
     1},                                                                 \
46968b6
@@ -188,8 +190,9 @@ void
46968b6
 grub_install_generate_image (const char *dir, const char *prefix,
46968b6
 			     FILE *out,
46968b6
 			     const char *outname, char *mods[],
46968b6
-			     char *memdisk_path, char **pubkey_paths,
46968b6
-			     size_t npubkeys,
46968b6
+			     char *memdisk_path,
46968b6
+			     char **pubkey_paths, size_t npubkeys,
46968b6
+			     char **x509key_paths, size_t nx509keys,
46968b6
 			     char *config_path,
46968b6
 			     const struct grub_install_image_target_desc *image_target,
46968b6
 			     int note, size_t appsig_size,