diff --git a/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
index 11510f5..2f053c8 100644
--- a/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
+++ b/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
@@ -25,11 +25,11 @@ solution":
 - http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm
 - http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/PC%20Keyboard.pdf
 ---
- grub-core/term/at_keyboard.c | 127 ++++++++++++++++++++++++++++++++++---------
- 1 file changed, 101 insertions(+), 26 deletions(-)
+ grub-core/term/at_keyboard.c | 121 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 96 insertions(+), 25 deletions(-)
 
 diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
-index 69d99b61df5..e7d51b249ad 100644
+index 69d99b61df5..c805cccbdde 100644
 --- a/grub-core/term/at_keyboard.c
 +++ b/grub-core/term/at_keyboard.c
 @@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
@@ -71,26 +71,22 @@ index 69d99b61df5..e7d51b249ad 100644
  static int
  write_mode (int mode)
  {
-@@ -113,11 +131,17 @@ write_mode (int mode)
+@@ -113,11 +131,14 @@ write_mode (int mode)
      {
        grub_uint8_t ack;
        keyboard_controller_wait_until_ready ();
 +      grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n");
        grub_outb (0xf0, KEYBOARD_REG_DATA);
-+      ack = wait_ack ();
-+      grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack);
-+      if (ack != GRUB_AT_ACK)
-+	continue;
        keyboard_controller_wait_until_ready ();
 +      grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode);
        grub_outb (mode, KEYBOARD_REG_DATA);
--      keyboard_controller_wait_until_ready ();
+       keyboard_controller_wait_until_ready ();
        ack = wait_ack ();
 +      grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack);
        if (ack == GRUB_AT_NACK)
  	continue;
        if (ack == GRUB_AT_ACK)
-@@ -125,6 +149,9 @@ write_mode (int mode)
+@@ -125,6 +146,9 @@ write_mode (int mode)
        return 0;
      }
  
@@ -100,7 +96,7 @@ index 69d99b61df5..e7d51b249ad 100644
    return (i != GRUB_AT_TRIES);
  }
  
-@@ -132,31 +159,66 @@ static int
+@@ -132,31 +156,66 @@ static int
  query_mode (void)
  {
    grub_uint8_t ret;
@@ -187,7 +183,7 @@ index 69d99b61df5..e7d51b249ad 100644
    return 0;
  }
  
-@@ -165,14 +227,25 @@ set_scancodes (void)
+@@ -165,14 +224,25 @@ set_scancodes (void)
  {
    /* You must have visited computer museum. Keyboard without scancode set
       knowledge. Assume XT. */
@@ -217,15 +213,7 @@ index 69d99b61df5..e7d51b249ad 100644
    if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) {
      grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set);
      ps2_state.current_set = 1;
-@@ -229,6 +302,7 @@ grub_at_keyboard_is_alive (void)
- 
-   if (KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
-     {
-+      grub_dprintf ("atkeyb", "grub_at_keyboard_is_alive: controller mode before self-test: 0x%x\n", grub_keyboard_controller_read());
-       grub_outb (0xaa, KEYBOARD_REG_STATUS);
-       ping_sent = 1;
-     }
-@@ -261,6 +335,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
+@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
  static void
  grub_keyboard_controller_init (void)
  {
@@ -233,7 +221,7 @@ index 69d99b61df5..e7d51b249ad 100644
    ps2_state.at_keyboard_status = 0;
    /* Drain input buffer. */
    while (1)
-@@ -282,6 +357,7 @@ grub_keyboard_controller_init (void)
+@@ -282,6 +353,7 @@ grub_keyboard_controller_init (void)
    grub_keyboard_controller_orig = grub_keyboard_controller_read ();
    grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig);
    grub_keyboard_orig_set = query_mode ();
@@ -241,7 +229,7 @@ index 69d99b61df5..e7d51b249ad 100644
  #endif
    set_scancodes ();
    keyboard_controller_led (ps2_state.led_status);
-@@ -329,7 +405,6 @@ grub_at_restore_hw (void)
+@@ -329,7 +401,6 @@ grub_at_restore_hw (void)
    return GRUB_ERR_NONE;
  }
  
diff --git a/SOURCES/0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/SOURCES/0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch
new file mode 100644
index 0000000..fada0a9
--- /dev/null
+++ b/SOURCES/0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch
@@ -0,0 +1,309 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Rashmica Gupta <rashmica.g@gmail.com>
+Date: Thu, 11 Jun 2020 11:26:23 +1000
+Subject: [PATCH] Add suport for signing grub with an appended signature
+
+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 this for inclusion in a future Power Architecture
+Platform Reference (PAPR).
+---
+ util/grub-install-common.c  | 16 +++++++++++++---
+ util/grub-mkimage.c         | 11 +++++++++++
+ util/grub-mkimagexx.c       | 39 ++++++++++++++++++++++++++++++++++++++-
+ util/mkimage.c              | 10 +++++-----
+ include/grub/util/install.h |  8 ++++++--
+ include/grub/util/mkimage.h |  4 ++--
+ 6 files changed, 75 insertions(+), 13 deletions(-)
+
+diff --git a/util/grub-install-common.c b/util/grub-install-common.c
+index cf993c059ad..561e671ff34 100644
+--- a/util/grub-install-common.c
++++ b/util/grub-install-common.c
+@@ -303,10 +303,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':
+@@ -395,6 +397,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;
+     }
+@@ -493,10 +501,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);
+@@ -506,7 +516,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 98d24cc06ea..9cc767088d3 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);
+ 
+   grub_util_file_sync  (fp);
+diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
+index f9aa1a033b5..1bb5eb84c14 100644
+--- a/util/grub-mkimagexx.c
++++ b/util/grub-mkimagexx.c
+@@ -82,6 +82,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
+@@ -205,7 +214,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)
+ {
+@@ -219,6 +228,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;
+ 
+@@ -449,6 +464,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 e22d82afa61..a81120f26be 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -777,7 +777,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;
+@@ -1694,11 +1694,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;
+     }
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index 0dba8b67f93..ba5e6a2ea8f 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 }
+ 
+@@ -119,7 +122,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;
+@@ -179,7 +183,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 b3a5ca132bc..cef7fffa7ae 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/SOURCES/0349-ieee1275-claim-up-to-256MB-memory.patch b/SOURCES/0349-ieee1275-claim-up-to-256MB-memory.patch
deleted file mode 100644
index ac0620c..0000000
--- a/SOURCES/0349-ieee1275-claim-up-to-256MB-memory.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 28 Oct 2020 11:44:29 +1100
-Subject: [PATCH] ieee1275: claim up to 256MB memory
-
-If we are verifying large kernels, we need more that 32MB. (Many distro
-kernels are quite large, and debug kernels can be even bigger!)
-
-We originally went with 512MB: qemu pseries gives you all the memory a
-32-bit number can handle, so there was lots left over to place a linux image
-and initrd.
-
-Here's what we said then:
-| This is possibly not the way we want to go with for upstream as it breaks
-| booting on systems with <= 512MB. We're working on a more upstream-friendly
-| solution and will post it shortly. However, for an end-user or packager with
-| a higher minimum memory requirement, this will work fine.
-
-However, we've since discovered that (at least on one P8 test system), PFW
-doesn't expose all of the memory allocated to the LPAR: it looks like it just
-exposes 512MB - at least unless we mess with the CHRP note section.
-Therefore, if we try to claim 512MB in grub, things _do not_ work when we try
-to load linux. As a compromise, and again we'd like a better upstream solution,
-go for 256MB. This is at least enough to verify distro kernels.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/kern/ieee1275/init.c | 6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index e731a57a47b..f8a4f8f4214 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -49,15 +49,13 @@
- #ifdef __i386__
- #define HEAP_MAX_SIZE		(unsigned long) (64 * 1024 * 1024)
- #else
--#define HEAP_MAX_SIZE		(unsigned long) (32 * 1024 * 1024)
-+#define HEAP_MAX_SIZE		(unsigned long) (256 * 1024 * 1024)
- #endif
- 
--/* If possible, we will avoid claiming heap above this address, because it
--   seems to cause relocation problems with OSes that link at 4 MiB */
- #ifdef __i386__
- #define HEAP_MAX_ADDR		(unsigned long) (64 * 1024 * 1024)
- #else
--#define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
-+#define HEAP_MAX_ADDR		(unsigned long) (256 * 1024 * 1024)
- #endif
- 
- extern char _end[];
diff --git a/SOURCES/0350-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/SOURCES/0350-Add-suport-for-signing-grub-with-an-appended-signatu.patch
deleted file mode 100644
index fada0a9..0000000
--- a/SOURCES/0350-Add-suport-for-signing-grub-with-an-appended-signatu.patch
+++ /dev/null
@@ -1,309 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Rashmica Gupta <rashmica.g@gmail.com>
-Date: Thu, 11 Jun 2020 11:26:23 +1000
-Subject: [PATCH] Add suport for signing grub with an appended signature
-
-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 this for inclusion in a future Power Architecture
-Platform Reference (PAPR).
----
- util/grub-install-common.c  | 16 +++++++++++++---
- util/grub-mkimage.c         | 11 +++++++++++
- util/grub-mkimagexx.c       | 39 ++++++++++++++++++++++++++++++++++++++-
- util/mkimage.c              | 10 +++++-----
- include/grub/util/install.h |  8 ++++++--
- include/grub/util/mkimage.h |  4 ++--
- 6 files changed, 75 insertions(+), 13 deletions(-)
-
-diff --git a/util/grub-install-common.c b/util/grub-install-common.c
-index cf993c059ad..561e671ff34 100644
---- a/util/grub-install-common.c
-+++ b/util/grub-install-common.c
-@@ -303,10 +303,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':
-@@ -395,6 +397,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;
-     }
-@@ -493,10 +501,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);
-@@ -506,7 +516,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 98d24cc06ea..9cc767088d3 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);
- 
-   grub_util_file_sync  (fp);
-diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
-index f9aa1a033b5..1bb5eb84c14 100644
---- a/util/grub-mkimagexx.c
-+++ b/util/grub-mkimagexx.c
-@@ -82,6 +82,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
-@@ -205,7 +214,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)
- {
-@@ -219,6 +228,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;
- 
-@@ -449,6 +464,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 e22d82afa61..a81120f26be 100644
---- a/util/mkimage.c
-+++ b/util/mkimage.c
-@@ -777,7 +777,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;
-@@ -1694,11 +1694,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;
-     }
-diff --git a/include/grub/util/install.h b/include/grub/util/install.h
-index 0dba8b67f93..ba5e6a2ea8f 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 }
- 
-@@ -119,7 +122,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;
-@@ -179,7 +183,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 b3a5ca132bc..cef7fffa7ae 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/SOURCES/0350-docs-grub-Document-signing-grub-under-UEFI.patch b/SOURCES/0350-docs-grub-Document-signing-grub-under-UEFI.patch
new file mode 100644
index 0000000..dee54ce
--- /dev/null
+++ b/SOURCES/0350-docs-grub-Document-signing-grub-under-UEFI.patch
@@ -0,0 +1,59 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 15 Aug 2020 02:00:57 +1000
+Subject: [PATCH] docs/grub: Document signing grub under UEFI
+
+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.
+
+(adjusted from upstream - s/grub/grub2/ in the docs)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index fa11cc0aff7..acace6c0737 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -5610,6 +5610,7 @@ environment variables and commands are listed in the same order.
+ @menu
+ * Authentication and authorisation:: Users and access control
+ * Using digital signatures::         Booting digitally signed code
++* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
+ @end menu
+ 
+ @node Authentication and authorisation
+@@ -5687,7 +5688,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}
+@@ -5772,6 +5773,22 @@ 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 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}. It will also be
++necessary to enrol the public key used into a relevant firmware key database.
++
+ @node Platform limitations
+ @chapter Platform limitations
+ 
diff --git a/SOURCES/0351-docs-grub-Document-signing-grub-under-UEFI.patch b/SOURCES/0351-docs-grub-Document-signing-grub-under-UEFI.patch
deleted file mode 100644
index dee54ce..0000000
--- a/SOURCES/0351-docs-grub-Document-signing-grub-under-UEFI.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 15 Aug 2020 02:00:57 +1000
-Subject: [PATCH] docs/grub: Document signing grub under UEFI
-
-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.
-
-(adjusted from upstream - s/grub/grub2/ in the docs)
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 19 ++++++++++++++++++-
- 1 file changed, 18 insertions(+), 1 deletion(-)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index fa11cc0aff7..acace6c0737 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -5610,6 +5610,7 @@ environment variables and commands are listed in the same order.
- @menu
- * Authentication and authorisation:: Users and access control
- * Using digital signatures::         Booting digitally signed code
-+* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
- @end menu
- 
- @node Authentication and authorisation
-@@ -5687,7 +5688,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}
-@@ -5772,6 +5773,22 @@ 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 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}. It will also be
-+necessary to enrol the public key used into a relevant firmware key database.
-+
- @node Platform limitations
- @chapter Platform limitations
- 
diff --git a/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch
new file mode 100644
index 0000000..6e65133
--- /dev/null
+++ b/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch
@@ -0,0 +1,67 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 15 Aug 2020 02:19:36 +1000
+Subject: [PATCH] docs/grub: Document signing grub with an appended signature
+
+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 acace6c0737..61c92a1e03d 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -5789,6 +5789,48 @@ 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}. 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
+ 
diff --git a/SOURCES/0352-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/SOURCES/0352-docs-grub-Document-signing-grub-with-an-appended-sig.patch
deleted file mode 100644
index 6e65133..0000000
--- a/SOURCES/0352-docs-grub-Document-signing-grub-with-an-appended-sig.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 15 Aug 2020 02:19:36 +1000
-Subject: [PATCH] docs/grub: Document signing grub with an appended signature
-
-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 acace6c0737..61c92a1e03d 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -5789,6 +5789,48 @@ 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}. 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
- 
diff --git a/SOURCES/0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch b/SOURCES/0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch
new file mode 100644
index 0000000..2e5823f
--- /dev/null
+++ b/SOURCES/0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 15 Aug 2020 01:00:11 +1000
+Subject: [PATCH] docs/grub: grub-install is no longer a shell script
+
+Since commit cd46aa6cefab in 2013, grub-install hasn't been a shell
+script. The para doesn't really add that much, especially since it's
+the user manual, so just drop it.
+
+(adjust docs: s/grub/grub2)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 61c92a1e03d..34517e67439 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -695,13 +695,6 @@ floppy instead of exposing the USB drive as a hard disk (they call it
+ This install doesn't conflict with standard install as long as they are in
+ separate directories.
+ 
+-Note that @command{grub2-install} is actually just a shell script and the
+-real task is done by other tools such as @command{grub2-mkimage}. Therefore,
+-you may run those commands directly to install GRUB, without using
+-@command{grub2-install}. Don't do that, however, unless you are very familiar
+-with the internals of GRUB. Installing a boot loader on a running OS may be
+-extremely dangerous.
+-
+ On EFI systems for fixed disk install you have to mount EFI System Partition.
+ If you mount it at @file{/boot/efi} then you don't need any special arguments:
+ 
diff --git a/SOURCES/0353-docs-grub-grub-install-is-no-longer-a-shell-script.patch b/SOURCES/0353-docs-grub-grub-install-is-no-longer-a-shell-script.patch
deleted file mode 100644
index 2e5823f..0000000
--- a/SOURCES/0353-docs-grub-grub-install-is-no-longer-a-shell-script.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 15 Aug 2020 01:00:11 +1000
-Subject: [PATCH] docs/grub: grub-install is no longer a shell script
-
-Since commit cd46aa6cefab in 2013, grub-install hasn't been a shell
-script. The para doesn't really add that much, especially since it's
-the user manual, so just drop it.
-
-(adjust docs: s/grub/grub2)
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 7 -------
- 1 file changed, 7 deletions(-)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 61c92a1e03d..34517e67439 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -695,13 +695,6 @@ floppy instead of exposing the USB drive as a hard disk (they call it
- This install doesn't conflict with standard install as long as they are in
- separate directories.
- 
--Note that @command{grub2-install} is actually just a shell script and the
--real task is done by other tools such as @command{grub2-mkimage}. Therefore,
--you may run those commands directly to install GRUB, without using
--@command{grub2-install}. Don't do that, however, unless you are very familiar
--with the internals of GRUB. Installing a boot loader on a running OS may be
--extremely dangerous.
--
- On EFI systems for fixed disk install you have to mount EFI System Partition.
- If you mount it at @file{/boot/efi} then you don't need any special arguments:
- 
diff --git a/SOURCES/0353-docs-grub-pubkey-has-been-supported-for-some-time.patch b/SOURCES/0353-docs-grub-pubkey-has-been-supported-for-some-time.patch
new file mode 100644
index 0000000..f8a2e9e
--- /dev/null
+++ b/SOURCES/0353-docs-grub-pubkey-has-been-supported-for-some-time.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 15 Aug 2020 02:04:01 +1000
+Subject: [PATCH] docs/grub: --pubkey has been supported for some time
+
+--pubkey is supported, so we can now document it.
+
+(adjust docs: s/grub/grub2)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 34517e67439..a833364d5ff 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -5695,15 +5695,9 @@ verified with a public key currently trusted by GRUB
+ validation fails, then file @file{foo} cannot be opened.  This failure
+ may halt or otherwise impact the boot process.
+ 
+-@comment Unfortunately --pubkey is not yet supported by grub2-install,
+-@comment but we should not bring up internal detail grub2-mkimage here
+-@comment in the user guide (as opposed to developer's manual).
+-
+-@comment An initial trusted public key can be embedded within the GRUB
+-@comment @file{core.img} using the @code{--pubkey} option to
+-@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}).  Presently it
+-@comment is necessary to write a custom wrapper around @command{grub2-mkimage}
+-@comment using the @code{--grub-mkimage} flag to @command{grub2-install}.
++An initial trusted public key can be embedded within the GRUB
++@file{core.img} using the @code{--pubkey} option to
++@command{grub2-install} (@pxref{Invoking grub2-install}).
+ 
+ GRUB uses GPG-style detached signatures (meaning that a file
+ @file{foo.sig} will be produced when file @file{foo} is signed), and
diff --git a/SOURCES/0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/SOURCES/0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
new file mode 100644
index 0000000..859472d
--- /dev/null
+++ b/SOURCES/0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 00:13:21 +1000
+Subject: [PATCH] dl: provide a fake grub_dl_set_persistent for the emu target
+
+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>
+---
+ include/grub/dl.h | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index f7cfe64823c..877821dcb04 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -243,11 +243,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)
diff --git a/SOURCES/0354-docs-grub-pubkey-has-been-supported-for-some-time.patch b/SOURCES/0354-docs-grub-pubkey-has-been-supported-for-some-time.patch
deleted file mode 100644
index f8a2e9e..0000000
--- a/SOURCES/0354-docs-grub-pubkey-has-been-supported-for-some-time.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 15 Aug 2020 02:04:01 +1000
-Subject: [PATCH] docs/grub: --pubkey has been supported for some time
-
---pubkey is supported, so we can now document it.
-
-(adjust docs: s/grub/grub2)
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 12 +++---------
- 1 file changed, 3 insertions(+), 9 deletions(-)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 34517e67439..a833364d5ff 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -5695,15 +5695,9 @@ verified with a public key currently trusted by GRUB
- validation fails, then file @file{foo} cannot be opened.  This failure
- may halt or otherwise impact the boot process.
- 
--@comment Unfortunately --pubkey is not yet supported by grub2-install,
--@comment but we should not bring up internal detail grub2-mkimage here
--@comment in the user guide (as opposed to developer's manual).
--
--@comment An initial trusted public key can be embedded within the GRUB
--@comment @file{core.img} using the @code{--pubkey} option to
--@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}).  Presently it
--@comment is necessary to write a custom wrapper around @command{grub2-mkimage}
--@comment using the @code{--grub-mkimage} flag to @command{grub2-install}.
-+An initial trusted public key can be embedded within the GRUB
-+@file{core.img} using the @code{--pubkey} option to
-+@command{grub2-install} (@pxref{Invoking grub2-install}).
- 
- GRUB uses GPG-style detached signatures (meaning that a file
- @file{foo.sig} will be produced when file @file{foo} is signed), and
diff --git a/SOURCES/0355-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/SOURCES/0355-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
deleted file mode 100644
index 859472d..0000000
--- a/SOURCES/0355-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 00:13:21 +1000
-Subject: [PATCH] dl: provide a fake grub_dl_set_persistent for the emu target
-
-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>
----
- include/grub/dl.h | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index f7cfe64823c..877821dcb04 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -243,11 +243,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)
diff --git a/SOURCES/0355-verifiers-provide-unsafe-module-list.patch b/SOURCES/0355-verifiers-provide-unsafe-module-list.patch
new file mode 100644
index 0000000..5a6148f
--- /dev/null
+++ b/SOURCES/0355-verifiers-provide-unsafe-module-list.patch
@@ -0,0 +1,96 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 29 Jul 2020 17:46:16 +1000
+Subject: [PATCH] verifiers: provide unsafe module list
+
+Other verifiers that implement secure boot may want to be able to
+use this list and behaviour.
+
+Upstream, this factors the list out of the shim_lock verifier.
+However, that hasn't hit the RHEL8.4 tree yet, so instead
+of factoring it out of that we just create it.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/verifiers.c | 46 ++++++++++++++++++++++++++++++++++++++++++
+ include/grub/verify.h          | 13 ++++++++++++
+ 2 files changed, 59 insertions(+)
+
+diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
+index 599d79b757e..f64343ac90b 100644
+--- a/grub-core/commands/verifiers.c
++++ b/grub-core/commands/verifiers.c
+@@ -218,6 +218,52 @@ grub_verify_string (char *str, enum grub_verify_string_type type)
+   return GRUB_ERR_NONE;
+ }
+ 
++/* List of modules which may allow for verifcation to be bypassed. */
++static const char *const disabled_mods[] = { "iorw", "memrw", "wrmsr", NULL };
++
++/*
++ * Does the module in file `io' allow for the a verifier to be bypassed?
++ *
++ * Returns 1 if so, otherwise 0.
++ */
++char
++grub_is_dangerous_module (grub_file_t io)
++{
++  char *b, *e;
++  int i;
++
++  /* Establish GRUB module name. */
++  b = grub_strrchr (io->name, '/');
++  e = grub_strrchr (io->name, '.');
++
++  b = b ? (b + 1) : io->name;
++  e = e ? e : io->name + grub_strlen (io->name);
++  e = (e > b) ? e : io->name + grub_strlen (io->name);
++
++  for (i = 0; disabled_mods[i]; i++)
++    if (!grub_strncmp (b, disabled_mods[i],
++		       grub_strlen (b) - grub_strlen (e)))
++      return 1;
++  return 0;
++}
++
++/*
++ * Is there already an unsafe module in memory?
++ * Returns the name if one is loaded, otherwise NULL.
++ */
++const char *
++grub_dangerous_module_loaded (void)
++{
++  int i;
++
++  for (i = 0; disabled_mods[i]; i++)
++    if (grub_dl_get (disabled_mods[i]))
++      {
++	return disabled_mods[i];
++      }
++  return NULL;
++}
++
+ GRUB_MOD_INIT(verifiers)
+ {
+   grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+index 79022b42258..60c13e7ea8e 100644
+--- a/include/grub/verify.h
++++ b/include/grub/verify.h
+@@ -76,3 +76,16 @@ grub_verifier_unregister (struct grub_file_verifier *ver)
+ 
+ grub_err_t
+ grub_verify_string (char *str, enum grub_verify_string_type type);
++
++/*
++ * Does the module in file `io' allow for the a verifier to be bypassed?
++ *
++ * Returns 1 if so, otherwise 0.
++ */
++char grub_is_dangerous_module (grub_file_t io);
++
++/*
++ * Is there already an unsafe module in memory?
++ * Returns the name if one is loaded, otherwise NULL.
++ */
++const char *grub_dangerous_module_loaded (void);
diff --git a/SOURCES/0356-pgp-factor-out-rsa_pad.patch b/SOURCES/0356-pgp-factor-out-rsa_pad.patch
new file mode 100644
index 0000000..79a73ec
--- /dev/null
+++ b/SOURCES/0356-pgp-factor-out-rsa_pad.patch
@@ -0,0 +1,191 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 1 Oct 2020 20:23:48 +1000
+Subject: [PATCH] pgp: factor out rsa_pad
+
+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>
+---
+ 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 809f11feaef..99615c07b94 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2387,6 +2387,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 d39846d8cfe..bb6543819f0 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 00000000000..dbacd563d01
+--- /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 00000000000..5c338c84a15
+--- /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);
++
diff --git a/SOURCES/0356-verifiers-provide-unsafe-module-list.patch b/SOURCES/0356-verifiers-provide-unsafe-module-list.patch
deleted file mode 100644
index 5a6148f..0000000
--- a/SOURCES/0356-verifiers-provide-unsafe-module-list.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 29 Jul 2020 17:46:16 +1000
-Subject: [PATCH] verifiers: provide unsafe module list
-
-Other verifiers that implement secure boot may want to be able to
-use this list and behaviour.
-
-Upstream, this factors the list out of the shim_lock verifier.
-However, that hasn't hit the RHEL8.4 tree yet, so instead
-of factoring it out of that we just create it.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/verifiers.c | 46 ++++++++++++++++++++++++++++++++++++++++++
- include/grub/verify.h          | 13 ++++++++++++
- 2 files changed, 59 insertions(+)
-
-diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
-index 599d79b757e..f64343ac90b 100644
---- a/grub-core/commands/verifiers.c
-+++ b/grub-core/commands/verifiers.c
-@@ -218,6 +218,52 @@ grub_verify_string (char *str, enum grub_verify_string_type type)
-   return GRUB_ERR_NONE;
- }
- 
-+/* List of modules which may allow for verifcation to be bypassed. */
-+static const char *const disabled_mods[] = { "iorw", "memrw", "wrmsr", NULL };
-+
-+/*
-+ * Does the module in file `io' allow for the a verifier to be bypassed?
-+ *
-+ * Returns 1 if so, otherwise 0.
-+ */
-+char
-+grub_is_dangerous_module (grub_file_t io)
-+{
-+  char *b, *e;
-+  int i;
-+
-+  /* Establish GRUB module name. */
-+  b = grub_strrchr (io->name, '/');
-+  e = grub_strrchr (io->name, '.');
-+
-+  b = b ? (b + 1) : io->name;
-+  e = e ? e : io->name + grub_strlen (io->name);
-+  e = (e > b) ? e : io->name + grub_strlen (io->name);
-+
-+  for (i = 0; disabled_mods[i]; i++)
-+    if (!grub_strncmp (b, disabled_mods[i],
-+		       grub_strlen (b) - grub_strlen (e)))
-+      return 1;
-+  return 0;
-+}
-+
-+/*
-+ * Is there already an unsafe module in memory?
-+ * Returns the name if one is loaded, otherwise NULL.
-+ */
-+const char *
-+grub_dangerous_module_loaded (void)
-+{
-+  int i;
-+
-+  for (i = 0; disabled_mods[i]; i++)
-+    if (grub_dl_get (disabled_mods[i]))
-+      {
-+	return disabled_mods[i];
-+      }
-+  return NULL;
-+}
-+
- GRUB_MOD_INIT(verifiers)
- {
-   grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
-diff --git a/include/grub/verify.h b/include/grub/verify.h
-index 79022b42258..60c13e7ea8e 100644
---- a/include/grub/verify.h
-+++ b/include/grub/verify.h
-@@ -76,3 +76,16 @@ grub_verifier_unregister (struct grub_file_verifier *ver)
- 
- grub_err_t
- grub_verify_string (char *str, enum grub_verify_string_type type);
-+
-+/*
-+ * Does the module in file `io' allow for the a verifier to be bypassed?
-+ *
-+ * Returns 1 if so, otherwise 0.
-+ */
-+char grub_is_dangerous_module (grub_file_t io);
-+
-+/*
-+ * Is there already an unsafe module in memory?
-+ * Returns the name if one is loaded, otherwise NULL.
-+ */
-+const char *grub_dangerous_module_loaded (void);
diff --git a/SOURCES/0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/SOURCES/0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
new file mode 100644
index 0000000..e8004d2
--- /dev/null
+++ b/SOURCES/0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 2 Oct 2020 10:49:26 +1000
+Subject: [PATCH] crypto: move storage for grub_crypto_pk_* to crypto.c
+
+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>
+---
+ 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 bb6543819f0..75de32c2a00 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 e6c78d16d39..ff62fa30e1a 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)
diff --git a/SOURCES/0357-pgp-factor-out-rsa_pad.patch b/SOURCES/0357-pgp-factor-out-rsa_pad.patch
deleted file mode 100644
index 79a73ec..0000000
--- a/SOURCES/0357-pgp-factor-out-rsa_pad.patch
+++ /dev/null
@@ -1,191 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 1 Oct 2020 20:23:48 +1000
-Subject: [PATCH] pgp: factor out rsa_pad
-
-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>
----
- 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 809f11feaef..99615c07b94 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2387,6 +2387,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 d39846d8cfe..bb6543819f0 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 00000000000..dbacd563d01
---- /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 00000000000..5c338c84a15
---- /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);
-+
diff --git a/SOURCES/0358-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/SOURCES/0358-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
deleted file mode 100644
index e8004d2..0000000
--- a/SOURCES/0358-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 2 Oct 2020 10:49:26 +1000
-Subject: [PATCH] crypto: move storage for grub_crypto_pk_* to crypto.c
-
-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>
----
- 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 bb6543819f0..75de32c2a00 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 e6c78d16d39..ff62fa30e1a 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)
diff --git a/SOURCES/0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/SOURCES/0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
new file mode 100644
index 0000000..2db2a84
--- /dev/null
+++ b/SOURCES/0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
@@ -0,0 +1,64 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 2 May 2020 00:27:57 +1000
+Subject: [PATCH] posix_wrap: tweaks in preparation for libtasn1
+
+ - Define SIZEOF_UNSIGNED_LONG_INT, it's the same as
+   SIZEOF_UNSIGNED_LONG.
+
+ - Define WORD_BIT, the size in bits of an int. This is a defined
+   in the Single Unix Specification and in gnulib's limits.h. gnulib
+   assumes it's 32 bits on all our platforms, including 64 bit
+   platforms, so we also use that value.
+
+ - Provide strto[u]l[l] preprocessor macros that resolve to
+   grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we
+   also define HAVE_STRTOUL here.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/posix_wrap/limits.h    | 1 +
+ grub-core/lib/posix_wrap/stdlib.h    | 8 ++++++++
+ grub-core/lib/posix_wrap/sys/types.h | 1 +
+ 3 files changed, 10 insertions(+)
+
+diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h
+index 95529540398..474a923b074 100644
+--- a/grub-core/lib/posix_wrap/limits.h
++++ b/grub-core/lib/posix_wrap/limits.h
+@@ -31,5 +31,6 @@
+ #define INT_MAX GRUB_INT_MAX
+ 
+ #define CHAR_BIT 8
++#define WORD_BIT 32
+ 
+ #endif
+diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h
+index 7a8d385e973..4634db09f29 100644
+--- a/grub-core/lib/posix_wrap/stdlib.h
++++ b/grub-core/lib/posix_wrap/stdlib.h
+@@ -58,4 +58,12 @@ abs (int c)
+   return (c >= 0) ? c : -c;
+ }
+ 
++#define strtol grub_strtol
++
++/* for libgcrypt */
++#define HAVE_STRTOUL
++#define strtoul grub_strtoul
++
++#define strtoull grub_strtoull
++
+ #endif
+diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h
+index 854eb0122ef..f63412c8da0 100644
+--- a/grub-core/lib/posix_wrap/sys/types.h
++++ b/grub-core/lib/posix_wrap/sys/types.h
+@@ -51,6 +51,7 @@ typedef grub_uint8_t byte;
+ typedef grub_addr_t uintptr_t;
+ 
+ #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG
++#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG
+ #define SIZEOF_UNSIGNED_INT 4
+ #define SIZEOF_UNSIGNED_LONG_LONG 8
+ #define SIZEOF_UNSIGNED_SHORT 2
diff --git a/SOURCES/0359-libtasn1-import-libtasn1-4.16.0.patch b/SOURCES/0359-libtasn1-import-libtasn1-4.16.0.patch
new file mode 100644
index 0000000..89552c8
--- /dev/null
+++ b/SOURCES/0359-libtasn1-import-libtasn1-4.16.0.patch
@@ -0,0 +1,8934 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 10 Jun 2020 16:31:22 +1000
+Subject: [PATCH] libtasn1: import libtasn1-4.16.0
+
+Import a very trimmed-down set of libtasn1 files:
+
+pushd /tmp
+wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz
+popd
+pushd grub-core/lib
+mkdir libtasn1
+cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/
+mkdir libtasn1/lib
+cp /tmp/libtasn1-4.16.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h}  libtasn1/lib
+cp /tmp/libtasn1-4.16.0/lib/includes/libtasn1.h ../../include/grub/
+git add libtasn1/ ../../include/grub/libtasn1.h
+popd
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/libtasn1/lib/coding.c     | 1415 ++++++++++++++++++
+ grub-core/lib/libtasn1/lib/decoding.c   | 2478 +++++++++++++++++++++++++++++++
+ grub-core/lib/libtasn1/lib/element.c    | 1111 ++++++++++++++
+ grub-core/lib/libtasn1/lib/errors.c     |  100 ++
+ grub-core/lib/libtasn1/lib/gstr.c       |   74 +
+ grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++
+ grub-core/lib/libtasn1/lib/structure.c  | 1220 +++++++++++++++
+ grub-core/lib/libtasn1/lib/element.h    |   40 +
+ grub-core/lib/libtasn1/lib/gstr.h       |   47 +
+ grub-core/lib/libtasn1/lib/int.h        |  221 +++
+ grub-core/lib/libtasn1/lib/parser_aux.h |  172 +++
+ grub-core/lib/libtasn1/lib/structure.h  |   45 +
+ include/grub/libtasn1.h                 |  588 ++++++++
+ grub-core/lib/libtasn1/LICENSE          |   16 +
+ grub-core/lib/libtasn1/README.md        |   91 ++
+ 15 files changed, 8791 insertions(+)
+ create mode 100644 grub-core/lib/libtasn1/lib/coding.c
+ create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
+ create mode 100644 grub-core/lib/libtasn1/lib/element.c
+ create mode 100644 grub-core/lib/libtasn1/lib/errors.c
+ create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
+ create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
+ create mode 100644 grub-core/lib/libtasn1/lib/structure.c
+ create mode 100644 grub-core/lib/libtasn1/lib/element.h
+ create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
+ create mode 100644 grub-core/lib/libtasn1/lib/int.h
+ create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
+ create mode 100644 grub-core/lib/libtasn1/lib/structure.h
+ create mode 100644 include/grub/libtasn1.h
+ create mode 100644 grub-core/lib/libtasn1/LICENSE
+ create mode 100644 grub-core/lib/libtasn1/README.md
+
+diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
+new file mode 100644
+index 00000000000..245ea64cf0a
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/coding.c
+@@ -0,0 +1,1415 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++
++/*****************************************************/
++/* File: coding.c                                    */
++/* Description: Functions to create a DER coding of  */
++/*   an ASN1 type.                                   */
++/*****************************************************/
++
++#include <int.h>
++#include "parser_aux.h"
++#include <gstr.h>
++#include "element.h"
++#include "minmax.h"
++#include <structure.h>
++
++#define MAX_TAG_LEN 16
++
++/******************************************************/
++/* Function : _asn1_error_description_value_not_found */
++/* Description: creates the ErrorDescription string   */
++/* for the ASN1_VALUE_NOT_FOUND error.                */
++/* Parameters:                                        */
++/*   node: node of the tree where the value is NULL.  */
++/*   ErrorDescription: string returned.               */
++/* Return:                                            */
++/******************************************************/
++static void
++_asn1_error_description_value_not_found (asn1_node node,
++					 char *ErrorDescription)
++{
++
++  if (ErrorDescription == NULL)
++    return;
++
++  Estrcpy (ErrorDescription, ":: value of element '");
++  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
++			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
++  Estrcat (ErrorDescription, "' not found");
++
++}
++
++/**
++ * asn1_length_der:
++ * @len: value to convert.
++ * @der: buffer to hold the returned encoding (may be %NULL).
++ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]).
++ *
++ * Creates the DER encoding of the provided length value.
++ * The @der buffer must have enough room for the output. The maximum
++ * length this function will encode is %ASN1_MAX_LENGTH_SIZE.
++ *
++ * To know the size of the DER encoding use a %NULL value for @der.
++ **/
++void
++asn1_length_der (unsigned long int len, unsigned char *der, int *der_len)
++{
++  int k;
++  unsigned char temp[ASN1_MAX_LENGTH_SIZE];
++#if SIZEOF_UNSIGNED_LONG_INT > 8
++  len &= 0xFFFFFFFFFFFFFFFF;
++#endif
++
++  if (len < 128)
++    {
++      /* short form */
++      if (der != NULL)
++	der[0] = (unsigned char) len;
++      *der_len = 1;
++    }
++  else
++    {
++      /* Long form */
++      k = 0;
++      while (len)
++	{
++	  temp[k++] = len & 0xFF;
++	  len = len >> 8;
++	}
++      *der_len = k + 1;
++      if (der != NULL)
++	{
++	  der[0] = ((unsigned char) k & 0x7F) + 128;
++	  while (k--)
++	    der[*der_len - 1 - k] = temp[k];
++	}
++    }
++}
++
++/******************************************************/
++/* Function : _asn1_tag_der                           */
++/* Description: creates the DER coding for the CLASS  */
++/* and TAG parameters.                                */
++/* It is limited by the ASN1_MAX_TAG_SIZE variable    */
++/* Parameters:                                        */
++/*   class: value to convert.                         */
++/*   tag_value: value to convert.                     */
++/*   ans: string returned.                            */
++/*   ans_len: number of meaningful bytes of ANS       */
++/*            (ans[0]..ans[ans_len-1]).               */
++/* Return:                                            */
++/******************************************************/
++static void
++_asn1_tag_der (unsigned char class, unsigned int tag_value,
++	       unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len)
++{
++  int k;
++  unsigned char temp[ASN1_MAX_TAG_SIZE];
++
++  if (tag_value < 31)
++    {
++      /* short form */
++      ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F));
++      *ans_len = 1;
++    }
++  else
++    {
++      /* Long form */
++      ans[0] = (class & 0xE0) + 31;
++      k = 0;
++      while (tag_value != 0)
++	{
++	  temp[k++] = tag_value & 0x7F;
++	  tag_value >>= 7;
++
++	  if (k > ASN1_MAX_TAG_SIZE - 1)
++	    break;		/* will not encode larger tags */
++	}
++      *ans_len = k + 1;
++      while (k--)
++	ans[*ans_len - 1 - k] = temp[k] + 128;
++      ans[*ans_len - 1] -= 128;
++    }
++}
++
++/**
++ * asn1_octet_der:
++ * @str: the input data.
++ * @str_len: STR length (str[0]..str[*str_len-1]).
++ * @der: encoded string returned.
++ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]).
++ *
++ * Creates a length-value DER encoding for the input data.
++ * The DER encoding of the input data will be placed in the @der variable.
++ *
++ * Note that the OCTET STRING tag is not included in the output.
++ *
++ * This function does not return any value because it is expected
++ * that @der_len will contain enough bytes to store the string
++ * plus the DER encoding. The DER encoding size can be obtained using
++ * asn1_length_der().
++ **/
++void
++asn1_octet_der (const unsigned char *str, int str_len,
++		unsigned char *der, int *der_len)
++{
++  int len_len;
++
++  if (der == NULL || str_len < 0)
++    return;
++
++  asn1_length_der (str_len, der, &len_len);
++  memcpy (der + len_len, str, str_len);
++  *der_len = str_len + len_len;
++}
++
++
++/**
++ * asn1_encode_simple_der:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @str: the string data.
++ * @str_len: the string length
++ * @tl: the encoded tag and length
++ * @tl_len: the bytes of the @tl field
++ *
++ * Creates the DER encoding for various simple ASN.1 types like strings etc.
++ * It stores the tag and length in @tl, which should have space for at least
++ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl.
++ *
++ * The complete DER encoding should consist of the value in @tl appended
++ * with the provided @str.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ **/
++int
++asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
++			unsigned int str_len, unsigned char *tl,
++			unsigned int *tl_len)
++{
++  int tag_len, len_len;
++  unsigned tlen;
++  unsigned char der_tag[ASN1_MAX_TAG_SIZE];
++  unsigned char der_length[ASN1_MAX_LENGTH_SIZE];
++  unsigned char *p;
++
++  if (str == NULL)
++    return ASN1_VALUE_NOT_VALID;
++
++  if (ETYPE_OK (etype) == 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  /* doesn't handle constructed classes */
++  if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL)
++    return ASN1_VALUE_NOT_VALID;
++
++  _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len);
++
++  asn1_length_der (str_len, der_length, &len_len);
++
++  if (tag_len <= 0 || len_len <= 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  tlen = tag_len + len_len;
++
++  if (*tl_len < tlen)
++    return ASN1_MEM_ERROR;
++
++  p = tl;
++  memcpy (p, der_tag, tag_len);
++  p += tag_len;
++  memcpy (p, der_length, len_len);
++
++  *tl_len = tlen;
++
++  return ASN1_SUCCESS;
++}
++
++/******************************************************/
++/* Function : _asn1_time_der                          */
++/* Description: creates the DER coding for a TIME     */
++/* type (length included).                            */
++/* Parameters:                                        */
++/*   str: TIME null-terminated string.                */
++/*   der: string returned.                            */
++/*   der_len: number of meaningful bytes of DER       */
++/*            (der[0]..der[ans_len-1]). Initially it  */
++/*            if must store the lenght of DER.        */
++/* Return:                                            */
++/*   ASN1_MEM_ERROR when DER isn't big enough         */
++/*   ASN1_SUCCESS otherwise                           */
++/******************************************************/
++static int
++_asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
++		int *der_len)
++{
++  int len_len;
++  int max_len;
++
++  if (der == NULL)
++    return ASN1_VALUE_NOT_VALID;
++
++  max_len = *der_len;
++
++  asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len);
++
++  if ((len_len + str_len) <= max_len)
++    memcpy (der + len_len, str, str_len);
++  *der_len = len_len + str_len;
++
++  if ((*der_len) > max_len)
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++
++/*
++void
++_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str)
++{
++  int len_len,str_len;
++  char temp[20];
++
++  if(str==NULL) return;
++  str_len=asn1_get_length_der(der,*der_len,&len_len);
++  if (str_len<0) return;
++  memcpy(temp,der+len_len,str_len);
++  *der_len=str_len+len_len;
++  switch(str_len)
++  {
++  case 11:
++    temp[10]=0;
++    strcat(temp,"00+0000");
++    break;
++  case 13:
++    temp[12]=0;
++    strcat(temp,"+0000");
++    break;
++  case 15:
++    temp[15]=0;
++    memmove(temp+12,temp+10,6);
++    temp[10]=temp[11]='0';
++    break;
++  case 17:
++    temp[17]=0;
++    break;
++  default:
++    return;
++  }
++  strcpy(str,temp);
++}
++*/
++
++static
++void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len)
++{
++  int first, k;
++  unsigned char bit7;
++
++  first = 0;
++  for (k = sizeof(val); k >= 0; k--)
++    {
++      bit7 = (val >> (k * 7)) & 0x7F;
++      if (bit7 || first || !k)
++	{
++	  if (k)
++	    bit7 |= 0x80;
++	  if (max_len > (*der_len))
++	    der[*der_len] = bit7;
++	  (*der_len)++;
++	  first = 1;
++	}
++    }
++}
++
++/******************************************************/
++/* Function : _asn1_object_id_der                     */
++/* Description: creates the DER coding for an         */
++/* OBJECT IDENTIFIER  type (length included).         */
++/* Parameters:                                        */
++/*   str: OBJECT IDENTIFIER null-terminated string.   */
++/*   der: string returned.                            */
++/*   der_len: number of meaningful bytes of DER       */
++/*            (der[0]..der[ans_len-1]). Initially it  */
++/*            must store the length of DER.           */
++/* Return:                                            */
++/*   ASN1_MEM_ERROR when DER isn't big enough         */
++/*   ASN1_SUCCESS if succesful                        */
++/*   or an error value.                               */
++/******************************************************/
++static int
++_asn1_object_id_der (const char *str, unsigned char *der, int *der_len)
++{
++  int len_len, counter, max_len;
++  char *temp, *n_end, *n_start;
++  uint64_t val, val1 = 0;
++  int str_len = _asn1_strlen (str);
++
++  max_len = *der_len;
++  *der_len = 0;
++
++  if (der == NULL && max_len > 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  temp = malloc (str_len + 2);
++  if (temp == NULL)
++    return ASN1_MEM_ALLOC_ERROR;
++
++  memcpy (temp, str, str_len);
++  temp[str_len] = '.';
++  temp[str_len + 1] = 0;
++
++  counter = 0;
++  n_start = temp;
++  while ((n_end = strchr (n_start, '.')))
++    {
++      *n_end = 0;
++      val = _asn1_strtou64 (n_start, NULL, 10);
++      counter++;
++
++      if (counter == 1)
++        {
++	  val1 = val;
++	}
++      else if (counter == 2)
++	{
++	  uint64_t val0;
++
++          if (val1 > 2)
++            {
++              free(temp);
++              return ASN1_VALUE_NOT_VALID;
++            }
++          else if ((val1 == 0 || val1 == 1) && val > 39)
++            {
++              free(temp);
++              return ASN1_VALUE_NOT_VALID;
++            }
++
++	  val0 = 40 * val1 + val;
++	  encode_val(val0, der, max_len, der_len);
++	}
++      else
++	{
++	  encode_val(val, der, max_len, der_len);
++	}
++      n_start = n_end + 1;
++    }
++
++  asn1_length_der (*der_len, NULL, &len_len);
++  if (max_len >= (*der_len + len_len))
++    {
++      memmove (der + len_len, der, *der_len);
++      asn1_length_der (*der_len, der, &len_len);
++    }
++  *der_len += len_len;
++
++  free (temp);
++
++  if (max_len < (*der_len))
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_object_id_der:
++ * @str: An object identifier in numeric, dot format.
++ * @der: buffer to hold the returned encoding (may be %NULL).
++ * @der_len: initially the size of @der; will hold the final size.
++ * @flags: must be zero
++ *
++ * Creates the DER encoding of the provided object identifier.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID
++ *   if @str is not a valid OID, %ASN1_MEM_ERROR if the @der
++ *   vector isn't big enough and in this case @der_len will contain the
++ *   length needed.
++ **/
++int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags)
++{
++  unsigned char tag_der[MAX_TAG_LEN];
++  int tag_len = 0, r;
++  int max_len = *der_len;
++
++  *der_len = 0;
++
++  _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID),
++                 tag_der, &tag_len);
++
++  if (max_len > tag_len)
++    {
++      memcpy(der, tag_der, tag_len);
++    }
++  max_len -= tag_len;
++  der += tag_len;
++
++  r = _asn1_object_id_der (str, der, &max_len);
++  if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS)
++    {
++      *der_len = max_len + tag_len;
++    }
++
++  return r;
++}
++
++static const unsigned char bit_mask[] =
++  { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };
++
++/**
++ * asn1_bit_der:
++ * @str: BIT string.
++ * @bit_len: number of meaningful bits in STR.
++ * @der: string returned.
++ * @der_len: number of meaningful bytes of DER
++ *   (der[0]..der[ans_len-1]).
++ *
++ * Creates a length-value DER encoding for the input data
++ * as it would have been for a BIT STRING.
++ * The DER encoded data will be copied in @der.
++ *
++ * Note that the BIT STRING tag is not included in the output.
++ *
++ * This function does not return any value because it is expected
++ * that @der_len will contain enough bytes to store the string
++ * plus the DER encoding. The DER encoding size can be obtained using
++ * asn1_length_der().
++ **/
++void
++asn1_bit_der (const unsigned char *str, int bit_len,
++	      unsigned char *der, int *der_len)
++{
++  int len_len, len_byte, len_pad;
++
++  if (der == NULL)
++    return;
++
++  len_byte = bit_len >> 3;
++  len_pad = 8 - (bit_len & 7);
++  if (len_pad == 8)
++    len_pad = 0;
++  else
++    len_byte++;
++  asn1_length_der (len_byte + 1, der, &len_len);
++  der[len_len] = len_pad;
++
++  if (str)
++    memcpy (der + len_len + 1, str, len_byte);
++  der[len_len + len_byte] &= bit_mask[len_pad];
++  *der_len = len_byte + len_len + 1;
++}
++
++
++/******************************************************/
++/* Function : _asn1_complete_explicit_tag             */
++/* Description: add the length coding to the EXPLICIT */
++/* tags.                                              */
++/* Parameters:                                        */
++/*   node: pointer to the tree element.               */
++/*   der: string with the DER coding of the whole tree*/
++/*   counter: number of meaningful bytes of DER       */
++/*            (der[0]..der[*counter-1]).              */
++/*   max_len: size of der vector                      */
++/* Return:                                            */
++/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
++/*   otherwise ASN1_SUCCESS.                          */
++/******************************************************/
++static int
++_asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
++			     int *counter, int *max_len)
++{
++  asn1_node p;
++  int is_tag_implicit, len2, len3;
++  unsigned char temp[SIZEOF_UNSIGNED_INT];
++
++  if (der == NULL && *max_len > 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  is_tag_implicit = 0;
++
++  if (node->type & CONST_TAG)
++    {
++      p = node->down;
++      if (p == NULL)
++        return ASN1_DER_ERROR;
++      /* When there are nested tags we must complete them reverse to
++         the order they were created. This is because completing a tag
++         modifies all data within it, including the incomplete tags
++         which store buffer positions -- simon@josefsson.org 2002-09-06
++       */
++      while (p->right)
++	p = p->right;
++      while (p && p != node->down->left)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if (p->type & CONST_EXPLICIT)
++		{
++		  len2 = strtol (p->name, NULL, 10);
++		  _asn1_set_name (p, NULL);
++
++		  asn1_length_der (*counter - len2, temp, &len3);
++		  if (len3 <= (*max_len))
++		    {
++		      memmove (der + len2 + len3, der + len2,
++			       *counter - len2);
++		      memcpy (der + len2, temp, len3);
++		    }
++		  *max_len -= len3;
++		  *counter += len3;
++		  is_tag_implicit = 0;
++		}
++	      else
++		{		/* CONST_IMPLICIT */
++		  if (!is_tag_implicit)
++		    {
++		      is_tag_implicit = 1;
++		    }
++		}
++	    }
++	  p = p->left;
++	}
++    }
++
++  if (*max_len < 0)
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++const tag_and_class_st _asn1_tags[] = {
++  [ASN1_ETYPE_GENERALSTRING] =
++    {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"},
++  [ASN1_ETYPE_NUMERIC_STRING] =
++    {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"},
++  [ASN1_ETYPE_IA5_STRING] =
++    {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"},
++  [ASN1_ETYPE_TELETEX_STRING] =
++    {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"},
++  [ASN1_ETYPE_PRINTABLE_STRING] =
++    {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"},
++  [ASN1_ETYPE_UNIVERSAL_STRING] =
++    {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"},
++  [ASN1_ETYPE_BMP_STRING] =
++    {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"},
++  [ASN1_ETYPE_UTF8_STRING] =
++    {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"},
++  [ASN1_ETYPE_VISIBLE_STRING] =
++    {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"},
++  [ASN1_ETYPE_OCTET_STRING] =
++    {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"},
++  [ASN1_ETYPE_BIT_STRING] =
++    {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"},
++  [ASN1_ETYPE_OBJECT_ID] =
++    {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"},
++  [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"},
++  [ASN1_ETYPE_BOOLEAN] =
++    {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"},
++  [ASN1_ETYPE_INTEGER] =
++    {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"},
++  [ASN1_ETYPE_ENUMERATED] =
++    {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"},
++  [ASN1_ETYPE_SEQUENCE] =
++    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
++     "type:SEQUENCE"},
++  [ASN1_ETYPE_SEQUENCE_OF] =
++    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
++     "type:SEQ_OF"},
++  [ASN1_ETYPE_SET] =
++    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"},
++  [ASN1_ETYPE_SET_OF] =
++    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
++     "type:SET_OF"},
++  [ASN1_ETYPE_GENERALIZED_TIME] =
++    {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"},
++  [ASN1_ETYPE_UTC_TIME] =
++    {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"},
++};
++
++unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
++
++/******************************************************/
++/* Function : _asn1_insert_tag_der                    */
++/* Description: creates the DER coding of tags of one */
++/* NODE.                                              */
++/* Parameters:                                        */
++/*   node: pointer to the tree element.               */
++/*   der: string returned                             */
++/*   counter: number of meaningful bytes of DER       */
++/*            (counter[0]..der[*counter-1]).          */
++/*   max_len: size of der vector                      */
++/* Return:                                            */
++/*   ASN1_GENERIC_ERROR if the type is unknown,       */
++/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
++/*   otherwise ASN1_SUCCESS.                          */
++/******************************************************/
++static int
++_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter,
++		      int *max_len)
++{
++  asn1_node p;
++  int tag_len, is_tag_implicit;
++  unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)];
++  unsigned long tag_implicit = 0;
++  unsigned char tag_der[MAX_TAG_LEN];
++
++  is_tag_implicit = 0;
++
++  if (node->type & CONST_TAG)
++    {
++      p = node->down;
++      while (p)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if (p->type & CONST_APPLICATION)
++		class = ASN1_CLASS_APPLICATION;
++	      else if (p->type & CONST_UNIVERSAL)
++		class = ASN1_CLASS_UNIVERSAL;
++	      else if (p->type & CONST_PRIVATE)
++		class = ASN1_CLASS_PRIVATE;
++	      else
++		class = ASN1_CLASS_CONTEXT_SPECIFIC;
++
++	      if (p->type & CONST_EXPLICIT)
++		{
++		  if (is_tag_implicit)
++		    _asn1_tag_der (class_implicit, tag_implicit, tag_der,
++				   &tag_len);
++		  else
++		    _asn1_tag_der (class | ASN1_CLASS_STRUCTURED,
++				   _asn1_strtoul (p->value, NULL, 10),
++				   tag_der, &tag_len);
++
++		  *max_len -= tag_len;
++		  if (der && *max_len >= 0)
++		    memcpy (der + *counter, tag_der, tag_len);
++		  *counter += tag_len;
++
++		  _asn1_ltostr (*counter, (char *) temp);
++		  _asn1_set_name (p, (const char *) temp);
++
++		  is_tag_implicit = 0;
++		}
++	      else
++		{		/* CONST_IMPLICIT */
++		  if (!is_tag_implicit)
++		    {
++		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
++			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
++			  || (type_field (node->type) == ASN1_ETYPE_SET)
++			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
++			class |= ASN1_CLASS_STRUCTURED;
++		      class_implicit = class;
++		      tag_implicit = _asn1_strtoul (p->value, NULL, 10);
++		      is_tag_implicit = 1;
++		    }
++		}
++	    }
++	  p = p->right;
++	}
++    }
++
++  if (is_tag_implicit)
++    {
++      _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len);
++    }
++  else
++    {
++      unsigned type = type_field (node->type);
++      switch (type)
++	{
++	CASE_HANDLED_ETYPES:
++	  _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag,
++			 tag_der, &tag_len);
++	  break;
++	case ASN1_ETYPE_TAG:
++	case ASN1_ETYPE_CHOICE:
++	case ASN1_ETYPE_ANY:
++	  tag_len = 0;
++	  break;
++	default:
++	  return ASN1_GENERIC_ERROR;
++	}
++    }
++
++  *max_len -= tag_len;
++  if (der && *max_len >= 0)
++    memcpy (der + *counter, tag_der, tag_len);
++  *counter += tag_len;
++
++  if (*max_len < 0)
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++/******************************************************/
++/* Function : _asn1_ordering_set                      */
++/* Description: puts the elements of a SET type in    */
++/* the correct order according to DER rules.          */
++/* Parameters:                                        */
++/*   der: string with the DER coding.                 */
++/*   node: pointer to the SET element.                */
++/* Return:                                            */
++/*    ASN1_SUCCESS if successful                      */
++/*    or an error value.                              */
++/******************************************************/
++static int
++_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node)
++{
++  struct vet
++  {
++    int end;
++    unsigned long value;
++    struct vet *next, *prev;
++  };
++
++  int counter, len, len2;
++  struct vet *first, *last, *p_vet, *p2_vet;
++  asn1_node p;
++  unsigned char class, *temp;
++  unsigned long tag, t;
++  int err;
++
++  counter = 0;
++
++  if (type_field (node->type) != ASN1_ETYPE_SET)
++    return ASN1_VALUE_NOT_VALID;
++
++  p = node->down;
++  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
++	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
++    p = p->right;
++
++  if ((p == NULL) || (p->right == NULL))
++    return ASN1_SUCCESS;
++
++  first = last = NULL;
++  while (p)
++    {
++      p_vet = malloc (sizeof (struct vet));
++      if (p_vet == NULL)
++        {
++	  err = ASN1_MEM_ALLOC_ERROR;
++	  goto error;
++	}
++
++      p_vet->next = NULL;
++      p_vet->prev = last;
++      if (first == NULL)
++	first = p_vet;
++      else
++	last->next = p_vet;
++      last = p_vet;
++
++      /* tag value calculation */
++      err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2,
++			      &tag);
++      if (err != ASN1_SUCCESS)
++	goto error;
++
++      t = ((unsigned int)class) << 24;
++      p_vet->value = t | tag;
++      counter += len2;
++
++      /* extraction and length */
++      len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
++      if (len2 < 0)
++	{
++	  err = ASN1_DER_ERROR;
++	  goto error;
++	}
++      counter += len + len2;
++
++      p_vet->end = counter;
++      p = p->right;
++    }
++
++  p_vet = first;
++
++  while (p_vet)
++    {
++      p2_vet = p_vet->next;
++      counter = 0;
++      while (p2_vet)
++	{
++	  if (p_vet->value > p2_vet->value)
++	    {
++	      /* change position */
++	      temp = malloc (p_vet->end - counter);
++	      if (temp == NULL)
++		{
++		  err = ASN1_MEM_ALLOC_ERROR;
++		  goto error;
++		}
++
++	      memcpy (temp, der + counter, p_vet->end - counter);
++	      memcpy (der + counter, der + p_vet->end,
++		      p2_vet->end - p_vet->end);
++	      memcpy (der + counter + p2_vet->end - p_vet->end, temp,
++		      p_vet->end - counter);
++	      free (temp);
++
++	      tag = p_vet->value;
++	      p_vet->value = p2_vet->value;
++	      p2_vet->value = tag;
++
++	      p_vet->end = counter + (p2_vet->end - p_vet->end);
++	    }
++	  counter = p_vet->end;
++
++	  p2_vet = p2_vet->next;
++	  p_vet = p_vet->next;
++	}
++
++      if (p_vet != first)
++	p_vet->prev->next = NULL;
++      else
++	first = NULL;
++      free (p_vet);
++      p_vet = first;
++    }
++  return ASN1_SUCCESS;
++
++error:
++  while (first != NULL)
++    {
++      p_vet = first;
++      first = first->next;
++      free(p_vet);
++    }
++  return err;
++}
++
++struct vet
++{
++  unsigned char *ptr;
++  int size;
++};
++
++static int setof_compar(const void *_e1, const void *_e2)
++{
++  unsigned length;
++  const struct vet *e1 = _e1, *e2 = _e2;
++  int rval;
++
++  /* The encodings of the component values of a set-of value shall
++   * appear in ascending order, the encodings being compared
++   * as octet strings with the shorter components being
++   * padded at their trailing end with 0-octets.
++   * The padding octets are for comparison purposes and
++   * do not appear in the encodings.
++   */
++  length = MIN(e1->size, e2->size);
++
++  rval = memcmp(e1->ptr, e2->ptr, length);
++  if (rval == 0 && e1->size != e2->size)
++    {
++      if (e1->size > e2->size)
++        rval = 1;
++      else if (e2->size > e1->size)
++        rval = -1;
++    }
++
++  return rval;
++}
++
++/******************************************************/
++/* Function : _asn1_ordering_set_of                   */
++/* Description: puts the elements of a SET OF type in */
++/* the correct order according to DER rules.          */
++/* Parameters:                                        */
++/*   der: string with the DER coding.                 */
++/*   node: pointer to the SET OF element.             */
++/* Return:                                            */
++/*    ASN1_SUCCESS if successful                      */
++/*    or an error value.                              */
++/******************************************************/
++static int
++_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node)
++{
++  int counter, len, len2;
++  struct vet *list = NULL, *tlist;
++  unsigned list_size = 0;
++  struct vet *p_vet;
++  asn1_node p;
++  unsigned char class;
++  unsigned i;
++  unsigned char *out = NULL;
++  int err;
++
++  if (der == NULL)
++    return ASN1_VALUE_NOT_VALID;
++
++  counter = 0;
++
++  if (type_field (node->type) != ASN1_ETYPE_SET_OF)
++    return ASN1_VALUE_NOT_VALID;
++
++  p = node->down;
++  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
++	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
++    p = p->right;
++  if (p == NULL)
++    return ASN1_VALUE_NOT_VALID;
++  p = p->right;
++
++  if ((p == NULL) || (p->right == NULL))
++    return ASN1_SUCCESS;
++
++  while (p)
++    {
++      list_size++;
++      tlist = realloc (list, list_size*sizeof(struct vet));
++      if (tlist == NULL)
++	{
++	  err = ASN1_MEM_ALLOC_ERROR;
++	  goto error;
++	}
++      list = tlist;
++      p_vet = &list[list_size-1];
++
++      p_vet->ptr = der+counter;
++      p_vet->size = 0;
++
++      /* extraction of tag and length */
++      if (der_len - counter > 0)
++	{
++	  err = asn1_get_tag_der (der + counter, der_len - counter, &class,
++	                          &len, NULL);
++	  if (err != ASN1_SUCCESS)
++	    goto error;
++	  counter += len;
++          p_vet->size += len;
++
++	  len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
++	  if (len2 < 0)
++	    {
++	      err = ASN1_DER_ERROR;
++	      goto error;
++	    }
++	  counter += len + len2;
++          p_vet->size += len + len2;
++
++	}
++      else
++	{
++	  err = ASN1_DER_ERROR;
++	  goto error;
++	}
++      p = p->right;
++    }
++
++  if (counter > der_len)
++    {
++      err = ASN1_DER_ERROR;
++      goto error;
++    }
++
++  qsort(list, list_size, sizeof(struct vet), setof_compar);
++
++  out = malloc(der_len);
++  if (out == NULL)
++    {
++      err = ASN1_MEM_ERROR;
++      goto error;
++    }
++
++  /* the sum of p_vet->size == der_len */
++  counter = 0;
++  for (i = 0; i < list_size; i++)
++    {
++      p_vet = &list[i];
++      memcpy(out+counter, p_vet->ptr, p_vet->size);
++      counter += p_vet->size;
++    }
++  memcpy(der, out, der_len);
++  free(out);
++
++  err = ASN1_SUCCESS;
++
++error:
++  free(list);
++  return err;
++}
++
++/**
++ * asn1_der_coding:
++ * @element: pointer to an ASN1 element
++ * @name: the name of the structure you want to encode (it must be
++ *   inside *POINTER).
++ * @ider: vector that will contain the DER encoding. DER must be a
++ *   pointer to memory cells already allocated.
++ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy
++ *   holds the sizeof of der vector.
++ * @ErrorDescription: return the error description or an empty
++ *   string if success.
++ *
++ * Creates the DER encoding for the NAME structure (inside *POINTER
++ * structure).
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there
++ *   is an element without a value, %ASN1_MEM_ERROR if the @ider
++ *   vector isn't big enough and in this case @len will contain the
++ *   length needed.
++ **/
++int
++asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len,
++		 char *ErrorDescription)
++{
++  asn1_node node, p, p2;
++  unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)];
++  int counter, counter_old, len2, len3, move, max_len, max_len_old;
++  int err;
++  unsigned char *der = ider;
++
++  if (ErrorDescription)
++    ErrorDescription[0] = 0;
++
++  node = asn1_find_node (element, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  /* Node is now a locally allocated variable.
++   * That is because in some point we modify the
++   * structure, and I don't know why! --nmav
++   */
++  node = _asn1_copy_structure3 (node);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  max_len = *len;
++
++  if (der == NULL && max_len > 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  counter = 0;
++  move = DOWN;
++  p = node;
++
++  while (1)
++    {
++
++      counter_old = counter;
++      max_len_old = max_len;
++      if (move != UP)
++	{
++          p->start = counter;
++	  err = _asn1_insert_tag_der (p, der, &counter, &max_len);
++	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++	    goto error;
++	}
++      switch (type_field (p->type))
++	{
++	case ASN1_ETYPE_NULL:
++	  max_len--;
++	  if (der != NULL && max_len >= 0)
++	    der[counter] = 0;
++	  counter++;
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_BOOLEAN:
++	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
++	    {
++	      counter = counter_old;
++	      max_len = max_len_old;
++	    }
++	  else
++	    {
++	      if (p->value == NULL)
++		{
++		  _asn1_error_description_value_not_found (p,
++							   ErrorDescription);
++		  err = ASN1_VALUE_NOT_FOUND;
++		  goto error;
++		}
++	      max_len -= 2;
++	      if (der != NULL && max_len >= 0)
++		{
++		  der[counter++] = 1;
++		  if (p->value[0] == 'F')
++		    der[counter++] = 0;
++		  else
++		    der[counter++] = 0xFF;
++		}
++	      else
++		counter += 2;
++	    }
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_INTEGER:
++	case ASN1_ETYPE_ENUMERATED:
++	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
++	    {
++	      counter = counter_old;
++	      max_len = max_len_old;
++	    }
++	  else
++	    {
++	      if (p->value == NULL)
++		{
++		  _asn1_error_description_value_not_found (p,
++							   ErrorDescription);
++		  err = ASN1_VALUE_NOT_FOUND;
++		  goto error;
++		}
++	      len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++	      if (len2 < 0)
++		{
++		  err = ASN1_DER_ERROR;
++		  goto error;
++		}
++	      max_len -= len2 + len3;
++	      if (der != NULL && max_len >= 0)
++		memcpy (der + counter, p->value, len3 + len2);
++	      counter += len3 + len2;
++	    }
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_OBJECT_ID:
++	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
++	    {
++	      counter = counter_old;
++	      max_len = max_len_old;
++	    }
++	  else
++	    {
++	      if (p->value == NULL)
++		{
++		  _asn1_error_description_value_not_found (p,
++							   ErrorDescription);
++		  err = ASN1_VALUE_NOT_FOUND;
++		  goto error;
++		}
++	      len2 = max_len;
++	      err = _asn1_object_id_der ((char*)p->value, der + counter, &len2);
++	      if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++		goto error;
++
++	      max_len -= len2;
++	      counter += len2;
++	    }
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_GENERALIZED_TIME:
++	case ASN1_ETYPE_UTC_TIME:
++	  if (p->value == NULL)
++	    {
++	      _asn1_error_description_value_not_found (p, ErrorDescription);
++	      err = ASN1_VALUE_NOT_FOUND;
++	      goto error;
++	    }
++	  len2 = max_len;
++	  err = _asn1_time_der (p->value, p->value_len, der + counter, &len2);
++	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++	    goto error;
++
++	  max_len -= len2;
++	  counter += len2;
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_OCTET_STRING:
++	case ASN1_ETYPE_GENERALSTRING:
++	case ASN1_ETYPE_NUMERIC_STRING:
++	case ASN1_ETYPE_IA5_STRING:
++	case ASN1_ETYPE_TELETEX_STRING:
++	case ASN1_ETYPE_PRINTABLE_STRING:
++	case ASN1_ETYPE_UNIVERSAL_STRING:
++	case ASN1_ETYPE_BMP_STRING:
++	case ASN1_ETYPE_UTF8_STRING:
++	case ASN1_ETYPE_VISIBLE_STRING:
++	case ASN1_ETYPE_BIT_STRING:
++	  if (p->value == NULL)
++	    {
++	      _asn1_error_description_value_not_found (p, ErrorDescription);
++	      err = ASN1_VALUE_NOT_FOUND;
++	      goto error;
++	    }
++	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++	  if (len2 < 0)
++	    {
++	      err = ASN1_DER_ERROR;
++	      goto error;
++	    }
++	  max_len -= len2 + len3;
++	  if (der != NULL && max_len >= 0)
++	    memcpy (der + counter, p->value, len3 + len2);
++	  counter += len3 + len2;
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_SEQUENCE:
++	case ASN1_ETYPE_SET:
++	  if (move != UP)
++	    {
++	      p->tmp_ival = counter;
++	      if (p->down == NULL)
++		{
++		  move = UP;
++		  continue;
++		}
++	      else
++		{
++		  p2 = p->down;
++		  while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG))
++		    p2 = p2->right;
++		  if (p2)
++		    {
++		      p = p2;
++		      move = RIGHT;
++		      continue;
++		    }
++		  move = UP;
++		  continue;
++		}
++	    }
++	  else
++	    {			/* move==UP */
++	      len2 = p->tmp_ival;
++	      p->tmp_ival = 0;
++	      if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0))
++		{
++		  err = _asn1_ordering_set (der + len2, counter - len2, p);
++		  if (err != ASN1_SUCCESS)
++		    goto error;
++		}
++	      asn1_length_der (counter - len2, temp, &len3);
++	      max_len -= len3;
++	      if (der != NULL && max_len >= 0)
++		{
++		  memmove (der + len2 + len3, der + len2, counter - len2);
++		  memcpy (der + len2, temp, len3);
++		}
++	      counter += len3;
++	      move = RIGHT;
++	    }
++	  break;
++	case ASN1_ETYPE_SEQUENCE_OF:
++	case ASN1_ETYPE_SET_OF:
++	  if (move != UP)
++	    {
++	      p->tmp_ival = counter;
++	      p = p->down;
++	      while ((type_field (p->type) == ASN1_ETYPE_TAG)
++		     || (type_field (p->type) == ASN1_ETYPE_SIZE))
++		p = p->right;
++	      if (p->right)
++		{
++		  p = p->right;
++		  move = RIGHT;
++		  continue;
++		}
++	      else
++		p = _asn1_find_up (p);
++	      move = UP;
++	    }
++	  if (move == UP)
++	    {
++	      len2 = p->tmp_ival;
++	      p->tmp_ival = 0;
++	      if ((type_field (p->type) == ASN1_ETYPE_SET_OF)
++		  && (counter - len2 > 0) && (max_len >= 0))
++		{
++		  err = _asn1_ordering_set_of (der + len2, counter - len2, p);
++		  if (err != ASN1_SUCCESS)
++		    goto error;
++		}
++	      asn1_length_der (counter - len2, temp, &len3);
++	      max_len -= len3;
++	      if (der != NULL && max_len >= 0)
++		{
++		  memmove (der + len2 + len3, der + len2, counter - len2);
++		  memcpy (der + len2, temp, len3);
++		}
++	      counter += len3;
++	      move = RIGHT;
++	    }
++	  break;
++	case ASN1_ETYPE_ANY:
++	  if (p->value == NULL)
++	    {
++	      _asn1_error_description_value_not_found (p, ErrorDescription);
++	      err = ASN1_VALUE_NOT_FOUND;
++	      goto error;
++	    }
++	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++	  if (len2 < 0)
++	    {
++	      err = ASN1_DER_ERROR;
++	      goto error;
++	    }
++	  max_len -= len2;
++	  if (der != NULL && max_len >= 0)
++	    memcpy (der + counter, p->value + len3, len2);
++	  counter += len2;
++	  move = RIGHT;
++	  break;
++	default:
++	  move = (move == UP) ? RIGHT : DOWN;
++	  break;
++	}
++
++      if ((move != DOWN) && (counter != counter_old))
++	{
++          p->end = counter - 1;
++	  err = _asn1_complete_explicit_tag (p, der, &counter, &max_len);
++	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++	    goto error;
++	}
++
++      if (p == node && move != DOWN)
++	break;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++      if (move == RIGHT)
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  *len = counter;
++
++  if (max_len < 0)
++    {
++      err = ASN1_MEM_ERROR;
++      goto error;
++    }
++
++  err = ASN1_SUCCESS;
++
++error:
++  asn1_delete_structure (&node);
++  return err;
++}
+diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
+new file mode 100644
+index 00000000000..ff04eb778cb
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/decoding.c
+@@ -0,0 +1,2478 @@
++/*
++ * Copyright (C) 2002-2016 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++
++/*****************************************************/
++/* File: decoding.c                                  */
++/* Description: Functions to manage DER decoding     */
++/*****************************************************/
++
++#include <int.h>
++#include <parser_aux.h>
++#include <gstr.h>
++#include <structure.h>
++#include <element.h>
++#include <limits.h>
++#include <intprops.h>
++#include <c-ctype.h>
++
++#ifdef DEBUG
++# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
++#else
++# define warn()
++#endif
++
++#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0))
++
++#define HAVE_TWO(x) (x>=2?1:0)
++
++/* Decoding flags (dflags) used in several decoding functions.
++ *  DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag
++ *  DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful
++ *                           when no tags are present).
++ *  DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings.
++ *  DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings.
++ *  DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings.
++ *                      This is the maximum levels of recursion possible to prevent stack
++ *                      exhaustion.
++ */
++
++#define DECODE_FLAG_HAVE_TAG 1
++#define DECODE_FLAG_CONSTRUCTED (1<<1)
++#define DECODE_FLAG_LEVEL1 (1<<2)
++#define DECODE_FLAG_LEVEL2 (1<<3)
++#define DECODE_FLAG_LEVEL3 (1<<4)
++
++#define DECR_LEN(l, s) do { \
++	  l -= s; \
++	  if (l < 0) { \
++	    warn(); \
++	    result = ASN1_DER_ERROR; \
++	    goto cleanup; \
++	  } \
++	} while (0)
++
++static int
++_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len);
++
++static int
++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, unsigned char **str,
++			unsigned int *str_len, unsigned int *ber_len,
++			unsigned dflags);
++
++static int
++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, const unsigned char **str,
++			unsigned int *str_len, unsigned dflags);
++
++static void
++_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription)
++{
++
++  Estrcpy (ErrorDescription, ":: tag error near element '");
++  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
++			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
++  Estrcat (ErrorDescription, "'");
++
++}
++
++/**
++ * asn1_get_length_der:
++ * @der: DER data to decode.
++ * @der_len: Length of DER data to decode.
++ * @len: Output variable containing the length of the DER length field.
++ *
++ * Extract a length field from DER data.
++ *
++ * Returns: Return the decoded length value, or -1 on indefinite
++ *   length, or -2 when the value was too big to fit in a int, or -4
++ *   when the decoded length value plus @len would exceed @der_len.
++ **/
++long
++asn1_get_length_der (const unsigned char *der, int der_len, int *len)
++{
++  unsigned int ans;
++  int k, punt, sum;
++
++  *len = 0;
++  if (der_len <= 0)
++    return 0;
++
++  if (!(der[0] & 128))
++    {
++      /* short form */
++      *len = 1;
++      ans = der[0];
++    }
++  else
++    {
++      /* Long form */
++      k = der[0] & 0x7F;
++      punt = 1;
++      if (k)
++	{ /* definite length method */
++	  ans = 0;
++	  while (punt <= k && punt < der_len)
++	    {
++	      if (INT_MULTIPLY_OVERFLOW (ans, 256))
++		return -2;
++	      ans *= 256;
++
++	      if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
++		return -2;
++	      ans += der[punt];
++	      punt++;
++	    }
++	}
++      else
++	{			/* indefinite length method */
++	  *len = punt;
++	  return -1;
++	}
++
++      *len = punt;
++    }
++
++  sum = ans;
++  if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len)))
++    return -2;
++  sum += *len;
++
++  if (sum > der_len)
++    return -4;
++
++  return ans;
++}
++
++/**
++ * asn1_get_tag_der:
++ * @der: DER data to decode.
++ * @der_len: Length of DER data to decode.
++ * @cls: Output variable containing decoded class.
++ * @len: Output variable containing the length of the DER TAG data.
++ * @tag: Output variable containing the decoded tag (may be %NULL).
++ *
++ * Decode the class and TAG from DER code.
++ *
++ * Returns: Returns %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_tag_der (const unsigned char *der, int der_len,
++		  unsigned char *cls, int *len, unsigned long *tag)
++{
++  unsigned int ris;
++  int punt;
++
++  if (der == NULL || der_len < 2 || len == NULL)
++    return ASN1_DER_ERROR;
++
++  *cls = der[0] & 0xE0;
++  if ((der[0] & 0x1F) != 0x1F)
++    {
++      /* short form */
++      *len = 1;
++      ris = der[0] & 0x1F;
++    }
++  else
++    {
++      /* Long form */
++      punt = 1;
++      ris = 0;
++      while (punt < der_len && der[punt] & 128)
++	{
++
++	  if (INT_MULTIPLY_OVERFLOW (ris, 128))
++	    return ASN1_DER_ERROR;
++	  ris *= 128;
++
++	  if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
++	    return ASN1_DER_ERROR;
++	  ris += (der[punt] & 0x7F);
++	  punt++;
++	}
++
++      if (punt >= der_len)
++	return ASN1_DER_ERROR;
++
++      if (INT_MULTIPLY_OVERFLOW (ris, 128))
++	return ASN1_DER_ERROR;
++      ris *= 128;
++
++      if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
++	return ASN1_DER_ERROR;
++      ris += (der[punt] & 0x7F);
++      punt++;
++
++      *len = punt;
++    }
++
++  if (tag)
++    *tag = ris;
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_get_length_ber:
++ * @ber: BER data to decode.
++ * @ber_len: Length of BER data to decode.
++ * @len: Output variable containing the length of the BER length field.
++ *
++ * Extract a length field from BER data.  The difference to
++ * asn1_get_length_der() is that this function will return a length
++ * even if the value has indefinite encoding.
++ *
++ * Returns: Return the decoded length value, or negative value when
++ *   the value was too big.
++ *
++ * Since: 2.0
++ **/
++long
++asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len)
++{
++  int ret;
++  long err;
++
++  ret = asn1_get_length_der (ber, ber_len, len);
++
++  if (ret == -1 && ber_len > 1)
++    {				/* indefinite length method */
++      err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret);
++      if (err != ASN1_SUCCESS)
++	return -3;
++    }
++
++  return ret;
++}
++
++/**
++ * asn1_get_octet_der:
++ * @der: DER data to decode containing the OCTET SEQUENCE.
++ * @der_len: The length of the @der data to decode.
++ * @ret_len: Output variable containing the encoded length of the DER data.
++ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in.
++ * @str_size: Length of pre-allocated output buffer.
++ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE.
++ *
++ * Extract an OCTET SEQUENCE from DER data. Note that this function
++ * expects the DER data past the tag field, i.e., the length and
++ * content octets.
++ *
++ * Returns: Returns %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_octet_der (const unsigned char *der, int der_len,
++		    int *ret_len, unsigned char *str, int str_size,
++		    int *str_len)
++{
++  int len_len = 0;
++
++  if (der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  *str_len = asn1_get_length_der (der, der_len, &len_len);
++
++  if (*str_len < 0)
++    return ASN1_DER_ERROR;
++
++  *ret_len = *str_len + len_len;
++  if (str_size >= *str_len)
++    {
++      if (*str_len > 0 && str != NULL)
++        memcpy (str, der + len_len, *str_len);
++    }
++  else
++    {
++      return ASN1_MEM_ERROR;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/*-
++ * _asn1_get_time_der:
++ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME
++ * @der: DER data to decode containing the time
++ * @der_len: Length of DER data to decode.
++ * @ret_len: Output variable containing the length of the DER data.
++ * @str: Pre-allocated output buffer to put the textual time in.
++ * @str_size: Length of pre-allocated output buffer.
++ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER
++ *
++ * Performs basic checks in the DER encoded time object and returns its textual form.
++ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime
++ * and YYMMDD000000Z for UTCTime.
++ *
++ * Returns: %ASN1_SUCCESS on success, or an error.
++ -*/
++static int
++_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len,
++		    char *str, int str_size, unsigned flags)
++{
++  int len_len, str_len;
++  unsigned i;
++  unsigned sign_count = 0;
++  unsigned dot_count = 0;
++  const unsigned char *p;
++
++  if (der_len <= 0 || str == NULL)
++    return ASN1_DER_ERROR;
++
++  str_len = asn1_get_length_der (der, der_len, &len_len);
++  if (str_len <= 0 || str_size < str_len)
++    return ASN1_DER_ERROR;
++
++  /* perform some sanity checks on the data */
++  if (str_len < 8)
++    {
++      warn();
++      return ASN1_TIME_ENCODING_ERROR;
++    }
++
++  if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME))
++    {
++      p = &der[len_len];
++      for (i=0;i<(unsigned)(str_len-1);i++)
++         {
++           if (c_isdigit(p[i]) == 0)
++             {
++               if (type == ASN1_ETYPE_GENERALIZED_TIME)
++                 {
++                   /* tolerate lax encodings */
++                   if (p[i] == '.' && dot_count == 0)
++                     {
++                       dot_count++;
++                       continue;
++                     }
++
++               /* This is not really valid DER, but there are
++                * structures using that */
++                   if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) &&
++                       (p[i] == '+' || p[i] == '-') && sign_count == 0)
++                     {
++                       sign_count++;
++                       continue;
++                     }
++                 }
++
++               warn();
++               return ASN1_TIME_ENCODING_ERROR;
++             }
++         }
++
++      if (sign_count == 0 && p[str_len-1] != 'Z')
++        {
++          warn();
++          return ASN1_TIME_ENCODING_ERROR;
++        }
++    }
++  memcpy (str, der + len_len, str_len);
++  str[str_len] = 0;
++  *ret_len = str_len + len_len;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_get_object_id_der:
++ * @der: DER data to decode containing the OBJECT IDENTIFIER
++ * @der_len: Length of DER data to decode.
++ * @ret_len: Output variable containing the length of the DER data.
++ * @str: Pre-allocated output buffer to put the textual object id in.
++ * @str_size: Length of pre-allocated output buffer.
++ *
++ * Converts a DER encoded object identifier to its textual form. This
++ * function expects the DER object identifier without the tag.
++ *
++ * Returns: %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len,
++			char *str, int str_size)
++{
++  int len_len, len, k;
++  int leading, parsed;
++  char temp[LTOSTR_MAX_SIZE];
++  uint64_t val, val1, val0;
++
++  *ret_len = 0;
++  if (str && str_size > 0)
++    str[0] = 0;			/* no oid */
++
++  if (str == NULL || der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  len = asn1_get_length_der (der, der_len, &len_len);
++
++  if (len <= 0 || len + len_len > der_len)
++    return ASN1_DER_ERROR;
++
++  /* leading octet can never be 0x80 */
++  if (der[len_len] == 0x80)
++    return ASN1_DER_ERROR;
++
++  val0 = 0;
++
++  for (k = 0; k < len; k++)
++    {
++      if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
++	return ASN1_DER_ERROR;
++
++      val0 <<= 7;
++      val0 |= der[len_len + k] & 0x7F;
++      if (!(der[len_len + k] & 0x80))
++	break;
++    }
++  parsed = ++k;
++
++  /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */
++  /* X = val, Y = val1 */
++
++  /* check if X == 0  */
++  val = 0;
++  val1 = val0;
++  if (val1 > 39)
++    {
++      val = 1;
++      val1 = val0 - 40;
++      if (val1  > 39)
++        {
++          val = 2;
++          val1 = val0 - 80;
++        }
++    }
++
++  _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp));
++  _asn1_str_cat (str, str_size, ".");
++  _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp));
++
++  val = 0;
++  leading = 1;
++  for (k = parsed; k < len; k++)
++    {
++      /* X.690 mandates that the leading byte must never be 0x80
++       */
++      if (leading != 0 && der[len_len + k] == 0x80)
++	return ASN1_DER_ERROR;
++      leading = 0;
++
++      /* check for wrap around */
++      if (INT_LEFT_SHIFT_OVERFLOW (val, 7))
++	return ASN1_DER_ERROR;
++
++      val = val << 7;
++      val |= der[len_len + k] & 0x7F;
++
++      if (!(der[len_len + k] & 0x80))
++	{
++	  _asn1_str_cat (str, str_size, ".");
++	  _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp));
++	  val = 0;
++	  leading = 1;
++	}
++    }
++
++  if (INT_ADD_OVERFLOW (len, len_len))
++    return ASN1_DER_ERROR;
++
++  *ret_len = len + len_len;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_get_bit_der:
++ * @der: DER data to decode containing the BIT SEQUENCE.
++ * @der_len: Length of DER data to decode.
++ * @ret_len: Output variable containing the length of the DER data.
++ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in.
++ * @str_size: Length of pre-allocated output buffer.
++ * @bit_len: Output variable containing the size of the BIT SEQUENCE.
++ *
++ * Extract a BIT SEQUENCE from DER data.
++ *
++ * Returns: %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_bit_der (const unsigned char *der, int der_len,
++		  int *ret_len, unsigned char *str, int str_size,
++		  int *bit_len)
++{
++  int len_len = 0, len_byte;
++
++  if (der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  len_byte = asn1_get_length_der (der, der_len, &len_len) - 1;
++  if (len_byte < 0)
++    return ASN1_DER_ERROR;
++
++  *ret_len = len_byte + len_len + 1;
++  *bit_len = len_byte * 8 - der[len_len];
++
++  if (*bit_len < 0)
++    return ASN1_DER_ERROR;
++
++  if (str_size >= len_byte)
++    {
++      if (len_byte > 0 && str)
++        memcpy (str, der + len_len + 1, len_byte);
++    }
++  else
++    {
++      return ASN1_MEM_ERROR;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++/* tag_len: the total tag length (explicit+inner)
++ * inner_tag_len: the inner_tag length
++ */
++static int
++_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len,
++		       int *tag_len, int *inner_tag_len, unsigned flags)
++{
++  asn1_node p;
++  int counter, len2, len3, is_tag_implicit;
++  int result;
++  unsigned long tag, tag_implicit = 0;
++  unsigned char class, class2, class_implicit = 0;
++
++  if (der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  counter = is_tag_implicit = 0;
++
++  if (node->type & CONST_TAG)
++    {
++      p = node->down;
++      while (p)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if (p->type & CONST_APPLICATION)
++		class2 = ASN1_CLASS_APPLICATION;
++	      else if (p->type & CONST_UNIVERSAL)
++		class2 = ASN1_CLASS_UNIVERSAL;
++	      else if (p->type & CONST_PRIVATE)
++		class2 = ASN1_CLASS_PRIVATE;
++	      else
++		class2 = ASN1_CLASS_CONTEXT_SPECIFIC;
++
++	      if (p->type & CONST_EXPLICIT)
++		{
++		  if (asn1_get_tag_der
++		      (der + counter, der_len, &class, &len2,
++		       &tag) != ASN1_SUCCESS)
++		    return ASN1_DER_ERROR;
++
++                  DECR_LEN(der_len, len2);
++		  counter += len2;
++
++		  if (flags & ASN1_DECODE_FLAG_STRICT_DER)
++		    len3 =
++		      asn1_get_length_der (der + counter, der_len,
++					 &len2);
++		  else
++		    len3 =
++		      asn1_get_length_ber (der + counter, der_len,
++					 &len2);
++		  if (len3 < 0)
++		    return ASN1_DER_ERROR;
++
++                  DECR_LEN(der_len, len2);
++		  counter += len2;
++
++		  if (!is_tag_implicit)
++		    {
++		      if ((class != (class2 | ASN1_CLASS_STRUCTURED)) ||
++			  (tag != strtoul ((char *) p->value, NULL, 10)))
++			return ASN1_TAG_ERROR;
++		    }
++		  else
++		    {		/* ASN1_TAG_IMPLICIT */
++		      if ((class != class_implicit) || (tag != tag_implicit))
++			return ASN1_TAG_ERROR;
++		    }
++		  is_tag_implicit = 0;
++		}
++	      else
++		{		/* ASN1_TAG_IMPLICIT */
++		  if (!is_tag_implicit)
++		    {
++		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
++			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
++			  || (type_field (node->type) == ASN1_ETYPE_SET)
++			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
++			class2 |= ASN1_CLASS_STRUCTURED;
++		      class_implicit = class2;
++		      tag_implicit = strtoul ((char *) p->value, NULL, 10);
++		      is_tag_implicit = 1;
++		    }
++		}
++	    }
++	  p = p->right;
++	}
++    }
++
++  if (is_tag_implicit)
++    {
++      if (asn1_get_tag_der
++	  (der + counter, der_len, &class, &len2,
++	   &tag) != ASN1_SUCCESS)
++	return ASN1_DER_ERROR;
++
++      DECR_LEN(der_len, len2);
++
++      if ((class != class_implicit) || (tag != tag_implicit))
++	{
++	  if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING)
++	    {
++	      class_implicit |= ASN1_CLASS_STRUCTURED;
++	      if ((class != class_implicit) || (tag != tag_implicit))
++		return ASN1_TAG_ERROR;
++	    }
++	  else
++	    return ASN1_TAG_ERROR;
++	}
++    }
++  else
++    {
++      unsigned type = type_field (node->type);
++      if (type == ASN1_ETYPE_TAG)
++	{
++	  *tag_len = 0;
++	  if (inner_tag_len)
++	    *inner_tag_len = 0;
++	  return ASN1_SUCCESS;
++	}
++
++      if (asn1_get_tag_der
++	  (der + counter, der_len, &class, &len2,
++	   &tag) != ASN1_SUCCESS)
++	return ASN1_DER_ERROR;
++
++      DECR_LEN(der_len, len2);
++
++      switch (type)
++	{
++	case ASN1_ETYPE_NULL:
++	case ASN1_ETYPE_BOOLEAN:
++	case ASN1_ETYPE_INTEGER:
++	case ASN1_ETYPE_ENUMERATED:
++	case ASN1_ETYPE_OBJECT_ID:
++	case ASN1_ETYPE_GENERALSTRING:
++	case ASN1_ETYPE_NUMERIC_STRING:
++	case ASN1_ETYPE_IA5_STRING:
++	case ASN1_ETYPE_TELETEX_STRING:
++	case ASN1_ETYPE_PRINTABLE_STRING:
++	case ASN1_ETYPE_UNIVERSAL_STRING:
++	case ASN1_ETYPE_BMP_STRING:
++	case ASN1_ETYPE_UTF8_STRING:
++	case ASN1_ETYPE_VISIBLE_STRING:
++	case ASN1_ETYPE_BIT_STRING:
++	case ASN1_ETYPE_SEQUENCE:
++	case ASN1_ETYPE_SEQUENCE_OF:
++	case ASN1_ETYPE_SET:
++	case ASN1_ETYPE_SET_OF:
++	case ASN1_ETYPE_GENERALIZED_TIME:
++	case ASN1_ETYPE_UTC_TIME:
++	  if ((class != _asn1_tags[type].class)
++	      || (tag != _asn1_tags[type].tag))
++	    return ASN1_DER_ERROR;
++	  break;
++
++	case ASN1_ETYPE_OCTET_STRING:
++	  /* OCTET STRING is handled differently to allow
++	   * BER encodings (structured class). */
++	  if (((class != ASN1_CLASS_UNIVERSAL)
++	       && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)))
++	      || (tag != ASN1_TAG_OCTET_STRING))
++	    return ASN1_DER_ERROR;
++	  break;
++	case ASN1_ETYPE_ANY:
++	  counter -= len2;
++	  break;
++	case ASN1_ETYPE_CHOICE:
++	  counter -= len2;
++	  break;
++	default:
++	  return ASN1_DER_ERROR;
++	  break;
++	}
++    }
++
++  counter += len2;
++  *tag_len = counter;
++  if (inner_tag_len)
++    *inner_tag_len = len2;
++  return ASN1_SUCCESS;
++
++cleanup:
++  return result;
++}
++
++static int
++extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len,
++		       int *ret_len, int *inner_len, unsigned flags)
++{
++asn1_node p;
++int ris = ASN1_DER_ERROR;
++
++  if (type_field (node->type) == ASN1_ETYPE_CHOICE)
++    {
++      p = node->down;
++      while (p)
++        {
++          ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags);
++          if (ris == ASN1_SUCCESS)
++            break;
++          p = p->right;
++	}
++
++      *ret_len = 0;
++      return ris;
++    }
++  else
++    return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags);
++}
++
++static int
++_asn1_delete_not_used (asn1_node node)
++{
++  asn1_node p, p2;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if (p->type & CONST_NOT_USED)
++	{
++	  p2 = NULL;
++	  if (p != node)
++	    {
++	      p2 = _asn1_find_left (p);
++	      if (!p2)
++		p2 = _asn1_find_up (p);
++	    }
++	  asn1_delete_structure (&p);
++	  p = p2;
++	}
++
++      if (!p)
++	break;			/* reach node */
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else
++	{
++	  if (p == node)
++	    p = NULL;
++	  else if (p->right)
++	    p = p->right;
++	  else
++	    {
++	      while (1)
++		{
++		  p = _asn1_find_up (p);
++		  if (p == node)
++		    {
++		      p = NULL;
++		      break;
++		    }
++		  if (p->right)
++		    {
++		      p = p->right;
++		      break;
++		    }
++		}
++	    }
++	}
++    }
++  return ASN1_SUCCESS;
++}
++
++static int
++_asn1_get_indefinite_length_string (const unsigned char *der,
++				    int der_len, int *len)
++{
++  int len2, len3, counter, indefinite;
++  int result;
++  unsigned long tag;
++  unsigned char class;
++
++  counter = indefinite = 0;
++
++  while (1)
++    {
++      if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0))
++	{
++	  counter += 2;
++	  DECR_LEN(der_len, 2);
++
++	  indefinite--;
++	  if (indefinite <= 0)
++	    break;
++	  else
++	    continue;
++	}
++
++      if (asn1_get_tag_der
++	  (der + counter, der_len, &class, &len2,
++	   &tag) != ASN1_SUCCESS)
++	return ASN1_DER_ERROR;
++
++      DECR_LEN(der_len, len2);
++      counter += len2;
++
++      len2 = asn1_get_length_der (der + counter, der_len, &len3);
++      if (len2 < -1)
++	return ASN1_DER_ERROR;
++
++      if (len2 == -1)
++	{
++	  indefinite++;
++	  counter += 1;
++          DECR_LEN(der_len, 1);
++	}
++      else
++	{
++	  counter += len2 + len3;
++          DECR_LEN(der_len, len2+len3);
++	}
++    }
++
++  *len = counter;
++  return ASN1_SUCCESS;
++
++cleanup:
++  return result;
++}
++
++static void delete_unneeded_choice_fields(asn1_node p)
++{
++  asn1_node p2;
++
++  while (p->right)
++    {
++      p2 = p->right;
++      asn1_delete_structure (&p2);
++    }
++}
++
++
++/**
++ * asn1_der_decoding2
++ * @element: pointer to an ASN1 structure.
++ * @ider: vector that contains the DER encoding.
++ * @max_ider_len: pointer to an integer giving the information about the
++ *   maximal number of bytes occupied by *@ider. The real size of the DER
++ *   encoding is returned through this pointer.
++ * @flags: flags controlling the behaviour of the function.
++ * @errorDescription: null-terminated string contains details when an
++ *   error occurred.
++ *
++ * Fill the structure *@element with values of a DER encoding string. The
++ * structure must just be created with function asn1_create_element().
++ *
++ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore
++ * padding after the decoded DER data. Upon a successful return the value of
++ * *@max_ider_len will be set to the number of bytes decoded.
++ *
++ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will
++ * not decode any BER-encoded elements.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
++ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
++ *   name (*@ELEMENT deleted).
++ **/
++int
++asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len,
++		    unsigned int flags, char *errorDescription)
++{
++  asn1_node node, p, p2, p3;
++  char temp[128];
++  int counter, len2, len3, len4, move, ris, tlen;
++  struct node_tail_cache_st tcache = {NULL, NULL};
++  unsigned char class;
++  unsigned long tag;
++  int tag_len;
++  int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len;
++  int inner_tag_len;
++  unsigned char *ptmp;
++  const unsigned char *ptag;
++  const unsigned char *der = ider;
++
++  node = *element;
++
++  if (errorDescription != NULL)
++    errorDescription[0] = 0;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if (node->type & CONST_OPTION)
++    {
++      result = ASN1_GENERIC_ERROR;
++      warn();
++      goto cleanup;
++    }
++
++  counter = 0;
++  move = DOWN;
++  p = node;
++  while (1)
++    {
++      tag_len = 0;
++      inner_tag_len = 0;
++      ris = ASN1_SUCCESS;
++      if (move != UP)
++	{
++	  if (p->type & CONST_SET)
++	    {
++	      p2 = _asn1_find_up (p);
++	      len2 = p2->tmp_ival;
++	      if (len2 == -1)
++		{
++		  if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1])
++		    {
++		      p = p2;
++		      move = UP;
++		      counter += 2;
++		      DECR_LEN(ider_len, 2);
++		      continue;
++		    }
++		}
++	      else if (counter == len2)
++		{
++		  p = p2;
++		  move = UP;
++		  continue;
++		}
++	      else if (counter > len2)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      p2 = p2->down;
++	      while (p2)
++		{
++		  if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED))
++		    {
++		      ris =
++			  extract_tag_der_recursive (p2, der + counter,
++						     ider_len, &len2, NULL, flags);
++		      if (ris == ASN1_SUCCESS)
++			{
++			  p2->type &= ~CONST_NOT_USED;
++			  p = p2;
++			  break;
++			}
++		    }
++		  p2 = p2->right;
++		}
++	      if (p2 == NULL)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	    }
++
++	  /* the position in the DER structure this starts */
++	  p->start = counter;
++	  p->end = total_len - 1;
++
++	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
++	    {
++	      p2 = _asn1_find_up (p);
++	      len2 = p2->tmp_ival;
++	      if (counter == len2)
++		{
++		  if (p->right)
++		    {
++		      p2 = p->right;
++		      move = RIGHT;
++		    }
++		  else
++		    move = UP;
++
++		  if (p->type & CONST_OPTION)
++		    asn1_delete_structure (&p);
++
++		  p = p2;
++		  continue;
++		}
++	    }
++
++	  if (type_field (p->type) == ASN1_ETYPE_CHOICE)
++	    {
++	      while (p->down)
++		{
++		  ris =
++		      extract_tag_der_recursive (p->down, der + counter,
++					         ider_len, &len2, NULL, flags);
++
++		  if (ris == ASN1_SUCCESS)
++		    {
++		      delete_unneeded_choice_fields(p->down);
++		      break;
++		    }
++		  else if (ris == ASN1_ERROR_TYPE_ANY)
++		    {
++		      result = ASN1_ERROR_TYPE_ANY;
++                      warn();
++		      goto cleanup;
++		    }
++		  else
++		    {
++		      p2 = p->down;
++		      asn1_delete_structure (&p2);
++		    }
++		}
++
++	      if (p->down == NULL)
++		{
++		  if (!(p->type & CONST_OPTION))
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++		}
++	      else if (type_field (p->type) != ASN1_ETYPE_CHOICE)
++		p = p->down;
++
++	      p->start = counter;
++	    }
++
++	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
++	    {
++	      p2 = _asn1_find_up (p);
++	      len2 = p2->tmp_ival;
++
++	      if ((len2 != -1) && (counter > len2))
++		ris = ASN1_TAG_ERROR;
++	    }
++
++	  if (ris == ASN1_SUCCESS)
++	    ris =
++	      extract_tag_der_recursive (p, der + counter, ider_len,
++	                                 &tag_len, &inner_tag_len, flags);
++
++	  if (ris != ASN1_SUCCESS)
++	    {
++	      if (p->type & CONST_OPTION)
++		{
++		  p->type |= CONST_NOT_USED;
++		  move = RIGHT;
++		}
++	      else if (p->type & CONST_DEFAULT)
++		{
++		  _asn1_set_value (p, NULL, 0);
++		  move = RIGHT;
++		}
++	      else
++		{
++		  if (errorDescription != NULL)
++		    _asn1_error_description_tag_error (p, errorDescription);
++
++		  result = ASN1_TAG_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	    }
++	  else
++	    {
++	      DECR_LEN(ider_len, tag_len);
++	      counter += tag_len;
++	    }
++	}
++
++      if (ris == ASN1_SUCCESS)
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_NULL:
++	      DECR_LEN(ider_len, 1);
++	      if (der[counter])
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      counter++;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_BOOLEAN:
++	      DECR_LEN(ider_len, 2);
++
++	      if (der[counter++] != 1)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      if (der[counter++] == 0)
++		_asn1_set_value (p, "F", 1);
++	      else
++		_asn1_set_value (p, "T", 1);
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_INTEGER:
++	    case ASN1_ETYPE_ENUMERATED:
++	      len2 =
++		asn1_get_length_der (der + counter, ider_len, &len3);
++	      if (len2 < 0)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len3+len2);
++
++	      _asn1_set_value (p, der + counter, len3 + len2);
++	      counter += len3 + len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_OBJECT_ID:
++	      result =
++		asn1_get_object_id_der (der + counter, ider_len, &len2,
++					temp, sizeof (temp));
++	      if (result != ASN1_SUCCESS)
++	        {
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len2);
++
++	      tlen = strlen (temp);
++	      if (tlen > 0)
++		_asn1_set_value (p, temp, tlen + 1);
++
++	      counter += len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_GENERALIZED_TIME:
++	    case ASN1_ETYPE_UTC_TIME:
++	      result =
++		_asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp,
++				    sizeof (temp) - 1, flags);
++	      if (result != ASN1_SUCCESS)
++	        {
++                  warn();
++                  goto cleanup;
++                }
++
++	      DECR_LEN(ider_len, len2);
++
++	      tlen = strlen (temp);
++	      if (tlen > 0)
++		_asn1_set_value (p, temp, tlen);
++
++	      counter += len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_OCTET_STRING:
++	      if (counter < inner_tag_len)
++	        {
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++	        }
++
++              ptag = der + counter - inner_tag_len;
++              if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED))
++                {
++	          if (ptag[0] & ASN1_CLASS_STRUCTURED)
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++	          len2 =
++		    asn1_get_length_der (der + counter, ider_len, &len3);
++	          if (len2 < 0)
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++	          DECR_LEN(ider_len, len3+len2);
++
++	          _asn1_set_value (p, der + counter, len3 + len2);
++	          counter += len3 + len2;
++                }
++              else
++                {
++                  unsigned dflags = 0, vlen, ber_len;
++
++                  if (ptag[0] & ASN1_CLASS_STRUCTURED)
++                    dflags |= DECODE_FLAG_CONSTRUCTED;
++
++                  result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags);
++                  if (result != ASN1_SUCCESS)
++	            {
++                      warn();
++		      goto cleanup;
++		    }
++
++		  DECR_LEN(ider_len, ber_len);
++
++		  _asn1_set_value_lv (p, ptmp, vlen);
++
++	          counter += ber_len;
++	          free(ptmp);
++                }
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_GENERALSTRING:
++	    case ASN1_ETYPE_NUMERIC_STRING:
++	    case ASN1_ETYPE_IA5_STRING:
++	    case ASN1_ETYPE_TELETEX_STRING:
++	    case ASN1_ETYPE_PRINTABLE_STRING:
++	    case ASN1_ETYPE_UNIVERSAL_STRING:
++	    case ASN1_ETYPE_BMP_STRING:
++	    case ASN1_ETYPE_UTF8_STRING:
++	    case ASN1_ETYPE_VISIBLE_STRING:
++	    case ASN1_ETYPE_BIT_STRING:
++	      len2 =
++		asn1_get_length_der (der + counter, ider_len, &len3);
++	      if (len2 < 0)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len3+len2);
++
++	      _asn1_set_value (p, der + counter, len3 + len2);
++	      counter += len3 + len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_SEQUENCE:
++	    case ASN1_ETYPE_SET:
++	      if (move == UP)
++		{
++		  len2 = p->tmp_ival;
++		  p->tmp_ival = 0;
++		  if (len2 == -1)
++		    {		/* indefinite length method */
++		      DECR_LEN(ider_len, 2);
++		      if ((der[counter]) || der[counter + 1])
++		        {
++		          result = ASN1_DER_ERROR;
++                          warn();
++		          goto cleanup;
++			}
++		      counter += 2;
++		    }
++		  else
++		    {		/* definite length method */
++		      if (len2 != counter)
++			{
++			  result = ASN1_DER_ERROR;
++                          warn();
++			  goto cleanup;
++			}
++		    }
++		  move = RIGHT;
++		}
++	      else
++		{		/* move==DOWN || move==RIGHT */
++		  len3 =
++		    asn1_get_length_der (der + counter, ider_len, &len2);
++                  if (IS_ERR(len3, flags))
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++	          DECR_LEN(ider_len, len2);
++		  counter += len2;
++
++		  if (len3 > 0)
++		    {
++		      p->tmp_ival = counter + len3;
++		      move = DOWN;
++		    }
++		  else if (len3 == 0)
++		    {
++		      p2 = p->down;
++		      while (p2)
++			{
++			  if (type_field (p2->type) != ASN1_ETYPE_TAG)
++			    {
++			      p3 = p2->right;
++			      asn1_delete_structure (&p2);
++			      p2 = p3;
++			    }
++			  else
++			    p2 = p2->right;
++			}
++		      move = RIGHT;
++		    }
++		  else
++		    {		/* indefinite length method */
++		      p->tmp_ival = -1;
++		      move = DOWN;
++		    }
++		}
++	      break;
++	    case ASN1_ETYPE_SEQUENCE_OF:
++	    case ASN1_ETYPE_SET_OF:
++	      if (move == UP)
++		{
++		  len2 = p->tmp_ival;
++		  if (len2 == -1)
++		    {		/* indefinite length method */
++		      if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1]))
++			{
++			  result = _asn1_append_sequence_set (p, &tcache);
++			  if (result != 0)
++			    {
++                              warn();
++		              goto cleanup;
++		            }
++			  p = tcache.tail;
++			  move = RIGHT;
++			  continue;
++			}
++
++		      p->tmp_ival = 0;
++		      tcache.tail = NULL; /* finished decoding this structure */
++		      tcache.head = NULL;
++		      DECR_LEN(ider_len, 2);
++		      counter += 2;
++		    }
++		  else
++		    {		/* definite length method */
++		      if (len2 > counter)
++			{
++			  result = _asn1_append_sequence_set (p, &tcache);
++			  if (result != 0)
++			    {
++                              warn();
++		              goto cleanup;
++		            }
++			  p = tcache.tail;
++			  move = RIGHT;
++			  continue;
++			}
++
++		      p->tmp_ival = 0;
++		      tcache.tail = NULL; /* finished decoding this structure */
++		      tcache.head = NULL;
++
++		      if (len2 != counter)
++			{
++			  result = ASN1_DER_ERROR;
++                          warn();
++			  goto cleanup;
++			}
++		    }
++		}
++	      else
++		{		/* move==DOWN || move==RIGHT */
++		  len3 =
++		    asn1_get_length_der (der + counter, ider_len, &len2);
++                  if (IS_ERR(len3, flags))
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++		  DECR_LEN(ider_len, len2);
++		  counter += len2;
++		  if (len3)
++		    {
++		      if (len3 > 0)
++			{	/* definite length method */
++		          p->tmp_ival = counter + len3;
++			}
++		      else
++			{	/* indefinite length method */
++		          p->tmp_ival = -1;
++			}
++
++		      p2 = p->down;
++                      if (p2 == NULL)
++		        {
++		          result = ASN1_DER_ERROR;
++                          warn();
++		          goto cleanup;
++		        }
++
++		      while ((type_field (p2->type) == ASN1_ETYPE_TAG)
++			     || (type_field (p2->type) == ASN1_ETYPE_SIZE))
++			p2 = p2->right;
++		      if (p2->right == NULL)
++		        {
++			  result = _asn1_append_sequence_set (p, &tcache);
++			  if (result != 0)
++			    {
++                              warn();
++		              goto cleanup;
++		            }
++			}
++		      p = p2;
++		    }
++		}
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_ANY:
++	      /* Check indefinite lenth method in an EXPLICIT TAG */
++
++	      if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) &&
++	          tag_len == 2 && (der[counter - 1] == 0x80))
++		indefinite = 1;
++	      else
++	        indefinite = 0;
++
++	      if (asn1_get_tag_der
++		  (der + counter, ider_len, &class, &len2,
++		   &tag) != ASN1_SUCCESS)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len2);
++
++	      len4 =
++		asn1_get_length_der (der + counter + len2,
++				     ider_len, &len3);
++              if (IS_ERR(len4, flags))
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      if (len4 != -1) /* definite */
++		{
++		  len2 += len4;
++
++	          DECR_LEN(ider_len, len4+len3);
++		  _asn1_set_value_lv (p, der + counter, len2 + len3);
++		  counter += len2 + len3;
++		}
++	      else /* == -1 */
++		{		/* indefinite length */
++		  ider_len += len2; /* undo DECR_LEN */
++
++		  if (counter == 0)
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++		  result =
++		    _asn1_get_indefinite_length_string (der + counter, ider_len, &len2);
++		  if (result != ASN1_SUCCESS)
++		    {
++                      warn();
++                      goto cleanup;
++                    }
++
++	          DECR_LEN(ider_len, len2);
++		  _asn1_set_value_lv (p, der + counter, len2);
++		  counter += len2;
++
++		}
++
++	        /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
++	           an indefinite length method. */
++	        if (indefinite)
++		  {
++	            DECR_LEN(ider_len, 2);
++		    if (!der[counter] && !der[counter + 1])
++		      {
++		        counter += 2;
++		      }
++		    else
++		      {
++		        result = ASN1_DER_ERROR;
++                        warn();
++		        goto cleanup;
++		      }
++		  }
++
++	      move = RIGHT;
++	      break;
++	    default:
++	      move = (move == UP) ? RIGHT : DOWN;
++	      break;
++	    }
++	}
++
++      if (p)
++        {
++          p->end = counter - 1;
++        }
++
++      if (p == node && move != DOWN)
++	break;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++      if ((move == RIGHT) && !(p->type & CONST_SET))
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  _asn1_delete_not_used (*element);
++
++  if ((ider_len < 0) ||
++      (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0)))
++    {
++      warn();
++      result = ASN1_DER_ERROR;
++      goto cleanup;
++    }
++
++  *max_ider_len = total_len - ider_len;
++
++  return ASN1_SUCCESS;
++
++cleanup:
++  asn1_delete_structure (element);
++  return result;
++}
++
++
++/**
++ * asn1_der_decoding:
++ * @element: pointer to an ASN1 structure.
++ * @ider: vector that contains the DER encoding.
++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1].
++ * @errorDescription: null-terminated string contains details when an
++ *   error occurred.
++ *
++ * Fill the structure *@element with values of a DER encoding
++ * string. The structure must just be created with function
++ * asn1_create_element().
++ *
++ * Note that the *@element variable is provided as a pointer for
++ * historical reasons.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
++ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
++ *   name (*@ELEMENT deleted).
++ **/
++int
++asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
++		   char *errorDescription)
++{
++  return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
++}
++
++/**
++ * asn1_der_decoding_element:
++ * @structure: pointer to an ASN1 structure
++ * @elementName: name of the element to fill
++ * @ider: vector that contains the DER encoding of the whole structure.
++ * @len: number of bytes of *der: der[0]..der[len-1]
++ * @errorDescription: null-terminated string contains details when an
++ *   error occurred.
++ *
++ * Fill the element named @ELEMENTNAME with values of a DER encoding
++ * string.  The structure must just be created with function
++ * asn1_create_element().  The DER vector must contain the encoding
++ * string of the whole @STRUCTURE.  If an error occurs during the
++ * decoding procedure, the *@STRUCTURE is deleted and set equal to
++ * %NULL.
++ *
++ * This function is deprecated and may just be an alias to asn1_der_decoding
++ * in future versions. Use asn1_der_decoding() instead.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if ELEMENT is %NULL or @elementName == NULL, and
++ *   %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't
++ *   match the structure @structure (*ELEMENT deleted).
++ **/
++int
++asn1_der_decoding_element (asn1_node * structure, const char *elementName,
++			   const void *ider, int len, char *errorDescription)
++{
++  return asn1_der_decoding(structure, ider, len, errorDescription);
++}
++
++/**
++ * asn1_der_decoding_startEnd:
++ * @element: pointer to an ASN1 element
++ * @ider: vector that contains the DER encoding.
++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]
++ * @name_element: an element of NAME structure.
++ * @start: the position of the first byte of NAME_ELEMENT decoding
++ *   (@ider[*start])
++ * @end: the position of the last byte of NAME_ELEMENT decoding
++ *  (@ider[*end])
++ *
++ * Find the start and end point of an element in a DER encoding
++ * string. I mean that if you have a der encoding and you have already
++ * used the function asn1_der_decoding() to fill a structure, it may
++ * happen that you want to find the piece of string concerning an
++ * element of the structure.
++ *
++ * One example is the sequence "tbsCertificate" inside an X509
++ * certificate.
++ *
++ * Note that since libtasn1 3.7 the @ider and @ider_len parameters
++ * can be omitted, if the element is already decoded using asn1_der_decoding().
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if ELEMENT is %asn1_node EMPTY or @name_element is not a valid
++ *   element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding
++ *   doesn't match the structure ELEMENT.
++ **/
++int
++asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
++			    const char *name_element, int *start, int *end)
++{
++  asn1_node node, node_to_find;
++  int result = ASN1_DER_ERROR;
++
++  node = element;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  node_to_find = asn1_find_node (node, name_element);
++
++  if (node_to_find == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  *start = node_to_find->start;
++  *end = node_to_find->end;
++
++  if (*start == 0 && *end == 0)
++    {
++      if (ider == NULL || ider_len == 0)
++        return ASN1_GENERIC_ERROR;
++
++      /* it seems asn1_der_decoding() wasn't called before. Do it now */
++      result = asn1_der_decoding (&node, ider, ider_len, NULL);
++      if (result != ASN1_SUCCESS)
++        {
++          warn();
++          return result;
++        }
++
++      node_to_find = asn1_find_node (node, name_element);
++      if (node_to_find == NULL)
++        return ASN1_ELEMENT_NOT_FOUND;
++
++      *start = node_to_find->start;
++      *end = node_to_find->end;
++    }
++
++  if (*end < *start)
++    return ASN1_GENERIC_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_expand_any_defined_by:
++ * @definitions: ASN1 definitions
++ * @element: pointer to an ASN1 structure
++ *
++ * Expands every "ANY DEFINED BY" element of a structure created from
++ * a DER decoding process (asn1_der_decoding function). The element
++ * ANY must be defined by an OBJECT IDENTIFIER. The type used to
++ * expand the element ANY is the first one following the definition of
++ * the actual value of the OBJECT IDENTIFIER.
++ *
++ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if
++ *   some "ANY DEFINED BY" element couldn't be expanded due to a
++ *   problem in OBJECT_ID -> TYPE association, or other error codes
++ *   depending on DER decoding.
++ **/
++int
++asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element)
++{
++  char name[2 * ASN1_MAX_NAME_SIZE + 2],
++    value[ASN1_MAX_NAME_SIZE];
++  int retCode = ASN1_SUCCESS, result;
++  int len, len2, len3;
++  asn1_node_const p2;
++  asn1_node p, p3, aux = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++  const char *definitionsName;
++
++  if ((definitions == NULL) || (*element == NULL))
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  definitionsName = definitions->name;
++
++  p = *element;
++  while (p)
++    {
++
++      switch (type_field (p->type))
++	{
++	case ASN1_ETYPE_ANY:
++	  if ((p->type & CONST_DEFINED_BY) && (p->value))
++	    {
++	      /* search the "DEF_BY" element */
++	      p2 = p->down;
++	      while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT))
++		p2 = p2->right;
++
++	      if (!p2)
++		{
++		  retCode = ASN1_ERROR_TYPE_ANY;
++		  break;
++		}
++
++	      p3 = _asn1_find_up (p);
++
++	      if (!p3)
++		{
++		  retCode = ASN1_ERROR_TYPE_ANY;
++		  break;
++		}
++
++	      p3 = p3->down;
++	      while (p3)
++		{
++		  if (!(strcmp (p3->name, p2->name)))
++		    break;
++		  p3 = p3->right;
++		}
++
++	      if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
++		  (p3->value == NULL))
++		{
++
++		  p3 = _asn1_find_up (p);
++		  p3 = _asn1_find_up (p3);
++
++		  if (!p3)
++		    {
++		      retCode = ASN1_ERROR_TYPE_ANY;
++		      break;
++		    }
++
++		  p3 = p3->down;
++
++		  while (p3)
++		    {
++		      if (!(strcmp (p3->name, p2->name)))
++			break;
++		      p3 = p3->right;
++		    }
++
++		  if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
++		      || (p3->value == NULL))
++		    {
++		      retCode = ASN1_ERROR_TYPE_ANY;
++		      break;
++		    }
++		}
++
++	      /* search the OBJECT_ID into definitions */
++	      p2 = definitions->down;
++	      while (p2)
++		{
++		  if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
++		      (p2->type & CONST_ASSIGN))
++		    {
++		      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
++
++		      len = ASN1_MAX_NAME_SIZE;
++		      result =
++			asn1_read_value (definitions, name, value, &len);
++
++		      if ((result == ASN1_SUCCESS)
++			  && (!_asn1_strcmp (p3->value, value)))
++			{
++			  p2 = p2->right;	/* pointer to the structure to
++						   use for expansion */
++			  while ((p2) && (p2->type & CONST_ASSIGN))
++			    p2 = p2->right;
++
++			  if (p2)
++			    {
++			      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
++
++			      result =
++				asn1_create_element (definitions, name, &aux);
++			      if (result == ASN1_SUCCESS)
++				{
++				  _asn1_cpy_name (aux, p);
++				  len2 =
++				    asn1_get_length_der (p->value,
++							 p->value_len, &len3);
++				  if (len2 < 0)
++				    return ASN1_DER_ERROR;
++
++				  result =
++				    asn1_der_decoding (&aux, p->value + len3,
++						       len2,
++						       errorDescription);
++				  if (result == ASN1_SUCCESS)
++				    {
++
++				      _asn1_set_right (aux, p->right);
++				      _asn1_set_right (p, aux);
++
++				      result = asn1_delete_structure (&p);
++				      if (result == ASN1_SUCCESS)
++					{
++					  p = aux;
++					  aux = NULL;
++					  break;
++					}
++				      else
++					{	/* error with asn1_delete_structure */
++					  asn1_delete_structure (&aux);
++					  retCode = result;
++					  break;
++					}
++				    }
++				  else
++				    {	/* error with asn1_der_decoding */
++				      retCode = result;
++				      break;
++				    }
++				}
++			      else
++				{	/* error with asn1_create_element */
++				  retCode = result;
++				  break;
++				}
++			    }
++			  else
++			    {	/* error with the pointer to the structure to exapand */
++			      retCode = ASN1_ERROR_TYPE_ANY;
++			      break;
++			    }
++			}
++		    }
++		  p2 = p2->right;
++		}		/* end while */
++
++	      if (!p2)
++		{
++		  retCode = ASN1_ERROR_TYPE_ANY;
++		  break;
++		}
++
++	    }
++	  break;
++	default:
++	  break;
++	}
++
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p == *element)
++	{
++	  p = NULL;
++	  break;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == *element)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  return retCode;
++}
++
++/**
++ * asn1_expand_octet_string:
++ * @definitions: ASN1 definitions
++ * @element: pointer to an ASN1 structure
++ * @octetName: name of the OCTECT STRING field to expand.
++ * @objectName: name of the OBJECT IDENTIFIER field to use to define
++ *    the type for expansion.
++ *
++ * Expands an "OCTET STRING" element of a structure created from a DER
++ * decoding process (the asn1_der_decoding() function).  The type used
++ * for expansion is the first one following the definition of the
++ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME.
++ *
++ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @objectName or @octetName are not correct,
++ *   %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to
++ *   use for expansion, or other errors depending on DER decoding.
++ **/
++int
++asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
++			  const char *octetName, const char *objectName)
++{
++  char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE];
++  int retCode = ASN1_SUCCESS, result;
++  int len, len2, len3;
++  asn1_node_const p2;
++  asn1_node aux = NULL;
++  asn1_node octetNode = NULL, objectNode = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++  if ((definitions == NULL) || (*element == NULL))
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  octetNode = asn1_find_node (*element, octetName);
++  if (octetNode == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++  if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING)
++    return ASN1_ELEMENT_NOT_FOUND;
++  if (octetNode->value == NULL)
++    return ASN1_VALUE_NOT_FOUND;
++
++  objectNode = asn1_find_node (*element, objectName);
++  if (objectNode == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if (objectNode->value == NULL)
++    return ASN1_VALUE_NOT_FOUND;
++
++
++  /* search the OBJECT_ID into definitions */
++  p2 = definitions->down;
++  while (p2)
++    {
++      if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
++	  (p2->type & CONST_ASSIGN))
++	{
++	  strcpy (name, definitions->name);
++	  strcat (name, ".");
++	  strcat (name, p2->name);
++
++	  len = sizeof (value);
++	  result = asn1_read_value (definitions, name, value, &len);
++
++	  if ((result == ASN1_SUCCESS)
++	      && (!_asn1_strcmp (objectNode->value, value)))
++	    {
++
++	      p2 = p2->right;	/* pointer to the structure to
++				   use for expansion */
++	      while ((p2) && (p2->type & CONST_ASSIGN))
++		p2 = p2->right;
++
++	      if (p2)
++		{
++		  strcpy (name, definitions->name);
++		  strcat (name, ".");
++		  strcat (name, p2->name);
++
++		  result = asn1_create_element (definitions, name, &aux);
++		  if (result == ASN1_SUCCESS)
++		    {
++		      _asn1_cpy_name (aux, octetNode);
++		      len2 =
++			asn1_get_length_der (octetNode->value,
++					     octetNode->value_len, &len3);
++		      if (len2 < 0)
++			return ASN1_DER_ERROR;
++
++		      result =
++			asn1_der_decoding (&aux, octetNode->value + len3,
++					   len2, errorDescription);
++		      if (result == ASN1_SUCCESS)
++			{
++
++			  _asn1_set_right (aux, octetNode->right);
++			  _asn1_set_right (octetNode, aux);
++
++			  result = asn1_delete_structure (&octetNode);
++			  if (result == ASN1_SUCCESS)
++			    {
++			      aux = NULL;
++			      break;
++			    }
++			  else
++			    {	/* error with asn1_delete_structure */
++			      asn1_delete_structure (&aux);
++			      retCode = result;
++			      break;
++			    }
++			}
++		      else
++			{	/* error with asn1_der_decoding */
++			  retCode = result;
++			  break;
++			}
++		    }
++		  else
++		    {		/* error with asn1_create_element */
++		      retCode = result;
++		      break;
++		    }
++		}
++	      else
++		{		/* error with the pointer to the structure to exapand */
++		  retCode = ASN1_VALUE_NOT_VALID;
++		  break;
++		}
++	    }
++	}
++
++      p2 = p2->right;
++
++    }
++
++  if (!p2)
++    retCode = ASN1_VALUE_NOT_VALID;
++
++  return retCode;
++}
++
++/*-
++ * _asn1_decode_simple_der:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ * @dflags: DECODE_FLAG_*
++ *
++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
++ * The output is a pointer inside the @der.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ -*/
++static int
++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, const unsigned char **str,
++			unsigned int *str_len, unsigned dflags)
++{
++  int tag_len, len_len;
++  const unsigned char *p;
++  int der_len = _der_len;
++  unsigned char class;
++  unsigned long tag;
++  long ret;
++
++  if (der == NULL || der_len == 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  /* doesn't handle constructed classes */
++  class = ETYPE_CLASS(etype);
++  if (class != ASN1_CLASS_UNIVERSAL)
++    return ASN1_VALUE_NOT_VALID;
++
++  p = der;
++
++  if (dflags & DECODE_FLAG_HAVE_TAG)
++    {
++      ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
++      if (ret != ASN1_SUCCESS)
++        return ret;
++
++      if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype))
++        {
++          warn();
++          return ASN1_DER_ERROR;
++        }
++
++      p += tag_len;
++      der_len -= tag_len;
++      if (der_len <= 0)
++        return ASN1_DER_ERROR;
++    }
++
++  ret = asn1_get_length_der (p, der_len, &len_len);
++  if (ret < 0)
++    return ASN1_DER_ERROR;
++
++  p += len_len;
++  der_len -= len_len;
++  if (der_len <= 0)
++    return ASN1_DER_ERROR;
++
++  *str_len = ret;
++  *str = p;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_decode_simple_der:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ *
++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
++ * The output is a pointer inside the @der.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ **/
++int
++asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, const unsigned char **str,
++			unsigned int *str_len)
++{
++  return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG);
++}
++
++static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size)
++{
++  if (src_size == 0)
++    return ASN1_SUCCESS;
++
++  *dst = _asn1_realloc(*dst, *dst_size+src_size);
++  if (*dst == NULL)
++    return ASN1_MEM_ALLOC_ERROR;
++  memcpy(*dst + *dst_size, src, src_size);
++  *dst_size += src_size;
++  return ASN1_SUCCESS;
++}
++
++/*-
++ * _asn1_decode_simple_ber:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ * @ber_len: the total length occupied by BER (may be %NULL)
++ * @have_tag: whether a DER tag is included
++ *
++ * Decodes a BER encoded type. The output is an allocated value
++ * of the data. This decodes BER STRINGS only. Other types are
++ * decoded as DER.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ -*/
++static int
++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, unsigned char **str,
++			unsigned int *str_len, unsigned int *ber_len,
++			unsigned dflags)
++{
++  int tag_len, len_len;
++  const unsigned char *p;
++  int der_len = _der_len;
++  uint8_t *total = NULL;
++  unsigned total_size = 0;
++  unsigned char class;
++  unsigned long tag;
++  unsigned char *out = NULL;
++  const unsigned char *cout = NULL;
++  unsigned out_len;
++  long result;
++
++  if (ber_len) *ber_len = 0;
++
++  if (der == NULL || der_len == 0)
++    {
++      warn();
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  if (ETYPE_OK (etype) == 0)
++    {
++      warn();
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  /* doesn't handle constructed + definite classes */
++  class = ETYPE_CLASS (etype);
++  if (class != ASN1_CLASS_UNIVERSAL)
++    {
++      warn();
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  p = der;
++
++  if (dflags & DECODE_FLAG_HAVE_TAG)
++    {
++      result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
++        if (result != ASN1_SUCCESS)
++          {
++            warn();
++            return result;
++          }
++
++        if (tag != ETYPE_TAG (etype))
++          {
++            warn();
++            return ASN1_DER_ERROR;
++          }
++
++        p += tag_len;
++
++        DECR_LEN(der_len, tag_len);
++
++        if (ber_len) *ber_len += tag_len;
++    }
++
++  /* indefinite constructed */
++  if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) &&
++      !(dflags & DECODE_FLAG_LEVEL3))
++    {
++      if (der_len == 0)
++        {
++          warn();
++          result = ASN1_DER_ERROR;
++          goto cleanup;
++        }
++
++      if (der_len > 0 && p[0] == 0x80) /* indefinite */
++        {
++          len_len = 1;
++          DECR_LEN(der_len, len_len);
++          p += len_len;
++
++          if (ber_len) *ber_len += len_len;
++
++          /* decode the available octet strings */
++          do
++            {
++              unsigned tmp_len;
++              unsigned flags = DECODE_FLAG_HAVE_TAG;
++
++              if (dflags & DECODE_FLAG_LEVEL1)
++                flags |= DECODE_FLAG_LEVEL2;
++              else if (dflags & DECODE_FLAG_LEVEL2)
++                flags |= DECODE_FLAG_LEVEL3;
++              else
++		flags |= DECODE_FLAG_LEVEL1;
++
++              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
++                                               flags);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++                }
++
++              p += tmp_len;
++              DECR_LEN(der_len, tmp_len);
++
++              if (ber_len) *ber_len += tmp_len;
++
++              DECR_LEN(der_len, 2); /* we need the EOC */
++
++              result = append(&total, &total_size, out, out_len);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++	        }
++
++              free(out);
++              out = NULL;
++
++	      if (p[0] == 0 && p[1] == 0) /* EOC */
++	        {
++                  if (ber_len) *ber_len += 2;
++                  break;
++                }
++
++              /* no EOC */
++              der_len += 2;
++
++              if (der_len == 2)
++                {
++                  warn();
++                  result = ASN1_DER_ERROR;
++                  goto cleanup;
++                }
++            }
++          while(1);
++        }
++      else /* constructed */
++        {
++          long const_len;
++
++          result = asn1_get_length_ber(p, der_len, &len_len);
++          if (result < 0)
++            {
++              warn();
++              result = ASN1_DER_ERROR;
++              goto cleanup;
++            }
++
++          DECR_LEN(der_len, len_len);
++          p += len_len;
++
++          const_len = result;
++
++          if (ber_len) *ber_len += len_len;
++
++          /* decode the available octet strings */
++          while(const_len > 0)
++            {
++              unsigned tmp_len;
++              unsigned flags = DECODE_FLAG_HAVE_TAG;
++
++              if (dflags & DECODE_FLAG_LEVEL1)
++                flags |= DECODE_FLAG_LEVEL2;
++              else if (dflags & DECODE_FLAG_LEVEL2)
++                flags |= DECODE_FLAG_LEVEL3;
++              else
++		flags |= DECODE_FLAG_LEVEL1;
++
++              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
++                                               flags);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++                }
++
++              p += tmp_len;
++              DECR_LEN(der_len, tmp_len);
++              DECR_LEN(const_len, tmp_len);
++
++              if (ber_len) *ber_len += tmp_len;
++
++              result = append(&total, &total_size, out, out_len);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++	        }
++
++              free(out);
++              out = NULL;
++            }
++        }
++    }
++  else if (class == ETYPE_CLASS(etype))
++    {
++      if (ber_len)
++        {
++          result = asn1_get_length_der (p, der_len, &len_len);
++          if (result < 0)
++            {
++              warn();
++              result = ASN1_DER_ERROR;
++              goto cleanup;
++            }
++          *ber_len += result + len_len;
++        }
++
++      /* non-string values are decoded as DER */
++      result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags);
++      if (result != ASN1_SUCCESS)
++        {
++          warn();
++          goto cleanup;
++        }
++
++      result = append(&total, &total_size, cout, out_len);
++      if (result != ASN1_SUCCESS)
++        {
++          warn();
++          goto cleanup;
++        }
++    }
++  else
++    {
++      warn();
++      result = ASN1_DER_ERROR;
++      goto cleanup;
++    }
++
++  *str = total;
++  *str_len = total_size;
++
++  return ASN1_SUCCESS;
++cleanup:
++  free(out);
++  free(total);
++  return result;
++}
++
++/**
++ * asn1_decode_simple_ber:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ * @ber_len: the total length occupied by BER (may be %NULL)
++ *
++ * Decodes a BER encoded type. The output is an allocated value
++ * of the data. This decodes BER STRINGS only. Other types are
++ * decoded as DER.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ **/
++int
++asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, unsigned char **str,
++			unsigned int *str_len, unsigned int *ber_len)
++{
++  return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG);
++}
+diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
+new file mode 100644
+index 00000000000..997eb2725dc
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/element.c
+@@ -0,0 +1,1111 @@
++/*
++ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++/*****************************************************/
++/* File: element.c                                   */
++/* Description: Functions with the read and write    */
++/*   functions.                                      */
++/*****************************************************/
++
++
++#include <int.h>
++#include "parser_aux.h"
++#include <gstr.h>
++#include "structure.h"
++#include "c-ctype.h"
++#include "element.h"
++
++void
++_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
++{
++  asn1_node_const p;
++  char tmp_name[64];
++
++  p = node;
++
++  name[0] = 0;
++
++  while (p != NULL)
++    {
++      if (p->name[0] != 0)
++	{
++	  _asn1_str_cpy (tmp_name, sizeof (tmp_name), name),
++	    _asn1_str_cpy (name, name_size, p->name);
++	  _asn1_str_cat (name, name_size, ".");
++	  _asn1_str_cat (name, name_size, tmp_name);
++	}
++      p = _asn1_find_up (p);
++    }
++
++  if (name[0] == 0)
++    _asn1_str_cpy (name, name_size, "ROOT");
++}
++
++
++/******************************************************************/
++/* Function : _asn1_convert_integer                               */
++/* Description: converts an integer from a null terminated string */
++/*              to der decoding. The convertion from a null       */
++/*              terminated string to an integer is made with      */
++/*              the 'strtol' function.                            */
++/* Parameters:                                                    */
++/*   value: null terminated string to convert.                    */
++/*   value_out: convertion result (memory must be already         */
++/*              allocated).                                       */
++/*   value_out_size: number of bytes of value_out.                */
++/*   len: number of significant byte of value_out.                */
++/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS                         */
++/******************************************************************/
++int
++_asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
++		       int value_out_size, int *len)
++{
++  char negative;
++  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
++  long valtmp;
++  int k, k2;
++
++  valtmp = _asn1_strtol (value, NULL, 10);
++
++  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
++    {
++      val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF;
++    }
++
++  if (val[0] & 0x80)
++    negative = 1;
++  else
++    negative = 0;
++
++  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++)
++    {
++      if (negative && (val[k] != 0xFF))
++	break;
++      else if (!negative && val[k])
++	break;
++    }
++
++  if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80)))
++    k--;
++
++  *len = SIZEOF_UNSIGNED_LONG_INT - k;
++
++  if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size)
++    /* VALUE_OUT is too short to contain the value conversion */
++    return ASN1_MEM_ERROR;
++
++  if (value_out != NULL)
++    {
++      for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++)
++        value_out[k2 - k] = val[k2];
++    }
++
++#if 0
++  printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
++  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
++    printf (", vOut[%d]=%d", k, value_out[k]);
++  printf ("\n");
++#endif
++
++  return ASN1_SUCCESS;
++}
++
++/* Appends a new element into the sequence (or set) defined by this
++ * node. The new element will have a name of '?number', where number
++ * is a monotonically increased serial number.
++ *
++ * The last element in the list may be provided in @pcache, to avoid
++ * traversing the list, an expensive operation in long lists.
++ *
++ * On success it returns in @pcache the added element (which is the
++ * tail in the list of added elements).
++ */
++int
++_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
++{
++  asn1_node p, p2;
++  char temp[LTOSTR_MAX_SIZE];
++  long n;
++
++  if (!node || !(node->down))
++    return ASN1_GENERIC_ERROR;
++
++  p = node->down;
++  while ((type_field (p->type) == ASN1_ETYPE_TAG)
++	 || (type_field (p->type) == ASN1_ETYPE_SIZE))
++    p = p->right;
++
++  p2 = _asn1_copy_structure3 (p);
++  if (p2 == NULL)
++    return ASN1_GENERIC_ERROR;
++
++  if (pcache == NULL || pcache->tail == NULL || pcache->head != node)
++    {
++      while (p->right)
++        {
++          p = p->right;
++        }
++    }
++  else
++    {
++      p = pcache->tail;
++    }
++
++  _asn1_set_right (p, p2);
++  if (pcache)
++    {
++      pcache->head = node;
++      pcache->tail = p2;
++    }
++
++  if (p->name[0] == 0)
++    _asn1_str_cpy (temp, sizeof (temp), "?1");
++  else
++    {
++      n = strtol (p->name + 1, NULL, 0);
++      n++;
++      temp[0] = '?';
++      _asn1_ltostr (n, temp + 1);
++    }
++  _asn1_set_name (p2, temp);
++  /*  p2->type |= CONST_OPTION; */
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_write_value:
++ * @node_root: pointer to a structure
++ * @name: the name of the element inside the structure that you want to set.
++ * @ivalue: vector used to specify the value to set. If len is >0,
++ *   VALUE must be a two's complement form integer.  if len=0 *VALUE
++ *   must be a null terminated string with an integer value.
++ * @len: number of bytes of *value to use to set the value:
++ *   value[0]..value[len-1] or 0 if value is a null terminated string
++ *
++ * Set the value of one element inside a structure.
++ *
++ * If an element is OPTIONAL and you want to delete it, you must use
++ * the value=NULL and len=0.  Using "pkix.asn":
++ *
++ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID",
++ * NULL, 0);
++ *
++ * Description for each type:
++ *
++ * INTEGER: VALUE must contain a two's complement form integer.
++ *
++ *            value[0]=0xFF ,               len=1 -> integer=-1.
++ *            value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1.
++ *            value[0]=0x01 ,               len=1 -> integer= 1.
++ *            value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1.
++ *            value="123"                 , len=0 -> integer= 123.
++ *
++ * ENUMERATED: As INTEGER (but only with not negative numbers).
++ *
++ * BOOLEAN: VALUE must be the null terminated string "TRUE" or
++ *   "FALSE" and LEN != 0.
++ *
++ *            value="TRUE" , len=1 -> boolean=TRUE.
++ *            value="FALSE" , len=1 -> boolean=FALSE.
++ *
++ * OBJECT IDENTIFIER: VALUE must be a null terminated string with
++ *   each number separated by a dot (e.g. "1.2.3.543.1").  LEN != 0.
++ *
++ *            value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha.
++ *
++ * UTCTime: VALUE must be a null terminated string in one of these
++ *   formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ",
++ *   "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'",
++ *   "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'".  LEN != 0.
++ *
++ *            value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998
++ *            at 12h 00m Greenwich Mean Time
++ *
++ * GeneralizedTime: VALUE must be in one of this format:
++ *   "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ",
++ *   "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'",
++ *   "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s
++ *   indicates the seconds with any precision like "10.1" or "01.02".
++ *   LEN != 0
++ *
++ *            value="2001010112001.12-0700" , len=1 -> time=Jannuary
++ *            1st, 2001 at 12h 00m 01.12s Pacific Daylight Time
++ *
++ * OCTET STRING: VALUE contains the octet string and LEN is the
++ *   number of octets.
++ *
++ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
++ *            len=3 -> three bytes octet string
++ *
++ * GeneralString: VALUE contains the generalstring and LEN is the
++ *   number of octets.
++ *
++ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
++ *            len=3 -> three bytes generalstring
++ *
++ * BIT STRING: VALUE contains the bit string organized by bytes and
++ *   LEN is the number of bits.
++ *
++ *   value="$\backslash$xCF" , len=6 -> bit string="110011" (six
++ *   bits)
++ *
++ * CHOICE: if NAME indicates a choice type, VALUE must specify one of
++ *   the alternatives with a null terminated string. LEN != 0. Using
++ *   "pkix.asn"\:
++ *
++ *           result=asn1_write_value(cert,
++ *           "certificate1.tbsCertificate.subject", "rdnSequence",
++ *           1);
++ *
++ * ANY: VALUE indicates the der encoding of a structure.  LEN != 0.
++ *
++ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and
++ *   LEN != 0. With this instruction another element is appended in
++ *   the sequence. The name of this element will be "?1" if it's the
++ *   first one, "?2" for the second and so on.
++ *
++ *   Using "pkix.asn"\:
++ *
++ *   result=asn1_write_value(cert,
++ *   "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1);
++ *
++ * SET OF: the same as SEQUENCE OF.  Using "pkix.asn":
++ *
++ *           result=asn1_write_value(cert,
++ *           "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1);
++ *
++ * Returns: %ASN1_SUCCESS if the value was set,
++ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and
++ *   %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format.
++ **/
++int
++asn1_write_value (asn1_node node_root, const char *name,
++		  const void *ivalue, int len)
++{
++  asn1_node node, p, p2;
++  unsigned char *temp, *value_temp = NULL, *default_temp = NULL;
++  int len2, k, k2, negative;
++  size_t i;
++  const unsigned char *value = ivalue;
++  unsigned int type;
++
++  node = asn1_find_node (node_root, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0))
++    {
++      asn1_delete_structure (&node);
++      return ASN1_SUCCESS;
++    }
++
++  type = type_field (node->type);
++
++  if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0))
++    {
++      p = node->down;
++      while ((type_field (p->type) == ASN1_ETYPE_TAG)
++	     || (type_field (p->type) == ASN1_ETYPE_SIZE))
++	p = p->right;
++
++      while (p->right)
++	asn1_delete_structure (&p->right);
++
++      return ASN1_SUCCESS;
++    }
++
++  /* Don't allow element deletion for other types */
++  if (value == NULL)
++    {
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  switch (type)
++    {
++    case ASN1_ETYPE_BOOLEAN:
++      if (!_asn1_strcmp (value, "TRUE"))
++	{
++	  if (node->type & CONST_DEFAULT)
++	    {
++	      p = node->down;
++	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++		p = p->right;
++	      if (p->type & CONST_TRUE)
++		_asn1_set_value (node, NULL, 0);
++	      else
++		_asn1_set_value (node, "T", 1);
++	    }
++	  else
++	    _asn1_set_value (node, "T", 1);
++	}
++      else if (!_asn1_strcmp (value, "FALSE"))
++	{
++	  if (node->type & CONST_DEFAULT)
++	    {
++	      p = node->down;
++	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++		p = p->right;
++	      if (p->type & CONST_FALSE)
++		_asn1_set_value (node, NULL, 0);
++	      else
++		_asn1_set_value (node, "F", 1);
++	    }
++	  else
++	    _asn1_set_value (node, "F", 1);
++	}
++      else
++	return ASN1_VALUE_NOT_VALID;
++      break;
++    case ASN1_ETYPE_INTEGER:
++    case ASN1_ETYPE_ENUMERATED:
++      if (len == 0)
++	{
++	  if ((c_isdigit (value[0])) || (value[0] == '-'))
++	    {
++	      value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++	      if (value_temp == NULL)
++		return ASN1_MEM_ALLOC_ERROR;
++
++	      _asn1_convert_integer (value, value_temp,
++				     SIZEOF_UNSIGNED_LONG_INT, &len);
++	    }
++	  else
++	    {			/* is an identifier like v1 */
++	      if (!(node->type & CONST_LIST))
++		return ASN1_VALUE_NOT_VALID;
++	      p = node->down;
++	      while (p)
++		{
++		  if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
++		    {
++		      if (!_asn1_strcmp (p->name, value))
++			{
++			  value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++			  if (value_temp == NULL)
++			    return ASN1_MEM_ALLOC_ERROR;
++
++			  _asn1_convert_integer (p->value,
++						 value_temp,
++						 SIZEOF_UNSIGNED_LONG_INT,
++						 &len);
++			  break;
++			}
++		    }
++		  p = p->right;
++		}
++	      if (p == NULL)
++		return ASN1_VALUE_NOT_VALID;
++	    }
++	}
++      else
++	{			/* len != 0 */
++	  value_temp = malloc (len);
++	  if (value_temp == NULL)
++	    return ASN1_MEM_ALLOC_ERROR;
++	  memcpy (value_temp, value, len);
++	}
++
++      if (value_temp[0] & 0x80)
++	negative = 1;
++      else
++	negative = 0;
++
++      if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED))
++	{
++	  free (value_temp);
++	  return ASN1_VALUE_NOT_VALID;
++	}
++
++      for (k = 0; k < len - 1; k++)
++	if (negative && (value_temp[k] != 0xFF))
++	  break;
++	else if (!negative && value_temp[k])
++	  break;
++
++      if ((negative && !(value_temp[k] & 0x80)) ||
++	  (!negative && (value_temp[k] & 0x80)))
++	k--;
++
++      _asn1_set_value_lv (node, value_temp + k, len - k);
++
++      if (node->type & CONST_DEFAULT)
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-'))
++	    {
++	      default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++	      if (default_temp == NULL)
++		{
++		  free (value_temp);
++		  return ASN1_MEM_ALLOC_ERROR;
++		}
++
++	      _asn1_convert_integer (p->value, default_temp,
++				     SIZEOF_UNSIGNED_LONG_INT, &len2);
++	    }
++	  else
++	    {			/* is an identifier like v1 */
++	      if (!(node->type & CONST_LIST))
++		{
++		  free (value_temp);
++		  return ASN1_VALUE_NOT_VALID;
++		}
++	      p2 = node->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
++		    {
++		      if (!_asn1_strcmp (p2->name, p->value))
++			{
++			  default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++			  if (default_temp == NULL)
++			    {
++			      free (value_temp);
++			      return ASN1_MEM_ALLOC_ERROR;
++			    }
++
++			  _asn1_convert_integer (p2->value,
++						 default_temp,
++						 SIZEOF_UNSIGNED_LONG_INT,
++						 &len2);
++			  break;
++			}
++		    }
++		  p2 = p2->right;
++		}
++	      if (p2 == NULL)
++		{
++		  free (value_temp);
++		  return ASN1_VALUE_NOT_VALID;
++		}
++	    }
++
++
++	  if ((len - k) == len2)
++	    {
++	      for (k2 = 0; k2 < len2; k2++)
++		if (value_temp[k + k2] != default_temp[k2])
++		  {
++		    break;
++		  }
++	      if (k2 == len2)
++		_asn1_set_value (node, NULL, 0);
++	    }
++	  free (default_temp);
++	}
++      free (value_temp);
++      break;
++    case ASN1_ETYPE_OBJECT_ID:
++      for (i = 0; i < _asn1_strlen (value); i++)
++	if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+'))
++	  return ASN1_VALUE_NOT_VALID;
++      if (node->type & CONST_DEFAULT)
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if (!_asn1_strcmp (value, p->value))
++	    {
++	      _asn1_set_value (node, NULL, 0);
++	      break;
++	    }
++	}
++      _asn1_set_value (node, value, _asn1_strlen (value) + 1);
++      break;
++    case ASN1_ETYPE_UTC_TIME:
++      {
++	len = _asn1_strlen (value);
++	if (len < 11)
++	  return ASN1_VALUE_NOT_VALID;
++	for (k = 0; k < 10; k++)
++	  if (!c_isdigit (value[k]))
++	    return ASN1_VALUE_NOT_VALID;
++	switch (len)
++	  {
++	  case 11:
++	    if (value[10] != 'Z')
++	      return ASN1_VALUE_NOT_VALID;
++	    break;
++	  case 13:
++	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) ||
++		(value[12] != 'Z'))
++	      return ASN1_VALUE_NOT_VALID;
++	    break;
++	  case 15:
++	    if ((value[10] != '+') && (value[10] != '-'))
++	      return ASN1_VALUE_NOT_VALID;
++	    for (k = 11; k < 15; k++)
++	      if (!c_isdigit (value[k]))
++		return ASN1_VALUE_NOT_VALID;
++	    break;
++	  case 17:
++	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])))
++	      return ASN1_VALUE_NOT_VALID;
++	    if ((value[12] != '+') && (value[12] != '-'))
++	      return ASN1_VALUE_NOT_VALID;
++	    for (k = 13; k < 17; k++)
++	      if (!c_isdigit (value[k]))
++		return ASN1_VALUE_NOT_VALID;
++	    break;
++	  default:
++	    return ASN1_VALUE_NOT_FOUND;
++	  }
++	_asn1_set_value (node, value, len);
++      }
++      break;
++    case ASN1_ETYPE_GENERALIZED_TIME:
++      len = _asn1_strlen (value);
++      _asn1_set_value (node, value, len);
++      break;
++    case ASN1_ETYPE_OCTET_STRING:
++    case ASN1_ETYPE_GENERALSTRING:
++    case ASN1_ETYPE_NUMERIC_STRING:
++    case ASN1_ETYPE_IA5_STRING:
++    case ASN1_ETYPE_TELETEX_STRING:
++    case ASN1_ETYPE_PRINTABLE_STRING:
++    case ASN1_ETYPE_UNIVERSAL_STRING:
++    case ASN1_ETYPE_BMP_STRING:
++    case ASN1_ETYPE_UTF8_STRING:
++    case ASN1_ETYPE_VISIBLE_STRING:
++      if (len == 0)
++	len = _asn1_strlen (value);
++      _asn1_set_value_lv (node, value, len);
++      break;
++    case ASN1_ETYPE_BIT_STRING:
++      if (len == 0)
++	len = _asn1_strlen (value);
++      asn1_length_der ((len >> 3) + 2, NULL, &len2);
++      temp = malloc ((len >> 3) + 2 + len2);
++      if (temp == NULL)
++	return ASN1_MEM_ALLOC_ERROR;
++
++      asn1_bit_der (value, len, temp, &len2);
++      _asn1_set_value_m (node, temp, len2);
++      temp = NULL;
++      break;
++    case ASN1_ETYPE_CHOICE:
++      p = node->down;
++      while (p)
++	{
++	  if (!_asn1_strcmp (p->name, value))
++	    {
++	      p2 = node->down;
++	      while (p2)
++		{
++		  if (p2 != p)
++		    {
++		      asn1_delete_structure (&p2);
++		      p2 = node->down;
++		    }
++		  else
++		    p2 = p2->right;
++		}
++	      break;
++	    }
++	  p = p->right;
++	}
++      if (!p)
++	return ASN1_ELEMENT_NOT_FOUND;
++      break;
++    case ASN1_ETYPE_ANY:
++      _asn1_set_value_lv (node, value, len);
++      break;
++    case ASN1_ETYPE_SEQUENCE_OF:
++    case ASN1_ETYPE_SET_OF:
++      if (_asn1_strcmp (value, "NEW"))
++	return ASN1_VALUE_NOT_VALID;
++      _asn1_append_sequence_set (node, NULL);
++      break;
++    default:
++      return ASN1_ELEMENT_NOT_FOUND;
++      break;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++#define PUT_VALUE( ptr, ptr_size, data, data_size) \
++	*len = data_size; \
++	if (ptr_size < data_size) { \
++		return ASN1_MEM_ERROR; \
++	} else { \
++		if (ptr && data_size > 0) \
++		  memcpy (ptr, data, data_size); \
++	}
++
++#define PUT_STR_VALUE( ptr, ptr_size, data) \
++	*len = _asn1_strlen (data) + 1; \
++	if (ptr_size < *len) { \
++		return ASN1_MEM_ERROR; \
++	} else { \
++		/* this strcpy is checked */ \
++		if (ptr) { \
++		  _asn1_strcpy (ptr, data); \
++		} \
++	}
++
++#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \
++	*len = data_size + 1; \
++	if (ptr_size < *len) { \
++		return ASN1_MEM_ERROR; \
++	} else { \
++		/* this strcpy is checked */ \
++		if (ptr) { \
++		  if (data_size > 0) \
++		    memcpy (ptr, data, data_size); \
++		  ptr[data_size] = 0; \
++		} \
++	}
++
++#define ADD_STR_VALUE( ptr, ptr_size, data) \
++        *len += _asn1_strlen(data); \
++        if (ptr_size < (int) *len) { \
++                (*len)++; \
++                return ASN1_MEM_ERROR; \
++        } else { \
++                /* this strcat is checked */ \
++                if (ptr) _asn1_strcat (ptr, data); \
++        }
++
++/**
++ * asn1_read_value:
++ * @root: pointer to a structure.
++ * @name: the name of the element inside a structure that you want to read.
++ * @ivalue: vector that will contain the element's content, must be a
++ *   pointer to memory cells already allocated (may be %NULL).
++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
++ *   holds the sizeof value.
++ *
++ * Returns the value of one element inside a structure.
++ * If an element is OPTIONAL and this returns
++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
++ * in the der encoding that created the structure.  The first element
++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
++ * so on. If the @root provided is a node to specific sequence element,
++ * then the keyword "?CURRENT" is also acceptable and indicates the
++ * current sequence element of this node.
++ *
++ * Note that there can be valid values with length zero. In these case
++ * this function will succeed and @len will be zero.
++ *
++ * INTEGER: VALUE will contain a two's complement form integer.
++ *
++ *            integer=-1  -> value[0]=0xFF , len=1.
++ *            integer=1   -> value[0]=0x01 , len=1.
++ *
++ * ENUMERATED: As INTEGER (but only with not negative numbers).
++ *
++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
++ *   "FALSE" and LEN=5 or LEN=6.
++ *
++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
++ *   each number separated by a dot (i.e. "1.2.3.543.1").
++ *
++ *                      LEN = strlen(VALUE)+1
++ *
++ * UTCTime: VALUE will be a null terminated string in one of these
++ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
++ *   LEN=strlen(VALUE)+1.
++ *
++ * GeneralizedTime: VALUE will be a null terminated string in the
++ *   same format used to set the value.
++ *
++ * OCTET STRING: VALUE will contain the octet string and LEN will be
++ *   the number of octets.
++ *
++ * GeneralString: VALUE will contain the generalstring and LEN will
++ *   be the number of octets.
++ *
++ * BIT STRING: VALUE will contain the bit string organized by bytes
++ *   and LEN will be the number of bits.
++ *
++ * CHOICE: If NAME indicates a choice type, VALUE will specify the
++ *   alternative selected.
++ *
++ * ANY: If NAME indicates an any type, VALUE will indicate the DER
++ *   encoding of the structure actually used.
++ *
++ * Returns: %ASN1_SUCCESS if value is returned,
++ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
++ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
++ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
++ *   to store the result, and in this case @len will contain the number of
++ *   bytes needed. On the occasion that the stored data are of zero-length
++ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
++ **/
++int
++asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len)
++{
++  return asn1_read_value_type (root, name, ivalue, len, NULL);
++}
++
++/**
++ * asn1_read_value_type:
++ * @root: pointer to a structure.
++ * @name: the name of the element inside a structure that you want to read.
++ * @ivalue: vector that will contain the element's content, must be a
++ *   pointer to memory cells already allocated (may be %NULL).
++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
++ *   holds the sizeof value.
++ * @etype: The type of the value read (ASN1_ETYPE)
++ *
++ * Returns the type and value of one element inside a structure.
++ * If an element is OPTIONAL and this returns
++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
++ * in the der encoding that created the structure.  The first element
++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
++ * so on. If the @root provided is a node to specific sequence element,
++ * then the keyword "?CURRENT" is also acceptable and indicates the
++ * current sequence element of this node.
++ *
++ * Note that there can be valid values with length zero. In these case
++ * this function will succeed and @len will be zero.
++ *
++ *
++ * INTEGER: VALUE will contain a two's complement form integer.
++ *
++ *            integer=-1  -> value[0]=0xFF , len=1.
++ *            integer=1   -> value[0]=0x01 , len=1.
++ *
++ * ENUMERATED: As INTEGER (but only with not negative numbers).
++ *
++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
++ *   "FALSE" and LEN=5 or LEN=6.
++ *
++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
++ *   each number separated by a dot (i.e. "1.2.3.543.1").
++ *
++ *                      LEN = strlen(VALUE)+1
++ *
++ * UTCTime: VALUE will be a null terminated string in one of these
++ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
++ *   LEN=strlen(VALUE)+1.
++ *
++ * GeneralizedTime: VALUE will be a null terminated string in the
++ *   same format used to set the value.
++ *
++ * OCTET STRING: VALUE will contain the octet string and LEN will be
++ *   the number of octets.
++ *
++ * GeneralString: VALUE will contain the generalstring and LEN will
++ *   be the number of octets.
++ *
++ * BIT STRING: VALUE will contain the bit string organized by bytes
++ *   and LEN will be the number of bits.
++ *
++ * CHOICE: If NAME indicates a choice type, VALUE will specify the
++ *   alternative selected.
++ *
++ * ANY: If NAME indicates an any type, VALUE will indicate the DER
++ *   encoding of the structure actually used.
++ *
++ * Returns: %ASN1_SUCCESS if value is returned,
++ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
++ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
++ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
++ *   to store the result, and in this case @len will contain the number of
++ *   bytes needed. On the occasion that the stored data are of zero-length
++ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
++ **/
++int
++asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue,
++		      int *len, unsigned int *etype)
++{
++  asn1_node_const node, p, p2;
++  int len2, len3, result;
++  int value_size = *len;
++  unsigned char *value = ivalue;
++  unsigned type;
++
++  node = asn1_find_node (root, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  type = type_field (node->type);
++
++  if ((type != ASN1_ETYPE_NULL) &&
++      (type != ASN1_ETYPE_CHOICE) &&
++      !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) &&
++      (node->value == NULL))
++    return ASN1_VALUE_NOT_FOUND;
++
++  if (etype)
++    *etype = type;
++  switch (type)
++    {
++    case ASN1_ETYPE_NULL:
++      PUT_STR_VALUE (value, value_size, "NULL");
++      break;
++    case ASN1_ETYPE_BOOLEAN:
++      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if (p->type & CONST_TRUE)
++	    {
++	      PUT_STR_VALUE (value, value_size, "TRUE");
++	    }
++	  else
++	    {
++	      PUT_STR_VALUE (value, value_size, "FALSE");
++	    }
++	}
++      else if (node->value[0] == 'T')
++	{
++	  PUT_STR_VALUE (value, value_size, "TRUE");
++	}
++      else
++	{
++	  PUT_STR_VALUE (value, value_size, "FALSE");
++	}
++      break;
++    case ASN1_ETYPE_INTEGER:
++    case ASN1_ETYPE_ENUMERATED:
++      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-')
++	      || (p->value[0] == '+'))
++	    {
++	      result = _asn1_convert_integer
++		  (p->value, value, value_size, len);
++              if (result != ASN1_SUCCESS)
++		return result;
++	    }
++	  else
++	    {			/* is an identifier like v1 */
++	      p2 = node->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
++		    {
++		      if (!_asn1_strcmp (p2->name, p->value))
++			{
++			  result = _asn1_convert_integer
++			      (p2->value, value, value_size,
++			       len);
++			  if (result != ASN1_SUCCESS)
++			    return result;
++			  break;
++			}
++		    }
++		  p2 = p2->right;
++		}
++	    }
++	}
++      else
++	{
++	  len2 = -1;
++	  result = asn1_get_octet_der
++	      (node->value, node->value_len, &len2, value, value_size,
++	       len);
++          if (result != ASN1_SUCCESS)
++	    return result;
++	}
++      break;
++    case ASN1_ETYPE_OBJECT_ID:
++      if (node->type & CONST_ASSIGN)
++	{
++	  *len = 0;
++	  if (value)
++	    value[0] = 0;
++	  p = node->down;
++	  while (p)
++	    {
++	      if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
++		{
++		  ADD_STR_VALUE (value, value_size, p->value);
++		  if (p->right)
++		    {
++		      ADD_STR_VALUE (value, value_size, ".");
++		    }
++		}
++	      p = p->right;
++	    }
++	  (*len)++;
++	}
++      else if ((node->type & CONST_DEFAULT) && (node->value == NULL))
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  PUT_STR_VALUE (value, value_size, p->value);
++	}
++      else
++	{
++	  PUT_STR_VALUE (value, value_size, node->value);
++	}
++      break;
++    case ASN1_ETYPE_GENERALIZED_TIME:
++    case ASN1_ETYPE_UTC_TIME:
++      PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len);
++      break;
++    case ASN1_ETYPE_OCTET_STRING:
++    case ASN1_ETYPE_GENERALSTRING:
++    case ASN1_ETYPE_NUMERIC_STRING:
++    case ASN1_ETYPE_IA5_STRING:
++    case ASN1_ETYPE_TELETEX_STRING:
++    case ASN1_ETYPE_PRINTABLE_STRING:
++    case ASN1_ETYPE_UNIVERSAL_STRING:
++    case ASN1_ETYPE_BMP_STRING:
++    case ASN1_ETYPE_UTF8_STRING:
++    case ASN1_ETYPE_VISIBLE_STRING:
++      len2 = -1;
++      result = asn1_get_octet_der
++	  (node->value, node->value_len, &len2, value, value_size,
++	   len);
++      if (result != ASN1_SUCCESS)
++	return result;
++      break;
++    case ASN1_ETYPE_BIT_STRING:
++      len2 = -1;
++      result = asn1_get_bit_der
++	  (node->value, node->value_len, &len2, value, value_size,
++	   len);
++      if (result != ASN1_SUCCESS)
++	return result;
++      break;
++    case ASN1_ETYPE_CHOICE:
++      PUT_STR_VALUE (value, value_size, node->down->name);
++      break;
++    case ASN1_ETYPE_ANY:
++      len3 = -1;
++      len2 = asn1_get_length_der (node->value, node->value_len, &len3);
++      if (len2 < 0)
++	return ASN1_DER_ERROR;
++      PUT_VALUE (value, value_size, node->value + len3, len2);
++      break;
++    default:
++      return ASN1_ELEMENT_NOT_FOUND;
++      break;
++    }
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_read_tag:
++ * @root: pointer to a structure
++ * @name: the name of the element inside a structure.
++ * @tagValue:  variable that will contain the TAG value.
++ * @classValue: variable that will specify the TAG type.
++ *
++ * Returns the TAG and the CLASS of one element inside a structure.
++ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION,
++ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or
++ * %ASN1_CLASS_CONTEXT_SPECIFIC.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   @name is not a valid element.
++ **/
++int
++asn1_read_tag (asn1_node_const root, const char *name, int *tagValue,
++	       int *classValue)
++{
++  asn1_node node, p, pTag;
++
++  node = asn1_find_node (root, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node->down;
++
++  /* pTag will points to the IMPLICIT TAG */
++  pTag = NULL;
++  if (node->type & CONST_TAG)
++    {
++      while (p)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if ((p->type & CONST_IMPLICIT) && (pTag == NULL))
++		pTag = p;
++	      else if (p->type & CONST_EXPLICIT)
++		pTag = NULL;
++	    }
++	  p = p->right;
++	}
++    }
++
++  if (pTag)
++    {
++      *tagValue = _asn1_strtoul (pTag->value, NULL, 10);
++
++      if (pTag->type & CONST_APPLICATION)
++	*classValue = ASN1_CLASS_APPLICATION;
++      else if (pTag->type & CONST_UNIVERSAL)
++	*classValue = ASN1_CLASS_UNIVERSAL;
++      else if (pTag->type & CONST_PRIVATE)
++	*classValue = ASN1_CLASS_PRIVATE;
++      else
++	*classValue = ASN1_CLASS_CONTEXT_SPECIFIC;
++    }
++  else
++    {
++      unsigned type = type_field (node->type);
++      *classValue = ASN1_CLASS_UNIVERSAL;
++
++      switch (type)
++	{
++	CASE_HANDLED_ETYPES:
++	  *tagValue = _asn1_tags[type].tag;
++	  break;
++	case ASN1_ETYPE_TAG:
++	case ASN1_ETYPE_CHOICE:
++	case ASN1_ETYPE_ANY:
++	  *tagValue = -1;
++	  break;
++	default:
++	  break;
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_read_node_value:
++ * @node: pointer to a node.
++ * @data: a point to a asn1_data_node_st
++ *
++ * Returns the value a data node inside a asn1_node structure.
++ * The data returned should be handled as constant values.
++ *
++ * Returns: %ASN1_SUCCESS if the node exists.
++ **/
++int
++asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data)
++{
++  data->name = node->name;
++  data->value = node->value;
++  data->value_len = node->value_len;
++  data->type = type_field (node->type);
++
++  return ASN1_SUCCESS;
++}
+diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
+new file mode 100644
+index 00000000000..cee74daf795
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/errors.c
+@@ -0,0 +1,100 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <int.h>
++#ifdef STDC_HEADERS
++#include <stdarg.h>
++#endif
++
++#define LIBTASN1_ERROR_ENTRY(name) { #name, name }
++
++struct libtasn1_error_entry
++{
++  const char *name;
++  int number;
++};
++typedef struct libtasn1_error_entry libtasn1_error_entry;
++
++static const libtasn1_error_entry error_algorithms[] = {
++  LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS),
++  LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID),
++  LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT),
++  LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY),
++  LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW),
++  LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG),
++  LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY),
++  LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_RECURSION),
++  {0, 0}
++};
++
++/**
++ * asn1_perror:
++ * @error: is an error returned by a libtasn1 function.
++ *
++ * Prints a string to stderr with a description of an error.  This
++ * function is like perror().  The only difference is that it accepts
++ * an error returned by a libtasn1 function.
++ *
++ * Since: 1.6
++ **/
++void
++asn1_perror (int error)
++{
++  const char *str = asn1_strerror (error);
++  fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
++}
++
++/**
++ * asn1_strerror:
++ * @error: is an error returned by a libtasn1 function.
++ *
++ * Returns a string with a description of an error.  This function is
++ * similar to strerror.  The only difference is that it accepts an
++ * error (number) returned by a libtasn1 function.
++ *
++ * Returns: Pointer to static zero-terminated string describing error
++ *   code.
++ *
++ * Since: 1.6
++ **/
++const char *
++asn1_strerror (int error)
++{
++  const libtasn1_error_entry *p;
++
++  for (p = error_algorithms; p->name != NULL; p++)
++    if (p->number == error)
++      return p->name + sizeof ("ASN1_") - 1;
++
++  return NULL;
++}
+diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
+new file mode 100644
+index 00000000000..e91a3a151c0
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/gstr.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <int.h>
++#include "gstr.h"
++
++/* These function are like strcat, strcpy. They only
++ * do bounds checking (they shouldn't cause buffer overruns),
++ * and they always produce null terminated strings.
++ *
++ * They should be used only with null terminated strings.
++ */
++void
++_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
++{
++  size_t str_size = strlen (src);
++  size_t dest_size = strlen (dest);
++
++  if (dest_tot_size - dest_size > str_size)
++    {
++      strcat (dest, src);
++    }
++  else
++    {
++      if (dest_tot_size - dest_size > 0)
++	{
++	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
++	  dest[dest_tot_size - 1] = 0;
++	}
++    }
++}
++
++/* Returns the bytes copied (not including the null terminator) */
++unsigned int
++_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src)
++{
++  size_t str_size = strlen (src);
++
++  if (dest_tot_size > str_size)
++    {
++      strcpy (dest, src);
++      return str_size;
++    }
++  else
++    {
++      if (dest_tot_size > 0)
++	{
++	  str_size = dest_tot_size - 1;
++	  memcpy (dest, src, str_size);
++	  dest[str_size] = 0;
++	  return str_size;
++	}
++      else
++	return 0;
++    }
++}
+diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
+new file mode 100644
+index 00000000000..d5dbbf8765d
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/parser_aux.c
+@@ -0,0 +1,1173 @@
++/*
++ * Copyright (C) 2000-2016 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <limits.h> // WORD_BIT
++
++#include "int.h"
++#include "parser_aux.h"
++#include "gstr.h"
++#include "structure.h"
++#include "element.h"
++#include "c-ctype.h"
++
++char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
++
++/* Return a hash of the N bytes of X using the method described by
++   Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
++   Note that while many hash functions reduce their result via modulo
++   to a 0..table_size-1 range, this function does not do that.
++
++   This implementation has been changed from size_t -> unsigned int. */
++
++#ifdef __clang__
++__attribute__((no_sanitize("integer")))
++#endif
++_GL_ATTRIBUTE_PURE
++static unsigned int
++_asn1_hash_name (const char *x)
++{
++  const unsigned char *s = (unsigned char *) x;
++  unsigned h = 0;
++
++  while (*s)
++    h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9)));
++
++  return h;
++}
++
++/******************************************************/
++/* Function : _asn1_add_static_node                   */
++/* Description: creates a new NODE_ASN element and    */
++/* puts it in the list pointed by e_list.       */
++/* Parameters:                                        */
++/*   e_list: of type list_type; must be NULL initially */
++/*   type: type of the new element (see ASN1_ETYPE_   */
++/*         and CONST_ constants).                     */
++/* Return: pointer to the new element.                */
++/******************************************************/
++asn1_node
++_asn1_add_static_node (list_type **e_list, unsigned int type)
++{
++  list_type *p;
++  asn1_node punt;
++
++  punt = calloc (1, sizeof (struct asn1_node_st));
++  if (punt == NULL)
++    return NULL;
++
++  p = malloc (sizeof (list_type));
++  if (p == NULL)
++    {
++      free (punt);
++      return NULL;
++    }
++
++  p->node = punt;
++  p->next = *e_list;
++  *e_list = p;
++
++  punt->type = type;
++
++  return punt;
++}
++
++static
++int _asn1_add_static_node2 (list_type **e_list, asn1_node node)
++{
++  list_type *p;
++
++  p = malloc (sizeof (list_type));
++  if (p == NULL)
++    {
++      return -1;
++    }
++
++  p->node = node;
++  p->next = *e_list;
++  *e_list = p;
++
++  return 0;
++}
++
++/**
++ * asn1_find_node:
++ * @pointer: NODE_ASN element pointer.
++ * @name: null terminated string with the element's name to find.
++ *
++ * Searches for an element called @name starting from @pointer.  The
++ * name is composed by different identifiers separated by dots.  When
++ * *@pointer has a name, the first identifier must be the name of
++ * *@pointer, otherwise it must be the name of one child of *@pointer.
++ *
++ * Returns: the search result, or %NULL if not found.
++ **/
++asn1_node
++asn1_find_node (asn1_node_const pointer, const char *name)
++{
++  asn1_node_const p;
++  char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
++  const char *n_start;
++  unsigned int nsize;
++  unsigned int nhash;
++
++  if (pointer == NULL)
++    return NULL;
++
++  if (name == NULL)
++    return NULL;
++
++  p = pointer;
++  n_start = name;
++
++  if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?')
++    { /* ?CURRENT */
++      n_start = strchr(n_start, '.');
++      if (n_start)
++        n_start++;
++    }
++  else if (p->name[0] != 0)
++    {				/* has *pointer got a name ? */
++      n_end = strchr (n_start, '.');	/* search the first dot */
++      if (n_end)
++	{
++	  nsize = n_end - n_start;
++	  if (nsize >= sizeof(n))
++		return NULL;
++
++	  memcpy (n, n_start, nsize);
++	  n[nsize] = 0;
++	  n_start = n_end;
++	  n_start++;
++
++	  nhash = _asn1_hash_name (n);
++	}
++      else
++	{
++	  _asn1_str_cpy (n, sizeof (n), n_start);
++	  nhash = _asn1_hash_name (n);
++
++	  n_start = NULL;
++	}
++
++      while (p)
++	{
++	  if (nhash == p->name_hash && (!strcmp (p->name, n)))
++	    break;
++	  else
++	    p = p->right;
++	}			/* while */
++
++      if (p == NULL)
++	return NULL;
++    }
++  else
++    {				/* *pointer doesn't have a name */
++      if (n_start[0] == 0)
++	return (asn1_node) p;
++    }
++
++  while (n_start)
++    {				/* Has the end of NAME been reached? */
++      n_end = strchr (n_start, '.');	/* search the next dot */
++      if (n_end)
++	{
++	  nsize = n_end - n_start;
++	  if (nsize >= sizeof(n))
++		return NULL;
++
++	  memcpy (n, n_start, nsize);
++	  n[nsize] = 0;
++	  n_start = n_end;
++	  n_start++;
++
++	  nhash = _asn1_hash_name (n);
++	}
++      else
++	{
++	  _asn1_str_cpy (n, sizeof (n), n_start);
++	  nhash = _asn1_hash_name (n);
++	  n_start = NULL;
++	}
++
++      if (p->down == NULL)
++	return NULL;
++
++      p = p->down;
++      if (p == NULL)
++        return NULL;
++
++      /* The identifier "?LAST" indicates the last element
++         in the right chain. */
++      if (n[0] == '?' && n[1] == 'L') /* ?LAST */
++	{
++	  while (p->right)
++	    p = p->right;
++	}
++      else
++	{			/* no "?LAST" */
++	  while (p)
++	    {
++	      if (p->name_hash == nhash && !strcmp (p->name, n))
++		break;
++	      else
++		p = p->right;
++	    }
++	}
++      if (p == NULL)
++        return NULL;
++    }				/* while */
++
++  return (asn1_node) p;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_set_value                                     */
++/* Description: sets the field VALUE in a NODE_ASN element. The   */
++/*              previous value (if exist) will be lost            */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   value: pointer to the value that you want to set.            */
++/*   len: character number of value.                              */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_set_value (asn1_node node, const void *value, unsigned int len)
++{
++  if (node == NULL)
++    return node;
++  if (node->value)
++    {
++      if (node->value != node->small_value)
++	free (node->value);
++      node->value = NULL;
++      node->value_len = 0;
++    }
++
++  if (!len)
++    return node;
++
++  if (len < sizeof (node->small_value))
++    {
++      node->value = node->small_value;
++    }
++  else
++    {
++      node->value = malloc (len);
++      if (node->value == NULL)
++	return NULL;
++    }
++  node->value_len = len;
++
++  memcpy (node->value, value, len);
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_set_value_lv                                  */
++/* Description: sets the field VALUE in a NODE_ASN element. The   */
++/*              previous value (if exist) will be lost. The value */
++/*		given is stored as an length-value format (LV     */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   value: pointer to the value that you want to set.            */
++/*   len: character number of value.                              */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
++{
++  int len2;
++  void *temp;
++
++  if (node == NULL)
++    return node;
++
++  asn1_length_der (len, NULL, &len2);
++  temp = malloc (len + len2);
++  if (temp == NULL)
++    return NULL;
++
++  asn1_octet_der (value, len, temp, &len2);
++  return _asn1_set_value_m (node, temp, len2);
++}
++
++/* the same as _asn1_set_value except that it sets an already malloc'ed
++ * value.
++ */
++asn1_node
++_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
++{
++  if (node == NULL)
++    return node;
++
++  if (node->value)
++    {
++      if (node->value != node->small_value)
++	free (node->value);
++      node->value = NULL;
++      node->value_len = 0;
++    }
++
++  if (!len)
++    return node;
++
++  node->value = value;
++  node->value_len = len;
++
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_append_value                                  */
++/* Description: appends to the field VALUE in a NODE_ASN element. */
++/*							          */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   value: pointer to the value that you want to be appended.    */
++/*   len: character number of value.                              */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_append_value (asn1_node node, const void *value, unsigned int len)
++{
++  if (node == NULL)
++    return node;
++
++  if (node->value == NULL)
++    return _asn1_set_value (node, value, len);
++
++  if (len == 0)
++    return node;
++
++  if (node->value == node->small_value)
++    {
++      /* value is in node */
++      int prev_len = node->value_len;
++      node->value_len += len;
++      node->value = malloc (node->value_len);
++      if (node->value == NULL)
++	{
++	  node->value_len = 0;
++	  return NULL;
++	}
++
++      if (prev_len > 0)
++        memcpy (node->value, node->small_value, prev_len);
++
++      memcpy (&node->value[prev_len], value, len);
++
++      return node;
++    }
++  else /* if (node->value != NULL && node->value != node->small_value) */
++    {
++      /* value is allocated */
++      int prev_len = node->value_len;
++      node->value_len += len;
++
++      node->value = _asn1_realloc (node->value, node->value_len);
++      if (node->value == NULL)
++	{
++	  node->value_len = 0;
++	  return NULL;
++	}
++
++      memcpy (&node->value[prev_len], value, len);
++
++      return node;
++    }
++}
++
++/******************************************************************/
++/* Function : _asn1_set_name                                      */
++/* Description: sets the field NAME in a NODE_ASN element. The    */
++/*              previous value (if exist) will be lost            */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   name: a null terminated string with the name that you want   */
++/*         to set.                                                */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_set_name (asn1_node node, const char *name)
++{
++  if (node == NULL)
++    return node;
++
++  _asn1_str_cpy (node->name, sizeof (node->name), name ? name : "");
++  node->name_hash = _asn1_hash_name (node->name);
++
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_cpy_name                                      */
++/* Description: copies the field NAME in a NODE_ASN element.      */
++/* Parameters:                                                    */
++/*   dst: a dest element pointer.                                 */
++/*   src: a source element pointer.                               */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_cpy_name (asn1_node dst, asn1_node_const src)
++{
++  if (dst == NULL)
++    return dst;
++
++  if (src == NULL)
++    {
++      dst->name[0] = 0;
++      dst->name_hash = _asn1_hash_name (dst->name);
++      return dst;
++    }
++
++  _asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
++  dst->name_hash = src->name_hash;
++
++  return dst;
++}
++
++/******************************************************************/
++/* Function : _asn1_set_right                                     */
++/* Description: sets the field RIGHT in a NODE_ASN element.       */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   right: pointer to a NODE_ASN element that you want be pointed*/
++/*          by NODE.                                              */
++/* Return: pointer to *NODE.                                      */
++/******************************************************************/
++asn1_node
++_asn1_set_right (asn1_node node, asn1_node right)
++{
++  if (node == NULL)
++    return node;
++  node->right = right;
++  if (right)
++    right->left = node;
++  return node;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_get_last_right                                */
++/* Description: return the last element along the right chain.    */
++/* Parameters:                                                    */
++/*   node: starting element pointer.                              */
++/* Return: pointer to the last element along the right chain.     */
++/******************************************************************/
++asn1_node
++_asn1_get_last_right (asn1_node_const node)
++{
++  asn1_node_const p;
++
++  if (node == NULL)
++    return NULL;
++  p = node;
++  while (p->right)
++    p = p->right;
++  return (asn1_node) p;
++}
++
++/******************************************************************/
++/* Function : _asn1_remove_node                                   */
++/* Description: gets free the memory allocated for an NODE_ASN    */
++/*              element (not the elements pointed by it).         */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/*   flags: ASN1_DELETE_FLAG_*                                    */
++/******************************************************************/
++void
++_asn1_remove_node (asn1_node node, unsigned int flags)
++{
++  if (node == NULL)
++    return;
++
++  if (node->value != NULL)
++    {
++      if (flags & ASN1_DELETE_FLAG_ZEROIZE)
++        {
++          safe_memset(node->value, 0, node->value_len);
++        }
++
++      if (node->value != node->small_value)
++        free (node->value);
++    }
++  free (node);
++}
++
++/******************************************************************/
++/* Function : _asn1_find_up                                       */
++/* Description: return the father of the NODE_ASN element.        */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: Null if not found.                                     */
++/******************************************************************/
++asn1_node
++_asn1_find_up (asn1_node_const node)
++{
++  asn1_node_const p;
++
++  if (node == NULL)
++    return NULL;
++
++  p = node;
++
++  while ((p->left != NULL) && (p->left->right == p))
++    p = p->left;
++
++  return p->left;
++}
++
++static
++unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down)
++{
++  asn1_node_const d, u;
++
++  if (up_cand == NULL || down == NULL)
++    return 0;
++
++  d = down;
++
++  while ((u = _asn1_find_up(d)) != NULL && u != d)
++    {
++      if (u == up_cand)
++        return 1;
++      d = u;
++    }
++
++  return 0;
++}
++
++/******************************************************************/
++/* Function : _asn1_delete_node_from_list                         */
++/* Description: deletes the list element given                    */
++/******************************************************************/
++void
++_asn1_delete_node_from_list (list_type *list, asn1_node node)
++{
++  list_type *p = list;
++
++  while (p)
++    {
++      if (p->node == node)
++        p->node = NULL;
++      p = p->next;
++    }
++}
++
++/******************************************************************/
++/* Function : _asn1_delete_list                                   */
++/* Description: deletes the list elements (not the elements       */
++/*  pointed by them).                                             */
++/******************************************************************/
++void
++_asn1_delete_list (list_type *e_list)
++{
++  list_type *p;
++
++  while (e_list)
++    {
++      p = e_list;
++      e_list = e_list->next;
++      free (p);
++    }
++}
++
++/******************************************************************/
++/* Function : _asn1_delete_list_and nodes                         */
++/* Description: deletes the list elements and the elements        */
++/*  pointed by them.                                              */
++/******************************************************************/
++void
++_asn1_delete_list_and_nodes (list_type *e_list)
++{
++  list_type *p;
++
++  while (e_list)
++    {
++      p = e_list;
++      e_list = e_list->next;
++      _asn1_remove_node (p->node, 0);
++      free (p);
++    }
++}
++
++
++char *
++_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
++{
++  uint64_t d, r;
++  char temp[LTOSTR_MAX_SIZE];
++  int count, k, start;
++  uint64_t val;
++
++  if (v < 0)
++    {
++      str[0] = '-';
++      start = 1;
++      val = -((uint64_t)v);
++    }
++  else
++    {
++      val = v;
++      start = 0;
++    }
++
++  count = 0;
++  do
++    {
++      d = val / 10;
++      r = val - d * 10;
++      temp[start + count] = '0' + (char) r;
++      count++;
++      val = d;
++    }
++  while (val && ((start+count) < LTOSTR_MAX_SIZE-1));
++
++  for (k = 0; k < count; k++)
++    str[k + start] = temp[start + count - k - 1];
++  str[count + start] = 0;
++  return str;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_change_integer_value                          */
++/* Description: converts into DER coding the value assign to an   */
++/*   INTEGER constant.                                            */
++/* Parameters:                                                    */
++/*   node: root of an ASN1element.                                */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
++/*   otherwise ASN1_SUCCESS                                             */
++/******************************************************************/
++int
++_asn1_change_integer_value (asn1_node node)
++{
++  asn1_node p;
++  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
++  unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
++  int len;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if ((type_field (p->type) == ASN1_ETYPE_INTEGER)
++	  && (p->type & CONST_ASSIGN))
++	{
++	  if (p->value)
++	    {
++	      _asn1_convert_integer (p->value, val, sizeof (val), &len);
++	      asn1_octet_der (val, len, val2, &len);
++	      _asn1_set_value (p, val2, len);
++	    }
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else
++	{
++	  if (p == node)
++	    p = NULL;
++	  else if (p->right)
++	    p = p->right;
++	  else
++	    {
++	      while (1)
++		{
++		  p = _asn1_find_up (p);
++		  if (p == node)
++		    {
++		      p = NULL;
++		      break;
++		    }
++		  if (p && p->right)
++		    {
++		      p = p->right;
++		      break;
++		    }
++		}
++	    }
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
++
++#define MAX_CONSTANTS 1024
++/******************************************************************/
++/* Function : _asn1_expand_object_id                              */
++/* Description: expand the IDs of an OBJECT IDENTIFIER constant.  */
++/* Parameters:                                                    */
++/*   list: root of an object list                                 */
++/*   node: root of an ASN1 element.                               */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                      */
++/*   otherwise ASN1_SUCCESS                                       */
++/******************************************************************/
++int
++_asn1_expand_object_id (list_type **list, asn1_node node)
++{
++  asn1_node p, p2, p3, p4, p5;
++  char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
++  int move, tlen, tries;
++  unsigned max_constants;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  _asn1_str_cpy (name_root, sizeof (name_root), node->name);
++
++  p = node;
++  move = DOWN;
++  tries = 0;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
++	      && (p->type & CONST_ASSIGN))
++	    {
++	      p2 = p->down;
++	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
++		{
++		  if (p2->value && !c_isdigit (p2->value[0]))
++		    {
++		      _asn1_str_cpy (name2, sizeof (name2), name_root);
++		      _asn1_str_cat (name2, sizeof (name2), ".");
++		      _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++		      p3 = asn1_find_node (node, name2);
++		      if (!p3 || _asn1_is_up(p2, p3) ||
++			  (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
++			  !(p3->type & CONST_ASSIGN))
++			return ASN1_ELEMENT_NOT_FOUND;
++
++		      _asn1_set_down (p, p2->right);
++		      if (p2->down)
++			_asn1_delete_structure (*list, &p2->down, 0);
++		      _asn1_delete_node_from_list(*list, p2);
++		      _asn1_remove_node (p2, 0);
++		      p2 = p;
++		      p4 = p3->down;
++		      max_constants = 0;
++		      while (p4)
++			{
++			  if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
++			    {
++			      max_constants++;
++			      if (max_constants == MAX_CONSTANTS)
++                                return ASN1_RECURSION;
++
++			      p5 =
++				_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
++			      _asn1_set_name (p5, p4->name);
++			      if (p4->value)
++			        {
++			          tlen = _asn1_strlen (p4->value);
++			          if (tlen > 0)
++			            _asn1_set_value (p5, p4->value, tlen + 1);
++			        }
++			      _asn1_add_static_node2(list, p5);
++
++			      if (p2 == p)
++				{
++				  _asn1_set_right (p5, p->down);
++				  _asn1_set_down (p, p5);
++				}
++			      else
++				{
++				  _asn1_set_right (p5, p2->right);
++				  _asn1_set_right (p2, p5);
++				}
++			      p2 = p5;
++			    }
++			  p4 = p4->right;
++			}
++		      move = DOWN;
++
++		      tries++;
++                      if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
++                        return ASN1_RECURSION;
++
++		      continue;
++		    }
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      tries = 0;
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p && p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  /*******************************/
++  /*       expand DEFAULT        */
++  /*******************************/
++  p = node;
++  move = DOWN;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	      (p->type & CONST_DEFAULT))
++	    {
++	      p2 = p->down;
++	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
++		{
++		  _asn1_str_cpy (name2, sizeof (name2), name_root);
++		  _asn1_str_cat (name2, sizeof (name2), ".");
++		  if (p2->value)
++		    _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++		  p3 = asn1_find_node (node, name2);
++		  if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
++		      || !(p3->type & CONST_ASSIGN))
++		    return ASN1_ELEMENT_NOT_FOUND;
++		  p4 = p3->down;
++		  name2[0] = 0;
++		  while (p4)
++		    {
++		      if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
++			{
++			  if (p4->value == NULL)
++			    return ASN1_VALUE_NOT_FOUND;
++
++			  if (name2[0])
++			    _asn1_str_cat (name2, sizeof (name2), ".");
++			  _asn1_str_cat (name2, sizeof (name2),
++					 (char *) p4->value);
++			}
++		      p4 = p4->right;
++		    }
++		  tlen = strlen (name2);
++		  if (tlen > 0)
++		    _asn1_set_value (p2, name2, tlen + 1);
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p && p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_type_set_config                               */
++/* Description: sets the CONST_SET and CONST_NOT_USED properties  */
++/*   in the fields of the SET elements.                           */
++/* Parameters:                                                    */
++/*   node: root of an ASN1 element.                               */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
++/*   otherwise ASN1_SUCCESS                                             */
++/******************************************************************/
++int
++_asn1_type_set_config (asn1_node node)
++{
++  asn1_node p, p2;
++  int move;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  move = DOWN;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_SET)
++	    {
++	      p2 = p->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
++		    p2->type |= CONST_SET | CONST_NOT_USED;
++		  p2 = p2->right;
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p && p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_check_identifier                              */
++/* Description: checks the definitions of all the identifiers     */
++/*   and the first element of an OBJECT_ID (e.g. {pkix 0 4}).     */
++/*   The _asn1_identifierMissing global variable is filled if     */
++/*   necessary.                                                   */
++/* Parameters:                                                    */
++/*   node: root of an ASN1 element.                               */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND      if NODE is NULL,                 */
++/*   ASN1_IDENTIFIER_NOT_FOUND   if an identifier is not defined, */
++/*   otherwise ASN1_SUCCESS                                       */
++/******************************************************************/
++int
++_asn1_check_identifier (asn1_node_const node)
++{
++  asn1_node_const p, p2;
++  char name2[ASN1_MAX_NAME_SIZE * 2 + 2];
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
++	{
++	  _asn1_str_cpy (name2, sizeof (name2), node->name);
++	  _asn1_str_cat (name2, sizeof (name2), ".");
++	  _asn1_str_cat (name2, sizeof (name2), (char *) p->value);
++	  p2 = asn1_find_node (node, name2);
++	  if (p2 == NULL)
++	    {
++	      if (p->value)
++		_asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value);
++	      else
++		_asn1_strcpy (_asn1_identifierMissing, "(null)");
++	      return ASN1_IDENTIFIER_NOT_FOUND;
++	    }
++	}
++      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	       (p->type & CONST_DEFAULT))
++	{
++	  p2 = p->down;
++	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
++	    {
++	      _asn1_str_cpy (name2, sizeof (name2), node->name);
++	      if (p2->value)
++	        {
++	          _asn1_str_cat (name2, sizeof (name2), ".");
++	          _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++	          _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
++	        }
++	      else
++		_asn1_strcpy (_asn1_identifierMissing, "(null)");
++
++	      p2 = asn1_find_node (node, name2);
++	      if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
++		  !(p2->type & CONST_ASSIGN))
++		return ASN1_IDENTIFIER_NOT_FOUND;
++	      else
++		_asn1_identifierMissing[0] = 0;
++	    }
++	}
++      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	       (p->type & CONST_ASSIGN))
++	{
++	  p2 = p->down;
++	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
++	    {
++	      if (p2->value && !c_isdigit (p2->value[0]))
++		{
++		  _asn1_str_cpy (name2, sizeof (name2), node->name);
++		  _asn1_str_cat (name2, sizeof (name2), ".");
++		  _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++		  _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
++
++		  p2 = asn1_find_node (node, name2);
++		  if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID)
++		      || !(p2->type & CONST_ASSIGN))
++		    return ASN1_IDENTIFIER_NOT_FOUND;
++		  else
++		    _asn1_identifierMissing[0] = 0;
++		}
++	    }
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (p)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == node)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p && p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_set_default_tag                               */
++/* Description: sets the default IMPLICIT or EXPLICIT property in */
++/*   the tagged elements that don't have this declaration.        */
++/* Parameters:                                                    */
++/*   node: pointer to a DEFINITIONS element.                      */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to   */
++/*     a DEFINITIONS element,                                     */
++/*   otherwise ASN1_SUCCESS                                       */
++/******************************************************************/
++int
++_asn1_set_default_tag (asn1_node node)
++{
++  asn1_node p;
++
++  if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if ((type_field (p->type) == ASN1_ETYPE_TAG) &&
++	  !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
++	{
++	  if (node->type & CONST_EXPLICIT)
++	    p->type |= CONST_EXPLICIT;
++	  else
++	    p->type |= CONST_IMPLICIT;
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == node)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p && p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
+diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
+new file mode 100644
+index 00000000000..8189c56a4c9
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/structure.c
+@@ -0,0 +1,1220 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++
++/*****************************************************/
++/* File: structure.c                                 */
++/* Description: Functions to create and delete an    */
++/*  ASN1 tree.                                       */
++/*****************************************************/
++
++
++#include <int.h>
++#include <structure.h>
++#include "parser_aux.h"
++#include <gstr.h>
++
++
++extern char _asn1_identifierMissing[];
++
++
++/******************************************************/
++/* Function : _asn1_add_single_node                     */
++/* Description: creates a new NODE_ASN element.       */
++/* Parameters:                                        */
++/*   type: type of the new element (see ASN1_ETYPE_         */
++/*         and CONST_ constants).                     */
++/* Return: pointer to the new element.                */
++/******************************************************/
++asn1_node
++_asn1_add_single_node (unsigned int type)
++{
++  asn1_node punt;
++
++  punt = calloc (1, sizeof (struct asn1_node_st));
++  if (punt == NULL)
++    return NULL;
++
++  punt->type = type;
++
++  return punt;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_find_left                                     */
++/* Description: returns the NODE_ASN element with RIGHT field that*/
++/*              points the element NODE.                          */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: NULL if not found.                                     */
++/******************************************************************/
++asn1_node
++_asn1_find_left (asn1_node_const node)
++{
++  if ((node == NULL) || (node->left == NULL) || (node->left->down == node))
++    return NULL;
++
++  return node->left;
++}
++
++
++int
++_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
++			       char *vector_name)
++{
++  FILE *file;
++  asn1_node_const p;
++  unsigned long t;
++
++  file = fopen (output_file_name, "w");
++
++  if (file == NULL)
++    return ASN1_FILE_NOT_FOUND;
++
++  fprintf (file, "#if HAVE_CONFIG_H\n");
++  fprintf (file, "# include \"config.h\"\n");
++  fprintf (file, "#endif\n\n");
++
++  fprintf (file, "#include <libtasn1.h>\n\n");
++
++  fprintf (file, "const asn1_static_node %s[] = {\n", vector_name);
++
++  p = pointer;
++
++  while (p)
++    {
++      fprintf (file, "  { ");
++
++      if (p->name[0] != 0)
++	fprintf (file, "\"%s\", ", p->name);
++      else
++	fprintf (file, "NULL, ");
++
++      t = p->type;
++      if (p->down)
++	t |= CONST_DOWN;
++      if (p->right)
++	t |= CONST_RIGHT;
++
++      fprintf (file, "%lu, ", t);
++
++      if (p->value)
++	fprintf (file, "\"%s\"},\n", p->value);
++      else
++	fprintf (file, "NULL },\n");
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p->right)
++	{
++	  p = p->right;
++	}
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == pointer)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  fprintf (file, "  { NULL, 0, NULL }\n};\n");
++
++  fclose (file);
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_array2tree:
++ * @array: specify the array that contains ASN.1 declarations
++ * @definitions: return the pointer to the structure created by
++ *   *ARRAY ASN.1 declarations
++ * @errorDescription: return the error description.
++ *
++ * Creates the structures needed to manage the ASN.1 definitions.
++ * @array is a vector created by asn1_parser2array().
++ *
++ * Returns: %ASN1_SUCCESS if structure was created correctly,
++ *   %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL,
++ *   %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier
++ *   that is not defined (see @errorDescription for more information),
++ *   %ASN1_ARRAY_ERROR if the array pointed by @array is wrong.
++ **/
++int
++asn1_array2tree (const asn1_static_node * array, asn1_node * definitions,
++		 char *errorDescription)
++{
++  asn1_node p, p_last = NULL;
++  unsigned long k;
++  int move;
++  int result;
++  unsigned int type;
++  list_type *e_list = NULL;
++
++  if (errorDescription)
++    errorDescription[0] = 0;
++
++  if (*definitions != NULL)
++    return ASN1_ELEMENT_NOT_EMPTY;
++
++  move = UP;
++
++  for (k = 0; array[k].value || array[k].type || array[k].name; k++)
++    {
++      type = convert_old_type (array[k].type);
++
++      p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN));
++      if (array[k].name)
++	_asn1_set_name (p, array[k].name);
++      if (array[k].value)
++	_asn1_set_value (p, array[k].value, strlen (array[k].value) + 1);
++
++      if (*definitions == NULL)
++	*definitions = p;
++
++      if (move == DOWN)
++	{
++	  if (p_last && p_last->down)
++	      _asn1_delete_structure (e_list, &p_last->down, 0);
++	  _asn1_set_down (p_last, p);
++	}
++      else if (move == RIGHT)
++        {
++	  if (p_last && p_last->right)
++	      _asn1_delete_structure (e_list, &p_last->right, 0);
++	  _asn1_set_right (p_last, p);
++        }
++
++      p_last = p;
++
++      if (type & CONST_DOWN)
++	move = DOWN;
++      else if (type & CONST_RIGHT)
++	move = RIGHT;
++      else
++	{
++	  while (p_last != *definitions)
++	    {
++	      p_last = _asn1_find_up (p_last);
++
++	      if (p_last == NULL)
++		break;
++
++	      if (p_last->type & CONST_RIGHT)
++		{
++		  p_last->type &= ~CONST_RIGHT;
++		  move = RIGHT;
++		  break;
++		}
++	    }			/* while */
++	}
++    }				/* while */
++
++  if (p_last == *definitions)
++    {
++      result = _asn1_check_identifier (*definitions);
++      if (result == ASN1_SUCCESS)
++	{
++	  _asn1_change_integer_value (*definitions);
++	  result = _asn1_expand_object_id (&e_list, *definitions);
++	}
++    }
++  else
++    {
++      result = ASN1_ARRAY_ERROR;
++    }
++
++  if (errorDescription != NULL)
++    {
++      if (result == ASN1_IDENTIFIER_NOT_FOUND)
++	{
++	  Estrcpy (errorDescription, ":: identifier '");
++	  Estrcat (errorDescription, _asn1_identifierMissing);
++	  Estrcat (errorDescription, "' not found");
++	}
++      else
++	errorDescription[0] = 0;
++    }
++
++  if (result != ASN1_SUCCESS)
++    {
++      _asn1_delete_list_and_nodes (e_list);
++      *definitions = NULL;
++    }
++  else
++    _asn1_delete_list (e_list);
++
++  return result;
++}
++
++/**
++ * asn1_delete_structure:
++ * @structure: pointer to the structure that you want to delete.
++ *
++ * Deletes the structure *@structure.  At the end, *@structure is set
++ * to NULL.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   *@structure was NULL.
++ **/
++int
++asn1_delete_structure (asn1_node * structure)
++{
++  return _asn1_delete_structure (NULL, structure, 0);
++}
++
++/**
++ * asn1_delete_structure2:
++ * @structure: pointer to the structure that you want to delete.
++ * @flags: additional flags (see %ASN1_DELETE_FLAG)
++ *
++ * Deletes the structure *@structure.  At the end, *@structure is set
++ * to NULL.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   *@structure was NULL.
++ **/
++int
++asn1_delete_structure2 (asn1_node * structure, unsigned int flags)
++{
++  return _asn1_delete_structure (NULL, structure, flags);
++}
++
++int
++_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags)
++{
++  asn1_node p, p2, p3;
++
++  if (*structure == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = *structure;
++  while (p)
++    {
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else
++	{			/* no down */
++	  p2 = p->right;
++	  if (p != *structure)
++	    {
++	      p3 = _asn1_find_up (p);
++	      _asn1_set_down (p3, p2);
++	      if (e_list)
++		_asn1_delete_node_from_list (e_list, p);
++	      _asn1_remove_node (p, flags);
++	      p = p3;
++	    }
++	  else
++	    {			/* p==root */
++	      p3 = _asn1_find_left (p);
++	      if (!p3)
++		{
++		  p3 = _asn1_find_up (p);
++		  if (p3)
++		    _asn1_set_down (p3, p2);
++		  else
++		    {
++		      if (p->right)
++			p->right->left = NULL;
++		    }
++		}
++	      else
++		_asn1_set_right (p3, p2);
++	      if (e_list)
++		_asn1_delete_node_from_list (e_list, p);
++	      _asn1_remove_node (p, flags);
++	      p = NULL;
++	    }
++	}
++    }
++
++  *structure = NULL;
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_delete_element:
++ * @structure: pointer to the structure that contains the element you
++ *   want to delete.
++ * @element_name: element's name you want to delete.
++ *
++ * Deletes the element named *@element_name inside *@structure.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   the @element_name was not found.
++ **/
++int
++asn1_delete_element (asn1_node structure, const char *element_name)
++{
++  asn1_node p2, p3, source_node;
++
++  source_node = asn1_find_node (structure, element_name);
++
++  if (source_node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p2 = source_node->right;
++  p3 = _asn1_find_left (source_node);
++  if (!p3)
++    {
++      p3 = _asn1_find_up (source_node);
++      if (p3)
++	_asn1_set_down (p3, p2);
++      else if (source_node->right)
++	source_node->right->left = NULL;
++    }
++  else
++    _asn1_set_right (p3, p2);
++
++  return asn1_delete_structure (&source_node);
++}
++
++#ifndef __clang_analyzer__
++asn1_node
++_asn1_copy_structure3 (asn1_node_const source_node)
++{
++  asn1_node_const p_s;
++  asn1_node dest_node, p_d, p_d_prev;
++  int move;
++
++  if (source_node == NULL)
++    return NULL;
++
++  dest_node = _asn1_add_single_node (source_node->type);
++
++  p_s = source_node;
++  p_d = dest_node;
++
++  move = DOWN;
++
++  do
++    {
++      if (move != UP)
++	{
++	  if (p_s->name[0] != 0)
++	    _asn1_cpy_name (p_d, p_s);
++	  if (p_s->value)
++	    _asn1_set_value (p_d, p_s->value, p_s->value_len);
++	  if (p_s->down)
++	    {
++	      p_s = p_s->down;
++	      p_d_prev = p_d;
++	      p_d = _asn1_add_single_node (p_s->type);
++	      _asn1_set_down (p_d_prev, p_d);
++	      continue;
++	    }
++	  p_d->start = p_s->start;
++	  p_d->end = p_s->end;
++	}
++
++      if (p_s == source_node)
++	break;
++
++      if (p_s->right)
++	{
++	  move = RIGHT;
++	  p_s = p_s->right;
++	  p_d_prev = p_d;
++	  p_d = _asn1_add_single_node (p_s->type);
++	  _asn1_set_right (p_d_prev, p_d);
++	}
++      else
++	{
++	  move = UP;
++	  p_s = _asn1_find_up (p_s);
++	  p_d = _asn1_find_up (p_d);
++	}
++    }
++  while (p_s != source_node);
++  return dest_node;
++}
++#else
++
++/* Non-production code */
++asn1_node
++_asn1_copy_structure3 (asn1_node_const source_node)
++{
++  return NULL;
++}
++#endif /* __clang_analyzer__ */
++
++
++static asn1_node
++_asn1_copy_structure2 (asn1_node_const root, const char *source_name)
++{
++  asn1_node source_node;
++
++  source_node = asn1_find_node (root, source_name);
++
++  return _asn1_copy_structure3 (source_node);
++
++}
++
++
++static int
++_asn1_type_choice_config (asn1_node node)
++{
++  asn1_node p, p2, p3, p4;
++  int move, tlen;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  move = DOWN;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if ((type_field (p->type) == ASN1_ETYPE_CHOICE)
++	      && (p->type & CONST_TAG))
++	    {
++	      p2 = p->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
++		    {
++		      p2->type |= CONST_TAG;
++		      p3 = _asn1_find_left (p2);
++		      while (p3)
++			{
++			  if (type_field (p3->type) == ASN1_ETYPE_TAG)
++			    {
++			      p4 = _asn1_add_single_node (p3->type);
++			      tlen = _asn1_strlen (p3->value);
++			      if (tlen > 0)
++				_asn1_set_value (p4, p3->value, tlen + 1);
++			      _asn1_set_right (p4, p2->down);
++			      _asn1_set_down (p2, p4);
++			    }
++			  p3 = _asn1_find_left (p3);
++			}
++		    }
++		  p2 = p2->right;
++		}
++	      p->type &= ~(CONST_TAG);
++	      p2 = p->down;
++	      while (p2)
++		{
++		  p3 = p2->right;
++		  if (type_field (p2->type) == ASN1_ETYPE_TAG)
++		    asn1_delete_structure (&p2);
++		  p2 = p3;
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++static int
++_asn1_expand_identifier (asn1_node * node, asn1_node_const root)
++{
++  asn1_node p, p2, p3;
++  char name2[ASN1_MAX_NAME_SIZE + 2];
++  int move;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = *node;
++  move = DOWN;
++
++  while (!((p == *node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
++	    {
++	      snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value);
++	      p2 = _asn1_copy_structure2 (root, name2);
++	      if (p2 == NULL)
++		{
++		  return ASN1_IDENTIFIER_NOT_FOUND;
++		}
++	      _asn1_cpy_name (p2, p);
++	      p2->right = p->right;
++	      p2->left = p->left;
++	      if (p->right)
++		p->right->left = p2;
++	      p3 = p->down;
++	      if (p3)
++		{
++		  while (p3->right)
++		    p3 = p3->right;
++		  _asn1_set_right (p3, p2->down);
++		  _asn1_set_down (p2, p->down);
++		}
++
++	      p3 = _asn1_find_left (p);
++	      if (p3)
++		_asn1_set_right (p3, p2);
++	      else
++		{
++		  p3 = _asn1_find_up (p);
++		  if (p3)
++		    _asn1_set_down (p3, p2);
++		  else
++		    {
++		      p2->left = NULL;
++		    }
++		}
++
++	      if (p->type & CONST_SIZE)
++		p2->type |= CONST_SIZE;
++	      if (p->type & CONST_TAG)
++		p2->type |= CONST_TAG;
++	      if (p->type & CONST_OPTION)
++		p2->type |= CONST_OPTION;
++	      if (p->type & CONST_DEFAULT)
++		p2->type |= CONST_DEFAULT;
++	      if (p->type & CONST_SET)
++		p2->type |= CONST_SET;
++	      if (p->type & CONST_NOT_USED)
++		p2->type |= CONST_NOT_USED;
++
++	      if (p == *node)
++		*node = p2;
++	      _asn1_remove_node (p, 0);
++	      p = p2;
++	      move = DOWN;
++	      continue;
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == *node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_create_element:
++ * @definitions: pointer to the structure returned by "parser_asn1" function
++ * @source_name: the name of the type of the new structure (must be
++ *   inside p_structure).
++ * @element: pointer to the structure created.
++ *
++ * Creates a structure of type @source_name.  Example using
++ *  "pkix.asn":
++ *
++ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr);
++ *
++ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if
++ *   @source_name is not known.
++ **/
++int
++asn1_create_element (asn1_node_const definitions, const char *source_name,
++		     asn1_node * element)
++{
++  asn1_node dest_node;
++  int res;
++
++  dest_node = _asn1_copy_structure2 (definitions, source_name);
++
++  if (dest_node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  _asn1_set_name (dest_node, "");
++
++  res = _asn1_expand_identifier (&dest_node, definitions);
++  _asn1_type_choice_config (dest_node);
++
++  *element = dest_node;
++
++  return res;
++}
++
++
++/**
++ * asn1_print_structure:
++ * @out: pointer to the output file (e.g. stdout).
++ * @structure: pointer to the structure that you want to visit.
++ * @name: an element of the structure
++ * @mode: specify how much of the structure to print, can be
++ *   %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE,
++ *   %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL.
++ *
++ * Prints on the @out file descriptor the structure's tree starting
++ * from the @name element inside the structure @structure.
++ **/
++void
++asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
++		      int mode)
++{
++  asn1_node_const p, root;
++  int k, indent = 0, len, len2, len3;
++
++  if (out == NULL)
++    return;
++
++  root = asn1_find_node (structure, name);
++
++  if (root == NULL)
++    return;
++
++  p = root;
++  while (p)
++    {
++      if (mode == ASN1_PRINT_ALL)
++	{
++	  for (k = 0; k < indent; k++)
++	    fprintf (out, " ");
++	  fprintf (out, "name:");
++	  if (p->name[0] != 0)
++	    fprintf (out, "%s  ", p->name);
++	  else
++	    fprintf (out, "NULL  ");
++	}
++      else
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	    case ASN1_ETYPE_TAG:
++	    case ASN1_ETYPE_SIZE:
++	      break;
++	    default:
++	      for (k = 0; k < indent; k++)
++		fprintf (out, " ");
++	      fprintf (out, "name:");
++	      if (p->name[0] != 0)
++		fprintf (out, "%s  ", p->name);
++	      else
++		fprintf (out, "NULL  ");
++	    }
++	}
++
++      if (mode != ASN1_PRINT_NAME)
++	{
++	  unsigned type = type_field (p->type);
++	  switch (type)
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	      if (mode == ASN1_PRINT_ALL)
++		fprintf (out, "type:CONST");
++	      break;
++	    case ASN1_ETYPE_TAG:
++	      if (mode == ASN1_PRINT_ALL)
++		fprintf (out, "type:TAG");
++	      break;
++	    case ASN1_ETYPE_SIZE:
++	      if (mode == ASN1_PRINT_ALL)
++		fprintf (out, "type:SIZE");
++	      break;
++	    case ASN1_ETYPE_DEFAULT:
++	      fprintf (out, "type:DEFAULT");
++	      break;
++	    case ASN1_ETYPE_IDENTIFIER:
++	      fprintf (out, "type:IDENTIFIER");
++	      break;
++	    case ASN1_ETYPE_ANY:
++	      fprintf (out, "type:ANY");
++	      break;
++	    case ASN1_ETYPE_CHOICE:
++	      fprintf (out, "type:CHOICE");
++	      break;
++	    case ASN1_ETYPE_DEFINITIONS:
++	      fprintf (out, "type:DEFINITIONS");
++	      break;
++	    CASE_HANDLED_ETYPES:
++	      fprintf (out, "%s", _asn1_tags[type].desc);
++	      break;
++	    default:
++	      break;
++	    }
++	}
++
++      if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL))
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	      if (mode == ASN1_PRINT_ALL)
++		if (p->value)
++		  fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_TAG:
++	      if (mode == ASN1_PRINT_ALL)
++		if (p->value)
++		  fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_SIZE:
++	      if (mode == ASN1_PRINT_ALL)
++		if (p->value)
++		  fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_DEFAULT:
++	      if (p->value)
++		fprintf (out, "  value:%s", p->value);
++	      else if (p->type & CONST_TRUE)
++		fprintf (out, "  value:TRUE");
++	      else if (p->type & CONST_FALSE)
++		fprintf (out, "  value:FALSE");
++	      break;
++	    case ASN1_ETYPE_IDENTIFIER:
++	      if (p->value)
++		fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_INTEGER:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:0x");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_ENUMERATED:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:0x");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_BOOLEAN:
++	      if (p->value)
++		{
++		  if (p->value[0] == 'T')
++		    fprintf (out, "  value:TRUE");
++		  else if (p->value[0] == 'F')
++		    fprintf (out, "  value:FALSE");
++		}
++	      break;
++	    case ASN1_ETYPE_BIT_STRING:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  if (len > 0)
++		    {
++		      fprintf (out, "  value(%i):",
++			       (len - 1) * 8 - (p->value[len2]));
++		      for (k = 1; k < len; k++)
++			fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		    }
++		}
++	      break;
++	    case ASN1_ETYPE_GENERALIZED_TIME:
++	    case ASN1_ETYPE_UTC_TIME:
++	      if (p->value)
++		{
++		  fprintf (out, "  value:");
++		  for (k = 0; k < p->value_len; k++)
++		    fprintf (out, "%c", (p->value)[k]);
++		}
++	      break;
++	    case ASN1_ETYPE_GENERALSTRING:
++	    case ASN1_ETYPE_NUMERIC_STRING:
++	    case ASN1_ETYPE_IA5_STRING:
++	    case ASN1_ETYPE_TELETEX_STRING:
++	    case ASN1_ETYPE_PRINTABLE_STRING:
++	    case ASN1_ETYPE_UNIVERSAL_STRING:
++	    case ASN1_ETYPE_UTF8_STRING:
++	    case ASN1_ETYPE_VISIBLE_STRING:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%c", (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_BMP_STRING:
++	    case ASN1_ETYPE_OCTET_STRING:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_OBJECT_ID:
++	      if (p->value)
++		fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_ANY:
++	      if (p->value)
++		{
++		  len3 = -1;
++		  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++		  fprintf (out, "  value:");
++		  if (len2 > 0)
++		    for (k = 0; k < len2; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len3]);
++		}
++	      break;
++	    case ASN1_ETYPE_SET:
++	    case ASN1_ETYPE_SET_OF:
++	    case ASN1_ETYPE_CHOICE:
++	    case ASN1_ETYPE_DEFINITIONS:
++	    case ASN1_ETYPE_SEQUENCE_OF:
++	    case ASN1_ETYPE_SEQUENCE:
++	    case ASN1_ETYPE_NULL:
++	      break;
++	    default:
++	      break;
++	    }
++	}
++
++      if (mode == ASN1_PRINT_ALL)
++	{
++	  if (p->type & 0x1FFFFF00)
++	    {
++	      fprintf (out, "  attr:");
++	      if (p->type & CONST_UNIVERSAL)
++		fprintf (out, "UNIVERSAL,");
++	      if (p->type & CONST_PRIVATE)
++		fprintf (out, "PRIVATE,");
++	      if (p->type & CONST_APPLICATION)
++		fprintf (out, "APPLICATION,");
++	      if (p->type & CONST_EXPLICIT)
++		fprintf (out, "EXPLICIT,");
++	      if (p->type & CONST_IMPLICIT)
++		fprintf (out, "IMPLICIT,");
++	      if (p->type & CONST_TAG)
++		fprintf (out, "TAG,");
++	      if (p->type & CONST_DEFAULT)
++		fprintf (out, "DEFAULT,");
++	      if (p->type & CONST_TRUE)
++		fprintf (out, "TRUE,");
++	      if (p->type & CONST_FALSE)
++		fprintf (out, "FALSE,");
++	      if (p->type & CONST_LIST)
++		fprintf (out, "LIST,");
++	      if (p->type & CONST_MIN_MAX)
++		fprintf (out, "MIN_MAX,");
++	      if (p->type & CONST_OPTION)
++		fprintf (out, "OPTION,");
++	      if (p->type & CONST_1_PARAM)
++		fprintf (out, "1_PARAM,");
++	      if (p->type & CONST_SIZE)
++		fprintf (out, "SIZE,");
++	      if (p->type & CONST_DEFINED_BY)
++		fprintf (out, "DEF_BY,");
++	      if (p->type & CONST_GENERALIZED)
++		fprintf (out, "GENERALIZED,");
++	      if (p->type & CONST_UTC)
++		fprintf (out, "UTC,");
++	      if (p->type & CONST_SET)
++		fprintf (out, "SET,");
++	      if (p->type & CONST_NOT_USED)
++		fprintf (out, "NOT_USED,");
++	      if (p->type & CONST_ASSIGN)
++		fprintf (out, "ASSIGNMENT,");
++	    }
++	}
++
++      if (mode == ASN1_PRINT_ALL)
++	{
++	  fprintf (out, "\n");
++	}
++      else
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	    case ASN1_ETYPE_TAG:
++	    case ASN1_ETYPE_SIZE:
++	      break;
++	    default:
++	      fprintf (out, "\n");
++	    }
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	  indent += 2;
++	}
++      else if (p == root)
++	{
++	  p = NULL;
++	  break;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == root)
++		{
++		  p = NULL;
++		  break;
++		}
++	      indent -= 2;
++	      if (p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++}
++
++
++
++/**
++ * asn1_number_of_elements:
++ * @element: pointer to the root of an ASN1 structure.
++ * @name: the name of a sub-structure of ROOT.
++ * @num: pointer to an integer where the result will be stored
++ *
++ * Counts the number of elements of a sub-structure called NAME with
++ * names equal to "?1","?2", ...
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL.
++ **/
++int
++asn1_number_of_elements (asn1_node_const element, const char *name, int *num)
++{
++  asn1_node_const node, p;
++
++  if (num == NULL)
++    return ASN1_GENERIC_ERROR;
++
++  *num = 0;
++
++  node = asn1_find_node (element, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node->down;
++
++  while (p)
++    {
++      if (p->name[0] == '?')
++	(*num)++;
++      p = p->right;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_find_structure_from_oid:
++ * @definitions: ASN1 definitions
++ * @oidValue: value of the OID to search (e.g. "1.2.3.4").
++ *
++ * Search the structure that is defined just after an OID definition.
++ *
++ * Returns: %NULL when @oidValue not found, otherwise the pointer to a
++ *   constant string that contains the element name defined just after
++ *   the OID.
++ **/
++const char *
++asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
++{
++  char name[2 * ASN1_MAX_NAME_SIZE + 2];
++  char value[ASN1_MAX_NAME_SIZE];
++  asn1_node p;
++  int len;
++  int result;
++  const char *definitionsName;
++
++  if ((definitions == NULL) || (oidValue == NULL))
++    return NULL;		/* ASN1_ELEMENT_NOT_FOUND; */
++
++  definitionsName = definitions->name;
++
++  /* search the OBJECT_ID into definitions */
++  p = definitions->down;
++  while (p)
++    {
++      if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	  (p->type & CONST_ASSIGN))
++	{
++          snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name);
++
++	  len = ASN1_MAX_NAME_SIZE;
++	  result = asn1_read_value (definitions, name, value, &len);
++
++	  if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value)))
++	    {
++	      p = p->right;
++	      if (p == NULL)	/* reach the end of ASN1 definitions */
++		return NULL;	/* ASN1_ELEMENT_NOT_FOUND; */
++
++	      return p->name;
++	    }
++	}
++      p = p->right;
++    }
++
++  return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
++}
++
++/**
++ * asn1_copy_node:
++ * @dst: Destination asn1 node.
++ * @dst_name: Field name in destination node.
++ * @src: Source asn1 node.
++ * @src_name: Field name in source node.
++ *
++ * Create a deep copy of a asn1_node variable. That
++ * function requires @dst to be expanded using asn1_create_element().
++ *
++ * Returns: Return %ASN1_SUCCESS on success.
++ **/
++int
++asn1_copy_node (asn1_node dst, const char *dst_name,
++		asn1_node_const src, const char *src_name)
++{
++  int result;
++  asn1_node dst_node;
++  void *data = NULL;
++  int size = 0;
++
++  result = asn1_der_coding (src, src_name, NULL, &size, NULL);
++  if (result != ASN1_MEM_ERROR)
++    return result;
++
++  data = malloc (size);
++  if (data == NULL)
++    return ASN1_MEM_ERROR;
++
++  result = asn1_der_coding (src, src_name, data, &size, NULL);
++  if (result != ASN1_SUCCESS)
++    {
++      free (data);
++      return result;
++    }
++
++  dst_node = asn1_find_node (dst, dst_name);
++  if (dst_node == NULL)
++    {
++      free (data);
++      return ASN1_ELEMENT_NOT_FOUND;
++    }
++
++  result = asn1_der_decoding (&dst_node, data, size, NULL);
++
++  free (data);
++
++  return result;
++}
++
++/**
++ * asn1_dup_node:
++ * @src: Source asn1 node.
++ * @src_name: Field name in source node.
++ *
++ * Create a deep copy of a asn1_node variable. This function
++ * will return an exact copy of the provided structure.
++ *
++ * Returns: Return %NULL on failure.
++ **/
++asn1_node
++asn1_dup_node (asn1_node_const src, const char *src_name)
++{
++  return _asn1_copy_structure2(src, src_name);
++}
+diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h
+new file mode 100644
+index 00000000000..440a33f4bb1
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/element.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef _ELEMENT_H
++#define _ELEMENT_H
++
++
++struct node_tail_cache_st
++{
++	asn1_node head; /* the first element of the sequence */
++	asn1_node tail;
++};
++
++int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached);
++
++int _asn1_convert_integer (const unsigned char *value,
++			   unsigned char *value_out,
++			   int value_out_size, int *len);
++
++void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size);
++
++#endif
+diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h
+new file mode 100644
+index 00000000000..48229844ff3
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/gstr.h
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef GSTR_H
++# define GSTR_H
++
++unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size,
++			    const char *src);
++void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src);
++
++#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
++#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
++
++inline static
++void safe_memset(void *data, int c, size_t size)
++{
++	volatile unsigned volatile_zero = 0;
++	volatile char *vdata = (volatile char*)data;
++
++	/* This is based on a nice trick for safe memset,
++	 * sent by David Jacobson in the openssl-dev mailing list.
++	 */
++
++	if (size > 0) do {
++		memset(data, c, size);
++	} while(vdata[volatile_zero] != c);
++}
++
++#endif /* GSTR_H */
+diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
+new file mode 100644
+index 00000000000..ea1625786c1
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/int.h
+@@ -0,0 +1,221 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef INT_H
++#define INT_H
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <stdint.h>
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include <libtasn1.h>
++
++#define ASN1_SMALL_VALUE_SIZE 16
++
++/* This structure is also in libtasn1.h, but then contains less
++   fields.  You cannot make any modifications to these first fields
++   without breaking ABI.  */
++struct asn1_node_st
++{
++  /* public fields: */
++  char name[ASN1_MAX_NAME_SIZE + 1];	/* Node name */
++  unsigned int name_hash;
++  unsigned int type;		/* Node type */
++  unsigned char *value;		/* Node value */
++  int value_len;
++  asn1_node down;		/* Pointer to the son node */
++  asn1_node right;		/* Pointer to the brother node */
++  asn1_node left;		/* Pointer to the next list element */
++  /* private fields: */
++  unsigned char small_value[ASN1_SMALL_VALUE_SIZE];	/* For small values */
++
++  /* values used during decoding/coding */
++  int tmp_ival;
++  unsigned start; /* the start of the DER sequence - if decoded */
++  unsigned end; /* the end of the DER sequence - if decoded */
++};
++
++typedef struct tag_and_class_st
++{
++  unsigned tag;
++  unsigned class;
++  const char *desc;
++} tag_and_class_st;
++
++/* the types that are handled in _asn1_tags */
++#define CASE_HANDLED_ETYPES \
++	case ASN1_ETYPE_NULL: \
++	case ASN1_ETYPE_BOOLEAN: \
++	case ASN1_ETYPE_INTEGER: \
++	case ASN1_ETYPE_ENUMERATED: \
++	case ASN1_ETYPE_OBJECT_ID: \
++	case ASN1_ETYPE_OCTET_STRING: \
++	case ASN1_ETYPE_GENERALSTRING: \
++        case ASN1_ETYPE_NUMERIC_STRING: \
++        case ASN1_ETYPE_IA5_STRING: \
++        case ASN1_ETYPE_TELETEX_STRING: \
++        case ASN1_ETYPE_PRINTABLE_STRING: \
++        case ASN1_ETYPE_UNIVERSAL_STRING: \
++        case ASN1_ETYPE_BMP_STRING: \
++        case ASN1_ETYPE_UTF8_STRING: \
++        case ASN1_ETYPE_VISIBLE_STRING: \
++	case ASN1_ETYPE_BIT_STRING: \
++	case ASN1_ETYPE_SEQUENCE: \
++	case ASN1_ETYPE_SEQUENCE_OF: \
++	case ASN1_ETYPE_SET: \
++	case ASN1_ETYPE_UTC_TIME: \
++	case ASN1_ETYPE_GENERALIZED_TIME: \
++	case ASN1_ETYPE_SET_OF
++
++#define ETYPE_TAG(etype) (_asn1_tags[etype].tag)
++#define ETYPE_CLASS(etype) (_asn1_tags[etype].class)
++#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \
++                          (etype) <= _asn1_tags_size && \
++                          _asn1_tags[(etype)].desc != NULL)?1:0)
++
++#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \
++	etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \
++	etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \
++	etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \
++	etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \
++	etype == ASN1_ETYPE_OCTET_STRING)?1:0)
++
++extern unsigned int _asn1_tags_size;
++extern const tag_and_class_st _asn1_tags[];
++
++#define _asn1_strlen(s) strlen((const char *) s)
++#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b)
++#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
++#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
++#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
++#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
++
++#if SIZEOF_UNSIGNED_LONG_INT == 8
++# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
++#else
++# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b)
++#endif
++
++#define MAX_LOG_SIZE 1024	/* maximum number of characters of a log message */
++
++/* Define used for visiting trees. */
++#define UP     1
++#define RIGHT  2
++#define DOWN   3
++
++/***********************************************************************/
++/* List of constants to better specify the type of typedef asn1_node_st.   */
++/***********************************************************************/
++/*  Used with TYPE_TAG  */
++#define CONST_UNIVERSAL   (1U<<8)
++#define CONST_PRIVATE     (1U<<9)
++#define CONST_APPLICATION (1U<<10)
++#define CONST_EXPLICIT    (1U<<11)
++#define CONST_IMPLICIT    (1U<<12)
++
++#define CONST_TAG         (1U<<13)	/*  Used in ASN.1 assignement  */
++#define CONST_OPTION      (1U<<14)
++#define CONST_DEFAULT     (1U<<15)
++#define CONST_TRUE        (1U<<16)
++#define CONST_FALSE       (1U<<17)
++
++#define CONST_LIST        (1U<<18)	/*  Used with TYPE_INTEGER and TYPE_BIT_STRING  */
++#define CONST_MIN_MAX     (1U<<19)
++
++#define CONST_1_PARAM     (1U<<20)
++
++#define CONST_SIZE        (1U<<21)
++
++#define CONST_DEFINED_BY  (1U<<22)
++
++/* Those two are deprecated and used for backwards compatibility */
++#define CONST_GENERALIZED (1U<<23)
++#define CONST_UTC         (1U<<24)
++
++/* #define CONST_IMPORTS     (1U<<25) */
++
++#define CONST_NOT_USED    (1U<<26)
++#define CONST_SET         (1U<<27)
++#define CONST_ASSIGN      (1U<<28)
++
++#define CONST_DOWN        (1U<<29)
++#define CONST_RIGHT       (1U<<30)
++
++
++#define ASN1_ETYPE_TIME 17
++/****************************************/
++/* Returns the first 8 bits.            */
++/* Used with the field type of asn1_node_st */
++/****************************************/
++inline static unsigned int
++type_field (unsigned int ntype)
++{
++  return (ntype & 0xff);
++}
++
++/* To convert old types from a static structure */
++inline static unsigned int
++convert_old_type (unsigned int ntype)
++{
++  unsigned int type = ntype & 0xff;
++  if (type == ASN1_ETYPE_TIME)
++    {
++      if (ntype & CONST_UTC)
++	type = ASN1_ETYPE_UTC_TIME;
++      else
++	type = ASN1_ETYPE_GENERALIZED_TIME;
++
++      ntype &= ~(CONST_UTC | CONST_GENERALIZED);
++      ntype &= 0xffffff00;
++      ntype |= type;
++
++      return ntype;
++    }
++  else
++    return ntype;
++}
++
++static inline
++void *_asn1_realloc(void *ptr, size_t size)
++{
++  void *ret;
++
++  if (size == 0)
++    return ptr;
++
++  ret = realloc(ptr, size);
++  if (ret == NULL)
++    {
++      free(ptr);
++    }
++  return ret;
++}
++
++#endif /* INT_H */
+diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h
+new file mode 100644
+index 00000000000..598e684b355
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/parser_aux.h
+@@ -0,0 +1,172 @@
++/*
++ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef _PARSER_AUX_H
++#define _PARSER_AUX_H
++
++/***********************************************/
++/* Type: list_type                             */
++/* Description: type used in the list during   */
++/* the structure creation.                     */
++/***********************************************/
++typedef struct list_struct
++{
++  asn1_node node;
++  struct list_struct *next;
++} list_type;
++
++/***************************************/
++/*  Functions used by ASN.1 parser     */
++/***************************************/
++asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type);
++
++void _asn1_delete_list (list_type *e_list);
++
++void _asn1_delete_list_and_nodes (list_type *e_list);
++
++void _asn1_delete_node_from_list (list_type *list, asn1_node node);
++
++asn1_node
++_asn1_set_value (asn1_node node, const void *value, unsigned int len);
++
++asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len);
++
++asn1_node
++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len);
++
++asn1_node
++_asn1_append_value (asn1_node node, const void *value, unsigned int len);
++
++asn1_node _asn1_set_name (asn1_node node, const char *name);
++
++asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src);
++
++asn1_node _asn1_set_right (asn1_node node, asn1_node right);
++
++asn1_node _asn1_get_last_right (asn1_node_const node);
++
++void _asn1_remove_node (asn1_node node, unsigned int flags);
++
++/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */
++#define LTOSTR_MAX_SIZE 22
++char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]);
++
++asn1_node _asn1_find_up (asn1_node_const node);
++
++int _asn1_change_integer_value (asn1_node node);
++
++#define EXPAND_OBJECT_ID_MAX_RECURSION 16
++int _asn1_expand_object_id (list_type **list, asn1_node node);
++
++int _asn1_type_set_config (asn1_node node);
++
++int _asn1_check_identifier (asn1_node_const node);
++
++int _asn1_set_default_tag (asn1_node node);
++
++/******************************************************************/
++/* Function : _asn1_get_right                                     */
++/* Description: returns the element pointed by the RIGHT field of */
++/*              a NODE_ASN element.                               */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: field RIGHT of NODE.                                   */
++/******************************************************************/
++inline static asn1_node
++_asn1_get_right (asn1_node_const node)
++{
++  if (node == NULL)
++    return NULL;
++  return node->right;
++}
++
++/******************************************************************/
++/* Function : _asn1_set_down                                      */
++/* Description: sets the field DOWN in a NODE_ASN element.        */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   down: pointer to a NODE_ASN element that you want be pointed */
++/*          by NODE.                                              */
++/* Return: pointer to *NODE.                                      */
++/******************************************************************/
++inline static asn1_node
++_asn1_set_down (asn1_node node, asn1_node down)
++{
++  if (node == NULL)
++    return node;
++  node->down = down;
++  if (down)
++    down->left = node;
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_get_down                                      */
++/* Description: returns the element pointed by the DOWN field of  */
++/*              a NODE_ASN element.                               */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: field DOWN of NODE.                                    */
++/******************************************************************/
++inline static asn1_node
++_asn1_get_down (asn1_node_const node)
++{
++  if (node == NULL)
++    return NULL;
++  return node->down;
++}
++
++/******************************************************************/
++/* Function : _asn1_get_name                                      */
++/* Description: returns the name of a NODE_ASN element.           */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: a null terminated string.                              */
++/******************************************************************/
++inline static char *
++_asn1_get_name (asn1_node_const node)
++{
++  if (node == NULL)
++    return NULL;
++  return (char *) node->name;
++}
++
++/******************************************************************/
++/* Function : _asn1_mod_type                                      */
++/* Description: change the field TYPE of an NODE_ASN element.     */
++/*              The new value is the old one | (bitwise or) the   */
++/*              paramener VALUE.                                  */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/*   value: the integer value that must be or-ed with the current */
++/*          value of field TYPE.                                  */
++/* Return: NODE pointer.                                          */
++/******************************************************************/
++inline static asn1_node
++_asn1_mod_type (asn1_node node, unsigned int value)
++{
++  if (node == NULL)
++    return node;
++  node->type |= value;
++  return node;
++}
++
++#endif
+diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h
+new file mode 100644
+index 00000000000..99e685da07a
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/structure.h
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++/*************************************************/
++/* File: structure.h                             */
++/* Description: list of exported object by       */
++/*   "structure.c"                               */
++/*************************************************/
++
++#ifndef _STRUCTURE_H
++#define _STRUCTURE_H
++
++#include "parser_aux.h" // list_type
++
++int _asn1_create_static_structure (asn1_node_const pointer,
++				   char *output_file_name, char *vector_name);
++
++asn1_node _asn1_copy_structure3 (asn1_node_const source_node);
++
++asn1_node _asn1_add_single_node (unsigned int type);
++
++asn1_node _asn1_find_left (asn1_node_const node);
++
++int
++_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags);
++
++#endif
+diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
+new file mode 100644
+index 00000000000..6fd7a30dc35
+--- /dev/null
++++ b/include/grub/libtasn1.h
+@@ -0,0 +1,588 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * LIBTASN1 is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * LIBTASN1 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with LIBTASN1; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ *
++ */
++
++/**
++ * libtasn1:Short_Description:
++ *
++ * GNU ASN.1 library
++ */
++/**
++ * libtasn1:Long_Description:
++ *
++ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as
++ * specified by the X.680 ITU-T recommendation) parsing and structures
++ * management, and Distinguished Encoding Rules (DER, as per X.690)
++ * encoding and decoding functions.
++ */
++
++
++#ifndef LIBTASN1_H
++#define LIBTASN1_H
++
++#ifndef ASN1_API
++#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
++#define ASN1_API __attribute__((__visibility__("default")))
++#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
++#define ASN1_API __declspec(dllexport)
++#elif defined _MSC_VER && ! defined ASN1_STATIC
++#define ASN1_API __declspec(dllimport)
++#else
++#define ASN1_API
++#endif
++#endif
++
++#ifdef __GNUC__
++# define __LIBTASN1_CONST__  __attribute__((const))
++# define __LIBTASN1_PURE__  __attribute__((pure))
++#else
++# define __LIBTASN1_CONST__
++# define __LIBTASN1_PURE__
++#endif
++
++#include <sys/types.h>
++#include <time.h>
++#include <stdio.h>		/* for FILE* */
++
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++/**
++ * ASN1_VERSION:
++ *
++ * Version of the library as a string.
++ */
++#define ASN1_VERSION "4.16.0"
++
++/**
++ * ASN1_VERSION_MAJOR:
++ *
++ * Major version number of the library.
++ */
++#define ASN1_VERSION_MAJOR 4
++
++/**
++ * ASN1_VERSION_MINOR:
++ *
++ * Minor version number of the library.
++ */
++#define ASN1_VERSION_MINOR 16
++
++/**
++ * ASN1_VERSION_PATCH:
++ *
++ * Patch version number of the library.
++ */
++#define ASN1_VERSION_PATCH 0
++
++/**
++ * ASN1_VERSION_NUMBER:
++ *
++ * Version number of the library as a number.
++ */
++#define ASN1_VERSION_NUMBER 0x041000
++
++
++#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD
++# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
++# if _ASN1_GCC_VERSION >= 30100
++#  define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__))
++# endif
++#endif
++
++#ifndef _ASN1_GCC_ATTR_DEPRECATED
++#define _ASN1_GCC_ATTR_DEPRECATED
++#endif
++
++/*****************************************/
++/* Errors returned by libtasn1 functions */
++/*****************************************/
++#define ASN1_SUCCESS			0
++#define ASN1_FILE_NOT_FOUND		1
++#define ASN1_ELEMENT_NOT_FOUND		2
++#define ASN1_IDENTIFIER_NOT_FOUND	3
++#define ASN1_DER_ERROR			4
++#define ASN1_VALUE_NOT_FOUND		5
++#define ASN1_GENERIC_ERROR		6
++#define ASN1_VALUE_NOT_VALID		7
++#define ASN1_TAG_ERROR			8
++#define ASN1_TAG_IMPLICIT		9
++#define ASN1_ERROR_TYPE_ANY		10
++#define ASN1_SYNTAX_ERROR		11
++#define ASN1_MEM_ERROR			12
++#define ASN1_MEM_ALLOC_ERROR		13
++#define ASN1_DER_OVERFLOW		14
++#define ASN1_NAME_TOO_LONG		15
++#define ASN1_ARRAY_ERROR		16
++#define ASN1_ELEMENT_NOT_EMPTY		17
++#define ASN1_TIME_ENCODING_ERROR	18
++#define ASN1_RECURSION			19
++
++/*************************************/
++/* Constants used in asn1_visit_tree */
++/*************************************/
++#define ASN1_PRINT_NAME			1
++#define ASN1_PRINT_NAME_TYPE		2
++#define ASN1_PRINT_NAME_TYPE_VALUE	3
++#define ASN1_PRINT_ALL			4
++
++/*****************************************/
++/* Constants returned by asn1_read_tag   */
++/*****************************************/
++#define ASN1_CLASS_UNIVERSAL		0x00	/* old: 1 */
++#define ASN1_CLASS_APPLICATION		0x40	/* old: 2 */
++#define ASN1_CLASS_CONTEXT_SPECIFIC	0x80	/* old: 3 */
++#define ASN1_CLASS_PRIVATE		0xC0	/* old: 4 */
++#define ASN1_CLASS_STRUCTURED		0x20
++
++/*****************************************/
++/* Constants returned by asn1_read_tag   */
++/*****************************************/
++#define ASN1_TAG_BOOLEAN		0x01
++#define ASN1_TAG_INTEGER		0x02
++#define ASN1_TAG_SEQUENCE		0x10
++#define ASN1_TAG_SET			0x11
++#define ASN1_TAG_OCTET_STRING		0x04
++#define ASN1_TAG_BIT_STRING		0x03
++#define ASN1_TAG_UTCTime		0x17
++#define ASN1_TAG_GENERALIZEDTime	0x18
++#define ASN1_TAG_OBJECT_ID		0x06
++#define ASN1_TAG_ENUMERATED		0x0A
++#define ASN1_TAG_NULL			0x05
++#define ASN1_TAG_GENERALSTRING		0x1B
++#define ASN1_TAG_NUMERIC_STRING		0x12
++#define ASN1_TAG_IA5_STRING		0x16
++#define ASN1_TAG_TELETEX_STRING		0x14
++#define ASN1_TAG_PRINTABLE_STRING	0x13
++#define ASN1_TAG_UNIVERSAL_STRING	0x1C
++#define ASN1_TAG_BMP_STRING		0x1E
++#define ASN1_TAG_UTF8_STRING		0x0C
++#define ASN1_TAG_VISIBLE_STRING		0x1A
++
++/**
++ * asn1_node:
++ *
++ * Structure definition used for the node of the tree
++ * that represents an ASN.1 DEFINITION.
++ */
++typedef struct asn1_node_st asn1_node_st;
++
++typedef asn1_node_st *asn1_node;
++typedef const asn1_node_st *asn1_node_const;
++
++/**
++ * ASN1_MAX_NAME_SIZE:
++ *
++ * Maximum number of characters of a name
++ * inside a file with ASN1 definitions.
++ */
++#define ASN1_MAX_NAME_SIZE 64
++
++
++/**
++ * asn1_static_node:
++ * @name: Node name
++ * @type: Node typ
++ * @value: Node value
++ *
++ * For the on-disk format of ASN.1 trees, created by asn1_parser2array().
++ */
++struct asn1_static_node_st
++{
++  const char *name;		/* Node name */
++  unsigned int type;		/* Node type */
++  const void *value;		/* Node value */
++};
++typedef struct asn1_static_node_st asn1_static_node;
++
++/* List of constants for field type of node_asn  */
++#define ASN1_ETYPE_INVALID        0
++#define ASN1_ETYPE_CONSTANT       1
++#define ASN1_ETYPE_IDENTIFIER     2
++#define ASN1_ETYPE_INTEGER        3
++#define ASN1_ETYPE_BOOLEAN        4
++#define ASN1_ETYPE_SEQUENCE       5
++#define ASN1_ETYPE_BIT_STRING     6
++#define ASN1_ETYPE_OCTET_STRING   7
++#define ASN1_ETYPE_TAG            8
++#define ASN1_ETYPE_DEFAULT        9
++#define ASN1_ETYPE_SIZE          10
++#define ASN1_ETYPE_SEQUENCE_OF   11
++#define ASN1_ETYPE_OBJECT_ID     12
++#define ASN1_ETYPE_ANY           13
++#define ASN1_ETYPE_SET           14
++#define ASN1_ETYPE_SET_OF        15
++#define ASN1_ETYPE_DEFINITIONS   16
++#define ASN1_ETYPE_CHOICE        18
++#define ASN1_ETYPE_IMPORTS       19
++#define ASN1_ETYPE_NULL          20
++#define ASN1_ETYPE_ENUMERATED    21
++#define ASN1_ETYPE_GENERALSTRING 27
++#define ASN1_ETYPE_NUMERIC_STRING 28
++#define ASN1_ETYPE_IA5_STRING     29
++#define ASN1_ETYPE_TELETEX_STRING 30
++#define ASN1_ETYPE_PRINTABLE_STRING 31
++#define ASN1_ETYPE_UNIVERSAL_STRING 32
++#define ASN1_ETYPE_BMP_STRING     33
++#define ASN1_ETYPE_UTF8_STRING    34
++#define ASN1_ETYPE_VISIBLE_STRING 35
++#define ASN1_ETYPE_UTC_TIME       36
++#define ASN1_ETYPE_GENERALIZED_TIME 37
++
++/**
++ * ASN1_DELETE_FLAG_ZEROIZE:
++ *
++ * Used by: asn1_delete_structure2()
++ *
++ * Zeroize values prior to deinitialization.
++ */
++#define ASN1_DELETE_FLAG_ZEROIZE 1
++
++/**
++ * ASN1_DECODE_FLAG_ALLOW_PADDING:
++ *
++ * Used by: asn1_der_decoding2()
++ *
++ * This flag would allow arbitrary data past the DER data.
++ */
++#define ASN1_DECODE_FLAG_ALLOW_PADDING 1
++/**
++ * ASN1_DECODE_FLAG_STRICT_DER:
++ *
++ * Used by: asn1_der_decoding2()
++ *
++ * This flag would ensure that no BER decoding takes place.
++ */
++#define ASN1_DECODE_FLAG_STRICT_DER (1<<1)
++/**
++ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME:
++ *
++ * Used by: asn1_der_decoding2()
++ *
++ * This flag will tolerate Time encoding errors when in strict DER.
++ */
++#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2)
++
++
++/**
++ * asn1_data_node_st:
++ * @name: Node name
++ * @value: Node value
++ * @value_len: Node value size
++ * @type: Node value type (ASN1_ETYPE_*)
++ *
++ * Data node inside a #asn1_node structure.
++ */
++struct asn1_data_node_st
++{
++  const char *name;		/* Node name */
++  const void *value;		/* Node value */
++  unsigned int value_len;	/* Node value size */
++  unsigned int type;		/* Node value type (ASN1_ETYPE_*) */
++};
++typedef struct asn1_data_node_st asn1_data_node_st;
++
++/***********************************/
++/*  Fixed constants                */
++/***********************************/
++
++/**
++ * ASN1_MAX_ERROR_DESCRIPTION_SIZE:
++ *
++ * Maximum number of characters
++ * of a description message
++ * (null character included).
++ */
++#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128
++
++/***********************************/
++/*  Functions definitions          */
++/***********************************/
++
++extern ASN1_API int
++  asn1_parser2tree (const char *file,
++		      asn1_node * definitions, char *error_desc);
++
++extern ASN1_API int
++  asn1_parser2array (const char *inputFileName,
++		       const char *outputFileName,
++		       const char *vectorName, char *error_desc);
++
++extern ASN1_API int
++  asn1_array2tree (const asn1_static_node * array,
++		     asn1_node * definitions, char *errorDescription);
++
++extern ASN1_API void
++  asn1_print_structure (FILE * out, asn1_node_const structure,
++			  const char *name, int mode);
++
++extern ASN1_API int
++  asn1_create_element (asn1_node_const definitions,
++			 const char *source_name, asn1_node * element);
++
++extern ASN1_API int asn1_delete_structure (asn1_node * structure);
++
++extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags);
++
++extern ASN1_API int
++  asn1_delete_element (asn1_node structure, const char *element_name);
++
++extern ASN1_API int
++  asn1_write_value (asn1_node node_root, const char *name,
++		      const void *ivalue, int len);
++
++extern ASN1_API int
++  asn1_read_value (asn1_node_const root, const char *name,
++		     void *ivalue, int *len);
++
++extern ASN1_API int
++  asn1_read_value_type (asn1_node_const root, const char *name,
++			  void *ivalue, int *len, unsigned int *etype);
++
++extern ASN1_API int
++  asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data);
++
++extern ASN1_API int
++  asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
++
++extern ASN1_API int
++  asn1_der_coding (asn1_node_const element, const char *name,
++		     void *ider, int *len, char *ErrorDescription);
++
++extern ASN1_API int
++  asn1_der_decoding2 (asn1_node *element, const void *ider,
++			int *max_ider_len, unsigned int flags,
++			char *errorDescription);
++
++extern ASN1_API int
++  asn1_der_decoding (asn1_node * element, const void *ider,
++		       int ider_len, char *errorDescription);
++
++/* Do not use. Use asn1_der_decoding() instead. */
++extern ASN1_API int
++  asn1_der_decoding_element (asn1_node * structure,
++			       const char *elementName,
++			       const void *ider, int len,
++			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
++
++extern ASN1_API int
++  asn1_der_decoding_startEnd (asn1_node element,
++				const void *ider, int ider_len,
++				const char *name_element,
++				int *start, int *end);
++
++extern ASN1_API int
++  asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element);
++
++extern ASN1_API int
++  asn1_expand_octet_string (asn1_node_const definitions,
++			      asn1_node * element,
++			      const char *octetName, const char *objectName);
++
++extern ASN1_API int
++  asn1_read_tag (asn1_node_const root, const char *name,
++		   int *tagValue, int *classValue);
++
++extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
++							    definitions,
++							    const char
++							    *oidValue);
++
++__LIBTASN1_PURE__
++extern ASN1_API const char *asn1_check_version (const char *req_version);
++
++__LIBTASN1_PURE__
++extern ASN1_API const char *asn1_strerror (int error);
++
++extern ASN1_API void asn1_perror (int error);
++
++#define ASN1_MAX_TAG_SIZE 4
++#define ASN1_MAX_LENGTH_SIZE 9
++#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE)
++extern ASN1_API long
++  asn1_get_length_der (const unsigned char *der, int der_len, int *len);
++
++extern ASN1_API long
++  asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len);
++
++extern ASN1_API void
++  asn1_length_der (unsigned long int len, unsigned char *der, int *der_len);
++
++/* Other utility functions. */
++
++extern ASN1_API
++  int asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++				unsigned int _der_len,
++				const unsigned char **str,
++				unsigned int *str_len);
++
++extern ASN1_API
++  int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++				unsigned int _der_len,
++				unsigned char **str,
++				unsigned int *str_len,
++				unsigned int *ber_len);
++
++extern ASN1_API int
++  asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
++			    unsigned int str_len, unsigned char *tl,
++			    unsigned int *tl_len);
++
++extern ASN1_API asn1_node
++  asn1_find_node (asn1_node_const pointer, const char *name);
++
++extern ASN1_API int
++  asn1_copy_node (asn1_node dst, const char *dst_name,
++		    asn1_node_const src, const char *src_name);
++extern ASN1_API asn1_node
++  asn1_dup_node (asn1_node_const src, const char *src_name);
++
++/* Internal and low-level DER utility functions. */
++
++extern ASN1_API int
++  asn1_get_tag_der (const unsigned char *der, int der_len,
++		      unsigned char *cls, int *len, unsigned long *tag);
++
++extern ASN1_API void
++  asn1_octet_der (const unsigned char *str, int str_len,
++		    unsigned char *der, int *der_len);
++
++extern ASN1_API int
++  asn1_get_octet_der (const unsigned char *der, int der_len,
++			int *ret_len, unsigned char *str,
++			int str_size, int *str_len);
++
++extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len,
++				     unsigned char *der, int *der_len);
++
++extern ASN1_API int
++  asn1_get_bit_der (const unsigned char *der, int der_len,
++		      int *ret_len, unsigned char *str,
++		      int str_size, int *bit_len);
++
++extern ASN1_API int
++  asn1_get_object_id_der (const unsigned char *der,
++                          int der_len, int *ret_len,
++                          char *str, int str_size);
++
++extern ASN1_API int
++  asn1_object_id_der (const char *str, unsigned char *der, int *der_len,
++                      unsigned flags);
++
++/* Compatibility types */
++
++/**
++ * asn1_retCode:
++ *
++ * Type formerly returned by libtasn1 functions.
++ *
++ * Deprecated: 3.0: Use int instead.
++ */
++typedef int asn1_retCode;
++
++/**
++ * node_asn_struct:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_node instead.
++ */
++#define node_asn_struct asn1_node_st
++
++/**
++ * node_asn:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_node instead.
++ */
++#define node_asn asn1_node_st
++
++/**
++ * ASN1_TYPE:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_node instead.
++ */
++#define ASN1_TYPE asn1_node
++
++/**
++ * ASN1_TYPE_EMPTY:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use NULL instead.
++ */
++#define ASN1_TYPE_EMPTY NULL
++
++/**
++ * static_struct_asn:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_static_node instead.
++ */
++#define static_struct_asn asn1_static_node_st
++
++/**
++ * ASN1_ARRAY_TYPE:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_static_node instead.
++ */
++#define ASN1_ARRAY_TYPE asn1_static_node
++
++/**
++ * asn1_static_node_t:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_static_node instead.
++ */
++#define asn1_static_node_t asn1_static_node
++
++/**
++ * node_data_struct:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_data_node_st instead.
++ */
++#define node_data_struct asn1_data_node_st
++
++/**
++ * ASN1_DATA_NODE:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_data_node_st instead.
++ */
++#define ASN1_DATA_NODE asn1_data_node_st
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif				/* LIBTASN1_H */
+diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE
+new file mode 100644
+index 00000000000..e8b3628db9b
+--- /dev/null
++++ b/grub-core/lib/libtasn1/LICENSE
+@@ -0,0 +1,16 @@
++LICENSING
++=========
++
++The libtasn1 library is released under the GNU Lesser General Public
++License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER)
++for the license terms.
++
++The GNU LGPL applies to the main libtasn1 library, while the
++included applications library are under the GNU GPL version 3.
++The libtasn1 library is located in the lib directory, while the applications
++in src/.
++
++The documentation in doc/ is under the GNU FDL license 1.3.
++
++For any copyright year range specified as YYYY-ZZZZ in this package
++note that the range specifies every single year in that closed interval.
+diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md
+new file mode 100644
+index 00000000000..50a8642296c
+--- /dev/null
++++ b/grub-core/lib/libtasn1/README.md
+@@ -0,0 +1,91 @@
++|Branch|CI system|Status|
++|:----:|:-------:|-----:|
++|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)|
++
++# libtasn1
++
++This is GNU Libtasn1, a small ASN.1 library.
++
++The C library (libtasn1.*) is licensed under the GNU Lesser General
++Public License version 2.1 or later.  See the file COPYING.LIB.
++
++The command line tool, self tests, examples, and other auxilliary
++files, are licensed under the GNU General Public License version 3.0
++or later.  See the file COPYING.
++
++## Building the library
++
++We require several tools to build the software, including:
++
++* [Make](https://www.gnu.org/software/make/)
++* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later)
++* [Autoconf](https://www.gnu.org/software/autoconf/)
++* [Libtool](https://www.gnu.org/software/libtool/)
++* [Texinfo](https://www.gnu.org/software/texinfo/)
++* [help2man](http://www.gnu.org/software/help2man/)
++* [Tar](https://www.gnu.org/software/tar/)
++* [Gzip](https://www.gnu.org/software/gzip/)
++* [bison](https://www.gnu.org/software/bison/)
++* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual)
++* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual)
++* [Git](https://git-scm.com/)
++* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist)
++* [Valgrind](https://valgrind.org/) (optional)
++
++The required software is typically distributed with your operating
++system, and the instructions for installing them differ.  Here are
++some hints:
++
++gNewSense/Debian/Ubuntu:
++```
++sudo apt-get install make git-core autoconf automake libtool
++sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils
++sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools
++```
++
++The next step is to run autoreconf, ./configure, etc:
++
++```
++$ ./bootstrap
++```
++
++Then build the project normally:
++
++```
++$ make
++$ make check
++```
++
++Happy hacking!
++
++
++## Manual
++
++The manual is in the `doc/` directory of the release.  You can also browse
++the manual online at:
++
++ - https://gnutls.gitlab.io/libtasn1/
++
++
++## Code coverage report
++
++The coverage report is at:
++
++ - https://gnutls.gitlab.io/libtasn1/coverage
++
++
++## Issue trackers
++
++ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues)
++ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2)
++
++
++## Homepage
++
++The project homepage at the gnu site is at:
++
++http://www.gnu.org/software/libtasn1/
++
++
++For any copyright year range specified as YYYY-ZZZZ in this package
++note that the range specifies every single year in that closed interval.
diff --git a/SOURCES/0359-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/SOURCES/0359-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
deleted file mode 100644
index 2db2a84..0000000
--- a/SOURCES/0359-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 2 May 2020 00:27:57 +1000
-Subject: [PATCH] posix_wrap: tweaks in preparation for libtasn1
-
- - Define SIZEOF_UNSIGNED_LONG_INT, it's the same as
-   SIZEOF_UNSIGNED_LONG.
-
- - Define WORD_BIT, the size in bits of an int. This is a defined
-   in the Single Unix Specification and in gnulib's limits.h. gnulib
-   assumes it's 32 bits on all our platforms, including 64 bit
-   platforms, so we also use that value.
-
- - Provide strto[u]l[l] preprocessor macros that resolve to
-   grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we
-   also define HAVE_STRTOUL here.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/posix_wrap/limits.h    | 1 +
- grub-core/lib/posix_wrap/stdlib.h    | 8 ++++++++
- grub-core/lib/posix_wrap/sys/types.h | 1 +
- 3 files changed, 10 insertions(+)
-
-diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h
-index 95529540398..474a923b074 100644
---- a/grub-core/lib/posix_wrap/limits.h
-+++ b/grub-core/lib/posix_wrap/limits.h
-@@ -31,5 +31,6 @@
- #define INT_MAX GRUB_INT_MAX
- 
- #define CHAR_BIT 8
-+#define WORD_BIT 32
- 
- #endif
-diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h
-index 7a8d385e973..4634db09f29 100644
---- a/grub-core/lib/posix_wrap/stdlib.h
-+++ b/grub-core/lib/posix_wrap/stdlib.h
-@@ -58,4 +58,12 @@ abs (int c)
-   return (c >= 0) ? c : -c;
- }
- 
-+#define strtol grub_strtol
-+
-+/* for libgcrypt */
-+#define HAVE_STRTOUL
-+#define strtoul grub_strtoul
-+
-+#define strtoull grub_strtoull
-+
- #endif
-diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h
-index 854eb0122ef..f63412c8da0 100644
---- a/grub-core/lib/posix_wrap/sys/types.h
-+++ b/grub-core/lib/posix_wrap/sys/types.h
-@@ -51,6 +51,7 @@ typedef grub_uint8_t byte;
- typedef grub_addr_t uintptr_t;
- 
- #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG
-+#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG
- #define SIZEOF_UNSIGNED_INT 4
- #define SIZEOF_UNSIGNED_LONG_LONG 8
- #define SIZEOF_UNSIGNED_SHORT 2
diff --git a/SOURCES/0360-libtasn1-disable-code-not-needed-in-grub.patch b/SOURCES/0360-libtasn1-disable-code-not-needed-in-grub.patch
new file mode 100644
index 0000000..00f5588
--- /dev/null
+++ b/SOURCES/0360-libtasn1-disable-code-not-needed-in-grub.patch
@@ -0,0 +1,307 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 1 May 2020 17:12:23 +1000
+Subject: [PATCH] libtasn1: disable code not needed in grub
+
+We don't expect to be able to write ASN.1, only read it,
+so we can disable some code.
+
+Do that with #if 0/#endif, rather than deletion. This means
+that the difference between upstream and grub is smaller,
+which should make updating libtasn1 easier in the future.
+
+With these exclusions we also avoid the need for minmax.h,
+which is convenient because it means we don't have to
+import it from gnulib.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/libtasn1/lib/coding.c    | 12 ++++++++++--
+ grub-core/lib/libtasn1/lib/decoding.c  |  2 ++
+ grub-core/lib/libtasn1/lib/element.c   |  4 ++--
+ grub-core/lib/libtasn1/lib/errors.c    |  3 +++
+ grub-core/lib/libtasn1/lib/structure.c | 10 ++++++----
+ include/grub/libtasn1.h                | 15 +++++++++++++++
+ 6 files changed, 38 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
+index 245ea64cf0a..52def598368 100644
+--- a/grub-core/lib/libtasn1/lib/coding.c
++++ b/grub-core/lib/libtasn1/lib/coding.c
+@@ -30,11 +30,11 @@
+ #include "parser_aux.h"
+ #include <gstr.h>
+ #include "element.h"
+-#include "minmax.h"
+ #include <structure.h>
+ 
+ #define MAX_TAG_LEN 16
+ 
++#if 0
+ /******************************************************/
+ /* Function : _asn1_error_description_value_not_found */
+ /* Description: creates the ErrorDescription string   */
+@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node,
+   Estrcat (ErrorDescription, "' not found");
+ 
+ }
++#endif
+ 
+ /**
+  * asn1_length_der:
+@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
+   return ASN1_SUCCESS;
+ }
+ 
++#if 0
+ /******************************************************/
+ /* Function : _asn1_time_der                          */
+ /* Description: creates the DER coding for a TIME     */
+@@ -281,7 +283,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
+ 
+   return ASN1_SUCCESS;
+ }
+-
++#endif
+ 
+ /*
+ void
+@@ -520,6 +522,7 @@ asn1_bit_der (const unsigned char *str, int bit_len,
+ }
+ 
+ 
++#if 0
+ /******************************************************/
+ /* Function : _asn1_complete_explicit_tag             */
+ /* Description: add the length coding to the EXPLICIT */
+@@ -596,6 +599,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
+ 
+   return ASN1_SUCCESS;
+ }
++#endif
+ 
+ const tag_and_class_st _asn1_tags[] = {
+   [ASN1_ETYPE_GENERALSTRING] =
+@@ -648,6 +652,8 @@ const tag_and_class_st _asn1_tags[] = {
+ 
+ unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
+ 
++
++#if 0
+ /******************************************************/
+ /* Function : _asn1_insert_tag_der                    */
+ /* Description: creates the DER coding of tags of one */
+@@ -1413,3 +1419,5 @@ error:
+   asn1_delete_structure (&node);
+   return err;
+ }
++
++#endif
+\ No newline at end of file
+diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
+index ff04eb778cb..42f9a92b5d4 100644
+--- a/grub-core/lib/libtasn1/lib/decoding.c
++++ b/grub-core/lib/libtasn1/lib/decoding.c
+@@ -1613,6 +1613,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
+   return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
+ }
+ 
++#if 0
+ /**
+  * asn1_der_decoding_element:
+  * @structure: pointer to an ASN1 structure
+@@ -1643,6 +1644,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName,
+ {
+   return asn1_der_decoding(structure, ider, len, errorDescription);
+ }
++#endif
+ 
+ /**
+  * asn1_der_decoding_startEnd:
+diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
+index 997eb2725dc..539008d8e94 100644
+--- a/grub-core/lib/libtasn1/lib/element.c
++++ b/grub-core/lib/libtasn1/lib/element.c
+@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
+   return ASN1_SUCCESS;
+ }
+ 
+-
++#if 0
+ /**
+  * asn1_write_value:
+  * @node_root: pointer to a structure
+@@ -645,7 +645,7 @@ asn1_write_value (asn1_node node_root, const char *name,
+ 
+   return ASN1_SUCCESS;
+ }
+-
++#endif
+ 
+ #define PUT_VALUE( ptr, ptr_size, data, data_size) \
+ 	*len = data_size; \
+diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
+index cee74daf795..42785e8622b 100644
+--- a/grub-core/lib/libtasn1/lib/errors.c
++++ b/grub-core/lib/libtasn1/lib/errors.c
+@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = {
+   {0, 0}
+ };
+ 
++
++#if 0
+ /**
+  * asn1_perror:
+  * @error: is an error returned by a libtasn1 function.
+@@ -73,6 +75,7 @@ asn1_perror (int error)
+   const char *str = asn1_strerror (error);
+   fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
+ }
++#endif
+ 
+ /**
+  * asn1_strerror:
+diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
+index 8189c56a4c9..fcfde01a393 100644
+--- a/grub-core/lib/libtasn1/lib/structure.c
++++ b/grub-core/lib/libtasn1/lib/structure.c
+@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node)
+   return node->left;
+ }
+ 
+-
++#if 0
+ int
+ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
+ 			       char *vector_name)
+@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
+ 
+   return ASN1_SUCCESS;
+ }
+-
++#endif
+ 
+ /**
+  * asn1_array2tree:
+@@ -718,7 +718,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name,
+   return res;
+ }
+ 
+-
++#if 0
+ /**
+  * asn1_print_structure:
+  * @out: pointer to the output file (e.g. stdout).
+@@ -1058,7 +1058,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
+ 	}
+     }
+ }
+-
++#endif
+ 
+ 
+ /**
+@@ -1153,6 +1153,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
+   return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
+ }
+ 
++#if 0
+ /**
+  * asn1_copy_node:
+  * @dst: Destination asn1 node.
+@@ -1202,6 +1203,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name,
+ 
+   return result;
+ }
++#endif
+ 
+ /**
+  * asn1_dup_node:
+diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
+index 6fd7a30dc35..785eda2ae3f 100644
+--- a/include/grub/libtasn1.h
++++ b/include/grub/libtasn1.h
+@@ -319,6 +319,8 @@ typedef struct asn1_data_node_st asn1_data_node_st;
+ /*  Functions definitions          */
+ /***********************************/
+ 
++/* These functions are not used in grub and should not be referenced. */
++#if 0
+ extern ASN1_API int
+   asn1_parser2tree (const char *file,
+ 		      asn1_node * definitions, char *error_desc);
+@@ -327,14 +329,17 @@ extern ASN1_API int
+   asn1_parser2array (const char *inputFileName,
+ 		       const char *outputFileName,
+ 		       const char *vectorName, char *error_desc);
++#endif
+ 
+ extern ASN1_API int
+   asn1_array2tree (const asn1_static_node * array,
+ 		     asn1_node * definitions, char *errorDescription);
+ 
++#if 0
+ extern ASN1_API void
+   asn1_print_structure (FILE * out, asn1_node_const structure,
+ 			  const char *name, int mode);
++#endif
+ 
+ extern ASN1_API int
+   asn1_create_element (asn1_node_const definitions,
+@@ -347,9 +352,11 @@ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int
+ extern ASN1_API int
+   asn1_delete_element (asn1_node structure, const char *element_name);
+ 
++#if 0
+ extern ASN1_API int
+   asn1_write_value (asn1_node node_root, const char *name,
+ 		      const void *ivalue, int len);
++#endif
+ 
+ extern ASN1_API int
+   asn1_read_value (asn1_node_const root, const char *name,
+@@ -365,9 +372,11 @@ extern ASN1_API int
+ extern ASN1_API int
+   asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
+ 
++#if 0
+ extern ASN1_API int
+   asn1_der_coding (asn1_node_const element, const char *name,
+ 		     void *ider, int *len, char *ErrorDescription);
++#endif
+ 
+ extern ASN1_API int
+   asn1_der_decoding2 (asn1_node *element, const void *ider,
+@@ -378,12 +387,14 @@ extern ASN1_API int
+   asn1_der_decoding (asn1_node * element, const void *ider,
+ 		       int ider_len, char *errorDescription);
+ 
++#if 0
+ /* Do not use. Use asn1_der_decoding() instead. */
+ extern ASN1_API int
+   asn1_der_decoding_element (asn1_node * structure,
+ 			       const char *elementName,
+ 			       const void *ider, int len,
+ 			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
++#endif
+ 
+ extern ASN1_API int
+   asn1_der_decoding_startEnd (asn1_node element,
+@@ -408,13 +419,17 @@ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
+ 							    const char
+ 							    *oidValue);
+ 
++#if 0
+ __LIBTASN1_PURE__
+ extern ASN1_API const char *asn1_check_version (const char *req_version);
++#endif
+ 
+ __LIBTASN1_PURE__
+ extern ASN1_API const char *asn1_strerror (int error);
+ 
++#if 0
+ extern ASN1_API void asn1_perror (int error);
++#endif
+ 
+ #define ASN1_MAX_TAG_SIZE 4
+ #define ASN1_MAX_LENGTH_SIZE 9
diff --git a/SOURCES/0360-libtasn1-import-libtasn1-4.16.0.patch b/SOURCES/0360-libtasn1-import-libtasn1-4.16.0.patch
deleted file mode 100644
index 89552c8..0000000
--- a/SOURCES/0360-libtasn1-import-libtasn1-4.16.0.patch
+++ /dev/null
@@ -1,8934 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 10 Jun 2020 16:31:22 +1000
-Subject: [PATCH] libtasn1: import libtasn1-4.16.0
-
-Import a very trimmed-down set of libtasn1 files:
-
-pushd /tmp
-wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz
-popd
-pushd grub-core/lib
-mkdir libtasn1
-cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/
-mkdir libtasn1/lib
-cp /tmp/libtasn1-4.16.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h}  libtasn1/lib
-cp /tmp/libtasn1-4.16.0/lib/includes/libtasn1.h ../../include/grub/
-git add libtasn1/ ../../include/grub/libtasn1.h
-popd
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/libtasn1/lib/coding.c     | 1415 ++++++++++++++++++
- grub-core/lib/libtasn1/lib/decoding.c   | 2478 +++++++++++++++++++++++++++++++
- grub-core/lib/libtasn1/lib/element.c    | 1111 ++++++++++++++
- grub-core/lib/libtasn1/lib/errors.c     |  100 ++
- grub-core/lib/libtasn1/lib/gstr.c       |   74 +
- grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++
- grub-core/lib/libtasn1/lib/structure.c  | 1220 +++++++++++++++
- grub-core/lib/libtasn1/lib/element.h    |   40 +
- grub-core/lib/libtasn1/lib/gstr.h       |   47 +
- grub-core/lib/libtasn1/lib/int.h        |  221 +++
- grub-core/lib/libtasn1/lib/parser_aux.h |  172 +++
- grub-core/lib/libtasn1/lib/structure.h  |   45 +
- include/grub/libtasn1.h                 |  588 ++++++++
- grub-core/lib/libtasn1/LICENSE          |   16 +
- grub-core/lib/libtasn1/README.md        |   91 ++
- 15 files changed, 8791 insertions(+)
- create mode 100644 grub-core/lib/libtasn1/lib/coding.c
- create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
- create mode 100644 grub-core/lib/libtasn1/lib/element.c
- create mode 100644 grub-core/lib/libtasn1/lib/errors.c
- create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
- create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
- create mode 100644 grub-core/lib/libtasn1/lib/structure.c
- create mode 100644 grub-core/lib/libtasn1/lib/element.h
- create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
- create mode 100644 grub-core/lib/libtasn1/lib/int.h
- create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
- create mode 100644 grub-core/lib/libtasn1/lib/structure.h
- create mode 100644 include/grub/libtasn1.h
- create mode 100644 grub-core/lib/libtasn1/LICENSE
- create mode 100644 grub-core/lib/libtasn1/README.md
-
-diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
-new file mode 100644
-index 00000000000..245ea64cf0a
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/coding.c
-@@ -0,0 +1,1415 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+
-+/*****************************************************/
-+/* File: coding.c                                    */
-+/* Description: Functions to create a DER coding of  */
-+/*   an ASN1 type.                                   */
-+/*****************************************************/
-+
-+#include <int.h>
-+#include "parser_aux.h"
-+#include <gstr.h>
-+#include "element.h"
-+#include "minmax.h"
-+#include <structure.h>
-+
-+#define MAX_TAG_LEN 16
-+
-+/******************************************************/
-+/* Function : _asn1_error_description_value_not_found */
-+/* Description: creates the ErrorDescription string   */
-+/* for the ASN1_VALUE_NOT_FOUND error.                */
-+/* Parameters:                                        */
-+/*   node: node of the tree where the value is NULL.  */
-+/*   ErrorDescription: string returned.               */
-+/* Return:                                            */
-+/******************************************************/
-+static void
-+_asn1_error_description_value_not_found (asn1_node node,
-+					 char *ErrorDescription)
-+{
-+
-+  if (ErrorDescription == NULL)
-+    return;
-+
-+  Estrcpy (ErrorDescription, ":: value of element '");
-+  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
-+			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
-+  Estrcat (ErrorDescription, "' not found");
-+
-+}
-+
-+/**
-+ * asn1_length_der:
-+ * @len: value to convert.
-+ * @der: buffer to hold the returned encoding (may be %NULL).
-+ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]).
-+ *
-+ * Creates the DER encoding of the provided length value.
-+ * The @der buffer must have enough room for the output. The maximum
-+ * length this function will encode is %ASN1_MAX_LENGTH_SIZE.
-+ *
-+ * To know the size of the DER encoding use a %NULL value for @der.
-+ **/
-+void
-+asn1_length_der (unsigned long int len, unsigned char *der, int *der_len)
-+{
-+  int k;
-+  unsigned char temp[ASN1_MAX_LENGTH_SIZE];
-+#if SIZEOF_UNSIGNED_LONG_INT > 8
-+  len &= 0xFFFFFFFFFFFFFFFF;
-+#endif
-+
-+  if (len < 128)
-+    {
-+      /* short form */
-+      if (der != NULL)
-+	der[0] = (unsigned char) len;
-+      *der_len = 1;
-+    }
-+  else
-+    {
-+      /* Long form */
-+      k = 0;
-+      while (len)
-+	{
-+	  temp[k++] = len & 0xFF;
-+	  len = len >> 8;
-+	}
-+      *der_len = k + 1;
-+      if (der != NULL)
-+	{
-+	  der[0] = ((unsigned char) k & 0x7F) + 128;
-+	  while (k--)
-+	    der[*der_len - 1 - k] = temp[k];
-+	}
-+    }
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_tag_der                           */
-+/* Description: creates the DER coding for the CLASS  */
-+/* and TAG parameters.                                */
-+/* It is limited by the ASN1_MAX_TAG_SIZE variable    */
-+/* Parameters:                                        */
-+/*   class: value to convert.                         */
-+/*   tag_value: value to convert.                     */
-+/*   ans: string returned.                            */
-+/*   ans_len: number of meaningful bytes of ANS       */
-+/*            (ans[0]..ans[ans_len-1]).               */
-+/* Return:                                            */
-+/******************************************************/
-+static void
-+_asn1_tag_der (unsigned char class, unsigned int tag_value,
-+	       unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len)
-+{
-+  int k;
-+  unsigned char temp[ASN1_MAX_TAG_SIZE];
-+
-+  if (tag_value < 31)
-+    {
-+      /* short form */
-+      ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F));
-+      *ans_len = 1;
-+    }
-+  else
-+    {
-+      /* Long form */
-+      ans[0] = (class & 0xE0) + 31;
-+      k = 0;
-+      while (tag_value != 0)
-+	{
-+	  temp[k++] = tag_value & 0x7F;
-+	  tag_value >>= 7;
-+
-+	  if (k > ASN1_MAX_TAG_SIZE - 1)
-+	    break;		/* will not encode larger tags */
-+	}
-+      *ans_len = k + 1;
-+      while (k--)
-+	ans[*ans_len - 1 - k] = temp[k] + 128;
-+      ans[*ans_len - 1] -= 128;
-+    }
-+}
-+
-+/**
-+ * asn1_octet_der:
-+ * @str: the input data.
-+ * @str_len: STR length (str[0]..str[*str_len-1]).
-+ * @der: encoded string returned.
-+ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]).
-+ *
-+ * Creates a length-value DER encoding for the input data.
-+ * The DER encoding of the input data will be placed in the @der variable.
-+ *
-+ * Note that the OCTET STRING tag is not included in the output.
-+ *
-+ * This function does not return any value because it is expected
-+ * that @der_len will contain enough bytes to store the string
-+ * plus the DER encoding. The DER encoding size can be obtained using
-+ * asn1_length_der().
-+ **/
-+void
-+asn1_octet_der (const unsigned char *str, int str_len,
-+		unsigned char *der, int *der_len)
-+{
-+  int len_len;
-+
-+  if (der == NULL || str_len < 0)
-+    return;
-+
-+  asn1_length_der (str_len, der, &len_len);
-+  memcpy (der + len_len, str, str_len);
-+  *der_len = str_len + len_len;
-+}
-+
-+
-+/**
-+ * asn1_encode_simple_der:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @str: the string data.
-+ * @str_len: the string length
-+ * @tl: the encoded tag and length
-+ * @tl_len: the bytes of the @tl field
-+ *
-+ * Creates the DER encoding for various simple ASN.1 types like strings etc.
-+ * It stores the tag and length in @tl, which should have space for at least
-+ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl.
-+ *
-+ * The complete DER encoding should consist of the value in @tl appended
-+ * with the provided @str.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ **/
-+int
-+asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
-+			unsigned int str_len, unsigned char *tl,
-+			unsigned int *tl_len)
-+{
-+  int tag_len, len_len;
-+  unsigned tlen;
-+  unsigned char der_tag[ASN1_MAX_TAG_SIZE];
-+  unsigned char der_length[ASN1_MAX_LENGTH_SIZE];
-+  unsigned char *p;
-+
-+  if (str == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  if (ETYPE_OK (etype) == 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  /* doesn't handle constructed classes */
-+  if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len);
-+
-+  asn1_length_der (str_len, der_length, &len_len);
-+
-+  if (tag_len <= 0 || len_len <= 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  tlen = tag_len + len_len;
-+
-+  if (*tl_len < tlen)
-+    return ASN1_MEM_ERROR;
-+
-+  p = tl;
-+  memcpy (p, der_tag, tag_len);
-+  p += tag_len;
-+  memcpy (p, der_length, len_len);
-+
-+  *tl_len = tlen;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_time_der                          */
-+/* Description: creates the DER coding for a TIME     */
-+/* type (length included).                            */
-+/* Parameters:                                        */
-+/*   str: TIME null-terminated string.                */
-+/*   der: string returned.                            */
-+/*   der_len: number of meaningful bytes of DER       */
-+/*            (der[0]..der[ans_len-1]). Initially it  */
-+/*            if must store the lenght of DER.        */
-+/* Return:                                            */
-+/*   ASN1_MEM_ERROR when DER isn't big enough         */
-+/*   ASN1_SUCCESS otherwise                           */
-+/******************************************************/
-+static int
-+_asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
-+		int *der_len)
-+{
-+  int len_len;
-+  int max_len;
-+
-+  if (der == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  max_len = *der_len;
-+
-+  asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len);
-+
-+  if ((len_len + str_len) <= max_len)
-+    memcpy (der + len_len, str, str_len);
-+  *der_len = len_len + str_len;
-+
-+  if ((*der_len) > max_len)
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/*
-+void
-+_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str)
-+{
-+  int len_len,str_len;
-+  char temp[20];
-+
-+  if(str==NULL) return;
-+  str_len=asn1_get_length_der(der,*der_len,&len_len);
-+  if (str_len<0) return;
-+  memcpy(temp,der+len_len,str_len);
-+  *der_len=str_len+len_len;
-+  switch(str_len)
-+  {
-+  case 11:
-+    temp[10]=0;
-+    strcat(temp,"00+0000");
-+    break;
-+  case 13:
-+    temp[12]=0;
-+    strcat(temp,"+0000");
-+    break;
-+  case 15:
-+    temp[15]=0;
-+    memmove(temp+12,temp+10,6);
-+    temp[10]=temp[11]='0';
-+    break;
-+  case 17:
-+    temp[17]=0;
-+    break;
-+  default:
-+    return;
-+  }
-+  strcpy(str,temp);
-+}
-+*/
-+
-+static
-+void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len)
-+{
-+  int first, k;
-+  unsigned char bit7;
-+
-+  first = 0;
-+  for (k = sizeof(val); k >= 0; k--)
-+    {
-+      bit7 = (val >> (k * 7)) & 0x7F;
-+      if (bit7 || first || !k)
-+	{
-+	  if (k)
-+	    bit7 |= 0x80;
-+	  if (max_len > (*der_len))
-+	    der[*der_len] = bit7;
-+	  (*der_len)++;
-+	  first = 1;
-+	}
-+    }
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_object_id_der                     */
-+/* Description: creates the DER coding for an         */
-+/* OBJECT IDENTIFIER  type (length included).         */
-+/* Parameters:                                        */
-+/*   str: OBJECT IDENTIFIER null-terminated string.   */
-+/*   der: string returned.                            */
-+/*   der_len: number of meaningful bytes of DER       */
-+/*            (der[0]..der[ans_len-1]). Initially it  */
-+/*            must store the length of DER.           */
-+/* Return:                                            */
-+/*   ASN1_MEM_ERROR when DER isn't big enough         */
-+/*   ASN1_SUCCESS if succesful                        */
-+/*   or an error value.                               */
-+/******************************************************/
-+static int
-+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len)
-+{
-+  int len_len, counter, max_len;
-+  char *temp, *n_end, *n_start;
-+  uint64_t val, val1 = 0;
-+  int str_len = _asn1_strlen (str);
-+
-+  max_len = *der_len;
-+  *der_len = 0;
-+
-+  if (der == NULL && max_len > 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  temp = malloc (str_len + 2);
-+  if (temp == NULL)
-+    return ASN1_MEM_ALLOC_ERROR;
-+
-+  memcpy (temp, str, str_len);
-+  temp[str_len] = '.';
-+  temp[str_len + 1] = 0;
-+
-+  counter = 0;
-+  n_start = temp;
-+  while ((n_end = strchr (n_start, '.')))
-+    {
-+      *n_end = 0;
-+      val = _asn1_strtou64 (n_start, NULL, 10);
-+      counter++;
-+
-+      if (counter == 1)
-+        {
-+	  val1 = val;
-+	}
-+      else if (counter == 2)
-+	{
-+	  uint64_t val0;
-+
-+          if (val1 > 2)
-+            {
-+              free(temp);
-+              return ASN1_VALUE_NOT_VALID;
-+            }
-+          else if ((val1 == 0 || val1 == 1) && val > 39)
-+            {
-+              free(temp);
-+              return ASN1_VALUE_NOT_VALID;
-+            }
-+
-+	  val0 = 40 * val1 + val;
-+	  encode_val(val0, der, max_len, der_len);
-+	}
-+      else
-+	{
-+	  encode_val(val, der, max_len, der_len);
-+	}
-+      n_start = n_end + 1;
-+    }
-+
-+  asn1_length_der (*der_len, NULL, &len_len);
-+  if (max_len >= (*der_len + len_len))
-+    {
-+      memmove (der + len_len, der, *der_len);
-+      asn1_length_der (*der_len, der, &len_len);
-+    }
-+  *der_len += len_len;
-+
-+  free (temp);
-+
-+  if (max_len < (*der_len))
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_object_id_der:
-+ * @str: An object identifier in numeric, dot format.
-+ * @der: buffer to hold the returned encoding (may be %NULL).
-+ * @der_len: initially the size of @der; will hold the final size.
-+ * @flags: must be zero
-+ *
-+ * Creates the DER encoding of the provided object identifier.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID
-+ *   if @str is not a valid OID, %ASN1_MEM_ERROR if the @der
-+ *   vector isn't big enough and in this case @der_len will contain the
-+ *   length needed.
-+ **/
-+int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags)
-+{
-+  unsigned char tag_der[MAX_TAG_LEN];
-+  int tag_len = 0, r;
-+  int max_len = *der_len;
-+
-+  *der_len = 0;
-+
-+  _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID),
-+                 tag_der, &tag_len);
-+
-+  if (max_len > tag_len)
-+    {
-+      memcpy(der, tag_der, tag_len);
-+    }
-+  max_len -= tag_len;
-+  der += tag_len;
-+
-+  r = _asn1_object_id_der (str, der, &max_len);
-+  if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS)
-+    {
-+      *der_len = max_len + tag_len;
-+    }
-+
-+  return r;
-+}
-+
-+static const unsigned char bit_mask[] =
-+  { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };
-+
-+/**
-+ * asn1_bit_der:
-+ * @str: BIT string.
-+ * @bit_len: number of meaningful bits in STR.
-+ * @der: string returned.
-+ * @der_len: number of meaningful bytes of DER
-+ *   (der[0]..der[ans_len-1]).
-+ *
-+ * Creates a length-value DER encoding for the input data
-+ * as it would have been for a BIT STRING.
-+ * The DER encoded data will be copied in @der.
-+ *
-+ * Note that the BIT STRING tag is not included in the output.
-+ *
-+ * This function does not return any value because it is expected
-+ * that @der_len will contain enough bytes to store the string
-+ * plus the DER encoding. The DER encoding size can be obtained using
-+ * asn1_length_der().
-+ **/
-+void
-+asn1_bit_der (const unsigned char *str, int bit_len,
-+	      unsigned char *der, int *der_len)
-+{
-+  int len_len, len_byte, len_pad;
-+
-+  if (der == NULL)
-+    return;
-+
-+  len_byte = bit_len >> 3;
-+  len_pad = 8 - (bit_len & 7);
-+  if (len_pad == 8)
-+    len_pad = 0;
-+  else
-+    len_byte++;
-+  asn1_length_der (len_byte + 1, der, &len_len);
-+  der[len_len] = len_pad;
-+
-+  if (str)
-+    memcpy (der + len_len + 1, str, len_byte);
-+  der[len_len + len_byte] &= bit_mask[len_pad];
-+  *der_len = len_byte + len_len + 1;
-+}
-+
-+
-+/******************************************************/
-+/* Function : _asn1_complete_explicit_tag             */
-+/* Description: add the length coding to the EXPLICIT */
-+/* tags.                                              */
-+/* Parameters:                                        */
-+/*   node: pointer to the tree element.               */
-+/*   der: string with the DER coding of the whole tree*/
-+/*   counter: number of meaningful bytes of DER       */
-+/*            (der[0]..der[*counter-1]).              */
-+/*   max_len: size of der vector                      */
-+/* Return:                                            */
-+/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
-+/*   otherwise ASN1_SUCCESS.                          */
-+/******************************************************/
-+static int
-+_asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
-+			     int *counter, int *max_len)
-+{
-+  asn1_node p;
-+  int is_tag_implicit, len2, len3;
-+  unsigned char temp[SIZEOF_UNSIGNED_INT];
-+
-+  if (der == NULL && *max_len > 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  is_tag_implicit = 0;
-+
-+  if (node->type & CONST_TAG)
-+    {
-+      p = node->down;
-+      if (p == NULL)
-+        return ASN1_DER_ERROR;
-+      /* When there are nested tags we must complete them reverse to
-+         the order they were created. This is because completing a tag
-+         modifies all data within it, including the incomplete tags
-+         which store buffer positions -- simon@josefsson.org 2002-09-06
-+       */
-+      while (p->right)
-+	p = p->right;
-+      while (p && p != node->down->left)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if (p->type & CONST_EXPLICIT)
-+		{
-+		  len2 = strtol (p->name, NULL, 10);
-+		  _asn1_set_name (p, NULL);
-+
-+		  asn1_length_der (*counter - len2, temp, &len3);
-+		  if (len3 <= (*max_len))
-+		    {
-+		      memmove (der + len2 + len3, der + len2,
-+			       *counter - len2);
-+		      memcpy (der + len2, temp, len3);
-+		    }
-+		  *max_len -= len3;
-+		  *counter += len3;
-+		  is_tag_implicit = 0;
-+		}
-+	      else
-+		{		/* CONST_IMPLICIT */
-+		  if (!is_tag_implicit)
-+		    {
-+		      is_tag_implicit = 1;
-+		    }
-+		}
-+	    }
-+	  p = p->left;
-+	}
-+    }
-+
-+  if (*max_len < 0)
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+const tag_and_class_st _asn1_tags[] = {
-+  [ASN1_ETYPE_GENERALSTRING] =
-+    {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"},
-+  [ASN1_ETYPE_NUMERIC_STRING] =
-+    {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"},
-+  [ASN1_ETYPE_IA5_STRING] =
-+    {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"},
-+  [ASN1_ETYPE_TELETEX_STRING] =
-+    {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"},
-+  [ASN1_ETYPE_PRINTABLE_STRING] =
-+    {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"},
-+  [ASN1_ETYPE_UNIVERSAL_STRING] =
-+    {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"},
-+  [ASN1_ETYPE_BMP_STRING] =
-+    {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"},
-+  [ASN1_ETYPE_UTF8_STRING] =
-+    {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"},
-+  [ASN1_ETYPE_VISIBLE_STRING] =
-+    {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"},
-+  [ASN1_ETYPE_OCTET_STRING] =
-+    {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"},
-+  [ASN1_ETYPE_BIT_STRING] =
-+    {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"},
-+  [ASN1_ETYPE_OBJECT_ID] =
-+    {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"},
-+  [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"},
-+  [ASN1_ETYPE_BOOLEAN] =
-+    {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"},
-+  [ASN1_ETYPE_INTEGER] =
-+    {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"},
-+  [ASN1_ETYPE_ENUMERATED] =
-+    {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"},
-+  [ASN1_ETYPE_SEQUENCE] =
-+    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
-+     "type:SEQUENCE"},
-+  [ASN1_ETYPE_SEQUENCE_OF] =
-+    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
-+     "type:SEQ_OF"},
-+  [ASN1_ETYPE_SET] =
-+    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"},
-+  [ASN1_ETYPE_SET_OF] =
-+    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
-+     "type:SET_OF"},
-+  [ASN1_ETYPE_GENERALIZED_TIME] =
-+    {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"},
-+  [ASN1_ETYPE_UTC_TIME] =
-+    {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"},
-+};
-+
-+unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
-+
-+/******************************************************/
-+/* Function : _asn1_insert_tag_der                    */
-+/* Description: creates the DER coding of tags of one */
-+/* NODE.                                              */
-+/* Parameters:                                        */
-+/*   node: pointer to the tree element.               */
-+/*   der: string returned                             */
-+/*   counter: number of meaningful bytes of DER       */
-+/*            (counter[0]..der[*counter-1]).          */
-+/*   max_len: size of der vector                      */
-+/* Return:                                            */
-+/*   ASN1_GENERIC_ERROR if the type is unknown,       */
-+/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
-+/*   otherwise ASN1_SUCCESS.                          */
-+/******************************************************/
-+static int
-+_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter,
-+		      int *max_len)
-+{
-+  asn1_node p;
-+  int tag_len, is_tag_implicit;
-+  unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)];
-+  unsigned long tag_implicit = 0;
-+  unsigned char tag_der[MAX_TAG_LEN];
-+
-+  is_tag_implicit = 0;
-+
-+  if (node->type & CONST_TAG)
-+    {
-+      p = node->down;
-+      while (p)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if (p->type & CONST_APPLICATION)
-+		class = ASN1_CLASS_APPLICATION;
-+	      else if (p->type & CONST_UNIVERSAL)
-+		class = ASN1_CLASS_UNIVERSAL;
-+	      else if (p->type & CONST_PRIVATE)
-+		class = ASN1_CLASS_PRIVATE;
-+	      else
-+		class = ASN1_CLASS_CONTEXT_SPECIFIC;
-+
-+	      if (p->type & CONST_EXPLICIT)
-+		{
-+		  if (is_tag_implicit)
-+		    _asn1_tag_der (class_implicit, tag_implicit, tag_der,
-+				   &tag_len);
-+		  else
-+		    _asn1_tag_der (class | ASN1_CLASS_STRUCTURED,
-+				   _asn1_strtoul (p->value, NULL, 10),
-+				   tag_der, &tag_len);
-+
-+		  *max_len -= tag_len;
-+		  if (der && *max_len >= 0)
-+		    memcpy (der + *counter, tag_der, tag_len);
-+		  *counter += tag_len;
-+
-+		  _asn1_ltostr (*counter, (char *) temp);
-+		  _asn1_set_name (p, (const char *) temp);
-+
-+		  is_tag_implicit = 0;
-+		}
-+	      else
-+		{		/* CONST_IMPLICIT */
-+		  if (!is_tag_implicit)
-+		    {
-+		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
-+			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
-+			class |= ASN1_CLASS_STRUCTURED;
-+		      class_implicit = class;
-+		      tag_implicit = _asn1_strtoul (p->value, NULL, 10);
-+		      is_tag_implicit = 1;
-+		    }
-+		}
-+	    }
-+	  p = p->right;
-+	}
-+    }
-+
-+  if (is_tag_implicit)
-+    {
-+      _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len);
-+    }
-+  else
-+    {
-+      unsigned type = type_field (node->type);
-+      switch (type)
-+	{
-+	CASE_HANDLED_ETYPES:
-+	  _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag,
-+			 tag_der, &tag_len);
-+	  break;
-+	case ASN1_ETYPE_TAG:
-+	case ASN1_ETYPE_CHOICE:
-+	case ASN1_ETYPE_ANY:
-+	  tag_len = 0;
-+	  break;
-+	default:
-+	  return ASN1_GENERIC_ERROR;
-+	}
-+    }
-+
-+  *max_len -= tag_len;
-+  if (der && *max_len >= 0)
-+    memcpy (der + *counter, tag_der, tag_len);
-+  *counter += tag_len;
-+
-+  if (*max_len < 0)
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_ordering_set                      */
-+/* Description: puts the elements of a SET type in    */
-+/* the correct order according to DER rules.          */
-+/* Parameters:                                        */
-+/*   der: string with the DER coding.                 */
-+/*   node: pointer to the SET element.                */
-+/* Return:                                            */
-+/*    ASN1_SUCCESS if successful                      */
-+/*    or an error value.                              */
-+/******************************************************/
-+static int
-+_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node)
-+{
-+  struct vet
-+  {
-+    int end;
-+    unsigned long value;
-+    struct vet *next, *prev;
-+  };
-+
-+  int counter, len, len2;
-+  struct vet *first, *last, *p_vet, *p2_vet;
-+  asn1_node p;
-+  unsigned char class, *temp;
-+  unsigned long tag, t;
-+  int err;
-+
-+  counter = 0;
-+
-+  if (type_field (node->type) != ASN1_ETYPE_SET)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  p = node->down;
-+  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
-+	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
-+    p = p->right;
-+
-+  if ((p == NULL) || (p->right == NULL))
-+    return ASN1_SUCCESS;
-+
-+  first = last = NULL;
-+  while (p)
-+    {
-+      p_vet = malloc (sizeof (struct vet));
-+      if (p_vet == NULL)
-+        {
-+	  err = ASN1_MEM_ALLOC_ERROR;
-+	  goto error;
-+	}
-+
-+      p_vet->next = NULL;
-+      p_vet->prev = last;
-+      if (first == NULL)
-+	first = p_vet;
-+      else
-+	last->next = p_vet;
-+      last = p_vet;
-+
-+      /* tag value calculation */
-+      err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2,
-+			      &tag);
-+      if (err != ASN1_SUCCESS)
-+	goto error;
-+
-+      t = ((unsigned int)class) << 24;
-+      p_vet->value = t | tag;
-+      counter += len2;
-+
-+      /* extraction and length */
-+      len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
-+      if (len2 < 0)
-+	{
-+	  err = ASN1_DER_ERROR;
-+	  goto error;
-+	}
-+      counter += len + len2;
-+
-+      p_vet->end = counter;
-+      p = p->right;
-+    }
-+
-+  p_vet = first;
-+
-+  while (p_vet)
-+    {
-+      p2_vet = p_vet->next;
-+      counter = 0;
-+      while (p2_vet)
-+	{
-+	  if (p_vet->value > p2_vet->value)
-+	    {
-+	      /* change position */
-+	      temp = malloc (p_vet->end - counter);
-+	      if (temp == NULL)
-+		{
-+		  err = ASN1_MEM_ALLOC_ERROR;
-+		  goto error;
-+		}
-+
-+	      memcpy (temp, der + counter, p_vet->end - counter);
-+	      memcpy (der + counter, der + p_vet->end,
-+		      p2_vet->end - p_vet->end);
-+	      memcpy (der + counter + p2_vet->end - p_vet->end, temp,
-+		      p_vet->end - counter);
-+	      free (temp);
-+
-+	      tag = p_vet->value;
-+	      p_vet->value = p2_vet->value;
-+	      p2_vet->value = tag;
-+
-+	      p_vet->end = counter + (p2_vet->end - p_vet->end);
-+	    }
-+	  counter = p_vet->end;
-+
-+	  p2_vet = p2_vet->next;
-+	  p_vet = p_vet->next;
-+	}
-+
-+      if (p_vet != first)
-+	p_vet->prev->next = NULL;
-+      else
-+	first = NULL;
-+      free (p_vet);
-+      p_vet = first;
-+    }
-+  return ASN1_SUCCESS;
-+
-+error:
-+  while (first != NULL)
-+    {
-+      p_vet = first;
-+      first = first->next;
-+      free(p_vet);
-+    }
-+  return err;
-+}
-+
-+struct vet
-+{
-+  unsigned char *ptr;
-+  int size;
-+};
-+
-+static int setof_compar(const void *_e1, const void *_e2)
-+{
-+  unsigned length;
-+  const struct vet *e1 = _e1, *e2 = _e2;
-+  int rval;
-+
-+  /* The encodings of the component values of a set-of value shall
-+   * appear in ascending order, the encodings being compared
-+   * as octet strings with the shorter components being
-+   * padded at their trailing end with 0-octets.
-+   * The padding octets are for comparison purposes and
-+   * do not appear in the encodings.
-+   */
-+  length = MIN(e1->size, e2->size);
-+
-+  rval = memcmp(e1->ptr, e2->ptr, length);
-+  if (rval == 0 && e1->size != e2->size)
-+    {
-+      if (e1->size > e2->size)
-+        rval = 1;
-+      else if (e2->size > e1->size)
-+        rval = -1;
-+    }
-+
-+  return rval;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_ordering_set_of                   */
-+/* Description: puts the elements of a SET OF type in */
-+/* the correct order according to DER rules.          */
-+/* Parameters:                                        */
-+/*   der: string with the DER coding.                 */
-+/*   node: pointer to the SET OF element.             */
-+/* Return:                                            */
-+/*    ASN1_SUCCESS if successful                      */
-+/*    or an error value.                              */
-+/******************************************************/
-+static int
-+_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node)
-+{
-+  int counter, len, len2;
-+  struct vet *list = NULL, *tlist;
-+  unsigned list_size = 0;
-+  struct vet *p_vet;
-+  asn1_node p;
-+  unsigned char class;
-+  unsigned i;
-+  unsigned char *out = NULL;
-+  int err;
-+
-+  if (der == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  counter = 0;
-+
-+  if (type_field (node->type) != ASN1_ETYPE_SET_OF)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  p = node->down;
-+  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
-+	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
-+    p = p->right;
-+  if (p == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+  p = p->right;
-+
-+  if ((p == NULL) || (p->right == NULL))
-+    return ASN1_SUCCESS;
-+
-+  while (p)
-+    {
-+      list_size++;
-+      tlist = realloc (list, list_size*sizeof(struct vet));
-+      if (tlist == NULL)
-+	{
-+	  err = ASN1_MEM_ALLOC_ERROR;
-+	  goto error;
-+	}
-+      list = tlist;
-+      p_vet = &list[list_size-1];
-+
-+      p_vet->ptr = der+counter;
-+      p_vet->size = 0;
-+
-+      /* extraction of tag and length */
-+      if (der_len - counter > 0)
-+	{
-+	  err = asn1_get_tag_der (der + counter, der_len - counter, &class,
-+	                          &len, NULL);
-+	  if (err != ASN1_SUCCESS)
-+	    goto error;
-+	  counter += len;
-+          p_vet->size += len;
-+
-+	  len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
-+	  if (len2 < 0)
-+	    {
-+	      err = ASN1_DER_ERROR;
-+	      goto error;
-+	    }
-+	  counter += len + len2;
-+          p_vet->size += len + len2;
-+
-+	}
-+      else
-+	{
-+	  err = ASN1_DER_ERROR;
-+	  goto error;
-+	}
-+      p = p->right;
-+    }
-+
-+  if (counter > der_len)
-+    {
-+      err = ASN1_DER_ERROR;
-+      goto error;
-+    }
-+
-+  qsort(list, list_size, sizeof(struct vet), setof_compar);
-+
-+  out = malloc(der_len);
-+  if (out == NULL)
-+    {
-+      err = ASN1_MEM_ERROR;
-+      goto error;
-+    }
-+
-+  /* the sum of p_vet->size == der_len */
-+  counter = 0;
-+  for (i = 0; i < list_size; i++)
-+    {
-+      p_vet = &list[i];
-+      memcpy(out+counter, p_vet->ptr, p_vet->size);
-+      counter += p_vet->size;
-+    }
-+  memcpy(der, out, der_len);
-+  free(out);
-+
-+  err = ASN1_SUCCESS;
-+
-+error:
-+  free(list);
-+  return err;
-+}
-+
-+/**
-+ * asn1_der_coding:
-+ * @element: pointer to an ASN1 element
-+ * @name: the name of the structure you want to encode (it must be
-+ *   inside *POINTER).
-+ * @ider: vector that will contain the DER encoding. DER must be a
-+ *   pointer to memory cells already allocated.
-+ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy
-+ *   holds the sizeof of der vector.
-+ * @ErrorDescription: return the error description or an empty
-+ *   string if success.
-+ *
-+ * Creates the DER encoding for the NAME structure (inside *POINTER
-+ * structure).
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there
-+ *   is an element without a value, %ASN1_MEM_ERROR if the @ider
-+ *   vector isn't big enough and in this case @len will contain the
-+ *   length needed.
-+ **/
-+int
-+asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len,
-+		 char *ErrorDescription)
-+{
-+  asn1_node node, p, p2;
-+  unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)];
-+  int counter, counter_old, len2, len3, move, max_len, max_len_old;
-+  int err;
-+  unsigned char *der = ider;
-+
-+  if (ErrorDescription)
-+    ErrorDescription[0] = 0;
-+
-+  node = asn1_find_node (element, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  /* Node is now a locally allocated variable.
-+   * That is because in some point we modify the
-+   * structure, and I don't know why! --nmav
-+   */
-+  node = _asn1_copy_structure3 (node);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  max_len = *len;
-+
-+  if (der == NULL && max_len > 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  counter = 0;
-+  move = DOWN;
-+  p = node;
-+
-+  while (1)
-+    {
-+
-+      counter_old = counter;
-+      max_len_old = max_len;
-+      if (move != UP)
-+	{
-+          p->start = counter;
-+	  err = _asn1_insert_tag_der (p, der, &counter, &max_len);
-+	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+	    goto error;
-+	}
-+      switch (type_field (p->type))
-+	{
-+	case ASN1_ETYPE_NULL:
-+	  max_len--;
-+	  if (der != NULL && max_len >= 0)
-+	    der[counter] = 0;
-+	  counter++;
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_BOOLEAN:
-+	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
-+	    {
-+	      counter = counter_old;
-+	      max_len = max_len_old;
-+	    }
-+	  else
-+	    {
-+	      if (p->value == NULL)
-+		{
-+		  _asn1_error_description_value_not_found (p,
-+							   ErrorDescription);
-+		  err = ASN1_VALUE_NOT_FOUND;
-+		  goto error;
-+		}
-+	      max_len -= 2;
-+	      if (der != NULL && max_len >= 0)
-+		{
-+		  der[counter++] = 1;
-+		  if (p->value[0] == 'F')
-+		    der[counter++] = 0;
-+		  else
-+		    der[counter++] = 0xFF;
-+		}
-+	      else
-+		counter += 2;
-+	    }
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_INTEGER:
-+	case ASN1_ETYPE_ENUMERATED:
-+	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
-+	    {
-+	      counter = counter_old;
-+	      max_len = max_len_old;
-+	    }
-+	  else
-+	    {
-+	      if (p->value == NULL)
-+		{
-+		  _asn1_error_description_value_not_found (p,
-+							   ErrorDescription);
-+		  err = ASN1_VALUE_NOT_FOUND;
-+		  goto error;
-+		}
-+	      len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+	      if (len2 < 0)
-+		{
-+		  err = ASN1_DER_ERROR;
-+		  goto error;
-+		}
-+	      max_len -= len2 + len3;
-+	      if (der != NULL && max_len >= 0)
-+		memcpy (der + counter, p->value, len3 + len2);
-+	      counter += len3 + len2;
-+	    }
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_OBJECT_ID:
-+	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
-+	    {
-+	      counter = counter_old;
-+	      max_len = max_len_old;
-+	    }
-+	  else
-+	    {
-+	      if (p->value == NULL)
-+		{
-+		  _asn1_error_description_value_not_found (p,
-+							   ErrorDescription);
-+		  err = ASN1_VALUE_NOT_FOUND;
-+		  goto error;
-+		}
-+	      len2 = max_len;
-+	      err = _asn1_object_id_der ((char*)p->value, der + counter, &len2);
-+	      if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+		goto error;
-+
-+	      max_len -= len2;
-+	      counter += len2;
-+	    }
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_GENERALIZED_TIME:
-+	case ASN1_ETYPE_UTC_TIME:
-+	  if (p->value == NULL)
-+	    {
-+	      _asn1_error_description_value_not_found (p, ErrorDescription);
-+	      err = ASN1_VALUE_NOT_FOUND;
-+	      goto error;
-+	    }
-+	  len2 = max_len;
-+	  err = _asn1_time_der (p->value, p->value_len, der + counter, &len2);
-+	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+	    goto error;
-+
-+	  max_len -= len2;
-+	  counter += len2;
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_OCTET_STRING:
-+	case ASN1_ETYPE_GENERALSTRING:
-+	case ASN1_ETYPE_NUMERIC_STRING:
-+	case ASN1_ETYPE_IA5_STRING:
-+	case ASN1_ETYPE_TELETEX_STRING:
-+	case ASN1_ETYPE_PRINTABLE_STRING:
-+	case ASN1_ETYPE_UNIVERSAL_STRING:
-+	case ASN1_ETYPE_BMP_STRING:
-+	case ASN1_ETYPE_UTF8_STRING:
-+	case ASN1_ETYPE_VISIBLE_STRING:
-+	case ASN1_ETYPE_BIT_STRING:
-+	  if (p->value == NULL)
-+	    {
-+	      _asn1_error_description_value_not_found (p, ErrorDescription);
-+	      err = ASN1_VALUE_NOT_FOUND;
-+	      goto error;
-+	    }
-+	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+	  if (len2 < 0)
-+	    {
-+	      err = ASN1_DER_ERROR;
-+	      goto error;
-+	    }
-+	  max_len -= len2 + len3;
-+	  if (der != NULL && max_len >= 0)
-+	    memcpy (der + counter, p->value, len3 + len2);
-+	  counter += len3 + len2;
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_SEQUENCE:
-+	case ASN1_ETYPE_SET:
-+	  if (move != UP)
-+	    {
-+	      p->tmp_ival = counter;
-+	      if (p->down == NULL)
-+		{
-+		  move = UP;
-+		  continue;
-+		}
-+	      else
-+		{
-+		  p2 = p->down;
-+		  while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG))
-+		    p2 = p2->right;
-+		  if (p2)
-+		    {
-+		      p = p2;
-+		      move = RIGHT;
-+		      continue;
-+		    }
-+		  move = UP;
-+		  continue;
-+		}
-+	    }
-+	  else
-+	    {			/* move==UP */
-+	      len2 = p->tmp_ival;
-+	      p->tmp_ival = 0;
-+	      if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0))
-+		{
-+		  err = _asn1_ordering_set (der + len2, counter - len2, p);
-+		  if (err != ASN1_SUCCESS)
-+		    goto error;
-+		}
-+	      asn1_length_der (counter - len2, temp, &len3);
-+	      max_len -= len3;
-+	      if (der != NULL && max_len >= 0)
-+		{
-+		  memmove (der + len2 + len3, der + len2, counter - len2);
-+		  memcpy (der + len2, temp, len3);
-+		}
-+	      counter += len3;
-+	      move = RIGHT;
-+	    }
-+	  break;
-+	case ASN1_ETYPE_SEQUENCE_OF:
-+	case ASN1_ETYPE_SET_OF:
-+	  if (move != UP)
-+	    {
-+	      p->tmp_ival = counter;
-+	      p = p->down;
-+	      while ((type_field (p->type) == ASN1_ETYPE_TAG)
-+		     || (type_field (p->type) == ASN1_ETYPE_SIZE))
-+		p = p->right;
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  move = RIGHT;
-+		  continue;
-+		}
-+	      else
-+		p = _asn1_find_up (p);
-+	      move = UP;
-+	    }
-+	  if (move == UP)
-+	    {
-+	      len2 = p->tmp_ival;
-+	      p->tmp_ival = 0;
-+	      if ((type_field (p->type) == ASN1_ETYPE_SET_OF)
-+		  && (counter - len2 > 0) && (max_len >= 0))
-+		{
-+		  err = _asn1_ordering_set_of (der + len2, counter - len2, p);
-+		  if (err != ASN1_SUCCESS)
-+		    goto error;
-+		}
-+	      asn1_length_der (counter - len2, temp, &len3);
-+	      max_len -= len3;
-+	      if (der != NULL && max_len >= 0)
-+		{
-+		  memmove (der + len2 + len3, der + len2, counter - len2);
-+		  memcpy (der + len2, temp, len3);
-+		}
-+	      counter += len3;
-+	      move = RIGHT;
-+	    }
-+	  break;
-+	case ASN1_ETYPE_ANY:
-+	  if (p->value == NULL)
-+	    {
-+	      _asn1_error_description_value_not_found (p, ErrorDescription);
-+	      err = ASN1_VALUE_NOT_FOUND;
-+	      goto error;
-+	    }
-+	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+	  if (len2 < 0)
-+	    {
-+	      err = ASN1_DER_ERROR;
-+	      goto error;
-+	    }
-+	  max_len -= len2;
-+	  if (der != NULL && max_len >= 0)
-+	    memcpy (der + counter, p->value + len3, len2);
-+	  counter += len2;
-+	  move = RIGHT;
-+	  break;
-+	default:
-+	  move = (move == UP) ? RIGHT : DOWN;
-+	  break;
-+	}
-+
-+      if ((move != DOWN) && (counter != counter_old))
-+	{
-+          p->end = counter - 1;
-+	  err = _asn1_complete_explicit_tag (p, der, &counter, &max_len);
-+	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+	    goto error;
-+	}
-+
-+      if (p == node && move != DOWN)
-+	break;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+      if (move == RIGHT)
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  *len = counter;
-+
-+  if (max_len < 0)
-+    {
-+      err = ASN1_MEM_ERROR;
-+      goto error;
-+    }
-+
-+  err = ASN1_SUCCESS;
-+
-+error:
-+  asn1_delete_structure (&node);
-+  return err;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
-new file mode 100644
-index 00000000000..ff04eb778cb
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/decoding.c
-@@ -0,0 +1,2478 @@
-+/*
-+ * Copyright (C) 2002-2016 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+
-+/*****************************************************/
-+/* File: decoding.c                                  */
-+/* Description: Functions to manage DER decoding     */
-+/*****************************************************/
-+
-+#include <int.h>
-+#include <parser_aux.h>
-+#include <gstr.h>
-+#include <structure.h>
-+#include <element.h>
-+#include <limits.h>
-+#include <intprops.h>
-+#include <c-ctype.h>
-+
-+#ifdef DEBUG
-+# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
-+#else
-+# define warn()
-+#endif
-+
-+#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0))
-+
-+#define HAVE_TWO(x) (x>=2?1:0)
-+
-+/* Decoding flags (dflags) used in several decoding functions.
-+ *  DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag
-+ *  DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful
-+ *                           when no tags are present).
-+ *  DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings.
-+ *  DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings.
-+ *  DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings.
-+ *                      This is the maximum levels of recursion possible to prevent stack
-+ *                      exhaustion.
-+ */
-+
-+#define DECODE_FLAG_HAVE_TAG 1
-+#define DECODE_FLAG_CONSTRUCTED (1<<1)
-+#define DECODE_FLAG_LEVEL1 (1<<2)
-+#define DECODE_FLAG_LEVEL2 (1<<3)
-+#define DECODE_FLAG_LEVEL3 (1<<4)
-+
-+#define DECR_LEN(l, s) do { \
-+	  l -= s; \
-+	  if (l < 0) { \
-+	    warn(); \
-+	    result = ASN1_DER_ERROR; \
-+	    goto cleanup; \
-+	  } \
-+	} while (0)
-+
-+static int
-+_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len);
-+
-+static int
-+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, unsigned char **str,
-+			unsigned int *str_len, unsigned int *ber_len,
-+			unsigned dflags);
-+
-+static int
-+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, const unsigned char **str,
-+			unsigned int *str_len, unsigned dflags);
-+
-+static void
-+_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription)
-+{
-+
-+  Estrcpy (ErrorDescription, ":: tag error near element '");
-+  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
-+			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
-+  Estrcat (ErrorDescription, "'");
-+
-+}
-+
-+/**
-+ * asn1_get_length_der:
-+ * @der: DER data to decode.
-+ * @der_len: Length of DER data to decode.
-+ * @len: Output variable containing the length of the DER length field.
-+ *
-+ * Extract a length field from DER data.
-+ *
-+ * Returns: Return the decoded length value, or -1 on indefinite
-+ *   length, or -2 when the value was too big to fit in a int, or -4
-+ *   when the decoded length value plus @len would exceed @der_len.
-+ **/
-+long
-+asn1_get_length_der (const unsigned char *der, int der_len, int *len)
-+{
-+  unsigned int ans;
-+  int k, punt, sum;
-+
-+  *len = 0;
-+  if (der_len <= 0)
-+    return 0;
-+
-+  if (!(der[0] & 128))
-+    {
-+      /* short form */
-+      *len = 1;
-+      ans = der[0];
-+    }
-+  else
-+    {
-+      /* Long form */
-+      k = der[0] & 0x7F;
-+      punt = 1;
-+      if (k)
-+	{ /* definite length method */
-+	  ans = 0;
-+	  while (punt <= k && punt < der_len)
-+	    {
-+	      if (INT_MULTIPLY_OVERFLOW (ans, 256))
-+		return -2;
-+	      ans *= 256;
-+
-+	      if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
-+		return -2;
-+	      ans += der[punt];
-+	      punt++;
-+	    }
-+	}
-+      else
-+	{			/* indefinite length method */
-+	  *len = punt;
-+	  return -1;
-+	}
-+
-+      *len = punt;
-+    }
-+
-+  sum = ans;
-+  if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len)))
-+    return -2;
-+  sum += *len;
-+
-+  if (sum > der_len)
-+    return -4;
-+
-+  return ans;
-+}
-+
-+/**
-+ * asn1_get_tag_der:
-+ * @der: DER data to decode.
-+ * @der_len: Length of DER data to decode.
-+ * @cls: Output variable containing decoded class.
-+ * @len: Output variable containing the length of the DER TAG data.
-+ * @tag: Output variable containing the decoded tag (may be %NULL).
-+ *
-+ * Decode the class and TAG from DER code.
-+ *
-+ * Returns: Returns %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_tag_der (const unsigned char *der, int der_len,
-+		  unsigned char *cls, int *len, unsigned long *tag)
-+{
-+  unsigned int ris;
-+  int punt;
-+
-+  if (der == NULL || der_len < 2 || len == NULL)
-+    return ASN1_DER_ERROR;
-+
-+  *cls = der[0] & 0xE0;
-+  if ((der[0] & 0x1F) != 0x1F)
-+    {
-+      /* short form */
-+      *len = 1;
-+      ris = der[0] & 0x1F;
-+    }
-+  else
-+    {
-+      /* Long form */
-+      punt = 1;
-+      ris = 0;
-+      while (punt < der_len && der[punt] & 128)
-+	{
-+
-+	  if (INT_MULTIPLY_OVERFLOW (ris, 128))
-+	    return ASN1_DER_ERROR;
-+	  ris *= 128;
-+
-+	  if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
-+	    return ASN1_DER_ERROR;
-+	  ris += (der[punt] & 0x7F);
-+	  punt++;
-+	}
-+
-+      if (punt >= der_len)
-+	return ASN1_DER_ERROR;
-+
-+      if (INT_MULTIPLY_OVERFLOW (ris, 128))
-+	return ASN1_DER_ERROR;
-+      ris *= 128;
-+
-+      if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
-+	return ASN1_DER_ERROR;
-+      ris += (der[punt] & 0x7F);
-+      punt++;
-+
-+      *len = punt;
-+    }
-+
-+  if (tag)
-+    *tag = ris;
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_get_length_ber:
-+ * @ber: BER data to decode.
-+ * @ber_len: Length of BER data to decode.
-+ * @len: Output variable containing the length of the BER length field.
-+ *
-+ * Extract a length field from BER data.  The difference to
-+ * asn1_get_length_der() is that this function will return a length
-+ * even if the value has indefinite encoding.
-+ *
-+ * Returns: Return the decoded length value, or negative value when
-+ *   the value was too big.
-+ *
-+ * Since: 2.0
-+ **/
-+long
-+asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len)
-+{
-+  int ret;
-+  long err;
-+
-+  ret = asn1_get_length_der (ber, ber_len, len);
-+
-+  if (ret == -1 && ber_len > 1)
-+    {				/* indefinite length method */
-+      err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret);
-+      if (err != ASN1_SUCCESS)
-+	return -3;
-+    }
-+
-+  return ret;
-+}
-+
-+/**
-+ * asn1_get_octet_der:
-+ * @der: DER data to decode containing the OCTET SEQUENCE.
-+ * @der_len: The length of the @der data to decode.
-+ * @ret_len: Output variable containing the encoded length of the DER data.
-+ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE.
-+ *
-+ * Extract an OCTET SEQUENCE from DER data. Note that this function
-+ * expects the DER data past the tag field, i.e., the length and
-+ * content octets.
-+ *
-+ * Returns: Returns %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_octet_der (const unsigned char *der, int der_len,
-+		    int *ret_len, unsigned char *str, int str_size,
-+		    int *str_len)
-+{
-+  int len_len = 0;
-+
-+  if (der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  *str_len = asn1_get_length_der (der, der_len, &len_len);
-+
-+  if (*str_len < 0)
-+    return ASN1_DER_ERROR;
-+
-+  *ret_len = *str_len + len_len;
-+  if (str_size >= *str_len)
-+    {
-+      if (*str_len > 0 && str != NULL)
-+        memcpy (str, der + len_len, *str_len);
-+    }
-+  else
-+    {
-+      return ASN1_MEM_ERROR;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/*-
-+ * _asn1_get_time_der:
-+ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME
-+ * @der: DER data to decode containing the time
-+ * @der_len: Length of DER data to decode.
-+ * @ret_len: Output variable containing the length of the DER data.
-+ * @str: Pre-allocated output buffer to put the textual time in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER
-+ *
-+ * Performs basic checks in the DER encoded time object and returns its textual form.
-+ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime
-+ * and YYMMDD000000Z for UTCTime.
-+ *
-+ * Returns: %ASN1_SUCCESS on success, or an error.
-+ -*/
-+static int
-+_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len,
-+		    char *str, int str_size, unsigned flags)
-+{
-+  int len_len, str_len;
-+  unsigned i;
-+  unsigned sign_count = 0;
-+  unsigned dot_count = 0;
-+  const unsigned char *p;
-+
-+  if (der_len <= 0 || str == NULL)
-+    return ASN1_DER_ERROR;
-+
-+  str_len = asn1_get_length_der (der, der_len, &len_len);
-+  if (str_len <= 0 || str_size < str_len)
-+    return ASN1_DER_ERROR;
-+
-+  /* perform some sanity checks on the data */
-+  if (str_len < 8)
-+    {
-+      warn();
-+      return ASN1_TIME_ENCODING_ERROR;
-+    }
-+
-+  if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME))
-+    {
-+      p = &der[len_len];
-+      for (i=0;i<(unsigned)(str_len-1);i++)
-+         {
-+           if (c_isdigit(p[i]) == 0)
-+             {
-+               if (type == ASN1_ETYPE_GENERALIZED_TIME)
-+                 {
-+                   /* tolerate lax encodings */
-+                   if (p[i] == '.' && dot_count == 0)
-+                     {
-+                       dot_count++;
-+                       continue;
-+                     }
-+
-+               /* This is not really valid DER, but there are
-+                * structures using that */
-+                   if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) &&
-+                       (p[i] == '+' || p[i] == '-') && sign_count == 0)
-+                     {
-+                       sign_count++;
-+                       continue;
-+                     }
-+                 }
-+
-+               warn();
-+               return ASN1_TIME_ENCODING_ERROR;
-+             }
-+         }
-+
-+      if (sign_count == 0 && p[str_len-1] != 'Z')
-+        {
-+          warn();
-+          return ASN1_TIME_ENCODING_ERROR;
-+        }
-+    }
-+  memcpy (str, der + len_len, str_len);
-+  str[str_len] = 0;
-+  *ret_len = str_len + len_len;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_get_object_id_der:
-+ * @der: DER data to decode containing the OBJECT IDENTIFIER
-+ * @der_len: Length of DER data to decode.
-+ * @ret_len: Output variable containing the length of the DER data.
-+ * @str: Pre-allocated output buffer to put the textual object id in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ *
-+ * Converts a DER encoded object identifier to its textual form. This
-+ * function expects the DER object identifier without the tag.
-+ *
-+ * Returns: %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len,
-+			char *str, int str_size)
-+{
-+  int len_len, len, k;
-+  int leading, parsed;
-+  char temp[LTOSTR_MAX_SIZE];
-+  uint64_t val, val1, val0;
-+
-+  *ret_len = 0;
-+  if (str && str_size > 0)
-+    str[0] = 0;			/* no oid */
-+
-+  if (str == NULL || der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  len = asn1_get_length_der (der, der_len, &len_len);
-+
-+  if (len <= 0 || len + len_len > der_len)
-+    return ASN1_DER_ERROR;
-+
-+  /* leading octet can never be 0x80 */
-+  if (der[len_len] == 0x80)
-+    return ASN1_DER_ERROR;
-+
-+  val0 = 0;
-+
-+  for (k = 0; k < len; k++)
-+    {
-+      if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
-+	return ASN1_DER_ERROR;
-+
-+      val0 <<= 7;
-+      val0 |= der[len_len + k] & 0x7F;
-+      if (!(der[len_len + k] & 0x80))
-+	break;
-+    }
-+  parsed = ++k;
-+
-+  /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */
-+  /* X = val, Y = val1 */
-+
-+  /* check if X == 0  */
-+  val = 0;
-+  val1 = val0;
-+  if (val1 > 39)
-+    {
-+      val = 1;
-+      val1 = val0 - 40;
-+      if (val1  > 39)
-+        {
-+          val = 2;
-+          val1 = val0 - 80;
-+        }
-+    }
-+
-+  _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp));
-+  _asn1_str_cat (str, str_size, ".");
-+  _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp));
-+
-+  val = 0;
-+  leading = 1;
-+  for (k = parsed; k < len; k++)
-+    {
-+      /* X.690 mandates that the leading byte must never be 0x80
-+       */
-+      if (leading != 0 && der[len_len + k] == 0x80)
-+	return ASN1_DER_ERROR;
-+      leading = 0;
-+
-+      /* check for wrap around */
-+      if (INT_LEFT_SHIFT_OVERFLOW (val, 7))
-+	return ASN1_DER_ERROR;
-+
-+      val = val << 7;
-+      val |= der[len_len + k] & 0x7F;
-+
-+      if (!(der[len_len + k] & 0x80))
-+	{
-+	  _asn1_str_cat (str, str_size, ".");
-+	  _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp));
-+	  val = 0;
-+	  leading = 1;
-+	}
-+    }
-+
-+  if (INT_ADD_OVERFLOW (len, len_len))
-+    return ASN1_DER_ERROR;
-+
-+  *ret_len = len + len_len;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_get_bit_der:
-+ * @der: DER data to decode containing the BIT SEQUENCE.
-+ * @der_len: Length of DER data to decode.
-+ * @ret_len: Output variable containing the length of the DER data.
-+ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ * @bit_len: Output variable containing the size of the BIT SEQUENCE.
-+ *
-+ * Extract a BIT SEQUENCE from DER data.
-+ *
-+ * Returns: %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_bit_der (const unsigned char *der, int der_len,
-+		  int *ret_len, unsigned char *str, int str_size,
-+		  int *bit_len)
-+{
-+  int len_len = 0, len_byte;
-+
-+  if (der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  len_byte = asn1_get_length_der (der, der_len, &len_len) - 1;
-+  if (len_byte < 0)
-+    return ASN1_DER_ERROR;
-+
-+  *ret_len = len_byte + len_len + 1;
-+  *bit_len = len_byte * 8 - der[len_len];
-+
-+  if (*bit_len < 0)
-+    return ASN1_DER_ERROR;
-+
-+  if (str_size >= len_byte)
-+    {
-+      if (len_byte > 0 && str)
-+        memcpy (str, der + len_len + 1, len_byte);
-+    }
-+  else
-+    {
-+      return ASN1_MEM_ERROR;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/* tag_len: the total tag length (explicit+inner)
-+ * inner_tag_len: the inner_tag length
-+ */
-+static int
-+_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len,
-+		       int *tag_len, int *inner_tag_len, unsigned flags)
-+{
-+  asn1_node p;
-+  int counter, len2, len3, is_tag_implicit;
-+  int result;
-+  unsigned long tag, tag_implicit = 0;
-+  unsigned char class, class2, class_implicit = 0;
-+
-+  if (der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  counter = is_tag_implicit = 0;
-+
-+  if (node->type & CONST_TAG)
-+    {
-+      p = node->down;
-+      while (p)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if (p->type & CONST_APPLICATION)
-+		class2 = ASN1_CLASS_APPLICATION;
-+	      else if (p->type & CONST_UNIVERSAL)
-+		class2 = ASN1_CLASS_UNIVERSAL;
-+	      else if (p->type & CONST_PRIVATE)
-+		class2 = ASN1_CLASS_PRIVATE;
-+	      else
-+		class2 = ASN1_CLASS_CONTEXT_SPECIFIC;
-+
-+	      if (p->type & CONST_EXPLICIT)
-+		{
-+		  if (asn1_get_tag_der
-+		      (der + counter, der_len, &class, &len2,
-+		       &tag) != ASN1_SUCCESS)
-+		    return ASN1_DER_ERROR;
-+
-+                  DECR_LEN(der_len, len2);
-+		  counter += len2;
-+
-+		  if (flags & ASN1_DECODE_FLAG_STRICT_DER)
-+		    len3 =
-+		      asn1_get_length_der (der + counter, der_len,
-+					 &len2);
-+		  else
-+		    len3 =
-+		      asn1_get_length_ber (der + counter, der_len,
-+					 &len2);
-+		  if (len3 < 0)
-+		    return ASN1_DER_ERROR;
-+
-+                  DECR_LEN(der_len, len2);
-+		  counter += len2;
-+
-+		  if (!is_tag_implicit)
-+		    {
-+		      if ((class != (class2 | ASN1_CLASS_STRUCTURED)) ||
-+			  (tag != strtoul ((char *) p->value, NULL, 10)))
-+			return ASN1_TAG_ERROR;
-+		    }
-+		  else
-+		    {		/* ASN1_TAG_IMPLICIT */
-+		      if ((class != class_implicit) || (tag != tag_implicit))
-+			return ASN1_TAG_ERROR;
-+		    }
-+		  is_tag_implicit = 0;
-+		}
-+	      else
-+		{		/* ASN1_TAG_IMPLICIT */
-+		  if (!is_tag_implicit)
-+		    {
-+		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
-+			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
-+			class2 |= ASN1_CLASS_STRUCTURED;
-+		      class_implicit = class2;
-+		      tag_implicit = strtoul ((char *) p->value, NULL, 10);
-+		      is_tag_implicit = 1;
-+		    }
-+		}
-+	    }
-+	  p = p->right;
-+	}
-+    }
-+
-+  if (is_tag_implicit)
-+    {
-+      if (asn1_get_tag_der
-+	  (der + counter, der_len, &class, &len2,
-+	   &tag) != ASN1_SUCCESS)
-+	return ASN1_DER_ERROR;
-+
-+      DECR_LEN(der_len, len2);
-+
-+      if ((class != class_implicit) || (tag != tag_implicit))
-+	{
-+	  if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING)
-+	    {
-+	      class_implicit |= ASN1_CLASS_STRUCTURED;
-+	      if ((class != class_implicit) || (tag != tag_implicit))
-+		return ASN1_TAG_ERROR;
-+	    }
-+	  else
-+	    return ASN1_TAG_ERROR;
-+	}
-+    }
-+  else
-+    {
-+      unsigned type = type_field (node->type);
-+      if (type == ASN1_ETYPE_TAG)
-+	{
-+	  *tag_len = 0;
-+	  if (inner_tag_len)
-+	    *inner_tag_len = 0;
-+	  return ASN1_SUCCESS;
-+	}
-+
-+      if (asn1_get_tag_der
-+	  (der + counter, der_len, &class, &len2,
-+	   &tag) != ASN1_SUCCESS)
-+	return ASN1_DER_ERROR;
-+
-+      DECR_LEN(der_len, len2);
-+
-+      switch (type)
-+	{
-+	case ASN1_ETYPE_NULL:
-+	case ASN1_ETYPE_BOOLEAN:
-+	case ASN1_ETYPE_INTEGER:
-+	case ASN1_ETYPE_ENUMERATED:
-+	case ASN1_ETYPE_OBJECT_ID:
-+	case ASN1_ETYPE_GENERALSTRING:
-+	case ASN1_ETYPE_NUMERIC_STRING:
-+	case ASN1_ETYPE_IA5_STRING:
-+	case ASN1_ETYPE_TELETEX_STRING:
-+	case ASN1_ETYPE_PRINTABLE_STRING:
-+	case ASN1_ETYPE_UNIVERSAL_STRING:
-+	case ASN1_ETYPE_BMP_STRING:
-+	case ASN1_ETYPE_UTF8_STRING:
-+	case ASN1_ETYPE_VISIBLE_STRING:
-+	case ASN1_ETYPE_BIT_STRING:
-+	case ASN1_ETYPE_SEQUENCE:
-+	case ASN1_ETYPE_SEQUENCE_OF:
-+	case ASN1_ETYPE_SET:
-+	case ASN1_ETYPE_SET_OF:
-+	case ASN1_ETYPE_GENERALIZED_TIME:
-+	case ASN1_ETYPE_UTC_TIME:
-+	  if ((class != _asn1_tags[type].class)
-+	      || (tag != _asn1_tags[type].tag))
-+	    return ASN1_DER_ERROR;
-+	  break;
-+
-+	case ASN1_ETYPE_OCTET_STRING:
-+	  /* OCTET STRING is handled differently to allow
-+	   * BER encodings (structured class). */
-+	  if (((class != ASN1_CLASS_UNIVERSAL)
-+	       && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)))
-+	      || (tag != ASN1_TAG_OCTET_STRING))
-+	    return ASN1_DER_ERROR;
-+	  break;
-+	case ASN1_ETYPE_ANY:
-+	  counter -= len2;
-+	  break;
-+	case ASN1_ETYPE_CHOICE:
-+	  counter -= len2;
-+	  break;
-+	default:
-+	  return ASN1_DER_ERROR;
-+	  break;
-+	}
-+    }
-+
-+  counter += len2;
-+  *tag_len = counter;
-+  if (inner_tag_len)
-+    *inner_tag_len = len2;
-+  return ASN1_SUCCESS;
-+
-+cleanup:
-+  return result;
-+}
-+
-+static int
-+extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len,
-+		       int *ret_len, int *inner_len, unsigned flags)
-+{
-+asn1_node p;
-+int ris = ASN1_DER_ERROR;
-+
-+  if (type_field (node->type) == ASN1_ETYPE_CHOICE)
-+    {
-+      p = node->down;
-+      while (p)
-+        {
-+          ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags);
-+          if (ris == ASN1_SUCCESS)
-+            break;
-+          p = p->right;
-+	}
-+
-+      *ret_len = 0;
-+      return ris;
-+    }
-+  else
-+    return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags);
-+}
-+
-+static int
-+_asn1_delete_not_used (asn1_node node)
-+{
-+  asn1_node p, p2;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if (p->type & CONST_NOT_USED)
-+	{
-+	  p2 = NULL;
-+	  if (p != node)
-+	    {
-+	      p2 = _asn1_find_left (p);
-+	      if (!p2)
-+		p2 = _asn1_find_up (p);
-+	    }
-+	  asn1_delete_structure (&p);
-+	  p = p2;
-+	}
-+
-+      if (!p)
-+	break;			/* reach node */
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else
-+	{
-+	  if (p == node)
-+	    p = NULL;
-+	  else if (p->right)
-+	    p = p->right;
-+	  else
-+	    {
-+	      while (1)
-+		{
-+		  p = _asn1_find_up (p);
-+		  if (p == node)
-+		    {
-+		      p = NULL;
-+		      break;
-+		    }
-+		  if (p->right)
-+		    {
-+		      p = p->right;
-+		      break;
-+		    }
-+		}
-+	    }
-+	}
-+    }
-+  return ASN1_SUCCESS;
-+}
-+
-+static int
-+_asn1_get_indefinite_length_string (const unsigned char *der,
-+				    int der_len, int *len)
-+{
-+  int len2, len3, counter, indefinite;
-+  int result;
-+  unsigned long tag;
-+  unsigned char class;
-+
-+  counter = indefinite = 0;
-+
-+  while (1)
-+    {
-+      if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0))
-+	{
-+	  counter += 2;
-+	  DECR_LEN(der_len, 2);
-+
-+	  indefinite--;
-+	  if (indefinite <= 0)
-+	    break;
-+	  else
-+	    continue;
-+	}
-+
-+      if (asn1_get_tag_der
-+	  (der + counter, der_len, &class, &len2,
-+	   &tag) != ASN1_SUCCESS)
-+	return ASN1_DER_ERROR;
-+
-+      DECR_LEN(der_len, len2);
-+      counter += len2;
-+
-+      len2 = asn1_get_length_der (der + counter, der_len, &len3);
-+      if (len2 < -1)
-+	return ASN1_DER_ERROR;
-+
-+      if (len2 == -1)
-+	{
-+	  indefinite++;
-+	  counter += 1;
-+          DECR_LEN(der_len, 1);
-+	}
-+      else
-+	{
-+	  counter += len2 + len3;
-+          DECR_LEN(der_len, len2+len3);
-+	}
-+    }
-+
-+  *len = counter;
-+  return ASN1_SUCCESS;
-+
-+cleanup:
-+  return result;
-+}
-+
-+static void delete_unneeded_choice_fields(asn1_node p)
-+{
-+  asn1_node p2;
-+
-+  while (p->right)
-+    {
-+      p2 = p->right;
-+      asn1_delete_structure (&p2);
-+    }
-+}
-+
-+
-+/**
-+ * asn1_der_decoding2
-+ * @element: pointer to an ASN1 structure.
-+ * @ider: vector that contains the DER encoding.
-+ * @max_ider_len: pointer to an integer giving the information about the
-+ *   maximal number of bytes occupied by *@ider. The real size of the DER
-+ *   encoding is returned through this pointer.
-+ * @flags: flags controlling the behaviour of the function.
-+ * @errorDescription: null-terminated string contains details when an
-+ *   error occurred.
-+ *
-+ * Fill the structure *@element with values of a DER encoding string. The
-+ * structure must just be created with function asn1_create_element().
-+ *
-+ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore
-+ * padding after the decoded DER data. Upon a successful return the value of
-+ * *@max_ider_len will be set to the number of bytes decoded.
-+ *
-+ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will
-+ * not decode any BER-encoded elements.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
-+ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
-+ *   name (*@ELEMENT deleted).
-+ **/
-+int
-+asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len,
-+		    unsigned int flags, char *errorDescription)
-+{
-+  asn1_node node, p, p2, p3;
-+  char temp[128];
-+  int counter, len2, len3, len4, move, ris, tlen;
-+  struct node_tail_cache_st tcache = {NULL, NULL};
-+  unsigned char class;
-+  unsigned long tag;
-+  int tag_len;
-+  int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len;
-+  int inner_tag_len;
-+  unsigned char *ptmp;
-+  const unsigned char *ptag;
-+  const unsigned char *der = ider;
-+
-+  node = *element;
-+
-+  if (errorDescription != NULL)
-+    errorDescription[0] = 0;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if (node->type & CONST_OPTION)
-+    {
-+      result = ASN1_GENERIC_ERROR;
-+      warn();
-+      goto cleanup;
-+    }
-+
-+  counter = 0;
-+  move = DOWN;
-+  p = node;
-+  while (1)
-+    {
-+      tag_len = 0;
-+      inner_tag_len = 0;
-+      ris = ASN1_SUCCESS;
-+      if (move != UP)
-+	{
-+	  if (p->type & CONST_SET)
-+	    {
-+	      p2 = _asn1_find_up (p);
-+	      len2 = p2->tmp_ival;
-+	      if (len2 == -1)
-+		{
-+		  if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1])
-+		    {
-+		      p = p2;
-+		      move = UP;
-+		      counter += 2;
-+		      DECR_LEN(ider_len, 2);
-+		      continue;
-+		    }
-+		}
-+	      else if (counter == len2)
-+		{
-+		  p = p2;
-+		  move = UP;
-+		  continue;
-+		}
-+	      else if (counter > len2)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      p2 = p2->down;
-+	      while (p2)
-+		{
-+		  if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED))
-+		    {
-+		      ris =
-+			  extract_tag_der_recursive (p2, der + counter,
-+						     ider_len, &len2, NULL, flags);
-+		      if (ris == ASN1_SUCCESS)
-+			{
-+			  p2->type &= ~CONST_NOT_USED;
-+			  p = p2;
-+			  break;
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	      if (p2 == NULL)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	    }
-+
-+	  /* the position in the DER structure this starts */
-+	  p->start = counter;
-+	  p->end = total_len - 1;
-+
-+	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
-+	    {
-+	      p2 = _asn1_find_up (p);
-+	      len2 = p2->tmp_ival;
-+	      if (counter == len2)
-+		{
-+		  if (p->right)
-+		    {
-+		      p2 = p->right;
-+		      move = RIGHT;
-+		    }
-+		  else
-+		    move = UP;
-+
-+		  if (p->type & CONST_OPTION)
-+		    asn1_delete_structure (&p);
-+
-+		  p = p2;
-+		  continue;
-+		}
-+	    }
-+
-+	  if (type_field (p->type) == ASN1_ETYPE_CHOICE)
-+	    {
-+	      while (p->down)
-+		{
-+		  ris =
-+		      extract_tag_der_recursive (p->down, der + counter,
-+					         ider_len, &len2, NULL, flags);
-+
-+		  if (ris == ASN1_SUCCESS)
-+		    {
-+		      delete_unneeded_choice_fields(p->down);
-+		      break;
-+		    }
-+		  else if (ris == ASN1_ERROR_TYPE_ANY)
-+		    {
-+		      result = ASN1_ERROR_TYPE_ANY;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+		  else
-+		    {
-+		      p2 = p->down;
-+		      asn1_delete_structure (&p2);
-+		    }
-+		}
-+
-+	      if (p->down == NULL)
-+		{
-+		  if (!(p->type & CONST_OPTION))
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+		}
-+	      else if (type_field (p->type) != ASN1_ETYPE_CHOICE)
-+		p = p->down;
-+
-+	      p->start = counter;
-+	    }
-+
-+	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
-+	    {
-+	      p2 = _asn1_find_up (p);
-+	      len2 = p2->tmp_ival;
-+
-+	      if ((len2 != -1) && (counter > len2))
-+		ris = ASN1_TAG_ERROR;
-+	    }
-+
-+	  if (ris == ASN1_SUCCESS)
-+	    ris =
-+	      extract_tag_der_recursive (p, der + counter, ider_len,
-+	                                 &tag_len, &inner_tag_len, flags);
-+
-+	  if (ris != ASN1_SUCCESS)
-+	    {
-+	      if (p->type & CONST_OPTION)
-+		{
-+		  p->type |= CONST_NOT_USED;
-+		  move = RIGHT;
-+		}
-+	      else if (p->type & CONST_DEFAULT)
-+		{
-+		  _asn1_set_value (p, NULL, 0);
-+		  move = RIGHT;
-+		}
-+	      else
-+		{
-+		  if (errorDescription != NULL)
-+		    _asn1_error_description_tag_error (p, errorDescription);
-+
-+		  result = ASN1_TAG_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	    }
-+	  else
-+	    {
-+	      DECR_LEN(ider_len, tag_len);
-+	      counter += tag_len;
-+	    }
-+	}
-+
-+      if (ris == ASN1_SUCCESS)
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_NULL:
-+	      DECR_LEN(ider_len, 1);
-+	      if (der[counter])
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      counter++;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_BOOLEAN:
-+	      DECR_LEN(ider_len, 2);
-+
-+	      if (der[counter++] != 1)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      if (der[counter++] == 0)
-+		_asn1_set_value (p, "F", 1);
-+	      else
-+		_asn1_set_value (p, "T", 1);
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_INTEGER:
-+	    case ASN1_ETYPE_ENUMERATED:
-+	      len2 =
-+		asn1_get_length_der (der + counter, ider_len, &len3);
-+	      if (len2 < 0)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len3+len2);
-+
-+	      _asn1_set_value (p, der + counter, len3 + len2);
-+	      counter += len3 + len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_OBJECT_ID:
-+	      result =
-+		asn1_get_object_id_der (der + counter, ider_len, &len2,
-+					temp, sizeof (temp));
-+	      if (result != ASN1_SUCCESS)
-+	        {
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len2);
-+
-+	      tlen = strlen (temp);
-+	      if (tlen > 0)
-+		_asn1_set_value (p, temp, tlen + 1);
-+
-+	      counter += len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_GENERALIZED_TIME:
-+	    case ASN1_ETYPE_UTC_TIME:
-+	      result =
-+		_asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp,
-+				    sizeof (temp) - 1, flags);
-+	      if (result != ASN1_SUCCESS)
-+	        {
-+                  warn();
-+                  goto cleanup;
-+                }
-+
-+	      DECR_LEN(ider_len, len2);
-+
-+	      tlen = strlen (temp);
-+	      if (tlen > 0)
-+		_asn1_set_value (p, temp, tlen);
-+
-+	      counter += len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_OCTET_STRING:
-+	      if (counter < inner_tag_len)
-+	        {
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+	        }
-+
-+              ptag = der + counter - inner_tag_len;
-+              if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED))
-+                {
-+	          if (ptag[0] & ASN1_CLASS_STRUCTURED)
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+	          len2 =
-+		    asn1_get_length_der (der + counter, ider_len, &len3);
-+	          if (len2 < 0)
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+	          DECR_LEN(ider_len, len3+len2);
-+
-+	          _asn1_set_value (p, der + counter, len3 + len2);
-+	          counter += len3 + len2;
-+                }
-+              else
-+                {
-+                  unsigned dflags = 0, vlen, ber_len;
-+
-+                  if (ptag[0] & ASN1_CLASS_STRUCTURED)
-+                    dflags |= DECODE_FLAG_CONSTRUCTED;
-+
-+                  result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags);
-+                  if (result != ASN1_SUCCESS)
-+	            {
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+		  DECR_LEN(ider_len, ber_len);
-+
-+		  _asn1_set_value_lv (p, ptmp, vlen);
-+
-+	          counter += ber_len;
-+	          free(ptmp);
-+                }
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_GENERALSTRING:
-+	    case ASN1_ETYPE_NUMERIC_STRING:
-+	    case ASN1_ETYPE_IA5_STRING:
-+	    case ASN1_ETYPE_TELETEX_STRING:
-+	    case ASN1_ETYPE_PRINTABLE_STRING:
-+	    case ASN1_ETYPE_UNIVERSAL_STRING:
-+	    case ASN1_ETYPE_BMP_STRING:
-+	    case ASN1_ETYPE_UTF8_STRING:
-+	    case ASN1_ETYPE_VISIBLE_STRING:
-+	    case ASN1_ETYPE_BIT_STRING:
-+	      len2 =
-+		asn1_get_length_der (der + counter, ider_len, &len3);
-+	      if (len2 < 0)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len3+len2);
-+
-+	      _asn1_set_value (p, der + counter, len3 + len2);
-+	      counter += len3 + len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_SEQUENCE:
-+	    case ASN1_ETYPE_SET:
-+	      if (move == UP)
-+		{
-+		  len2 = p->tmp_ival;
-+		  p->tmp_ival = 0;
-+		  if (len2 == -1)
-+		    {		/* indefinite length method */
-+		      DECR_LEN(ider_len, 2);
-+		      if ((der[counter]) || der[counter + 1])
-+		        {
-+		          result = ASN1_DER_ERROR;
-+                          warn();
-+		          goto cleanup;
-+			}
-+		      counter += 2;
-+		    }
-+		  else
-+		    {		/* definite length method */
-+		      if (len2 != counter)
-+			{
-+			  result = ASN1_DER_ERROR;
-+                          warn();
-+			  goto cleanup;
-+			}
-+		    }
-+		  move = RIGHT;
-+		}
-+	      else
-+		{		/* move==DOWN || move==RIGHT */
-+		  len3 =
-+		    asn1_get_length_der (der + counter, ider_len, &len2);
-+                  if (IS_ERR(len3, flags))
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+	          DECR_LEN(ider_len, len2);
-+		  counter += len2;
-+
-+		  if (len3 > 0)
-+		    {
-+		      p->tmp_ival = counter + len3;
-+		      move = DOWN;
-+		    }
-+		  else if (len3 == 0)
-+		    {
-+		      p2 = p->down;
-+		      while (p2)
-+			{
-+			  if (type_field (p2->type) != ASN1_ETYPE_TAG)
-+			    {
-+			      p3 = p2->right;
-+			      asn1_delete_structure (&p2);
-+			      p2 = p3;
-+			    }
-+			  else
-+			    p2 = p2->right;
-+			}
-+		      move = RIGHT;
-+		    }
-+		  else
-+		    {		/* indefinite length method */
-+		      p->tmp_ival = -1;
-+		      move = DOWN;
-+		    }
-+		}
-+	      break;
-+	    case ASN1_ETYPE_SEQUENCE_OF:
-+	    case ASN1_ETYPE_SET_OF:
-+	      if (move == UP)
-+		{
-+		  len2 = p->tmp_ival;
-+		  if (len2 == -1)
-+		    {		/* indefinite length method */
-+		      if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1]))
-+			{
-+			  result = _asn1_append_sequence_set (p, &tcache);
-+			  if (result != 0)
-+			    {
-+                              warn();
-+		              goto cleanup;
-+		            }
-+			  p = tcache.tail;
-+			  move = RIGHT;
-+			  continue;
-+			}
-+
-+		      p->tmp_ival = 0;
-+		      tcache.tail = NULL; /* finished decoding this structure */
-+		      tcache.head = NULL;
-+		      DECR_LEN(ider_len, 2);
-+		      counter += 2;
-+		    }
-+		  else
-+		    {		/* definite length method */
-+		      if (len2 > counter)
-+			{
-+			  result = _asn1_append_sequence_set (p, &tcache);
-+			  if (result != 0)
-+			    {
-+                              warn();
-+		              goto cleanup;
-+		            }
-+			  p = tcache.tail;
-+			  move = RIGHT;
-+			  continue;
-+			}
-+
-+		      p->tmp_ival = 0;
-+		      tcache.tail = NULL; /* finished decoding this structure */
-+		      tcache.head = NULL;
-+
-+		      if (len2 != counter)
-+			{
-+			  result = ASN1_DER_ERROR;
-+                          warn();
-+			  goto cleanup;
-+			}
-+		    }
-+		}
-+	      else
-+		{		/* move==DOWN || move==RIGHT */
-+		  len3 =
-+		    asn1_get_length_der (der + counter, ider_len, &len2);
-+                  if (IS_ERR(len3, flags))
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+		  DECR_LEN(ider_len, len2);
-+		  counter += len2;
-+		  if (len3)
-+		    {
-+		      if (len3 > 0)
-+			{	/* definite length method */
-+		          p->tmp_ival = counter + len3;
-+			}
-+		      else
-+			{	/* indefinite length method */
-+		          p->tmp_ival = -1;
-+			}
-+
-+		      p2 = p->down;
-+                      if (p2 == NULL)
-+		        {
-+		          result = ASN1_DER_ERROR;
-+                          warn();
-+		          goto cleanup;
-+		        }
-+
-+		      while ((type_field (p2->type) == ASN1_ETYPE_TAG)
-+			     || (type_field (p2->type) == ASN1_ETYPE_SIZE))
-+			p2 = p2->right;
-+		      if (p2->right == NULL)
-+		        {
-+			  result = _asn1_append_sequence_set (p, &tcache);
-+			  if (result != 0)
-+			    {
-+                              warn();
-+		              goto cleanup;
-+		            }
-+			}
-+		      p = p2;
-+		    }
-+		}
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_ANY:
-+	      /* Check indefinite lenth method in an EXPLICIT TAG */
-+
-+	      if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) &&
-+	          tag_len == 2 && (der[counter - 1] == 0x80))
-+		indefinite = 1;
-+	      else
-+	        indefinite = 0;
-+
-+	      if (asn1_get_tag_der
-+		  (der + counter, ider_len, &class, &len2,
-+		   &tag) != ASN1_SUCCESS)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len2);
-+
-+	      len4 =
-+		asn1_get_length_der (der + counter + len2,
-+				     ider_len, &len3);
-+              if (IS_ERR(len4, flags))
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      if (len4 != -1) /* definite */
-+		{
-+		  len2 += len4;
-+
-+	          DECR_LEN(ider_len, len4+len3);
-+		  _asn1_set_value_lv (p, der + counter, len2 + len3);
-+		  counter += len2 + len3;
-+		}
-+	      else /* == -1 */
-+		{		/* indefinite length */
-+		  ider_len += len2; /* undo DECR_LEN */
-+
-+		  if (counter == 0)
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+		  result =
-+		    _asn1_get_indefinite_length_string (der + counter, ider_len, &len2);
-+		  if (result != ASN1_SUCCESS)
-+		    {
-+                      warn();
-+                      goto cleanup;
-+                    }
-+
-+	          DECR_LEN(ider_len, len2);
-+		  _asn1_set_value_lv (p, der + counter, len2);
-+		  counter += len2;
-+
-+		}
-+
-+	        /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
-+	           an indefinite length method. */
-+	        if (indefinite)
-+		  {
-+	            DECR_LEN(ider_len, 2);
-+		    if (!der[counter] && !der[counter + 1])
-+		      {
-+		        counter += 2;
-+		      }
-+		    else
-+		      {
-+		        result = ASN1_DER_ERROR;
-+                        warn();
-+		        goto cleanup;
-+		      }
-+		  }
-+
-+	      move = RIGHT;
-+	      break;
-+	    default:
-+	      move = (move == UP) ? RIGHT : DOWN;
-+	      break;
-+	    }
-+	}
-+
-+      if (p)
-+        {
-+          p->end = counter - 1;
-+        }
-+
-+      if (p == node && move != DOWN)
-+	break;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+      if ((move == RIGHT) && !(p->type & CONST_SET))
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  _asn1_delete_not_used (*element);
-+
-+  if ((ider_len < 0) ||
-+      (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0)))
-+    {
-+      warn();
-+      result = ASN1_DER_ERROR;
-+      goto cleanup;
-+    }
-+
-+  *max_ider_len = total_len - ider_len;
-+
-+  return ASN1_SUCCESS;
-+
-+cleanup:
-+  asn1_delete_structure (element);
-+  return result;
-+}
-+
-+
-+/**
-+ * asn1_der_decoding:
-+ * @element: pointer to an ASN1 structure.
-+ * @ider: vector that contains the DER encoding.
-+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1].
-+ * @errorDescription: null-terminated string contains details when an
-+ *   error occurred.
-+ *
-+ * Fill the structure *@element with values of a DER encoding
-+ * string. The structure must just be created with function
-+ * asn1_create_element().
-+ *
-+ * Note that the *@element variable is provided as a pointer for
-+ * historical reasons.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
-+ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
-+ *   name (*@ELEMENT deleted).
-+ **/
-+int
-+asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
-+		   char *errorDescription)
-+{
-+  return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
-+}
-+
-+/**
-+ * asn1_der_decoding_element:
-+ * @structure: pointer to an ASN1 structure
-+ * @elementName: name of the element to fill
-+ * @ider: vector that contains the DER encoding of the whole structure.
-+ * @len: number of bytes of *der: der[0]..der[len-1]
-+ * @errorDescription: null-terminated string contains details when an
-+ *   error occurred.
-+ *
-+ * Fill the element named @ELEMENTNAME with values of a DER encoding
-+ * string.  The structure must just be created with function
-+ * asn1_create_element().  The DER vector must contain the encoding
-+ * string of the whole @STRUCTURE.  If an error occurs during the
-+ * decoding procedure, the *@STRUCTURE is deleted and set equal to
-+ * %NULL.
-+ *
-+ * This function is deprecated and may just be an alias to asn1_der_decoding
-+ * in future versions. Use asn1_der_decoding() instead.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if ELEMENT is %NULL or @elementName == NULL, and
-+ *   %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't
-+ *   match the structure @structure (*ELEMENT deleted).
-+ **/
-+int
-+asn1_der_decoding_element (asn1_node * structure, const char *elementName,
-+			   const void *ider, int len, char *errorDescription)
-+{
-+  return asn1_der_decoding(structure, ider, len, errorDescription);
-+}
-+
-+/**
-+ * asn1_der_decoding_startEnd:
-+ * @element: pointer to an ASN1 element
-+ * @ider: vector that contains the DER encoding.
-+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]
-+ * @name_element: an element of NAME structure.
-+ * @start: the position of the first byte of NAME_ELEMENT decoding
-+ *   (@ider[*start])
-+ * @end: the position of the last byte of NAME_ELEMENT decoding
-+ *  (@ider[*end])
-+ *
-+ * Find the start and end point of an element in a DER encoding
-+ * string. I mean that if you have a der encoding and you have already
-+ * used the function asn1_der_decoding() to fill a structure, it may
-+ * happen that you want to find the piece of string concerning an
-+ * element of the structure.
-+ *
-+ * One example is the sequence "tbsCertificate" inside an X509
-+ * certificate.
-+ *
-+ * Note that since libtasn1 3.7 the @ider and @ider_len parameters
-+ * can be omitted, if the element is already decoded using asn1_der_decoding().
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if ELEMENT is %asn1_node EMPTY or @name_element is not a valid
-+ *   element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding
-+ *   doesn't match the structure ELEMENT.
-+ **/
-+int
-+asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
-+			    const char *name_element, int *start, int *end)
-+{
-+  asn1_node node, node_to_find;
-+  int result = ASN1_DER_ERROR;
-+
-+  node = element;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  node_to_find = asn1_find_node (node, name_element);
-+
-+  if (node_to_find == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  *start = node_to_find->start;
-+  *end = node_to_find->end;
-+
-+  if (*start == 0 && *end == 0)
-+    {
-+      if (ider == NULL || ider_len == 0)
-+        return ASN1_GENERIC_ERROR;
-+
-+      /* it seems asn1_der_decoding() wasn't called before. Do it now */
-+      result = asn1_der_decoding (&node, ider, ider_len, NULL);
-+      if (result != ASN1_SUCCESS)
-+        {
-+          warn();
-+          return result;
-+        }
-+
-+      node_to_find = asn1_find_node (node, name_element);
-+      if (node_to_find == NULL)
-+        return ASN1_ELEMENT_NOT_FOUND;
-+
-+      *start = node_to_find->start;
-+      *end = node_to_find->end;
-+    }
-+
-+  if (*end < *start)
-+    return ASN1_GENERIC_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_expand_any_defined_by:
-+ * @definitions: ASN1 definitions
-+ * @element: pointer to an ASN1 structure
-+ *
-+ * Expands every "ANY DEFINED BY" element of a structure created from
-+ * a DER decoding process (asn1_der_decoding function). The element
-+ * ANY must be defined by an OBJECT IDENTIFIER. The type used to
-+ * expand the element ANY is the first one following the definition of
-+ * the actual value of the OBJECT IDENTIFIER.
-+ *
-+ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if
-+ *   some "ANY DEFINED BY" element couldn't be expanded due to a
-+ *   problem in OBJECT_ID -> TYPE association, or other error codes
-+ *   depending on DER decoding.
-+ **/
-+int
-+asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element)
-+{
-+  char name[2 * ASN1_MAX_NAME_SIZE + 2],
-+    value[ASN1_MAX_NAME_SIZE];
-+  int retCode = ASN1_SUCCESS, result;
-+  int len, len2, len3;
-+  asn1_node_const p2;
-+  asn1_node p, p3, aux = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+  const char *definitionsName;
-+
-+  if ((definitions == NULL) || (*element == NULL))
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  definitionsName = definitions->name;
-+
-+  p = *element;
-+  while (p)
-+    {
-+
-+      switch (type_field (p->type))
-+	{
-+	case ASN1_ETYPE_ANY:
-+	  if ((p->type & CONST_DEFINED_BY) && (p->value))
-+	    {
-+	      /* search the "DEF_BY" element */
-+	      p2 = p->down;
-+	      while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT))
-+		p2 = p2->right;
-+
-+	      if (!p2)
-+		{
-+		  retCode = ASN1_ERROR_TYPE_ANY;
-+		  break;
-+		}
-+
-+	      p3 = _asn1_find_up (p);
-+
-+	      if (!p3)
-+		{
-+		  retCode = ASN1_ERROR_TYPE_ANY;
-+		  break;
-+		}
-+
-+	      p3 = p3->down;
-+	      while (p3)
-+		{
-+		  if (!(strcmp (p3->name, p2->name)))
-+		    break;
-+		  p3 = p3->right;
-+		}
-+
-+	      if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
-+		  (p3->value == NULL))
-+		{
-+
-+		  p3 = _asn1_find_up (p);
-+		  p3 = _asn1_find_up (p3);
-+
-+		  if (!p3)
-+		    {
-+		      retCode = ASN1_ERROR_TYPE_ANY;
-+		      break;
-+		    }
-+
-+		  p3 = p3->down;
-+
-+		  while (p3)
-+		    {
-+		      if (!(strcmp (p3->name, p2->name)))
-+			break;
-+		      p3 = p3->right;
-+		    }
-+
-+		  if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
-+		      || (p3->value == NULL))
-+		    {
-+		      retCode = ASN1_ERROR_TYPE_ANY;
-+		      break;
-+		    }
-+		}
-+
-+	      /* search the OBJECT_ID into definitions */
-+	      p2 = definitions->down;
-+	      while (p2)
-+		{
-+		  if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
-+		      (p2->type & CONST_ASSIGN))
-+		    {
-+		      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
-+
-+		      len = ASN1_MAX_NAME_SIZE;
-+		      result =
-+			asn1_read_value (definitions, name, value, &len);
-+
-+		      if ((result == ASN1_SUCCESS)
-+			  && (!_asn1_strcmp (p3->value, value)))
-+			{
-+			  p2 = p2->right;	/* pointer to the structure to
-+						   use for expansion */
-+			  while ((p2) && (p2->type & CONST_ASSIGN))
-+			    p2 = p2->right;
-+
-+			  if (p2)
-+			    {
-+			      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
-+
-+			      result =
-+				asn1_create_element (definitions, name, &aux);
-+			      if (result == ASN1_SUCCESS)
-+				{
-+				  _asn1_cpy_name (aux, p);
-+				  len2 =
-+				    asn1_get_length_der (p->value,
-+							 p->value_len, &len3);
-+				  if (len2 < 0)
-+				    return ASN1_DER_ERROR;
-+
-+				  result =
-+				    asn1_der_decoding (&aux, p->value + len3,
-+						       len2,
-+						       errorDescription);
-+				  if (result == ASN1_SUCCESS)
-+				    {
-+
-+				      _asn1_set_right (aux, p->right);
-+				      _asn1_set_right (p, aux);
-+
-+				      result = asn1_delete_structure (&p);
-+				      if (result == ASN1_SUCCESS)
-+					{
-+					  p = aux;
-+					  aux = NULL;
-+					  break;
-+					}
-+				      else
-+					{	/* error with asn1_delete_structure */
-+					  asn1_delete_structure (&aux);
-+					  retCode = result;
-+					  break;
-+					}
-+				    }
-+				  else
-+				    {	/* error with asn1_der_decoding */
-+				      retCode = result;
-+				      break;
-+				    }
-+				}
-+			      else
-+				{	/* error with asn1_create_element */
-+				  retCode = result;
-+				  break;
-+				}
-+			    }
-+			  else
-+			    {	/* error with the pointer to the structure to exapand */
-+			      retCode = ASN1_ERROR_TYPE_ANY;
-+			      break;
-+			    }
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}		/* end while */
-+
-+	      if (!p2)
-+		{
-+		  retCode = ASN1_ERROR_TYPE_ANY;
-+		  break;
-+		}
-+
-+	    }
-+	  break;
-+	default:
-+	  break;
-+	}
-+
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p == *element)
-+	{
-+	  p = NULL;
-+	  break;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == *element)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  return retCode;
-+}
-+
-+/**
-+ * asn1_expand_octet_string:
-+ * @definitions: ASN1 definitions
-+ * @element: pointer to an ASN1 structure
-+ * @octetName: name of the OCTECT STRING field to expand.
-+ * @objectName: name of the OBJECT IDENTIFIER field to use to define
-+ *    the type for expansion.
-+ *
-+ * Expands an "OCTET STRING" element of a structure created from a DER
-+ * decoding process (the asn1_der_decoding() function).  The type used
-+ * for expansion is the first one following the definition of the
-+ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME.
-+ *
-+ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @objectName or @octetName are not correct,
-+ *   %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to
-+ *   use for expansion, or other errors depending on DER decoding.
-+ **/
-+int
-+asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
-+			  const char *octetName, const char *objectName)
-+{
-+  char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE];
-+  int retCode = ASN1_SUCCESS, result;
-+  int len, len2, len3;
-+  asn1_node_const p2;
-+  asn1_node aux = NULL;
-+  asn1_node octetNode = NULL, objectNode = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+  if ((definitions == NULL) || (*element == NULL))
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  octetNode = asn1_find_node (*element, octetName);
-+  if (octetNode == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+  if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+  if (octetNode->value == NULL)
-+    return ASN1_VALUE_NOT_FOUND;
-+
-+  objectNode = asn1_find_node (*element, objectName);
-+  if (objectNode == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if (objectNode->value == NULL)
-+    return ASN1_VALUE_NOT_FOUND;
-+
-+
-+  /* search the OBJECT_ID into definitions */
-+  p2 = definitions->down;
-+  while (p2)
-+    {
-+      if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	  (p2->type & CONST_ASSIGN))
-+	{
-+	  strcpy (name, definitions->name);
-+	  strcat (name, ".");
-+	  strcat (name, p2->name);
-+
-+	  len = sizeof (value);
-+	  result = asn1_read_value (definitions, name, value, &len);
-+
-+	  if ((result == ASN1_SUCCESS)
-+	      && (!_asn1_strcmp (objectNode->value, value)))
-+	    {
-+
-+	      p2 = p2->right;	/* pointer to the structure to
-+				   use for expansion */
-+	      while ((p2) && (p2->type & CONST_ASSIGN))
-+		p2 = p2->right;
-+
-+	      if (p2)
-+		{
-+		  strcpy (name, definitions->name);
-+		  strcat (name, ".");
-+		  strcat (name, p2->name);
-+
-+		  result = asn1_create_element (definitions, name, &aux);
-+		  if (result == ASN1_SUCCESS)
-+		    {
-+		      _asn1_cpy_name (aux, octetNode);
-+		      len2 =
-+			asn1_get_length_der (octetNode->value,
-+					     octetNode->value_len, &len3);
-+		      if (len2 < 0)
-+			return ASN1_DER_ERROR;
-+
-+		      result =
-+			asn1_der_decoding (&aux, octetNode->value + len3,
-+					   len2, errorDescription);
-+		      if (result == ASN1_SUCCESS)
-+			{
-+
-+			  _asn1_set_right (aux, octetNode->right);
-+			  _asn1_set_right (octetNode, aux);
-+
-+			  result = asn1_delete_structure (&octetNode);
-+			  if (result == ASN1_SUCCESS)
-+			    {
-+			      aux = NULL;
-+			      break;
-+			    }
-+			  else
-+			    {	/* error with asn1_delete_structure */
-+			      asn1_delete_structure (&aux);
-+			      retCode = result;
-+			      break;
-+			    }
-+			}
-+		      else
-+			{	/* error with asn1_der_decoding */
-+			  retCode = result;
-+			  break;
-+			}
-+		    }
-+		  else
-+		    {		/* error with asn1_create_element */
-+		      retCode = result;
-+		      break;
-+		    }
-+		}
-+	      else
-+		{		/* error with the pointer to the structure to exapand */
-+		  retCode = ASN1_VALUE_NOT_VALID;
-+		  break;
-+		}
-+	    }
-+	}
-+
-+      p2 = p2->right;
-+
-+    }
-+
-+  if (!p2)
-+    retCode = ASN1_VALUE_NOT_VALID;
-+
-+  return retCode;
-+}
-+
-+/*-
-+ * _asn1_decode_simple_der:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ * @dflags: DECODE_FLAG_*
-+ *
-+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
-+ * The output is a pointer inside the @der.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ -*/
-+static int
-+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, const unsigned char **str,
-+			unsigned int *str_len, unsigned dflags)
-+{
-+  int tag_len, len_len;
-+  const unsigned char *p;
-+  int der_len = _der_len;
-+  unsigned char class;
-+  unsigned long tag;
-+  long ret;
-+
-+  if (der == NULL || der_len == 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  /* doesn't handle constructed classes */
-+  class = ETYPE_CLASS(etype);
-+  if (class != ASN1_CLASS_UNIVERSAL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  p = der;
-+
-+  if (dflags & DECODE_FLAG_HAVE_TAG)
-+    {
-+      ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
-+      if (ret != ASN1_SUCCESS)
-+        return ret;
-+
-+      if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype))
-+        {
-+          warn();
-+          return ASN1_DER_ERROR;
-+        }
-+
-+      p += tag_len;
-+      der_len -= tag_len;
-+      if (der_len <= 0)
-+        return ASN1_DER_ERROR;
-+    }
-+
-+  ret = asn1_get_length_der (p, der_len, &len_len);
-+  if (ret < 0)
-+    return ASN1_DER_ERROR;
-+
-+  p += len_len;
-+  der_len -= len_len;
-+  if (der_len <= 0)
-+    return ASN1_DER_ERROR;
-+
-+  *str_len = ret;
-+  *str = p;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_decode_simple_der:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ *
-+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
-+ * The output is a pointer inside the @der.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ **/
-+int
-+asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, const unsigned char **str,
-+			unsigned int *str_len)
-+{
-+  return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG);
-+}
-+
-+static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size)
-+{
-+  if (src_size == 0)
-+    return ASN1_SUCCESS;
-+
-+  *dst = _asn1_realloc(*dst, *dst_size+src_size);
-+  if (*dst == NULL)
-+    return ASN1_MEM_ALLOC_ERROR;
-+  memcpy(*dst + *dst_size, src, src_size);
-+  *dst_size += src_size;
-+  return ASN1_SUCCESS;
-+}
-+
-+/*-
-+ * _asn1_decode_simple_ber:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ * @ber_len: the total length occupied by BER (may be %NULL)
-+ * @have_tag: whether a DER tag is included
-+ *
-+ * Decodes a BER encoded type. The output is an allocated value
-+ * of the data. This decodes BER STRINGS only. Other types are
-+ * decoded as DER.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ -*/
-+static int
-+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, unsigned char **str,
-+			unsigned int *str_len, unsigned int *ber_len,
-+			unsigned dflags)
-+{
-+  int tag_len, len_len;
-+  const unsigned char *p;
-+  int der_len = _der_len;
-+  uint8_t *total = NULL;
-+  unsigned total_size = 0;
-+  unsigned char class;
-+  unsigned long tag;
-+  unsigned char *out = NULL;
-+  const unsigned char *cout = NULL;
-+  unsigned out_len;
-+  long result;
-+
-+  if (ber_len) *ber_len = 0;
-+
-+  if (der == NULL || der_len == 0)
-+    {
-+      warn();
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  if (ETYPE_OK (etype) == 0)
-+    {
-+      warn();
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  /* doesn't handle constructed + definite classes */
-+  class = ETYPE_CLASS (etype);
-+  if (class != ASN1_CLASS_UNIVERSAL)
-+    {
-+      warn();
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  p = der;
-+
-+  if (dflags & DECODE_FLAG_HAVE_TAG)
-+    {
-+      result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
-+        if (result != ASN1_SUCCESS)
-+          {
-+            warn();
-+            return result;
-+          }
-+
-+        if (tag != ETYPE_TAG (etype))
-+          {
-+            warn();
-+            return ASN1_DER_ERROR;
-+          }
-+
-+        p += tag_len;
-+
-+        DECR_LEN(der_len, tag_len);
-+
-+        if (ber_len) *ber_len += tag_len;
-+    }
-+
-+  /* indefinite constructed */
-+  if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) &&
-+      !(dflags & DECODE_FLAG_LEVEL3))
-+    {
-+      if (der_len == 0)
-+        {
-+          warn();
-+          result = ASN1_DER_ERROR;
-+          goto cleanup;
-+        }
-+
-+      if (der_len > 0 && p[0] == 0x80) /* indefinite */
-+        {
-+          len_len = 1;
-+          DECR_LEN(der_len, len_len);
-+          p += len_len;
-+
-+          if (ber_len) *ber_len += len_len;
-+
-+          /* decode the available octet strings */
-+          do
-+            {
-+              unsigned tmp_len;
-+              unsigned flags = DECODE_FLAG_HAVE_TAG;
-+
-+              if (dflags & DECODE_FLAG_LEVEL1)
-+                flags |= DECODE_FLAG_LEVEL2;
-+              else if (dflags & DECODE_FLAG_LEVEL2)
-+                flags |= DECODE_FLAG_LEVEL3;
-+              else
-+		flags |= DECODE_FLAG_LEVEL1;
-+
-+              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
-+                                               flags);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+                }
-+
-+              p += tmp_len;
-+              DECR_LEN(der_len, tmp_len);
-+
-+              if (ber_len) *ber_len += tmp_len;
-+
-+              DECR_LEN(der_len, 2); /* we need the EOC */
-+
-+              result = append(&total, &total_size, out, out_len);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+	        }
-+
-+              free(out);
-+              out = NULL;
-+
-+	      if (p[0] == 0 && p[1] == 0) /* EOC */
-+	        {
-+                  if (ber_len) *ber_len += 2;
-+                  break;
-+                }
-+
-+              /* no EOC */
-+              der_len += 2;
-+
-+              if (der_len == 2)
-+                {
-+                  warn();
-+                  result = ASN1_DER_ERROR;
-+                  goto cleanup;
-+                }
-+            }
-+          while(1);
-+        }
-+      else /* constructed */
-+        {
-+          long const_len;
-+
-+          result = asn1_get_length_ber(p, der_len, &len_len);
-+          if (result < 0)
-+            {
-+              warn();
-+              result = ASN1_DER_ERROR;
-+              goto cleanup;
-+            }
-+
-+          DECR_LEN(der_len, len_len);
-+          p += len_len;
-+
-+          const_len = result;
-+
-+          if (ber_len) *ber_len += len_len;
-+
-+          /* decode the available octet strings */
-+          while(const_len > 0)
-+            {
-+              unsigned tmp_len;
-+              unsigned flags = DECODE_FLAG_HAVE_TAG;
-+
-+              if (dflags & DECODE_FLAG_LEVEL1)
-+                flags |= DECODE_FLAG_LEVEL2;
-+              else if (dflags & DECODE_FLAG_LEVEL2)
-+                flags |= DECODE_FLAG_LEVEL3;
-+              else
-+		flags |= DECODE_FLAG_LEVEL1;
-+
-+              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
-+                                               flags);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+                }
-+
-+              p += tmp_len;
-+              DECR_LEN(der_len, tmp_len);
-+              DECR_LEN(const_len, tmp_len);
-+
-+              if (ber_len) *ber_len += tmp_len;
-+
-+              result = append(&total, &total_size, out, out_len);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+	        }
-+
-+              free(out);
-+              out = NULL;
-+            }
-+        }
-+    }
-+  else if (class == ETYPE_CLASS(etype))
-+    {
-+      if (ber_len)
-+        {
-+          result = asn1_get_length_der (p, der_len, &len_len);
-+          if (result < 0)
-+            {
-+              warn();
-+              result = ASN1_DER_ERROR;
-+              goto cleanup;
-+            }
-+          *ber_len += result + len_len;
-+        }
-+
-+      /* non-string values are decoded as DER */
-+      result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags);
-+      if (result != ASN1_SUCCESS)
-+        {
-+          warn();
-+          goto cleanup;
-+        }
-+
-+      result = append(&total, &total_size, cout, out_len);
-+      if (result != ASN1_SUCCESS)
-+        {
-+          warn();
-+          goto cleanup;
-+        }
-+    }
-+  else
-+    {
-+      warn();
-+      result = ASN1_DER_ERROR;
-+      goto cleanup;
-+    }
-+
-+  *str = total;
-+  *str_len = total_size;
-+
-+  return ASN1_SUCCESS;
-+cleanup:
-+  free(out);
-+  free(total);
-+  return result;
-+}
-+
-+/**
-+ * asn1_decode_simple_ber:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ * @ber_len: the total length occupied by BER (may be %NULL)
-+ *
-+ * Decodes a BER encoded type. The output is an allocated value
-+ * of the data. This decodes BER STRINGS only. Other types are
-+ * decoded as DER.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ **/
-+int
-+asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, unsigned char **str,
-+			unsigned int *str_len, unsigned int *ber_len)
-+{
-+  return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG);
-+}
-diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
-new file mode 100644
-index 00000000000..997eb2725dc
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/element.c
-@@ -0,0 +1,1111 @@
-+/*
-+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+/*****************************************************/
-+/* File: element.c                                   */
-+/* Description: Functions with the read and write    */
-+/*   functions.                                      */
-+/*****************************************************/
-+
-+
-+#include <int.h>
-+#include "parser_aux.h"
-+#include <gstr.h>
-+#include "structure.h"
-+#include "c-ctype.h"
-+#include "element.h"
-+
-+void
-+_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
-+{
-+  asn1_node_const p;
-+  char tmp_name[64];
-+
-+  p = node;
-+
-+  name[0] = 0;
-+
-+  while (p != NULL)
-+    {
-+      if (p->name[0] != 0)
-+	{
-+	  _asn1_str_cpy (tmp_name, sizeof (tmp_name), name),
-+	    _asn1_str_cpy (name, name_size, p->name);
-+	  _asn1_str_cat (name, name_size, ".");
-+	  _asn1_str_cat (name, name_size, tmp_name);
-+	}
-+      p = _asn1_find_up (p);
-+    }
-+
-+  if (name[0] == 0)
-+    _asn1_str_cpy (name, name_size, "ROOT");
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_convert_integer                               */
-+/* Description: converts an integer from a null terminated string */
-+/*              to der decoding. The convertion from a null       */
-+/*              terminated string to an integer is made with      */
-+/*              the 'strtol' function.                            */
-+/* Parameters:                                                    */
-+/*   value: null terminated string to convert.                    */
-+/*   value_out: convertion result (memory must be already         */
-+/*              allocated).                                       */
-+/*   value_out_size: number of bytes of value_out.                */
-+/*   len: number of significant byte of value_out.                */
-+/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS                         */
-+/******************************************************************/
-+int
-+_asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
-+		       int value_out_size, int *len)
-+{
-+  char negative;
-+  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
-+  long valtmp;
-+  int k, k2;
-+
-+  valtmp = _asn1_strtol (value, NULL, 10);
-+
-+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
-+    {
-+      val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF;
-+    }
-+
-+  if (val[0] & 0x80)
-+    negative = 1;
-+  else
-+    negative = 0;
-+
-+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++)
-+    {
-+      if (negative && (val[k] != 0xFF))
-+	break;
-+      else if (!negative && val[k])
-+	break;
-+    }
-+
-+  if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80)))
-+    k--;
-+
-+  *len = SIZEOF_UNSIGNED_LONG_INT - k;
-+
-+  if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size)
-+    /* VALUE_OUT is too short to contain the value conversion */
-+    return ASN1_MEM_ERROR;
-+
-+  if (value_out != NULL)
-+    {
-+      for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++)
-+        value_out[k2 - k] = val[k2];
-+    }
-+
-+#if 0
-+  printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
-+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
-+    printf (", vOut[%d]=%d", k, value_out[k]);
-+  printf ("\n");
-+#endif
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/* Appends a new element into the sequence (or set) defined by this
-+ * node. The new element will have a name of '?number', where number
-+ * is a monotonically increased serial number.
-+ *
-+ * The last element in the list may be provided in @pcache, to avoid
-+ * traversing the list, an expensive operation in long lists.
-+ *
-+ * On success it returns in @pcache the added element (which is the
-+ * tail in the list of added elements).
-+ */
-+int
-+_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
-+{
-+  asn1_node p, p2;
-+  char temp[LTOSTR_MAX_SIZE];
-+  long n;
-+
-+  if (!node || !(node->down))
-+    return ASN1_GENERIC_ERROR;
-+
-+  p = node->down;
-+  while ((type_field (p->type) == ASN1_ETYPE_TAG)
-+	 || (type_field (p->type) == ASN1_ETYPE_SIZE))
-+    p = p->right;
-+
-+  p2 = _asn1_copy_structure3 (p);
-+  if (p2 == NULL)
-+    return ASN1_GENERIC_ERROR;
-+
-+  if (pcache == NULL || pcache->tail == NULL || pcache->head != node)
-+    {
-+      while (p->right)
-+        {
-+          p = p->right;
-+        }
-+    }
-+  else
-+    {
-+      p = pcache->tail;
-+    }
-+
-+  _asn1_set_right (p, p2);
-+  if (pcache)
-+    {
-+      pcache->head = node;
-+      pcache->tail = p2;
-+    }
-+
-+  if (p->name[0] == 0)
-+    _asn1_str_cpy (temp, sizeof (temp), "?1");
-+  else
-+    {
-+      n = strtol (p->name + 1, NULL, 0);
-+      n++;
-+      temp[0] = '?';
-+      _asn1_ltostr (n, temp + 1);
-+    }
-+  _asn1_set_name (p2, temp);
-+  /*  p2->type |= CONST_OPTION; */
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_write_value:
-+ * @node_root: pointer to a structure
-+ * @name: the name of the element inside the structure that you want to set.
-+ * @ivalue: vector used to specify the value to set. If len is >0,
-+ *   VALUE must be a two's complement form integer.  if len=0 *VALUE
-+ *   must be a null terminated string with an integer value.
-+ * @len: number of bytes of *value to use to set the value:
-+ *   value[0]..value[len-1] or 0 if value is a null terminated string
-+ *
-+ * Set the value of one element inside a structure.
-+ *
-+ * If an element is OPTIONAL and you want to delete it, you must use
-+ * the value=NULL and len=0.  Using "pkix.asn":
-+ *
-+ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID",
-+ * NULL, 0);
-+ *
-+ * Description for each type:
-+ *
-+ * INTEGER: VALUE must contain a two's complement form integer.
-+ *
-+ *            value[0]=0xFF ,               len=1 -> integer=-1.
-+ *            value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1.
-+ *            value[0]=0x01 ,               len=1 -> integer= 1.
-+ *            value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1.
-+ *            value="123"                 , len=0 -> integer= 123.
-+ *
-+ * ENUMERATED: As INTEGER (but only with not negative numbers).
-+ *
-+ * BOOLEAN: VALUE must be the null terminated string "TRUE" or
-+ *   "FALSE" and LEN != 0.
-+ *
-+ *            value="TRUE" , len=1 -> boolean=TRUE.
-+ *            value="FALSE" , len=1 -> boolean=FALSE.
-+ *
-+ * OBJECT IDENTIFIER: VALUE must be a null terminated string with
-+ *   each number separated by a dot (e.g. "1.2.3.543.1").  LEN != 0.
-+ *
-+ *            value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha.
-+ *
-+ * UTCTime: VALUE must be a null terminated string in one of these
-+ *   formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ",
-+ *   "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'",
-+ *   "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'".  LEN != 0.
-+ *
-+ *            value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998
-+ *            at 12h 00m Greenwich Mean Time
-+ *
-+ * GeneralizedTime: VALUE must be in one of this format:
-+ *   "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ",
-+ *   "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'",
-+ *   "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s
-+ *   indicates the seconds with any precision like "10.1" or "01.02".
-+ *   LEN != 0
-+ *
-+ *            value="2001010112001.12-0700" , len=1 -> time=Jannuary
-+ *            1st, 2001 at 12h 00m 01.12s Pacific Daylight Time
-+ *
-+ * OCTET STRING: VALUE contains the octet string and LEN is the
-+ *   number of octets.
-+ *
-+ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
-+ *            len=3 -> three bytes octet string
-+ *
-+ * GeneralString: VALUE contains the generalstring and LEN is the
-+ *   number of octets.
-+ *
-+ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
-+ *            len=3 -> three bytes generalstring
-+ *
-+ * BIT STRING: VALUE contains the bit string organized by bytes and
-+ *   LEN is the number of bits.
-+ *
-+ *   value="$\backslash$xCF" , len=6 -> bit string="110011" (six
-+ *   bits)
-+ *
-+ * CHOICE: if NAME indicates a choice type, VALUE must specify one of
-+ *   the alternatives with a null terminated string. LEN != 0. Using
-+ *   "pkix.asn"\:
-+ *
-+ *           result=asn1_write_value(cert,
-+ *           "certificate1.tbsCertificate.subject", "rdnSequence",
-+ *           1);
-+ *
-+ * ANY: VALUE indicates the der encoding of a structure.  LEN != 0.
-+ *
-+ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and
-+ *   LEN != 0. With this instruction another element is appended in
-+ *   the sequence. The name of this element will be "?1" if it's the
-+ *   first one, "?2" for the second and so on.
-+ *
-+ *   Using "pkix.asn"\:
-+ *
-+ *   result=asn1_write_value(cert,
-+ *   "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1);
-+ *
-+ * SET OF: the same as SEQUENCE OF.  Using "pkix.asn":
-+ *
-+ *           result=asn1_write_value(cert,
-+ *           "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1);
-+ *
-+ * Returns: %ASN1_SUCCESS if the value was set,
-+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and
-+ *   %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format.
-+ **/
-+int
-+asn1_write_value (asn1_node node_root, const char *name,
-+		  const void *ivalue, int len)
-+{
-+  asn1_node node, p, p2;
-+  unsigned char *temp, *value_temp = NULL, *default_temp = NULL;
-+  int len2, k, k2, negative;
-+  size_t i;
-+  const unsigned char *value = ivalue;
-+  unsigned int type;
-+
-+  node = asn1_find_node (node_root, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0))
-+    {
-+      asn1_delete_structure (&node);
-+      return ASN1_SUCCESS;
-+    }
-+
-+  type = type_field (node->type);
-+
-+  if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0))
-+    {
-+      p = node->down;
-+      while ((type_field (p->type) == ASN1_ETYPE_TAG)
-+	     || (type_field (p->type) == ASN1_ETYPE_SIZE))
-+	p = p->right;
-+
-+      while (p->right)
-+	asn1_delete_structure (&p->right);
-+
-+      return ASN1_SUCCESS;
-+    }
-+
-+  /* Don't allow element deletion for other types */
-+  if (value == NULL)
-+    {
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  switch (type)
-+    {
-+    case ASN1_ETYPE_BOOLEAN:
-+      if (!_asn1_strcmp (value, "TRUE"))
-+	{
-+	  if (node->type & CONST_DEFAULT)
-+	    {
-+	      p = node->down;
-+	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+		p = p->right;
-+	      if (p->type & CONST_TRUE)
-+		_asn1_set_value (node, NULL, 0);
-+	      else
-+		_asn1_set_value (node, "T", 1);
-+	    }
-+	  else
-+	    _asn1_set_value (node, "T", 1);
-+	}
-+      else if (!_asn1_strcmp (value, "FALSE"))
-+	{
-+	  if (node->type & CONST_DEFAULT)
-+	    {
-+	      p = node->down;
-+	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+		p = p->right;
-+	      if (p->type & CONST_FALSE)
-+		_asn1_set_value (node, NULL, 0);
-+	      else
-+		_asn1_set_value (node, "F", 1);
-+	    }
-+	  else
-+	    _asn1_set_value (node, "F", 1);
-+	}
-+      else
-+	return ASN1_VALUE_NOT_VALID;
-+      break;
-+    case ASN1_ETYPE_INTEGER:
-+    case ASN1_ETYPE_ENUMERATED:
-+      if (len == 0)
-+	{
-+	  if ((c_isdigit (value[0])) || (value[0] == '-'))
-+	    {
-+	      value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+	      if (value_temp == NULL)
-+		return ASN1_MEM_ALLOC_ERROR;
-+
-+	      _asn1_convert_integer (value, value_temp,
-+				     SIZEOF_UNSIGNED_LONG_INT, &len);
-+	    }
-+	  else
-+	    {			/* is an identifier like v1 */
-+	      if (!(node->type & CONST_LIST))
-+		return ASN1_VALUE_NOT_VALID;
-+	      p = node->down;
-+	      while (p)
-+		{
-+		  if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
-+		    {
-+		      if (!_asn1_strcmp (p->name, value))
-+			{
-+			  value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+			  if (value_temp == NULL)
-+			    return ASN1_MEM_ALLOC_ERROR;
-+
-+			  _asn1_convert_integer (p->value,
-+						 value_temp,
-+						 SIZEOF_UNSIGNED_LONG_INT,
-+						 &len);
-+			  break;
-+			}
-+		    }
-+		  p = p->right;
-+		}
-+	      if (p == NULL)
-+		return ASN1_VALUE_NOT_VALID;
-+	    }
-+	}
-+      else
-+	{			/* len != 0 */
-+	  value_temp = malloc (len);
-+	  if (value_temp == NULL)
-+	    return ASN1_MEM_ALLOC_ERROR;
-+	  memcpy (value_temp, value, len);
-+	}
-+
-+      if (value_temp[0] & 0x80)
-+	negative = 1;
-+      else
-+	negative = 0;
-+
-+      if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED))
-+	{
-+	  free (value_temp);
-+	  return ASN1_VALUE_NOT_VALID;
-+	}
-+
-+      for (k = 0; k < len - 1; k++)
-+	if (negative && (value_temp[k] != 0xFF))
-+	  break;
-+	else if (!negative && value_temp[k])
-+	  break;
-+
-+      if ((negative && !(value_temp[k] & 0x80)) ||
-+	  (!negative && (value_temp[k] & 0x80)))
-+	k--;
-+
-+      _asn1_set_value_lv (node, value_temp + k, len - k);
-+
-+      if (node->type & CONST_DEFAULT)
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-'))
-+	    {
-+	      default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+	      if (default_temp == NULL)
-+		{
-+		  free (value_temp);
-+		  return ASN1_MEM_ALLOC_ERROR;
-+		}
-+
-+	      _asn1_convert_integer (p->value, default_temp,
-+				     SIZEOF_UNSIGNED_LONG_INT, &len2);
-+	    }
-+	  else
-+	    {			/* is an identifier like v1 */
-+	      if (!(node->type & CONST_LIST))
-+		{
-+		  free (value_temp);
-+		  return ASN1_VALUE_NOT_VALID;
-+		}
-+	      p2 = node->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
-+		    {
-+		      if (!_asn1_strcmp (p2->name, p->value))
-+			{
-+			  default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+			  if (default_temp == NULL)
-+			    {
-+			      free (value_temp);
-+			      return ASN1_MEM_ALLOC_ERROR;
-+			    }
-+
-+			  _asn1_convert_integer (p2->value,
-+						 default_temp,
-+						 SIZEOF_UNSIGNED_LONG_INT,
-+						 &len2);
-+			  break;
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	      if (p2 == NULL)
-+		{
-+		  free (value_temp);
-+		  return ASN1_VALUE_NOT_VALID;
-+		}
-+	    }
-+
-+
-+	  if ((len - k) == len2)
-+	    {
-+	      for (k2 = 0; k2 < len2; k2++)
-+		if (value_temp[k + k2] != default_temp[k2])
-+		  {
-+		    break;
-+		  }
-+	      if (k2 == len2)
-+		_asn1_set_value (node, NULL, 0);
-+	    }
-+	  free (default_temp);
-+	}
-+      free (value_temp);
-+      break;
-+    case ASN1_ETYPE_OBJECT_ID:
-+      for (i = 0; i < _asn1_strlen (value); i++)
-+	if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+'))
-+	  return ASN1_VALUE_NOT_VALID;
-+      if (node->type & CONST_DEFAULT)
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if (!_asn1_strcmp (value, p->value))
-+	    {
-+	      _asn1_set_value (node, NULL, 0);
-+	      break;
-+	    }
-+	}
-+      _asn1_set_value (node, value, _asn1_strlen (value) + 1);
-+      break;
-+    case ASN1_ETYPE_UTC_TIME:
-+      {
-+	len = _asn1_strlen (value);
-+	if (len < 11)
-+	  return ASN1_VALUE_NOT_VALID;
-+	for (k = 0; k < 10; k++)
-+	  if (!c_isdigit (value[k]))
-+	    return ASN1_VALUE_NOT_VALID;
-+	switch (len)
-+	  {
-+	  case 11:
-+	    if (value[10] != 'Z')
-+	      return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  case 13:
-+	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) ||
-+		(value[12] != 'Z'))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  case 15:
-+	    if ((value[10] != '+') && (value[10] != '-'))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    for (k = 11; k < 15; k++)
-+	      if (!c_isdigit (value[k]))
-+		return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  case 17:
-+	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    if ((value[12] != '+') && (value[12] != '-'))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    for (k = 13; k < 17; k++)
-+	      if (!c_isdigit (value[k]))
-+		return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  default:
-+	    return ASN1_VALUE_NOT_FOUND;
-+	  }
-+	_asn1_set_value (node, value, len);
-+      }
-+      break;
-+    case ASN1_ETYPE_GENERALIZED_TIME:
-+      len = _asn1_strlen (value);
-+      _asn1_set_value (node, value, len);
-+      break;
-+    case ASN1_ETYPE_OCTET_STRING:
-+    case ASN1_ETYPE_GENERALSTRING:
-+    case ASN1_ETYPE_NUMERIC_STRING:
-+    case ASN1_ETYPE_IA5_STRING:
-+    case ASN1_ETYPE_TELETEX_STRING:
-+    case ASN1_ETYPE_PRINTABLE_STRING:
-+    case ASN1_ETYPE_UNIVERSAL_STRING:
-+    case ASN1_ETYPE_BMP_STRING:
-+    case ASN1_ETYPE_UTF8_STRING:
-+    case ASN1_ETYPE_VISIBLE_STRING:
-+      if (len == 0)
-+	len = _asn1_strlen (value);
-+      _asn1_set_value_lv (node, value, len);
-+      break;
-+    case ASN1_ETYPE_BIT_STRING:
-+      if (len == 0)
-+	len = _asn1_strlen (value);
-+      asn1_length_der ((len >> 3) + 2, NULL, &len2);
-+      temp = malloc ((len >> 3) + 2 + len2);
-+      if (temp == NULL)
-+	return ASN1_MEM_ALLOC_ERROR;
-+
-+      asn1_bit_der (value, len, temp, &len2);
-+      _asn1_set_value_m (node, temp, len2);
-+      temp = NULL;
-+      break;
-+    case ASN1_ETYPE_CHOICE:
-+      p = node->down;
-+      while (p)
-+	{
-+	  if (!_asn1_strcmp (p->name, value))
-+	    {
-+	      p2 = node->down;
-+	      while (p2)
-+		{
-+		  if (p2 != p)
-+		    {
-+		      asn1_delete_structure (&p2);
-+		      p2 = node->down;
-+		    }
-+		  else
-+		    p2 = p2->right;
-+		}
-+	      break;
-+	    }
-+	  p = p->right;
-+	}
-+      if (!p)
-+	return ASN1_ELEMENT_NOT_FOUND;
-+      break;
-+    case ASN1_ETYPE_ANY:
-+      _asn1_set_value_lv (node, value, len);
-+      break;
-+    case ASN1_ETYPE_SEQUENCE_OF:
-+    case ASN1_ETYPE_SET_OF:
-+      if (_asn1_strcmp (value, "NEW"))
-+	return ASN1_VALUE_NOT_VALID;
-+      _asn1_append_sequence_set (node, NULL);
-+      break;
-+    default:
-+      return ASN1_ELEMENT_NOT_FOUND;
-+      break;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+#define PUT_VALUE( ptr, ptr_size, data, data_size) \
-+	*len = data_size; \
-+	if (ptr_size < data_size) { \
-+		return ASN1_MEM_ERROR; \
-+	} else { \
-+		if (ptr && data_size > 0) \
-+		  memcpy (ptr, data, data_size); \
-+	}
-+
-+#define PUT_STR_VALUE( ptr, ptr_size, data) \
-+	*len = _asn1_strlen (data) + 1; \
-+	if (ptr_size < *len) { \
-+		return ASN1_MEM_ERROR; \
-+	} else { \
-+		/* this strcpy is checked */ \
-+		if (ptr) { \
-+		  _asn1_strcpy (ptr, data); \
-+		} \
-+	}
-+
-+#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \
-+	*len = data_size + 1; \
-+	if (ptr_size < *len) { \
-+		return ASN1_MEM_ERROR; \
-+	} else { \
-+		/* this strcpy is checked */ \
-+		if (ptr) { \
-+		  if (data_size > 0) \
-+		    memcpy (ptr, data, data_size); \
-+		  ptr[data_size] = 0; \
-+		} \
-+	}
-+
-+#define ADD_STR_VALUE( ptr, ptr_size, data) \
-+        *len += _asn1_strlen(data); \
-+        if (ptr_size < (int) *len) { \
-+                (*len)++; \
-+                return ASN1_MEM_ERROR; \
-+        } else { \
-+                /* this strcat is checked */ \
-+                if (ptr) _asn1_strcat (ptr, data); \
-+        }
-+
-+/**
-+ * asn1_read_value:
-+ * @root: pointer to a structure.
-+ * @name: the name of the element inside a structure that you want to read.
-+ * @ivalue: vector that will contain the element's content, must be a
-+ *   pointer to memory cells already allocated (may be %NULL).
-+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
-+ *   holds the sizeof value.
-+ *
-+ * Returns the value of one element inside a structure.
-+ * If an element is OPTIONAL and this returns
-+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
-+ * in the der encoding that created the structure.  The first element
-+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
-+ * so on. If the @root provided is a node to specific sequence element,
-+ * then the keyword "?CURRENT" is also acceptable and indicates the
-+ * current sequence element of this node.
-+ *
-+ * Note that there can be valid values with length zero. In these case
-+ * this function will succeed and @len will be zero.
-+ *
-+ * INTEGER: VALUE will contain a two's complement form integer.
-+ *
-+ *            integer=-1  -> value[0]=0xFF , len=1.
-+ *            integer=1   -> value[0]=0x01 , len=1.
-+ *
-+ * ENUMERATED: As INTEGER (but only with not negative numbers).
-+ *
-+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
-+ *   "FALSE" and LEN=5 or LEN=6.
-+ *
-+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
-+ *   each number separated by a dot (i.e. "1.2.3.543.1").
-+ *
-+ *                      LEN = strlen(VALUE)+1
-+ *
-+ * UTCTime: VALUE will be a null terminated string in one of these
-+ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
-+ *   LEN=strlen(VALUE)+1.
-+ *
-+ * GeneralizedTime: VALUE will be a null terminated string in the
-+ *   same format used to set the value.
-+ *
-+ * OCTET STRING: VALUE will contain the octet string and LEN will be
-+ *   the number of octets.
-+ *
-+ * GeneralString: VALUE will contain the generalstring and LEN will
-+ *   be the number of octets.
-+ *
-+ * BIT STRING: VALUE will contain the bit string organized by bytes
-+ *   and LEN will be the number of bits.
-+ *
-+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
-+ *   alternative selected.
-+ *
-+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
-+ *   encoding of the structure actually used.
-+ *
-+ * Returns: %ASN1_SUCCESS if value is returned,
-+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
-+ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
-+ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
-+ *   to store the result, and in this case @len will contain the number of
-+ *   bytes needed. On the occasion that the stored data are of zero-length
-+ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
-+ **/
-+int
-+asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len)
-+{
-+  return asn1_read_value_type (root, name, ivalue, len, NULL);
-+}
-+
-+/**
-+ * asn1_read_value_type:
-+ * @root: pointer to a structure.
-+ * @name: the name of the element inside a structure that you want to read.
-+ * @ivalue: vector that will contain the element's content, must be a
-+ *   pointer to memory cells already allocated (may be %NULL).
-+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
-+ *   holds the sizeof value.
-+ * @etype: The type of the value read (ASN1_ETYPE)
-+ *
-+ * Returns the type and value of one element inside a structure.
-+ * If an element is OPTIONAL and this returns
-+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
-+ * in the der encoding that created the structure.  The first element
-+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
-+ * so on. If the @root provided is a node to specific sequence element,
-+ * then the keyword "?CURRENT" is also acceptable and indicates the
-+ * current sequence element of this node.
-+ *
-+ * Note that there can be valid values with length zero. In these case
-+ * this function will succeed and @len will be zero.
-+ *
-+ *
-+ * INTEGER: VALUE will contain a two's complement form integer.
-+ *
-+ *            integer=-1  -> value[0]=0xFF , len=1.
-+ *            integer=1   -> value[0]=0x01 , len=1.
-+ *
-+ * ENUMERATED: As INTEGER (but only with not negative numbers).
-+ *
-+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
-+ *   "FALSE" and LEN=5 or LEN=6.
-+ *
-+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
-+ *   each number separated by a dot (i.e. "1.2.3.543.1").
-+ *
-+ *                      LEN = strlen(VALUE)+1
-+ *
-+ * UTCTime: VALUE will be a null terminated string in one of these
-+ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
-+ *   LEN=strlen(VALUE)+1.
-+ *
-+ * GeneralizedTime: VALUE will be a null terminated string in the
-+ *   same format used to set the value.
-+ *
-+ * OCTET STRING: VALUE will contain the octet string and LEN will be
-+ *   the number of octets.
-+ *
-+ * GeneralString: VALUE will contain the generalstring and LEN will
-+ *   be the number of octets.
-+ *
-+ * BIT STRING: VALUE will contain the bit string organized by bytes
-+ *   and LEN will be the number of bits.
-+ *
-+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
-+ *   alternative selected.
-+ *
-+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
-+ *   encoding of the structure actually used.
-+ *
-+ * Returns: %ASN1_SUCCESS if value is returned,
-+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
-+ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
-+ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
-+ *   to store the result, and in this case @len will contain the number of
-+ *   bytes needed. On the occasion that the stored data are of zero-length
-+ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
-+ **/
-+int
-+asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue,
-+		      int *len, unsigned int *etype)
-+{
-+  asn1_node_const node, p, p2;
-+  int len2, len3, result;
-+  int value_size = *len;
-+  unsigned char *value = ivalue;
-+  unsigned type;
-+
-+  node = asn1_find_node (root, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  type = type_field (node->type);
-+
-+  if ((type != ASN1_ETYPE_NULL) &&
-+      (type != ASN1_ETYPE_CHOICE) &&
-+      !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) &&
-+      (node->value == NULL))
-+    return ASN1_VALUE_NOT_FOUND;
-+
-+  if (etype)
-+    *etype = type;
-+  switch (type)
-+    {
-+    case ASN1_ETYPE_NULL:
-+      PUT_STR_VALUE (value, value_size, "NULL");
-+      break;
-+    case ASN1_ETYPE_BOOLEAN:
-+      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if (p->type & CONST_TRUE)
-+	    {
-+	      PUT_STR_VALUE (value, value_size, "TRUE");
-+	    }
-+	  else
-+	    {
-+	      PUT_STR_VALUE (value, value_size, "FALSE");
-+	    }
-+	}
-+      else if (node->value[0] == 'T')
-+	{
-+	  PUT_STR_VALUE (value, value_size, "TRUE");
-+	}
-+      else
-+	{
-+	  PUT_STR_VALUE (value, value_size, "FALSE");
-+	}
-+      break;
-+    case ASN1_ETYPE_INTEGER:
-+    case ASN1_ETYPE_ENUMERATED:
-+      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-')
-+	      || (p->value[0] == '+'))
-+	    {
-+	      result = _asn1_convert_integer
-+		  (p->value, value, value_size, len);
-+              if (result != ASN1_SUCCESS)
-+		return result;
-+	    }
-+	  else
-+	    {			/* is an identifier like v1 */
-+	      p2 = node->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
-+		    {
-+		      if (!_asn1_strcmp (p2->name, p->value))
-+			{
-+			  result = _asn1_convert_integer
-+			      (p2->value, value, value_size,
-+			       len);
-+			  if (result != ASN1_SUCCESS)
-+			    return result;
-+			  break;
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	    }
-+	}
-+      else
-+	{
-+	  len2 = -1;
-+	  result = asn1_get_octet_der
-+	      (node->value, node->value_len, &len2, value, value_size,
-+	       len);
-+          if (result != ASN1_SUCCESS)
-+	    return result;
-+	}
-+      break;
-+    case ASN1_ETYPE_OBJECT_ID:
-+      if (node->type & CONST_ASSIGN)
-+	{
-+	  *len = 0;
-+	  if (value)
-+	    value[0] = 0;
-+	  p = node->down;
-+	  while (p)
-+	    {
-+	      if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
-+		{
-+		  ADD_STR_VALUE (value, value_size, p->value);
-+		  if (p->right)
-+		    {
-+		      ADD_STR_VALUE (value, value_size, ".");
-+		    }
-+		}
-+	      p = p->right;
-+	    }
-+	  (*len)++;
-+	}
-+      else if ((node->type & CONST_DEFAULT) && (node->value == NULL))
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  PUT_STR_VALUE (value, value_size, p->value);
-+	}
-+      else
-+	{
-+	  PUT_STR_VALUE (value, value_size, node->value);
-+	}
-+      break;
-+    case ASN1_ETYPE_GENERALIZED_TIME:
-+    case ASN1_ETYPE_UTC_TIME:
-+      PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len);
-+      break;
-+    case ASN1_ETYPE_OCTET_STRING:
-+    case ASN1_ETYPE_GENERALSTRING:
-+    case ASN1_ETYPE_NUMERIC_STRING:
-+    case ASN1_ETYPE_IA5_STRING:
-+    case ASN1_ETYPE_TELETEX_STRING:
-+    case ASN1_ETYPE_PRINTABLE_STRING:
-+    case ASN1_ETYPE_UNIVERSAL_STRING:
-+    case ASN1_ETYPE_BMP_STRING:
-+    case ASN1_ETYPE_UTF8_STRING:
-+    case ASN1_ETYPE_VISIBLE_STRING:
-+      len2 = -1;
-+      result = asn1_get_octet_der
-+	  (node->value, node->value_len, &len2, value, value_size,
-+	   len);
-+      if (result != ASN1_SUCCESS)
-+	return result;
-+      break;
-+    case ASN1_ETYPE_BIT_STRING:
-+      len2 = -1;
-+      result = asn1_get_bit_der
-+	  (node->value, node->value_len, &len2, value, value_size,
-+	   len);
-+      if (result != ASN1_SUCCESS)
-+	return result;
-+      break;
-+    case ASN1_ETYPE_CHOICE:
-+      PUT_STR_VALUE (value, value_size, node->down->name);
-+      break;
-+    case ASN1_ETYPE_ANY:
-+      len3 = -1;
-+      len2 = asn1_get_length_der (node->value, node->value_len, &len3);
-+      if (len2 < 0)
-+	return ASN1_DER_ERROR;
-+      PUT_VALUE (value, value_size, node->value + len3, len2);
-+      break;
-+    default:
-+      return ASN1_ELEMENT_NOT_FOUND;
-+      break;
-+    }
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_read_tag:
-+ * @root: pointer to a structure
-+ * @name: the name of the element inside a structure.
-+ * @tagValue:  variable that will contain the TAG value.
-+ * @classValue: variable that will specify the TAG type.
-+ *
-+ * Returns the TAG and the CLASS of one element inside a structure.
-+ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION,
-+ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or
-+ * %ASN1_CLASS_CONTEXT_SPECIFIC.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   @name is not a valid element.
-+ **/
-+int
-+asn1_read_tag (asn1_node_const root, const char *name, int *tagValue,
-+	       int *classValue)
-+{
-+  asn1_node node, p, pTag;
-+
-+  node = asn1_find_node (root, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node->down;
-+
-+  /* pTag will points to the IMPLICIT TAG */
-+  pTag = NULL;
-+  if (node->type & CONST_TAG)
-+    {
-+      while (p)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if ((p->type & CONST_IMPLICIT) && (pTag == NULL))
-+		pTag = p;
-+	      else if (p->type & CONST_EXPLICIT)
-+		pTag = NULL;
-+	    }
-+	  p = p->right;
-+	}
-+    }
-+
-+  if (pTag)
-+    {
-+      *tagValue = _asn1_strtoul (pTag->value, NULL, 10);
-+
-+      if (pTag->type & CONST_APPLICATION)
-+	*classValue = ASN1_CLASS_APPLICATION;
-+      else if (pTag->type & CONST_UNIVERSAL)
-+	*classValue = ASN1_CLASS_UNIVERSAL;
-+      else if (pTag->type & CONST_PRIVATE)
-+	*classValue = ASN1_CLASS_PRIVATE;
-+      else
-+	*classValue = ASN1_CLASS_CONTEXT_SPECIFIC;
-+    }
-+  else
-+    {
-+      unsigned type = type_field (node->type);
-+      *classValue = ASN1_CLASS_UNIVERSAL;
-+
-+      switch (type)
-+	{
-+	CASE_HANDLED_ETYPES:
-+	  *tagValue = _asn1_tags[type].tag;
-+	  break;
-+	case ASN1_ETYPE_TAG:
-+	case ASN1_ETYPE_CHOICE:
-+	case ASN1_ETYPE_ANY:
-+	  *tagValue = -1;
-+	  break;
-+	default:
-+	  break;
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_read_node_value:
-+ * @node: pointer to a node.
-+ * @data: a point to a asn1_data_node_st
-+ *
-+ * Returns the value a data node inside a asn1_node structure.
-+ * The data returned should be handled as constant values.
-+ *
-+ * Returns: %ASN1_SUCCESS if the node exists.
-+ **/
-+int
-+asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data)
-+{
-+  data->name = node->name;
-+  data->value = node->value;
-+  data->value_len = node->value_len;
-+  data->type = type_field (node->type);
-+
-+  return ASN1_SUCCESS;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
-new file mode 100644
-index 00000000000..cee74daf795
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/errors.c
-@@ -0,0 +1,100 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#include <int.h>
-+#ifdef STDC_HEADERS
-+#include <stdarg.h>
-+#endif
-+
-+#define LIBTASN1_ERROR_ENTRY(name) { #name, name }
-+
-+struct libtasn1_error_entry
-+{
-+  const char *name;
-+  int number;
-+};
-+typedef struct libtasn1_error_entry libtasn1_error_entry;
-+
-+static const libtasn1_error_entry error_algorithms[] = {
-+  LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS),
-+  LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID),
-+  LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY),
-+  LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW),
-+  LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY),
-+  LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_RECURSION),
-+  {0, 0}
-+};
-+
-+/**
-+ * asn1_perror:
-+ * @error: is an error returned by a libtasn1 function.
-+ *
-+ * Prints a string to stderr with a description of an error.  This
-+ * function is like perror().  The only difference is that it accepts
-+ * an error returned by a libtasn1 function.
-+ *
-+ * Since: 1.6
-+ **/
-+void
-+asn1_perror (int error)
-+{
-+  const char *str = asn1_strerror (error);
-+  fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
-+}
-+
-+/**
-+ * asn1_strerror:
-+ * @error: is an error returned by a libtasn1 function.
-+ *
-+ * Returns a string with a description of an error.  This function is
-+ * similar to strerror.  The only difference is that it accepts an
-+ * error (number) returned by a libtasn1 function.
-+ *
-+ * Returns: Pointer to static zero-terminated string describing error
-+ *   code.
-+ *
-+ * Since: 1.6
-+ **/
-+const char *
-+asn1_strerror (int error)
-+{
-+  const libtasn1_error_entry *p;
-+
-+  for (p = error_algorithms; p->name != NULL; p++)
-+    if (p->number == error)
-+      return p->name + sizeof ("ASN1_") - 1;
-+
-+  return NULL;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
-new file mode 100644
-index 00000000000..e91a3a151c0
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/gstr.c
-@@ -0,0 +1,74 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#include <int.h>
-+#include "gstr.h"
-+
-+/* These function are like strcat, strcpy. They only
-+ * do bounds checking (they shouldn't cause buffer overruns),
-+ * and they always produce null terminated strings.
-+ *
-+ * They should be used only with null terminated strings.
-+ */
-+void
-+_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
-+{
-+  size_t str_size = strlen (src);
-+  size_t dest_size = strlen (dest);
-+
-+  if (dest_tot_size - dest_size > str_size)
-+    {
-+      strcat (dest, src);
-+    }
-+  else
-+    {
-+      if (dest_tot_size - dest_size > 0)
-+	{
-+	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
-+	  dest[dest_tot_size - 1] = 0;
-+	}
-+    }
-+}
-+
-+/* Returns the bytes copied (not including the null terminator) */
-+unsigned int
-+_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src)
-+{
-+  size_t str_size = strlen (src);
-+
-+  if (dest_tot_size > str_size)
-+    {
-+      strcpy (dest, src);
-+      return str_size;
-+    }
-+  else
-+    {
-+      if (dest_tot_size > 0)
-+	{
-+	  str_size = dest_tot_size - 1;
-+	  memcpy (dest, src, str_size);
-+	  dest[str_size] = 0;
-+	  return str_size;
-+	}
-+      else
-+	return 0;
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
-new file mode 100644
-index 00000000000..d5dbbf8765d
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/parser_aux.c
-@@ -0,0 +1,1173 @@
-+/*
-+ * Copyright (C) 2000-2016 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#include <limits.h> // WORD_BIT
-+
-+#include "int.h"
-+#include "parser_aux.h"
-+#include "gstr.h"
-+#include "structure.h"
-+#include "element.h"
-+#include "c-ctype.h"
-+
-+char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
-+
-+/* Return a hash of the N bytes of X using the method described by
-+   Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
-+   Note that while many hash functions reduce their result via modulo
-+   to a 0..table_size-1 range, this function does not do that.
-+
-+   This implementation has been changed from size_t -> unsigned int. */
-+
-+#ifdef __clang__
-+__attribute__((no_sanitize("integer")))
-+#endif
-+_GL_ATTRIBUTE_PURE
-+static unsigned int
-+_asn1_hash_name (const char *x)
-+{
-+  const unsigned char *s = (unsigned char *) x;
-+  unsigned h = 0;
-+
-+  while (*s)
-+    h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9)));
-+
-+  return h;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_add_static_node                   */
-+/* Description: creates a new NODE_ASN element and    */
-+/* puts it in the list pointed by e_list.       */
-+/* Parameters:                                        */
-+/*   e_list: of type list_type; must be NULL initially */
-+/*   type: type of the new element (see ASN1_ETYPE_   */
-+/*         and CONST_ constants).                     */
-+/* Return: pointer to the new element.                */
-+/******************************************************/
-+asn1_node
-+_asn1_add_static_node (list_type **e_list, unsigned int type)
-+{
-+  list_type *p;
-+  asn1_node punt;
-+
-+  punt = calloc (1, sizeof (struct asn1_node_st));
-+  if (punt == NULL)
-+    return NULL;
-+
-+  p = malloc (sizeof (list_type));
-+  if (p == NULL)
-+    {
-+      free (punt);
-+      return NULL;
-+    }
-+
-+  p->node = punt;
-+  p->next = *e_list;
-+  *e_list = p;
-+
-+  punt->type = type;
-+
-+  return punt;
-+}
-+
-+static
-+int _asn1_add_static_node2 (list_type **e_list, asn1_node node)
-+{
-+  list_type *p;
-+
-+  p = malloc (sizeof (list_type));
-+  if (p == NULL)
-+    {
-+      return -1;
-+    }
-+
-+  p->node = node;
-+  p->next = *e_list;
-+  *e_list = p;
-+
-+  return 0;
-+}
-+
-+/**
-+ * asn1_find_node:
-+ * @pointer: NODE_ASN element pointer.
-+ * @name: null terminated string with the element's name to find.
-+ *
-+ * Searches for an element called @name starting from @pointer.  The
-+ * name is composed by different identifiers separated by dots.  When
-+ * *@pointer has a name, the first identifier must be the name of
-+ * *@pointer, otherwise it must be the name of one child of *@pointer.
-+ *
-+ * Returns: the search result, or %NULL if not found.
-+ **/
-+asn1_node
-+asn1_find_node (asn1_node_const pointer, const char *name)
-+{
-+  asn1_node_const p;
-+  char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
-+  const char *n_start;
-+  unsigned int nsize;
-+  unsigned int nhash;
-+
-+  if (pointer == NULL)
-+    return NULL;
-+
-+  if (name == NULL)
-+    return NULL;
-+
-+  p = pointer;
-+  n_start = name;
-+
-+  if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?')
-+    { /* ?CURRENT */
-+      n_start = strchr(n_start, '.');
-+      if (n_start)
-+        n_start++;
-+    }
-+  else if (p->name[0] != 0)
-+    {				/* has *pointer got a name ? */
-+      n_end = strchr (n_start, '.');	/* search the first dot */
-+      if (n_end)
-+	{
-+	  nsize = n_end - n_start;
-+	  if (nsize >= sizeof(n))
-+		return NULL;
-+
-+	  memcpy (n, n_start, nsize);
-+	  n[nsize] = 0;
-+	  n_start = n_end;
-+	  n_start++;
-+
-+	  nhash = _asn1_hash_name (n);
-+	}
-+      else
-+	{
-+	  _asn1_str_cpy (n, sizeof (n), n_start);
-+	  nhash = _asn1_hash_name (n);
-+
-+	  n_start = NULL;
-+	}
-+
-+      while (p)
-+	{
-+	  if (nhash == p->name_hash && (!strcmp (p->name, n)))
-+	    break;
-+	  else
-+	    p = p->right;
-+	}			/* while */
-+
-+      if (p == NULL)
-+	return NULL;
-+    }
-+  else
-+    {				/* *pointer doesn't have a name */
-+      if (n_start[0] == 0)
-+	return (asn1_node) p;
-+    }
-+
-+  while (n_start)
-+    {				/* Has the end of NAME been reached? */
-+      n_end = strchr (n_start, '.');	/* search the next dot */
-+      if (n_end)
-+	{
-+	  nsize = n_end - n_start;
-+	  if (nsize >= sizeof(n))
-+		return NULL;
-+
-+	  memcpy (n, n_start, nsize);
-+	  n[nsize] = 0;
-+	  n_start = n_end;
-+	  n_start++;
-+
-+	  nhash = _asn1_hash_name (n);
-+	}
-+      else
-+	{
-+	  _asn1_str_cpy (n, sizeof (n), n_start);
-+	  nhash = _asn1_hash_name (n);
-+	  n_start = NULL;
-+	}
-+
-+      if (p->down == NULL)
-+	return NULL;
-+
-+      p = p->down;
-+      if (p == NULL)
-+        return NULL;
-+
-+      /* The identifier "?LAST" indicates the last element
-+         in the right chain. */
-+      if (n[0] == '?' && n[1] == 'L') /* ?LAST */
-+	{
-+	  while (p->right)
-+	    p = p->right;
-+	}
-+      else
-+	{			/* no "?LAST" */
-+	  while (p)
-+	    {
-+	      if (p->name_hash == nhash && !strcmp (p->name, n))
-+		break;
-+	      else
-+		p = p->right;
-+	    }
-+	}
-+      if (p == NULL)
-+        return NULL;
-+    }				/* while */
-+
-+  return (asn1_node) p;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_set_value                                     */
-+/* Description: sets the field VALUE in a NODE_ASN element. The   */
-+/*              previous value (if exist) will be lost            */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   value: pointer to the value that you want to set.            */
-+/*   len: character number of value.                              */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_value (asn1_node node, const void *value, unsigned int len)
-+{
-+  if (node == NULL)
-+    return node;
-+  if (node->value)
-+    {
-+      if (node->value != node->small_value)
-+	free (node->value);
-+      node->value = NULL;
-+      node->value_len = 0;
-+    }
-+
-+  if (!len)
-+    return node;
-+
-+  if (len < sizeof (node->small_value))
-+    {
-+      node->value = node->small_value;
-+    }
-+  else
-+    {
-+      node->value = malloc (len);
-+      if (node->value == NULL)
-+	return NULL;
-+    }
-+  node->value_len = len;
-+
-+  memcpy (node->value, value, len);
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_value_lv                                  */
-+/* Description: sets the field VALUE in a NODE_ASN element. The   */
-+/*              previous value (if exist) will be lost. The value */
-+/*		given is stored as an length-value format (LV     */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   value: pointer to the value that you want to set.            */
-+/*   len: character number of value.                              */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
-+{
-+  int len2;
-+  void *temp;
-+
-+  if (node == NULL)
-+    return node;
-+
-+  asn1_length_der (len, NULL, &len2);
-+  temp = malloc (len + len2);
-+  if (temp == NULL)
-+    return NULL;
-+
-+  asn1_octet_der (value, len, temp, &len2);
-+  return _asn1_set_value_m (node, temp, len2);
-+}
-+
-+/* the same as _asn1_set_value except that it sets an already malloc'ed
-+ * value.
-+ */
-+asn1_node
-+_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
-+{
-+  if (node == NULL)
-+    return node;
-+
-+  if (node->value)
-+    {
-+      if (node->value != node->small_value)
-+	free (node->value);
-+      node->value = NULL;
-+      node->value_len = 0;
-+    }
-+
-+  if (!len)
-+    return node;
-+
-+  node->value = value;
-+  node->value_len = len;
-+
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_append_value                                  */
-+/* Description: appends to the field VALUE in a NODE_ASN element. */
-+/*							          */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   value: pointer to the value that you want to be appended.    */
-+/*   len: character number of value.                              */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_append_value (asn1_node node, const void *value, unsigned int len)
-+{
-+  if (node == NULL)
-+    return node;
-+
-+  if (node->value == NULL)
-+    return _asn1_set_value (node, value, len);
-+
-+  if (len == 0)
-+    return node;
-+
-+  if (node->value == node->small_value)
-+    {
-+      /* value is in node */
-+      int prev_len = node->value_len;
-+      node->value_len += len;
-+      node->value = malloc (node->value_len);
-+      if (node->value == NULL)
-+	{
-+	  node->value_len = 0;
-+	  return NULL;
-+	}
-+
-+      if (prev_len > 0)
-+        memcpy (node->value, node->small_value, prev_len);
-+
-+      memcpy (&node->value[prev_len], value, len);
-+
-+      return node;
-+    }
-+  else /* if (node->value != NULL && node->value != node->small_value) */
-+    {
-+      /* value is allocated */
-+      int prev_len = node->value_len;
-+      node->value_len += len;
-+
-+      node->value = _asn1_realloc (node->value, node->value_len);
-+      if (node->value == NULL)
-+	{
-+	  node->value_len = 0;
-+	  return NULL;
-+	}
-+
-+      memcpy (&node->value[prev_len], value, len);
-+
-+      return node;
-+    }
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_name                                      */
-+/* Description: sets the field NAME in a NODE_ASN element. The    */
-+/*              previous value (if exist) will be lost            */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   name: a null terminated string with the name that you want   */
-+/*         to set.                                                */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_name (asn1_node node, const char *name)
-+{
-+  if (node == NULL)
-+    return node;
-+
-+  _asn1_str_cpy (node->name, sizeof (node->name), name ? name : "");
-+  node->name_hash = _asn1_hash_name (node->name);
-+
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_cpy_name                                      */
-+/* Description: copies the field NAME in a NODE_ASN element.      */
-+/* Parameters:                                                    */
-+/*   dst: a dest element pointer.                                 */
-+/*   src: a source element pointer.                               */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_cpy_name (asn1_node dst, asn1_node_const src)
-+{
-+  if (dst == NULL)
-+    return dst;
-+
-+  if (src == NULL)
-+    {
-+      dst->name[0] = 0;
-+      dst->name_hash = _asn1_hash_name (dst->name);
-+      return dst;
-+    }
-+
-+  _asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
-+  dst->name_hash = src->name_hash;
-+
-+  return dst;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_right                                     */
-+/* Description: sets the field RIGHT in a NODE_ASN element.       */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   right: pointer to a NODE_ASN element that you want be pointed*/
-+/*          by NODE.                                              */
-+/* Return: pointer to *NODE.                                      */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_right (asn1_node node, asn1_node right)
-+{
-+  if (node == NULL)
-+    return node;
-+  node->right = right;
-+  if (right)
-+    right->left = node;
-+  return node;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_get_last_right                                */
-+/* Description: return the last element along the right chain.    */
-+/* Parameters:                                                    */
-+/*   node: starting element pointer.                              */
-+/* Return: pointer to the last element along the right chain.     */
-+/******************************************************************/
-+asn1_node
-+_asn1_get_last_right (asn1_node_const node)
-+{
-+  asn1_node_const p;
-+
-+  if (node == NULL)
-+    return NULL;
-+  p = node;
-+  while (p->right)
-+    p = p->right;
-+  return (asn1_node) p;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_remove_node                                   */
-+/* Description: gets free the memory allocated for an NODE_ASN    */
-+/*              element (not the elements pointed by it).         */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/*   flags: ASN1_DELETE_FLAG_*                                    */
-+/******************************************************************/
-+void
-+_asn1_remove_node (asn1_node node, unsigned int flags)
-+{
-+  if (node == NULL)
-+    return;
-+
-+  if (node->value != NULL)
-+    {
-+      if (flags & ASN1_DELETE_FLAG_ZEROIZE)
-+        {
-+          safe_memset(node->value, 0, node->value_len);
-+        }
-+
-+      if (node->value != node->small_value)
-+        free (node->value);
-+    }
-+  free (node);
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_find_up                                       */
-+/* Description: return the father of the NODE_ASN element.        */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: Null if not found.                                     */
-+/******************************************************************/
-+asn1_node
-+_asn1_find_up (asn1_node_const node)
-+{
-+  asn1_node_const p;
-+
-+  if (node == NULL)
-+    return NULL;
-+
-+  p = node;
-+
-+  while ((p->left != NULL) && (p->left->right == p))
-+    p = p->left;
-+
-+  return p->left;
-+}
-+
-+static
-+unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down)
-+{
-+  asn1_node_const d, u;
-+
-+  if (up_cand == NULL || down == NULL)
-+    return 0;
-+
-+  d = down;
-+
-+  while ((u = _asn1_find_up(d)) != NULL && u != d)
-+    {
-+      if (u == up_cand)
-+        return 1;
-+      d = u;
-+    }
-+
-+  return 0;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_delete_node_from_list                         */
-+/* Description: deletes the list element given                    */
-+/******************************************************************/
-+void
-+_asn1_delete_node_from_list (list_type *list, asn1_node node)
-+{
-+  list_type *p = list;
-+
-+  while (p)
-+    {
-+      if (p->node == node)
-+        p->node = NULL;
-+      p = p->next;
-+    }
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_delete_list                                   */
-+/* Description: deletes the list elements (not the elements       */
-+/*  pointed by them).                                             */
-+/******************************************************************/
-+void
-+_asn1_delete_list (list_type *e_list)
-+{
-+  list_type *p;
-+
-+  while (e_list)
-+    {
-+      p = e_list;
-+      e_list = e_list->next;
-+      free (p);
-+    }
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_delete_list_and nodes                         */
-+/* Description: deletes the list elements and the elements        */
-+/*  pointed by them.                                              */
-+/******************************************************************/
-+void
-+_asn1_delete_list_and_nodes (list_type *e_list)
-+{
-+  list_type *p;
-+
-+  while (e_list)
-+    {
-+      p = e_list;
-+      e_list = e_list->next;
-+      _asn1_remove_node (p->node, 0);
-+      free (p);
-+    }
-+}
-+
-+
-+char *
-+_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
-+{
-+  uint64_t d, r;
-+  char temp[LTOSTR_MAX_SIZE];
-+  int count, k, start;
-+  uint64_t val;
-+
-+  if (v < 0)
-+    {
-+      str[0] = '-';
-+      start = 1;
-+      val = -((uint64_t)v);
-+    }
-+  else
-+    {
-+      val = v;
-+      start = 0;
-+    }
-+
-+  count = 0;
-+  do
-+    {
-+      d = val / 10;
-+      r = val - d * 10;
-+      temp[start + count] = '0' + (char) r;
-+      count++;
-+      val = d;
-+    }
-+  while (val && ((start+count) < LTOSTR_MAX_SIZE-1));
-+
-+  for (k = 0; k < count; k++)
-+    str[k + start] = temp[start + count - k - 1];
-+  str[count + start] = 0;
-+  return str;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_change_integer_value                          */
-+/* Description: converts into DER coding the value assign to an   */
-+/*   INTEGER constant.                                            */
-+/* Parameters:                                                    */
-+/*   node: root of an ASN1element.                                */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
-+/*   otherwise ASN1_SUCCESS                                             */
-+/******************************************************************/
-+int
-+_asn1_change_integer_value (asn1_node node)
-+{
-+  asn1_node p;
-+  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
-+  unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
-+  int len;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if ((type_field (p->type) == ASN1_ETYPE_INTEGER)
-+	  && (p->type & CONST_ASSIGN))
-+	{
-+	  if (p->value)
-+	    {
-+	      _asn1_convert_integer (p->value, val, sizeof (val), &len);
-+	      asn1_octet_der (val, len, val2, &len);
-+	      _asn1_set_value (p, val2, len);
-+	    }
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else
-+	{
-+	  if (p == node)
-+	    p = NULL;
-+	  else if (p->right)
-+	    p = p->right;
-+	  else
-+	    {
-+	      while (1)
-+		{
-+		  p = _asn1_find_up (p);
-+		  if (p == node)
-+		    {
-+		      p = NULL;
-+		      break;
-+		    }
-+		  if (p && p->right)
-+		    {
-+		      p = p->right;
-+		      break;
-+		    }
-+		}
-+	    }
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+#define MAX_CONSTANTS 1024
-+/******************************************************************/
-+/* Function : _asn1_expand_object_id                              */
-+/* Description: expand the IDs of an OBJECT IDENTIFIER constant.  */
-+/* Parameters:                                                    */
-+/*   list: root of an object list                                 */
-+/*   node: root of an ASN1 element.                               */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                      */
-+/*   otherwise ASN1_SUCCESS                                       */
-+/******************************************************************/
-+int
-+_asn1_expand_object_id (list_type **list, asn1_node node)
-+{
-+  asn1_node p, p2, p3, p4, p5;
-+  char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
-+  int move, tlen, tries;
-+  unsigned max_constants;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  _asn1_str_cpy (name_root, sizeof (name_root), node->name);
-+
-+  p = node;
-+  move = DOWN;
-+  tries = 0;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
-+	      && (p->type & CONST_ASSIGN))
-+	    {
-+	      p2 = p->down;
-+	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
-+		{
-+		  if (p2->value && !c_isdigit (p2->value[0]))
-+		    {
-+		      _asn1_str_cpy (name2, sizeof (name2), name_root);
-+		      _asn1_str_cat (name2, sizeof (name2), ".");
-+		      _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+		      p3 = asn1_find_node (node, name2);
-+		      if (!p3 || _asn1_is_up(p2, p3) ||
-+			  (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
-+			  !(p3->type & CONST_ASSIGN))
-+			return ASN1_ELEMENT_NOT_FOUND;
-+
-+		      _asn1_set_down (p, p2->right);
-+		      if (p2->down)
-+			_asn1_delete_structure (*list, &p2->down, 0);
-+		      _asn1_delete_node_from_list(*list, p2);
-+		      _asn1_remove_node (p2, 0);
-+		      p2 = p;
-+		      p4 = p3->down;
-+		      max_constants = 0;
-+		      while (p4)
-+			{
-+			  if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
-+			    {
-+			      max_constants++;
-+			      if (max_constants == MAX_CONSTANTS)
-+                                return ASN1_RECURSION;
-+
-+			      p5 =
-+				_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
-+			      _asn1_set_name (p5, p4->name);
-+			      if (p4->value)
-+			        {
-+			          tlen = _asn1_strlen (p4->value);
-+			          if (tlen > 0)
-+			            _asn1_set_value (p5, p4->value, tlen + 1);
-+			        }
-+			      _asn1_add_static_node2(list, p5);
-+
-+			      if (p2 == p)
-+				{
-+				  _asn1_set_right (p5, p->down);
-+				  _asn1_set_down (p, p5);
-+				}
-+			      else
-+				{
-+				  _asn1_set_right (p5, p2->right);
-+				  _asn1_set_right (p2, p5);
-+				}
-+			      p2 = p5;
-+			    }
-+			  p4 = p4->right;
-+			}
-+		      move = DOWN;
-+
-+		      tries++;
-+                      if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
-+                        return ASN1_RECURSION;
-+
-+		      continue;
-+		    }
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      tries = 0;
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p && p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  /*******************************/
-+  /*       expand DEFAULT        */
-+  /*******************************/
-+  p = node;
-+  move = DOWN;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	      (p->type & CONST_DEFAULT))
-+	    {
-+	      p2 = p->down;
-+	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
-+		{
-+		  _asn1_str_cpy (name2, sizeof (name2), name_root);
-+		  _asn1_str_cat (name2, sizeof (name2), ".");
-+		  if (p2->value)
-+		    _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+		  p3 = asn1_find_node (node, name2);
-+		  if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
-+		      || !(p3->type & CONST_ASSIGN))
-+		    return ASN1_ELEMENT_NOT_FOUND;
-+		  p4 = p3->down;
-+		  name2[0] = 0;
-+		  while (p4)
-+		    {
-+		      if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
-+			{
-+			  if (p4->value == NULL)
-+			    return ASN1_VALUE_NOT_FOUND;
-+
-+			  if (name2[0])
-+			    _asn1_str_cat (name2, sizeof (name2), ".");
-+			  _asn1_str_cat (name2, sizeof (name2),
-+					 (char *) p4->value);
-+			}
-+		      p4 = p4->right;
-+		    }
-+		  tlen = strlen (name2);
-+		  if (tlen > 0)
-+		    _asn1_set_value (p2, name2, tlen + 1);
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p && p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_type_set_config                               */
-+/* Description: sets the CONST_SET and CONST_NOT_USED properties  */
-+/*   in the fields of the SET elements.                           */
-+/* Parameters:                                                    */
-+/*   node: root of an ASN1 element.                               */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
-+/*   otherwise ASN1_SUCCESS                                             */
-+/******************************************************************/
-+int
-+_asn1_type_set_config (asn1_node node)
-+{
-+  asn1_node p, p2;
-+  int move;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  move = DOWN;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_SET)
-+	    {
-+	      p2 = p->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
-+		    p2->type |= CONST_SET | CONST_NOT_USED;
-+		  p2 = p2->right;
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p && p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_check_identifier                              */
-+/* Description: checks the definitions of all the identifiers     */
-+/*   and the first element of an OBJECT_ID (e.g. {pkix 0 4}).     */
-+/*   The _asn1_identifierMissing global variable is filled if     */
-+/*   necessary.                                                   */
-+/* Parameters:                                                    */
-+/*   node: root of an ASN1 element.                               */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND      if NODE is NULL,                 */
-+/*   ASN1_IDENTIFIER_NOT_FOUND   if an identifier is not defined, */
-+/*   otherwise ASN1_SUCCESS                                       */
-+/******************************************************************/
-+int
-+_asn1_check_identifier (asn1_node_const node)
-+{
-+  asn1_node_const p, p2;
-+  char name2[ASN1_MAX_NAME_SIZE * 2 + 2];
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
-+	{
-+	  _asn1_str_cpy (name2, sizeof (name2), node->name);
-+	  _asn1_str_cat (name2, sizeof (name2), ".");
-+	  _asn1_str_cat (name2, sizeof (name2), (char *) p->value);
-+	  p2 = asn1_find_node (node, name2);
-+	  if (p2 == NULL)
-+	    {
-+	      if (p->value)
-+		_asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value);
-+	      else
-+		_asn1_strcpy (_asn1_identifierMissing, "(null)");
-+	      return ASN1_IDENTIFIER_NOT_FOUND;
-+	    }
-+	}
-+      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	       (p->type & CONST_DEFAULT))
-+	{
-+	  p2 = p->down;
-+	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
-+	    {
-+	      _asn1_str_cpy (name2, sizeof (name2), node->name);
-+	      if (p2->value)
-+	        {
-+	          _asn1_str_cat (name2, sizeof (name2), ".");
-+	          _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+	          _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
-+	        }
-+	      else
-+		_asn1_strcpy (_asn1_identifierMissing, "(null)");
-+
-+	      p2 = asn1_find_node (node, name2);
-+	      if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
-+		  !(p2->type & CONST_ASSIGN))
-+		return ASN1_IDENTIFIER_NOT_FOUND;
-+	      else
-+		_asn1_identifierMissing[0] = 0;
-+	    }
-+	}
-+      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	       (p->type & CONST_ASSIGN))
-+	{
-+	  p2 = p->down;
-+	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
-+	    {
-+	      if (p2->value && !c_isdigit (p2->value[0]))
-+		{
-+		  _asn1_str_cpy (name2, sizeof (name2), node->name);
-+		  _asn1_str_cat (name2, sizeof (name2), ".");
-+		  _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+		  _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
-+
-+		  p2 = asn1_find_node (node, name2);
-+		  if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID)
-+		      || !(p2->type & CONST_ASSIGN))
-+		    return ASN1_IDENTIFIER_NOT_FOUND;
-+		  else
-+		    _asn1_identifierMissing[0] = 0;
-+		}
-+	    }
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (p)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == node)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p && p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_set_default_tag                               */
-+/* Description: sets the default IMPLICIT or EXPLICIT property in */
-+/*   the tagged elements that don't have this declaration.        */
-+/* Parameters:                                                    */
-+/*   node: pointer to a DEFINITIONS element.                      */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to   */
-+/*     a DEFINITIONS element,                                     */
-+/*   otherwise ASN1_SUCCESS                                       */
-+/******************************************************************/
-+int
-+_asn1_set_default_tag (asn1_node node)
-+{
-+  asn1_node p;
-+
-+  if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if ((type_field (p->type) == ASN1_ETYPE_TAG) &&
-+	  !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
-+	{
-+	  if (node->type & CONST_EXPLICIT)
-+	    p->type |= CONST_EXPLICIT;
-+	  else
-+	    p->type |= CONST_IMPLICIT;
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == node)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p && p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
-new file mode 100644
-index 00000000000..8189c56a4c9
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/structure.c
-@@ -0,0 +1,1220 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+
-+/*****************************************************/
-+/* File: structure.c                                 */
-+/* Description: Functions to create and delete an    */
-+/*  ASN1 tree.                                       */
-+/*****************************************************/
-+
-+
-+#include <int.h>
-+#include <structure.h>
-+#include "parser_aux.h"
-+#include <gstr.h>
-+
-+
-+extern char _asn1_identifierMissing[];
-+
-+
-+/******************************************************/
-+/* Function : _asn1_add_single_node                     */
-+/* Description: creates a new NODE_ASN element.       */
-+/* Parameters:                                        */
-+/*   type: type of the new element (see ASN1_ETYPE_         */
-+/*         and CONST_ constants).                     */
-+/* Return: pointer to the new element.                */
-+/******************************************************/
-+asn1_node
-+_asn1_add_single_node (unsigned int type)
-+{
-+  asn1_node punt;
-+
-+  punt = calloc (1, sizeof (struct asn1_node_st));
-+  if (punt == NULL)
-+    return NULL;
-+
-+  punt->type = type;
-+
-+  return punt;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_find_left                                     */
-+/* Description: returns the NODE_ASN element with RIGHT field that*/
-+/*              points the element NODE.                          */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: NULL if not found.                                     */
-+/******************************************************************/
-+asn1_node
-+_asn1_find_left (asn1_node_const node)
-+{
-+  if ((node == NULL) || (node->left == NULL) || (node->left->down == node))
-+    return NULL;
-+
-+  return node->left;
-+}
-+
-+
-+int
-+_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
-+			       char *vector_name)
-+{
-+  FILE *file;
-+  asn1_node_const p;
-+  unsigned long t;
-+
-+  file = fopen (output_file_name, "w");
-+
-+  if (file == NULL)
-+    return ASN1_FILE_NOT_FOUND;
-+
-+  fprintf (file, "#if HAVE_CONFIG_H\n");
-+  fprintf (file, "# include \"config.h\"\n");
-+  fprintf (file, "#endif\n\n");
-+
-+  fprintf (file, "#include <libtasn1.h>\n\n");
-+
-+  fprintf (file, "const asn1_static_node %s[] = {\n", vector_name);
-+
-+  p = pointer;
-+
-+  while (p)
-+    {
-+      fprintf (file, "  { ");
-+
-+      if (p->name[0] != 0)
-+	fprintf (file, "\"%s\", ", p->name);
-+      else
-+	fprintf (file, "NULL, ");
-+
-+      t = p->type;
-+      if (p->down)
-+	t |= CONST_DOWN;
-+      if (p->right)
-+	t |= CONST_RIGHT;
-+
-+      fprintf (file, "%lu, ", t);
-+
-+      if (p->value)
-+	fprintf (file, "\"%s\"},\n", p->value);
-+      else
-+	fprintf (file, "NULL },\n");
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p->right)
-+	{
-+	  p = p->right;
-+	}
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == pointer)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  fprintf (file, "  { NULL, 0, NULL }\n};\n");
-+
-+  fclose (file);
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_array2tree:
-+ * @array: specify the array that contains ASN.1 declarations
-+ * @definitions: return the pointer to the structure created by
-+ *   *ARRAY ASN.1 declarations
-+ * @errorDescription: return the error description.
-+ *
-+ * Creates the structures needed to manage the ASN.1 definitions.
-+ * @array is a vector created by asn1_parser2array().
-+ *
-+ * Returns: %ASN1_SUCCESS if structure was created correctly,
-+ *   %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL,
-+ *   %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier
-+ *   that is not defined (see @errorDescription for more information),
-+ *   %ASN1_ARRAY_ERROR if the array pointed by @array is wrong.
-+ **/
-+int
-+asn1_array2tree (const asn1_static_node * array, asn1_node * definitions,
-+		 char *errorDescription)
-+{
-+  asn1_node p, p_last = NULL;
-+  unsigned long k;
-+  int move;
-+  int result;
-+  unsigned int type;
-+  list_type *e_list = NULL;
-+
-+  if (errorDescription)
-+    errorDescription[0] = 0;
-+
-+  if (*definitions != NULL)
-+    return ASN1_ELEMENT_NOT_EMPTY;
-+
-+  move = UP;
-+
-+  for (k = 0; array[k].value || array[k].type || array[k].name; k++)
-+    {
-+      type = convert_old_type (array[k].type);
-+
-+      p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN));
-+      if (array[k].name)
-+	_asn1_set_name (p, array[k].name);
-+      if (array[k].value)
-+	_asn1_set_value (p, array[k].value, strlen (array[k].value) + 1);
-+
-+      if (*definitions == NULL)
-+	*definitions = p;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p_last && p_last->down)
-+	      _asn1_delete_structure (e_list, &p_last->down, 0);
-+	  _asn1_set_down (p_last, p);
-+	}
-+      else if (move == RIGHT)
-+        {
-+	  if (p_last && p_last->right)
-+	      _asn1_delete_structure (e_list, &p_last->right, 0);
-+	  _asn1_set_right (p_last, p);
-+        }
-+
-+      p_last = p;
-+
-+      if (type & CONST_DOWN)
-+	move = DOWN;
-+      else if (type & CONST_RIGHT)
-+	move = RIGHT;
-+      else
-+	{
-+	  while (p_last != *definitions)
-+	    {
-+	      p_last = _asn1_find_up (p_last);
-+
-+	      if (p_last == NULL)
-+		break;
-+
-+	      if (p_last->type & CONST_RIGHT)
-+		{
-+		  p_last->type &= ~CONST_RIGHT;
-+		  move = RIGHT;
-+		  break;
-+		}
-+	    }			/* while */
-+	}
-+    }				/* while */
-+
-+  if (p_last == *definitions)
-+    {
-+      result = _asn1_check_identifier (*definitions);
-+      if (result == ASN1_SUCCESS)
-+	{
-+	  _asn1_change_integer_value (*definitions);
-+	  result = _asn1_expand_object_id (&e_list, *definitions);
-+	}
-+    }
-+  else
-+    {
-+      result = ASN1_ARRAY_ERROR;
-+    }
-+
-+  if (errorDescription != NULL)
-+    {
-+      if (result == ASN1_IDENTIFIER_NOT_FOUND)
-+	{
-+	  Estrcpy (errorDescription, ":: identifier '");
-+	  Estrcat (errorDescription, _asn1_identifierMissing);
-+	  Estrcat (errorDescription, "' not found");
-+	}
-+      else
-+	errorDescription[0] = 0;
-+    }
-+
-+  if (result != ASN1_SUCCESS)
-+    {
-+      _asn1_delete_list_and_nodes (e_list);
-+      *definitions = NULL;
-+    }
-+  else
-+    _asn1_delete_list (e_list);
-+
-+  return result;
-+}
-+
-+/**
-+ * asn1_delete_structure:
-+ * @structure: pointer to the structure that you want to delete.
-+ *
-+ * Deletes the structure *@structure.  At the end, *@structure is set
-+ * to NULL.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   *@structure was NULL.
-+ **/
-+int
-+asn1_delete_structure (asn1_node * structure)
-+{
-+  return _asn1_delete_structure (NULL, structure, 0);
-+}
-+
-+/**
-+ * asn1_delete_structure2:
-+ * @structure: pointer to the structure that you want to delete.
-+ * @flags: additional flags (see %ASN1_DELETE_FLAG)
-+ *
-+ * Deletes the structure *@structure.  At the end, *@structure is set
-+ * to NULL.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   *@structure was NULL.
-+ **/
-+int
-+asn1_delete_structure2 (asn1_node * structure, unsigned int flags)
-+{
-+  return _asn1_delete_structure (NULL, structure, flags);
-+}
-+
-+int
-+_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags)
-+{
-+  asn1_node p, p2, p3;
-+
-+  if (*structure == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = *structure;
-+  while (p)
-+    {
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else
-+	{			/* no down */
-+	  p2 = p->right;
-+	  if (p != *structure)
-+	    {
-+	      p3 = _asn1_find_up (p);
-+	      _asn1_set_down (p3, p2);
-+	      if (e_list)
-+		_asn1_delete_node_from_list (e_list, p);
-+	      _asn1_remove_node (p, flags);
-+	      p = p3;
-+	    }
-+	  else
-+	    {			/* p==root */
-+	      p3 = _asn1_find_left (p);
-+	      if (!p3)
-+		{
-+		  p3 = _asn1_find_up (p);
-+		  if (p3)
-+		    _asn1_set_down (p3, p2);
-+		  else
-+		    {
-+		      if (p->right)
-+			p->right->left = NULL;
-+		    }
-+		}
-+	      else
-+		_asn1_set_right (p3, p2);
-+	      if (e_list)
-+		_asn1_delete_node_from_list (e_list, p);
-+	      _asn1_remove_node (p, flags);
-+	      p = NULL;
-+	    }
-+	}
-+    }
-+
-+  *structure = NULL;
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_delete_element:
-+ * @structure: pointer to the structure that contains the element you
-+ *   want to delete.
-+ * @element_name: element's name you want to delete.
-+ *
-+ * Deletes the element named *@element_name inside *@structure.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   the @element_name was not found.
-+ **/
-+int
-+asn1_delete_element (asn1_node structure, const char *element_name)
-+{
-+  asn1_node p2, p3, source_node;
-+
-+  source_node = asn1_find_node (structure, element_name);
-+
-+  if (source_node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p2 = source_node->right;
-+  p3 = _asn1_find_left (source_node);
-+  if (!p3)
-+    {
-+      p3 = _asn1_find_up (source_node);
-+      if (p3)
-+	_asn1_set_down (p3, p2);
-+      else if (source_node->right)
-+	source_node->right->left = NULL;
-+    }
-+  else
-+    _asn1_set_right (p3, p2);
-+
-+  return asn1_delete_structure (&source_node);
-+}
-+
-+#ifndef __clang_analyzer__
-+asn1_node
-+_asn1_copy_structure3 (asn1_node_const source_node)
-+{
-+  asn1_node_const p_s;
-+  asn1_node dest_node, p_d, p_d_prev;
-+  int move;
-+
-+  if (source_node == NULL)
-+    return NULL;
-+
-+  dest_node = _asn1_add_single_node (source_node->type);
-+
-+  p_s = source_node;
-+  p_d = dest_node;
-+
-+  move = DOWN;
-+
-+  do
-+    {
-+      if (move != UP)
-+	{
-+	  if (p_s->name[0] != 0)
-+	    _asn1_cpy_name (p_d, p_s);
-+	  if (p_s->value)
-+	    _asn1_set_value (p_d, p_s->value, p_s->value_len);
-+	  if (p_s->down)
-+	    {
-+	      p_s = p_s->down;
-+	      p_d_prev = p_d;
-+	      p_d = _asn1_add_single_node (p_s->type);
-+	      _asn1_set_down (p_d_prev, p_d);
-+	      continue;
-+	    }
-+	  p_d->start = p_s->start;
-+	  p_d->end = p_s->end;
-+	}
-+
-+      if (p_s == source_node)
-+	break;
-+
-+      if (p_s->right)
-+	{
-+	  move = RIGHT;
-+	  p_s = p_s->right;
-+	  p_d_prev = p_d;
-+	  p_d = _asn1_add_single_node (p_s->type);
-+	  _asn1_set_right (p_d_prev, p_d);
-+	}
-+      else
-+	{
-+	  move = UP;
-+	  p_s = _asn1_find_up (p_s);
-+	  p_d = _asn1_find_up (p_d);
-+	}
-+    }
-+  while (p_s != source_node);
-+  return dest_node;
-+}
-+#else
-+
-+/* Non-production code */
-+asn1_node
-+_asn1_copy_structure3 (asn1_node_const source_node)
-+{
-+  return NULL;
-+}
-+#endif /* __clang_analyzer__ */
-+
-+
-+static asn1_node
-+_asn1_copy_structure2 (asn1_node_const root, const char *source_name)
-+{
-+  asn1_node source_node;
-+
-+  source_node = asn1_find_node (root, source_name);
-+
-+  return _asn1_copy_structure3 (source_node);
-+
-+}
-+
-+
-+static int
-+_asn1_type_choice_config (asn1_node node)
-+{
-+  asn1_node p, p2, p3, p4;
-+  int move, tlen;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  move = DOWN;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if ((type_field (p->type) == ASN1_ETYPE_CHOICE)
-+	      && (p->type & CONST_TAG))
-+	    {
-+	      p2 = p->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
-+		    {
-+		      p2->type |= CONST_TAG;
-+		      p3 = _asn1_find_left (p2);
-+		      while (p3)
-+			{
-+			  if (type_field (p3->type) == ASN1_ETYPE_TAG)
-+			    {
-+			      p4 = _asn1_add_single_node (p3->type);
-+			      tlen = _asn1_strlen (p3->value);
-+			      if (tlen > 0)
-+				_asn1_set_value (p4, p3->value, tlen + 1);
-+			      _asn1_set_right (p4, p2->down);
-+			      _asn1_set_down (p2, p4);
-+			    }
-+			  p3 = _asn1_find_left (p3);
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	      p->type &= ~(CONST_TAG);
-+	      p2 = p->down;
-+	      while (p2)
-+		{
-+		  p3 = p2->right;
-+		  if (type_field (p2->type) == ASN1_ETYPE_TAG)
-+		    asn1_delete_structure (&p2);
-+		  p2 = p3;
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+static int
-+_asn1_expand_identifier (asn1_node * node, asn1_node_const root)
-+{
-+  asn1_node p, p2, p3;
-+  char name2[ASN1_MAX_NAME_SIZE + 2];
-+  int move;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = *node;
-+  move = DOWN;
-+
-+  while (!((p == *node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
-+	    {
-+	      snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value);
-+	      p2 = _asn1_copy_structure2 (root, name2);
-+	      if (p2 == NULL)
-+		{
-+		  return ASN1_IDENTIFIER_NOT_FOUND;
-+		}
-+	      _asn1_cpy_name (p2, p);
-+	      p2->right = p->right;
-+	      p2->left = p->left;
-+	      if (p->right)
-+		p->right->left = p2;
-+	      p3 = p->down;
-+	      if (p3)
-+		{
-+		  while (p3->right)
-+		    p3 = p3->right;
-+		  _asn1_set_right (p3, p2->down);
-+		  _asn1_set_down (p2, p->down);
-+		}
-+
-+	      p3 = _asn1_find_left (p);
-+	      if (p3)
-+		_asn1_set_right (p3, p2);
-+	      else
-+		{
-+		  p3 = _asn1_find_up (p);
-+		  if (p3)
-+		    _asn1_set_down (p3, p2);
-+		  else
-+		    {
-+		      p2->left = NULL;
-+		    }
-+		}
-+
-+	      if (p->type & CONST_SIZE)
-+		p2->type |= CONST_SIZE;
-+	      if (p->type & CONST_TAG)
-+		p2->type |= CONST_TAG;
-+	      if (p->type & CONST_OPTION)
-+		p2->type |= CONST_OPTION;
-+	      if (p->type & CONST_DEFAULT)
-+		p2->type |= CONST_DEFAULT;
-+	      if (p->type & CONST_SET)
-+		p2->type |= CONST_SET;
-+	      if (p->type & CONST_NOT_USED)
-+		p2->type |= CONST_NOT_USED;
-+
-+	      if (p == *node)
-+		*node = p2;
-+	      _asn1_remove_node (p, 0);
-+	      p = p2;
-+	      move = DOWN;
-+	      continue;
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == *node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_create_element:
-+ * @definitions: pointer to the structure returned by "parser_asn1" function
-+ * @source_name: the name of the type of the new structure (must be
-+ *   inside p_structure).
-+ * @element: pointer to the structure created.
-+ *
-+ * Creates a structure of type @source_name.  Example using
-+ *  "pkix.asn":
-+ *
-+ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr);
-+ *
-+ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if
-+ *   @source_name is not known.
-+ **/
-+int
-+asn1_create_element (asn1_node_const definitions, const char *source_name,
-+		     asn1_node * element)
-+{
-+  asn1_node dest_node;
-+  int res;
-+
-+  dest_node = _asn1_copy_structure2 (definitions, source_name);
-+
-+  if (dest_node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  _asn1_set_name (dest_node, "");
-+
-+  res = _asn1_expand_identifier (&dest_node, definitions);
-+  _asn1_type_choice_config (dest_node);
-+
-+  *element = dest_node;
-+
-+  return res;
-+}
-+
-+
-+/**
-+ * asn1_print_structure:
-+ * @out: pointer to the output file (e.g. stdout).
-+ * @structure: pointer to the structure that you want to visit.
-+ * @name: an element of the structure
-+ * @mode: specify how much of the structure to print, can be
-+ *   %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE,
-+ *   %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL.
-+ *
-+ * Prints on the @out file descriptor the structure's tree starting
-+ * from the @name element inside the structure @structure.
-+ **/
-+void
-+asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
-+		      int mode)
-+{
-+  asn1_node_const p, root;
-+  int k, indent = 0, len, len2, len3;
-+
-+  if (out == NULL)
-+    return;
-+
-+  root = asn1_find_node (structure, name);
-+
-+  if (root == NULL)
-+    return;
-+
-+  p = root;
-+  while (p)
-+    {
-+      if (mode == ASN1_PRINT_ALL)
-+	{
-+	  for (k = 0; k < indent; k++)
-+	    fprintf (out, " ");
-+	  fprintf (out, "name:");
-+	  if (p->name[0] != 0)
-+	    fprintf (out, "%s  ", p->name);
-+	  else
-+	    fprintf (out, "NULL  ");
-+	}
-+      else
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	    case ASN1_ETYPE_TAG:
-+	    case ASN1_ETYPE_SIZE:
-+	      break;
-+	    default:
-+	      for (k = 0; k < indent; k++)
-+		fprintf (out, " ");
-+	      fprintf (out, "name:");
-+	      if (p->name[0] != 0)
-+		fprintf (out, "%s  ", p->name);
-+	      else
-+		fprintf (out, "NULL  ");
-+	    }
-+	}
-+
-+      if (mode != ASN1_PRINT_NAME)
-+	{
-+	  unsigned type = type_field (p->type);
-+	  switch (type)
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	      if (mode == ASN1_PRINT_ALL)
-+		fprintf (out, "type:CONST");
-+	      break;
-+	    case ASN1_ETYPE_TAG:
-+	      if (mode == ASN1_PRINT_ALL)
-+		fprintf (out, "type:TAG");
-+	      break;
-+	    case ASN1_ETYPE_SIZE:
-+	      if (mode == ASN1_PRINT_ALL)
-+		fprintf (out, "type:SIZE");
-+	      break;
-+	    case ASN1_ETYPE_DEFAULT:
-+	      fprintf (out, "type:DEFAULT");
-+	      break;
-+	    case ASN1_ETYPE_IDENTIFIER:
-+	      fprintf (out, "type:IDENTIFIER");
-+	      break;
-+	    case ASN1_ETYPE_ANY:
-+	      fprintf (out, "type:ANY");
-+	      break;
-+	    case ASN1_ETYPE_CHOICE:
-+	      fprintf (out, "type:CHOICE");
-+	      break;
-+	    case ASN1_ETYPE_DEFINITIONS:
-+	      fprintf (out, "type:DEFINITIONS");
-+	      break;
-+	    CASE_HANDLED_ETYPES:
-+	      fprintf (out, "%s", _asn1_tags[type].desc);
-+	      break;
-+	    default:
-+	      break;
-+	    }
-+	}
-+
-+      if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL))
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	      if (mode == ASN1_PRINT_ALL)
-+		if (p->value)
-+		  fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_TAG:
-+	      if (mode == ASN1_PRINT_ALL)
-+		if (p->value)
-+		  fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_SIZE:
-+	      if (mode == ASN1_PRINT_ALL)
-+		if (p->value)
-+		  fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_DEFAULT:
-+	      if (p->value)
-+		fprintf (out, "  value:%s", p->value);
-+	      else if (p->type & CONST_TRUE)
-+		fprintf (out, "  value:TRUE");
-+	      else if (p->type & CONST_FALSE)
-+		fprintf (out, "  value:FALSE");
-+	      break;
-+	    case ASN1_ETYPE_IDENTIFIER:
-+	      if (p->value)
-+		fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_INTEGER:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:0x");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_ENUMERATED:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:0x");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_BOOLEAN:
-+	      if (p->value)
-+		{
-+		  if (p->value[0] == 'T')
-+		    fprintf (out, "  value:TRUE");
-+		  else if (p->value[0] == 'F')
-+		    fprintf (out, "  value:FALSE");
-+		}
-+	      break;
-+	    case ASN1_ETYPE_BIT_STRING:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  if (len > 0)
-+		    {
-+		      fprintf (out, "  value(%i):",
-+			       (len - 1) * 8 - (p->value[len2]));
-+		      for (k = 1; k < len; k++)
-+			fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		    }
-+		}
-+	      break;
-+	    case ASN1_ETYPE_GENERALIZED_TIME:
-+	    case ASN1_ETYPE_UTC_TIME:
-+	      if (p->value)
-+		{
-+		  fprintf (out, "  value:");
-+		  for (k = 0; k < p->value_len; k++)
-+		    fprintf (out, "%c", (p->value)[k]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_GENERALSTRING:
-+	    case ASN1_ETYPE_NUMERIC_STRING:
-+	    case ASN1_ETYPE_IA5_STRING:
-+	    case ASN1_ETYPE_TELETEX_STRING:
-+	    case ASN1_ETYPE_PRINTABLE_STRING:
-+	    case ASN1_ETYPE_UNIVERSAL_STRING:
-+	    case ASN1_ETYPE_UTF8_STRING:
-+	    case ASN1_ETYPE_VISIBLE_STRING:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%c", (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_BMP_STRING:
-+	    case ASN1_ETYPE_OCTET_STRING:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_OBJECT_ID:
-+	      if (p->value)
-+		fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_ANY:
-+	      if (p->value)
-+		{
-+		  len3 = -1;
-+		  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+		  fprintf (out, "  value:");
-+		  if (len2 > 0)
-+		    for (k = 0; k < len2; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len3]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_SET:
-+	    case ASN1_ETYPE_SET_OF:
-+	    case ASN1_ETYPE_CHOICE:
-+	    case ASN1_ETYPE_DEFINITIONS:
-+	    case ASN1_ETYPE_SEQUENCE_OF:
-+	    case ASN1_ETYPE_SEQUENCE:
-+	    case ASN1_ETYPE_NULL:
-+	      break;
-+	    default:
-+	      break;
-+	    }
-+	}
-+
-+      if (mode == ASN1_PRINT_ALL)
-+	{
-+	  if (p->type & 0x1FFFFF00)
-+	    {
-+	      fprintf (out, "  attr:");
-+	      if (p->type & CONST_UNIVERSAL)
-+		fprintf (out, "UNIVERSAL,");
-+	      if (p->type & CONST_PRIVATE)
-+		fprintf (out, "PRIVATE,");
-+	      if (p->type & CONST_APPLICATION)
-+		fprintf (out, "APPLICATION,");
-+	      if (p->type & CONST_EXPLICIT)
-+		fprintf (out, "EXPLICIT,");
-+	      if (p->type & CONST_IMPLICIT)
-+		fprintf (out, "IMPLICIT,");
-+	      if (p->type & CONST_TAG)
-+		fprintf (out, "TAG,");
-+	      if (p->type & CONST_DEFAULT)
-+		fprintf (out, "DEFAULT,");
-+	      if (p->type & CONST_TRUE)
-+		fprintf (out, "TRUE,");
-+	      if (p->type & CONST_FALSE)
-+		fprintf (out, "FALSE,");
-+	      if (p->type & CONST_LIST)
-+		fprintf (out, "LIST,");
-+	      if (p->type & CONST_MIN_MAX)
-+		fprintf (out, "MIN_MAX,");
-+	      if (p->type & CONST_OPTION)
-+		fprintf (out, "OPTION,");
-+	      if (p->type & CONST_1_PARAM)
-+		fprintf (out, "1_PARAM,");
-+	      if (p->type & CONST_SIZE)
-+		fprintf (out, "SIZE,");
-+	      if (p->type & CONST_DEFINED_BY)
-+		fprintf (out, "DEF_BY,");
-+	      if (p->type & CONST_GENERALIZED)
-+		fprintf (out, "GENERALIZED,");
-+	      if (p->type & CONST_UTC)
-+		fprintf (out, "UTC,");
-+	      if (p->type & CONST_SET)
-+		fprintf (out, "SET,");
-+	      if (p->type & CONST_NOT_USED)
-+		fprintf (out, "NOT_USED,");
-+	      if (p->type & CONST_ASSIGN)
-+		fprintf (out, "ASSIGNMENT,");
-+	    }
-+	}
-+
-+      if (mode == ASN1_PRINT_ALL)
-+	{
-+	  fprintf (out, "\n");
-+	}
-+      else
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	    case ASN1_ETYPE_TAG:
-+	    case ASN1_ETYPE_SIZE:
-+	      break;
-+	    default:
-+	      fprintf (out, "\n");
-+	    }
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	  indent += 2;
-+	}
-+      else if (p == root)
-+	{
-+	  p = NULL;
-+	  break;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == root)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      indent -= 2;
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+}
-+
-+
-+
-+/**
-+ * asn1_number_of_elements:
-+ * @element: pointer to the root of an ASN1 structure.
-+ * @name: the name of a sub-structure of ROOT.
-+ * @num: pointer to an integer where the result will be stored
-+ *
-+ * Counts the number of elements of a sub-structure called NAME with
-+ * names equal to "?1","?2", ...
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL.
-+ **/
-+int
-+asn1_number_of_elements (asn1_node_const element, const char *name, int *num)
-+{
-+  asn1_node_const node, p;
-+
-+  if (num == NULL)
-+    return ASN1_GENERIC_ERROR;
-+
-+  *num = 0;
-+
-+  node = asn1_find_node (element, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node->down;
-+
-+  while (p)
-+    {
-+      if (p->name[0] == '?')
-+	(*num)++;
-+      p = p->right;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_find_structure_from_oid:
-+ * @definitions: ASN1 definitions
-+ * @oidValue: value of the OID to search (e.g. "1.2.3.4").
-+ *
-+ * Search the structure that is defined just after an OID definition.
-+ *
-+ * Returns: %NULL when @oidValue not found, otherwise the pointer to a
-+ *   constant string that contains the element name defined just after
-+ *   the OID.
-+ **/
-+const char *
-+asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
-+{
-+  char name[2 * ASN1_MAX_NAME_SIZE + 2];
-+  char value[ASN1_MAX_NAME_SIZE];
-+  asn1_node p;
-+  int len;
-+  int result;
-+  const char *definitionsName;
-+
-+  if ((definitions == NULL) || (oidValue == NULL))
-+    return NULL;		/* ASN1_ELEMENT_NOT_FOUND; */
-+
-+  definitionsName = definitions->name;
-+
-+  /* search the OBJECT_ID into definitions */
-+  p = definitions->down;
-+  while (p)
-+    {
-+      if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	  (p->type & CONST_ASSIGN))
-+	{
-+          snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name);
-+
-+	  len = ASN1_MAX_NAME_SIZE;
-+	  result = asn1_read_value (definitions, name, value, &len);
-+
-+	  if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value)))
-+	    {
-+	      p = p->right;
-+	      if (p == NULL)	/* reach the end of ASN1 definitions */
-+		return NULL;	/* ASN1_ELEMENT_NOT_FOUND; */
-+
-+	      return p->name;
-+	    }
-+	}
-+      p = p->right;
-+    }
-+
-+  return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
-+}
-+
-+/**
-+ * asn1_copy_node:
-+ * @dst: Destination asn1 node.
-+ * @dst_name: Field name in destination node.
-+ * @src: Source asn1 node.
-+ * @src_name: Field name in source node.
-+ *
-+ * Create a deep copy of a asn1_node variable. That
-+ * function requires @dst to be expanded using asn1_create_element().
-+ *
-+ * Returns: Return %ASN1_SUCCESS on success.
-+ **/
-+int
-+asn1_copy_node (asn1_node dst, const char *dst_name,
-+		asn1_node_const src, const char *src_name)
-+{
-+  int result;
-+  asn1_node dst_node;
-+  void *data = NULL;
-+  int size = 0;
-+
-+  result = asn1_der_coding (src, src_name, NULL, &size, NULL);
-+  if (result != ASN1_MEM_ERROR)
-+    return result;
-+
-+  data = malloc (size);
-+  if (data == NULL)
-+    return ASN1_MEM_ERROR;
-+
-+  result = asn1_der_coding (src, src_name, data, &size, NULL);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      free (data);
-+      return result;
-+    }
-+
-+  dst_node = asn1_find_node (dst, dst_name);
-+  if (dst_node == NULL)
-+    {
-+      free (data);
-+      return ASN1_ELEMENT_NOT_FOUND;
-+    }
-+
-+  result = asn1_der_decoding (&dst_node, data, size, NULL);
-+
-+  free (data);
-+
-+  return result;
-+}
-+
-+/**
-+ * asn1_dup_node:
-+ * @src: Source asn1 node.
-+ * @src_name: Field name in source node.
-+ *
-+ * Create a deep copy of a asn1_node variable. This function
-+ * will return an exact copy of the provided structure.
-+ *
-+ * Returns: Return %NULL on failure.
-+ **/
-+asn1_node
-+asn1_dup_node (asn1_node_const src, const char *src_name)
-+{
-+  return _asn1_copy_structure2(src, src_name);
-+}
-diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h
-new file mode 100644
-index 00000000000..440a33f4bb1
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/element.h
-@@ -0,0 +1,40 @@
-+/*
-+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef _ELEMENT_H
-+#define _ELEMENT_H
-+
-+
-+struct node_tail_cache_st
-+{
-+	asn1_node head; /* the first element of the sequence */
-+	asn1_node tail;
-+};
-+
-+int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached);
-+
-+int _asn1_convert_integer (const unsigned char *value,
-+			   unsigned char *value_out,
-+			   int value_out_size, int *len);
-+
-+void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size);
-+
-+#endif
-diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h
-new file mode 100644
-index 00000000000..48229844ff3
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/gstr.h
-@@ -0,0 +1,47 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef GSTR_H
-+# define GSTR_H
-+
-+unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size,
-+			    const char *src);
-+void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src);
-+
-+#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
-+#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
-+
-+inline static
-+void safe_memset(void *data, int c, size_t size)
-+{
-+	volatile unsigned volatile_zero = 0;
-+	volatile char *vdata = (volatile char*)data;
-+
-+	/* This is based on a nice trick for safe memset,
-+	 * sent by David Jacobson in the openssl-dev mailing list.
-+	 */
-+
-+	if (size > 0) do {
-+		memset(data, c, size);
-+	} while(vdata[volatile_zero] != c);
-+}
-+
-+#endif /* GSTR_H */
-diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
-new file mode 100644
-index 00000000000..ea1625786c1
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/int.h
-@@ -0,0 +1,221 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef INT_H
-+#define INT_H
-+
-+#ifdef HAVE_CONFIG_H
-+#include <config.h>
-+#endif
-+
-+#include <string.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <stdint.h>
-+
-+#ifdef HAVE_SYS_TYPES_H
-+#include <sys/types.h>
-+#endif
-+
-+#include <libtasn1.h>
-+
-+#define ASN1_SMALL_VALUE_SIZE 16
-+
-+/* This structure is also in libtasn1.h, but then contains less
-+   fields.  You cannot make any modifications to these first fields
-+   without breaking ABI.  */
-+struct asn1_node_st
-+{
-+  /* public fields: */
-+  char name[ASN1_MAX_NAME_SIZE + 1];	/* Node name */
-+  unsigned int name_hash;
-+  unsigned int type;		/* Node type */
-+  unsigned char *value;		/* Node value */
-+  int value_len;
-+  asn1_node down;		/* Pointer to the son node */
-+  asn1_node right;		/* Pointer to the brother node */
-+  asn1_node left;		/* Pointer to the next list element */
-+  /* private fields: */
-+  unsigned char small_value[ASN1_SMALL_VALUE_SIZE];	/* For small values */
-+
-+  /* values used during decoding/coding */
-+  int tmp_ival;
-+  unsigned start; /* the start of the DER sequence - if decoded */
-+  unsigned end; /* the end of the DER sequence - if decoded */
-+};
-+
-+typedef struct tag_and_class_st
-+{
-+  unsigned tag;
-+  unsigned class;
-+  const char *desc;
-+} tag_and_class_st;
-+
-+/* the types that are handled in _asn1_tags */
-+#define CASE_HANDLED_ETYPES \
-+	case ASN1_ETYPE_NULL: \
-+	case ASN1_ETYPE_BOOLEAN: \
-+	case ASN1_ETYPE_INTEGER: \
-+	case ASN1_ETYPE_ENUMERATED: \
-+	case ASN1_ETYPE_OBJECT_ID: \
-+	case ASN1_ETYPE_OCTET_STRING: \
-+	case ASN1_ETYPE_GENERALSTRING: \
-+        case ASN1_ETYPE_NUMERIC_STRING: \
-+        case ASN1_ETYPE_IA5_STRING: \
-+        case ASN1_ETYPE_TELETEX_STRING: \
-+        case ASN1_ETYPE_PRINTABLE_STRING: \
-+        case ASN1_ETYPE_UNIVERSAL_STRING: \
-+        case ASN1_ETYPE_BMP_STRING: \
-+        case ASN1_ETYPE_UTF8_STRING: \
-+        case ASN1_ETYPE_VISIBLE_STRING: \
-+	case ASN1_ETYPE_BIT_STRING: \
-+	case ASN1_ETYPE_SEQUENCE: \
-+	case ASN1_ETYPE_SEQUENCE_OF: \
-+	case ASN1_ETYPE_SET: \
-+	case ASN1_ETYPE_UTC_TIME: \
-+	case ASN1_ETYPE_GENERALIZED_TIME: \
-+	case ASN1_ETYPE_SET_OF
-+
-+#define ETYPE_TAG(etype) (_asn1_tags[etype].tag)
-+#define ETYPE_CLASS(etype) (_asn1_tags[etype].class)
-+#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \
-+                          (etype) <= _asn1_tags_size && \
-+                          _asn1_tags[(etype)].desc != NULL)?1:0)
-+
-+#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \
-+	etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \
-+	etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \
-+	etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \
-+	etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \
-+	etype == ASN1_ETYPE_OCTET_STRING)?1:0)
-+
-+extern unsigned int _asn1_tags_size;
-+extern const tag_and_class_st _asn1_tags[];
-+
-+#define _asn1_strlen(s) strlen((const char *) s)
-+#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b)
-+#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
-+#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
-+#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
-+#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
-+
-+#if SIZEOF_UNSIGNED_LONG_INT == 8
-+# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
-+#else
-+# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b)
-+#endif
-+
-+#define MAX_LOG_SIZE 1024	/* maximum number of characters of a log message */
-+
-+/* Define used for visiting trees. */
-+#define UP     1
-+#define RIGHT  2
-+#define DOWN   3
-+
-+/***********************************************************************/
-+/* List of constants to better specify the type of typedef asn1_node_st.   */
-+/***********************************************************************/
-+/*  Used with TYPE_TAG  */
-+#define CONST_UNIVERSAL   (1U<<8)
-+#define CONST_PRIVATE     (1U<<9)
-+#define CONST_APPLICATION (1U<<10)
-+#define CONST_EXPLICIT    (1U<<11)
-+#define CONST_IMPLICIT    (1U<<12)
-+
-+#define CONST_TAG         (1U<<13)	/*  Used in ASN.1 assignement  */
-+#define CONST_OPTION      (1U<<14)
-+#define CONST_DEFAULT     (1U<<15)
-+#define CONST_TRUE        (1U<<16)
-+#define CONST_FALSE       (1U<<17)
-+
-+#define CONST_LIST        (1U<<18)	/*  Used with TYPE_INTEGER and TYPE_BIT_STRING  */
-+#define CONST_MIN_MAX     (1U<<19)
-+
-+#define CONST_1_PARAM     (1U<<20)
-+
-+#define CONST_SIZE        (1U<<21)
-+
-+#define CONST_DEFINED_BY  (1U<<22)
-+
-+/* Those two are deprecated and used for backwards compatibility */
-+#define CONST_GENERALIZED (1U<<23)
-+#define CONST_UTC         (1U<<24)
-+
-+/* #define CONST_IMPORTS     (1U<<25) */
-+
-+#define CONST_NOT_USED    (1U<<26)
-+#define CONST_SET         (1U<<27)
-+#define CONST_ASSIGN      (1U<<28)
-+
-+#define CONST_DOWN        (1U<<29)
-+#define CONST_RIGHT       (1U<<30)
-+
-+
-+#define ASN1_ETYPE_TIME 17
-+/****************************************/
-+/* Returns the first 8 bits.            */
-+/* Used with the field type of asn1_node_st */
-+/****************************************/
-+inline static unsigned int
-+type_field (unsigned int ntype)
-+{
-+  return (ntype & 0xff);
-+}
-+
-+/* To convert old types from a static structure */
-+inline static unsigned int
-+convert_old_type (unsigned int ntype)
-+{
-+  unsigned int type = ntype & 0xff;
-+  if (type == ASN1_ETYPE_TIME)
-+    {
-+      if (ntype & CONST_UTC)
-+	type = ASN1_ETYPE_UTC_TIME;
-+      else
-+	type = ASN1_ETYPE_GENERALIZED_TIME;
-+
-+      ntype &= ~(CONST_UTC | CONST_GENERALIZED);
-+      ntype &= 0xffffff00;
-+      ntype |= type;
-+
-+      return ntype;
-+    }
-+  else
-+    return ntype;
-+}
-+
-+static inline
-+void *_asn1_realloc(void *ptr, size_t size)
-+{
-+  void *ret;
-+
-+  if (size == 0)
-+    return ptr;
-+
-+  ret = realloc(ptr, size);
-+  if (ret == NULL)
-+    {
-+      free(ptr);
-+    }
-+  return ret;
-+}
-+
-+#endif /* INT_H */
-diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h
-new file mode 100644
-index 00000000000..598e684b355
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/parser_aux.h
-@@ -0,0 +1,172 @@
-+/*
-+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef _PARSER_AUX_H
-+#define _PARSER_AUX_H
-+
-+/***********************************************/
-+/* Type: list_type                             */
-+/* Description: type used in the list during   */
-+/* the structure creation.                     */
-+/***********************************************/
-+typedef struct list_struct
-+{
-+  asn1_node node;
-+  struct list_struct *next;
-+} list_type;
-+
-+/***************************************/
-+/*  Functions used by ASN.1 parser     */
-+/***************************************/
-+asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type);
-+
-+void _asn1_delete_list (list_type *e_list);
-+
-+void _asn1_delete_list_and_nodes (list_type *e_list);
-+
-+void _asn1_delete_node_from_list (list_type *list, asn1_node node);
-+
-+asn1_node
-+_asn1_set_value (asn1_node node, const void *value, unsigned int len);
-+
-+asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len);
-+
-+asn1_node
-+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len);
-+
-+asn1_node
-+_asn1_append_value (asn1_node node, const void *value, unsigned int len);
-+
-+asn1_node _asn1_set_name (asn1_node node, const char *name);
-+
-+asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src);
-+
-+asn1_node _asn1_set_right (asn1_node node, asn1_node right);
-+
-+asn1_node _asn1_get_last_right (asn1_node_const node);
-+
-+void _asn1_remove_node (asn1_node node, unsigned int flags);
-+
-+/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */
-+#define LTOSTR_MAX_SIZE 22
-+char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]);
-+
-+asn1_node _asn1_find_up (asn1_node_const node);
-+
-+int _asn1_change_integer_value (asn1_node node);
-+
-+#define EXPAND_OBJECT_ID_MAX_RECURSION 16
-+int _asn1_expand_object_id (list_type **list, asn1_node node);
-+
-+int _asn1_type_set_config (asn1_node node);
-+
-+int _asn1_check_identifier (asn1_node_const node);
-+
-+int _asn1_set_default_tag (asn1_node node);
-+
-+/******************************************************************/
-+/* Function : _asn1_get_right                                     */
-+/* Description: returns the element pointed by the RIGHT field of */
-+/*              a NODE_ASN element.                               */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: field RIGHT of NODE.                                   */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_get_right (asn1_node_const node)
-+{
-+  if (node == NULL)
-+    return NULL;
-+  return node->right;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_down                                      */
-+/* Description: sets the field DOWN in a NODE_ASN element.        */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   down: pointer to a NODE_ASN element that you want be pointed */
-+/*          by NODE.                                              */
-+/* Return: pointer to *NODE.                                      */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_set_down (asn1_node node, asn1_node down)
-+{
-+  if (node == NULL)
-+    return node;
-+  node->down = down;
-+  if (down)
-+    down->left = node;
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_get_down                                      */
-+/* Description: returns the element pointed by the DOWN field of  */
-+/*              a NODE_ASN element.                               */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: field DOWN of NODE.                                    */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_get_down (asn1_node_const node)
-+{
-+  if (node == NULL)
-+    return NULL;
-+  return node->down;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_get_name                                      */
-+/* Description: returns the name of a NODE_ASN element.           */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: a null terminated string.                              */
-+/******************************************************************/
-+inline static char *
-+_asn1_get_name (asn1_node_const node)
-+{
-+  if (node == NULL)
-+    return NULL;
-+  return (char *) node->name;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_mod_type                                      */
-+/* Description: change the field TYPE of an NODE_ASN element.     */
-+/*              The new value is the old one | (bitwise or) the   */
-+/*              paramener VALUE.                                  */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/*   value: the integer value that must be or-ed with the current */
-+/*          value of field TYPE.                                  */
-+/* Return: NODE pointer.                                          */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_mod_type (asn1_node node, unsigned int value)
-+{
-+  if (node == NULL)
-+    return node;
-+  node->type |= value;
-+  return node;
-+}
-+
-+#endif
-diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h
-new file mode 100644
-index 00000000000..99e685da07a
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/structure.h
-@@ -0,0 +1,45 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+/*************************************************/
-+/* File: structure.h                             */
-+/* Description: list of exported object by       */
-+/*   "structure.c"                               */
-+/*************************************************/
-+
-+#ifndef _STRUCTURE_H
-+#define _STRUCTURE_H
-+
-+#include "parser_aux.h" // list_type
-+
-+int _asn1_create_static_structure (asn1_node_const pointer,
-+				   char *output_file_name, char *vector_name);
-+
-+asn1_node _asn1_copy_structure3 (asn1_node_const source_node);
-+
-+asn1_node _asn1_add_single_node (unsigned int type);
-+
-+asn1_node _asn1_find_left (asn1_node_const node);
-+
-+int
-+_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags);
-+
-+#endif
-diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
-new file mode 100644
-index 00000000000..6fd7a30dc35
---- /dev/null
-+++ b/include/grub/libtasn1.h
-@@ -0,0 +1,588 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * LIBTASN1 is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Lesser General Public License as
-+ * published by the Free Software Foundation; either version 2.1 of
-+ * the License, or (at your option) any later version.
-+ *
-+ * LIBTASN1 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with LIBTASN1; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ *
-+ */
-+
-+/**
-+ * libtasn1:Short_Description:
-+ *
-+ * GNU ASN.1 library
-+ */
-+/**
-+ * libtasn1:Long_Description:
-+ *
-+ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as
-+ * specified by the X.680 ITU-T recommendation) parsing and structures
-+ * management, and Distinguished Encoding Rules (DER, as per X.690)
-+ * encoding and decoding functions.
-+ */
-+
-+
-+#ifndef LIBTASN1_H
-+#define LIBTASN1_H
-+
-+#ifndef ASN1_API
-+#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
-+#define ASN1_API __attribute__((__visibility__("default")))
-+#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
-+#define ASN1_API __declspec(dllexport)
-+#elif defined _MSC_VER && ! defined ASN1_STATIC
-+#define ASN1_API __declspec(dllimport)
-+#else
-+#define ASN1_API
-+#endif
-+#endif
-+
-+#ifdef __GNUC__
-+# define __LIBTASN1_CONST__  __attribute__((const))
-+# define __LIBTASN1_PURE__  __attribute__((pure))
-+#else
-+# define __LIBTASN1_CONST__
-+# define __LIBTASN1_PURE__
-+#endif
-+
-+#include <sys/types.h>
-+#include <time.h>
-+#include <stdio.h>		/* for FILE* */
-+
-+#ifdef __cplusplus
-+extern "C"
-+{
-+#endif
-+
-+/**
-+ * ASN1_VERSION:
-+ *
-+ * Version of the library as a string.
-+ */
-+#define ASN1_VERSION "4.16.0"
-+
-+/**
-+ * ASN1_VERSION_MAJOR:
-+ *
-+ * Major version number of the library.
-+ */
-+#define ASN1_VERSION_MAJOR 4
-+
-+/**
-+ * ASN1_VERSION_MINOR:
-+ *
-+ * Minor version number of the library.
-+ */
-+#define ASN1_VERSION_MINOR 16
-+
-+/**
-+ * ASN1_VERSION_PATCH:
-+ *
-+ * Patch version number of the library.
-+ */
-+#define ASN1_VERSION_PATCH 0
-+
-+/**
-+ * ASN1_VERSION_NUMBER:
-+ *
-+ * Version number of the library as a number.
-+ */
-+#define ASN1_VERSION_NUMBER 0x041000
-+
-+
-+#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD
-+# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-+# if _ASN1_GCC_VERSION >= 30100
-+#  define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__))
-+# endif
-+#endif
-+
-+#ifndef _ASN1_GCC_ATTR_DEPRECATED
-+#define _ASN1_GCC_ATTR_DEPRECATED
-+#endif
-+
-+/*****************************************/
-+/* Errors returned by libtasn1 functions */
-+/*****************************************/
-+#define ASN1_SUCCESS			0
-+#define ASN1_FILE_NOT_FOUND		1
-+#define ASN1_ELEMENT_NOT_FOUND		2
-+#define ASN1_IDENTIFIER_NOT_FOUND	3
-+#define ASN1_DER_ERROR			4
-+#define ASN1_VALUE_NOT_FOUND		5
-+#define ASN1_GENERIC_ERROR		6
-+#define ASN1_VALUE_NOT_VALID		7
-+#define ASN1_TAG_ERROR			8
-+#define ASN1_TAG_IMPLICIT		9
-+#define ASN1_ERROR_TYPE_ANY		10
-+#define ASN1_SYNTAX_ERROR		11
-+#define ASN1_MEM_ERROR			12
-+#define ASN1_MEM_ALLOC_ERROR		13
-+#define ASN1_DER_OVERFLOW		14
-+#define ASN1_NAME_TOO_LONG		15
-+#define ASN1_ARRAY_ERROR		16
-+#define ASN1_ELEMENT_NOT_EMPTY		17
-+#define ASN1_TIME_ENCODING_ERROR	18
-+#define ASN1_RECURSION			19
-+
-+/*************************************/
-+/* Constants used in asn1_visit_tree */
-+/*************************************/
-+#define ASN1_PRINT_NAME			1
-+#define ASN1_PRINT_NAME_TYPE		2
-+#define ASN1_PRINT_NAME_TYPE_VALUE	3
-+#define ASN1_PRINT_ALL			4
-+
-+/*****************************************/
-+/* Constants returned by asn1_read_tag   */
-+/*****************************************/
-+#define ASN1_CLASS_UNIVERSAL		0x00	/* old: 1 */
-+#define ASN1_CLASS_APPLICATION		0x40	/* old: 2 */
-+#define ASN1_CLASS_CONTEXT_SPECIFIC	0x80	/* old: 3 */
-+#define ASN1_CLASS_PRIVATE		0xC0	/* old: 4 */
-+#define ASN1_CLASS_STRUCTURED		0x20
-+
-+/*****************************************/
-+/* Constants returned by asn1_read_tag   */
-+/*****************************************/
-+#define ASN1_TAG_BOOLEAN		0x01
-+#define ASN1_TAG_INTEGER		0x02
-+#define ASN1_TAG_SEQUENCE		0x10
-+#define ASN1_TAG_SET			0x11
-+#define ASN1_TAG_OCTET_STRING		0x04
-+#define ASN1_TAG_BIT_STRING		0x03
-+#define ASN1_TAG_UTCTime		0x17
-+#define ASN1_TAG_GENERALIZEDTime	0x18
-+#define ASN1_TAG_OBJECT_ID		0x06
-+#define ASN1_TAG_ENUMERATED		0x0A
-+#define ASN1_TAG_NULL			0x05
-+#define ASN1_TAG_GENERALSTRING		0x1B
-+#define ASN1_TAG_NUMERIC_STRING		0x12
-+#define ASN1_TAG_IA5_STRING		0x16
-+#define ASN1_TAG_TELETEX_STRING		0x14
-+#define ASN1_TAG_PRINTABLE_STRING	0x13
-+#define ASN1_TAG_UNIVERSAL_STRING	0x1C
-+#define ASN1_TAG_BMP_STRING		0x1E
-+#define ASN1_TAG_UTF8_STRING		0x0C
-+#define ASN1_TAG_VISIBLE_STRING		0x1A
-+
-+/**
-+ * asn1_node:
-+ *
-+ * Structure definition used for the node of the tree
-+ * that represents an ASN.1 DEFINITION.
-+ */
-+typedef struct asn1_node_st asn1_node_st;
-+
-+typedef asn1_node_st *asn1_node;
-+typedef const asn1_node_st *asn1_node_const;
-+
-+/**
-+ * ASN1_MAX_NAME_SIZE:
-+ *
-+ * Maximum number of characters of a name
-+ * inside a file with ASN1 definitions.
-+ */
-+#define ASN1_MAX_NAME_SIZE 64
-+
-+
-+/**
-+ * asn1_static_node:
-+ * @name: Node name
-+ * @type: Node typ
-+ * @value: Node value
-+ *
-+ * For the on-disk format of ASN.1 trees, created by asn1_parser2array().
-+ */
-+struct asn1_static_node_st
-+{
-+  const char *name;		/* Node name */
-+  unsigned int type;		/* Node type */
-+  const void *value;		/* Node value */
-+};
-+typedef struct asn1_static_node_st asn1_static_node;
-+
-+/* List of constants for field type of node_asn  */
-+#define ASN1_ETYPE_INVALID        0
-+#define ASN1_ETYPE_CONSTANT       1
-+#define ASN1_ETYPE_IDENTIFIER     2
-+#define ASN1_ETYPE_INTEGER        3
-+#define ASN1_ETYPE_BOOLEAN        4
-+#define ASN1_ETYPE_SEQUENCE       5
-+#define ASN1_ETYPE_BIT_STRING     6
-+#define ASN1_ETYPE_OCTET_STRING   7
-+#define ASN1_ETYPE_TAG            8
-+#define ASN1_ETYPE_DEFAULT        9
-+#define ASN1_ETYPE_SIZE          10
-+#define ASN1_ETYPE_SEQUENCE_OF   11
-+#define ASN1_ETYPE_OBJECT_ID     12
-+#define ASN1_ETYPE_ANY           13
-+#define ASN1_ETYPE_SET           14
-+#define ASN1_ETYPE_SET_OF        15
-+#define ASN1_ETYPE_DEFINITIONS   16
-+#define ASN1_ETYPE_CHOICE        18
-+#define ASN1_ETYPE_IMPORTS       19
-+#define ASN1_ETYPE_NULL          20
-+#define ASN1_ETYPE_ENUMERATED    21
-+#define ASN1_ETYPE_GENERALSTRING 27
-+#define ASN1_ETYPE_NUMERIC_STRING 28
-+#define ASN1_ETYPE_IA5_STRING     29
-+#define ASN1_ETYPE_TELETEX_STRING 30
-+#define ASN1_ETYPE_PRINTABLE_STRING 31
-+#define ASN1_ETYPE_UNIVERSAL_STRING 32
-+#define ASN1_ETYPE_BMP_STRING     33
-+#define ASN1_ETYPE_UTF8_STRING    34
-+#define ASN1_ETYPE_VISIBLE_STRING 35
-+#define ASN1_ETYPE_UTC_TIME       36
-+#define ASN1_ETYPE_GENERALIZED_TIME 37
-+
-+/**
-+ * ASN1_DELETE_FLAG_ZEROIZE:
-+ *
-+ * Used by: asn1_delete_structure2()
-+ *
-+ * Zeroize values prior to deinitialization.
-+ */
-+#define ASN1_DELETE_FLAG_ZEROIZE 1
-+
-+/**
-+ * ASN1_DECODE_FLAG_ALLOW_PADDING:
-+ *
-+ * Used by: asn1_der_decoding2()
-+ *
-+ * This flag would allow arbitrary data past the DER data.
-+ */
-+#define ASN1_DECODE_FLAG_ALLOW_PADDING 1
-+/**
-+ * ASN1_DECODE_FLAG_STRICT_DER:
-+ *
-+ * Used by: asn1_der_decoding2()
-+ *
-+ * This flag would ensure that no BER decoding takes place.
-+ */
-+#define ASN1_DECODE_FLAG_STRICT_DER (1<<1)
-+/**
-+ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME:
-+ *
-+ * Used by: asn1_der_decoding2()
-+ *
-+ * This flag will tolerate Time encoding errors when in strict DER.
-+ */
-+#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2)
-+
-+
-+/**
-+ * asn1_data_node_st:
-+ * @name: Node name
-+ * @value: Node value
-+ * @value_len: Node value size
-+ * @type: Node value type (ASN1_ETYPE_*)
-+ *
-+ * Data node inside a #asn1_node structure.
-+ */
-+struct asn1_data_node_st
-+{
-+  const char *name;		/* Node name */
-+  const void *value;		/* Node value */
-+  unsigned int value_len;	/* Node value size */
-+  unsigned int type;		/* Node value type (ASN1_ETYPE_*) */
-+};
-+typedef struct asn1_data_node_st asn1_data_node_st;
-+
-+/***********************************/
-+/*  Fixed constants                */
-+/***********************************/
-+
-+/**
-+ * ASN1_MAX_ERROR_DESCRIPTION_SIZE:
-+ *
-+ * Maximum number of characters
-+ * of a description message
-+ * (null character included).
-+ */
-+#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128
-+
-+/***********************************/
-+/*  Functions definitions          */
-+/***********************************/
-+
-+extern ASN1_API int
-+  asn1_parser2tree (const char *file,
-+		      asn1_node * definitions, char *error_desc);
-+
-+extern ASN1_API int
-+  asn1_parser2array (const char *inputFileName,
-+		       const char *outputFileName,
-+		       const char *vectorName, char *error_desc);
-+
-+extern ASN1_API int
-+  asn1_array2tree (const asn1_static_node * array,
-+		     asn1_node * definitions, char *errorDescription);
-+
-+extern ASN1_API void
-+  asn1_print_structure (FILE * out, asn1_node_const structure,
-+			  const char *name, int mode);
-+
-+extern ASN1_API int
-+  asn1_create_element (asn1_node_const definitions,
-+			 const char *source_name, asn1_node * element);
-+
-+extern ASN1_API int asn1_delete_structure (asn1_node * structure);
-+
-+extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags);
-+
-+extern ASN1_API int
-+  asn1_delete_element (asn1_node structure, const char *element_name);
-+
-+extern ASN1_API int
-+  asn1_write_value (asn1_node node_root, const char *name,
-+		      const void *ivalue, int len);
-+
-+extern ASN1_API int
-+  asn1_read_value (asn1_node_const root, const char *name,
-+		     void *ivalue, int *len);
-+
-+extern ASN1_API int
-+  asn1_read_value_type (asn1_node_const root, const char *name,
-+			  void *ivalue, int *len, unsigned int *etype);
-+
-+extern ASN1_API int
-+  asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data);
-+
-+extern ASN1_API int
-+  asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
-+
-+extern ASN1_API int
-+  asn1_der_coding (asn1_node_const element, const char *name,
-+		     void *ider, int *len, char *ErrorDescription);
-+
-+extern ASN1_API int
-+  asn1_der_decoding2 (asn1_node *element, const void *ider,
-+			int *max_ider_len, unsigned int flags,
-+			char *errorDescription);
-+
-+extern ASN1_API int
-+  asn1_der_decoding (asn1_node * element, const void *ider,
-+		       int ider_len, char *errorDescription);
-+
-+/* Do not use. Use asn1_der_decoding() instead. */
-+extern ASN1_API int
-+  asn1_der_decoding_element (asn1_node * structure,
-+			       const char *elementName,
-+			       const void *ider, int len,
-+			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
-+
-+extern ASN1_API int
-+  asn1_der_decoding_startEnd (asn1_node element,
-+				const void *ider, int ider_len,
-+				const char *name_element,
-+				int *start, int *end);
-+
-+extern ASN1_API int
-+  asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element);
-+
-+extern ASN1_API int
-+  asn1_expand_octet_string (asn1_node_const definitions,
-+			      asn1_node * element,
-+			      const char *octetName, const char *objectName);
-+
-+extern ASN1_API int
-+  asn1_read_tag (asn1_node_const root, const char *name,
-+		   int *tagValue, int *classValue);
-+
-+extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
-+							    definitions,
-+							    const char
-+							    *oidValue);
-+
-+__LIBTASN1_PURE__
-+extern ASN1_API const char *asn1_check_version (const char *req_version);
-+
-+__LIBTASN1_PURE__
-+extern ASN1_API const char *asn1_strerror (int error);
-+
-+extern ASN1_API void asn1_perror (int error);
-+
-+#define ASN1_MAX_TAG_SIZE 4
-+#define ASN1_MAX_LENGTH_SIZE 9
-+#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE)
-+extern ASN1_API long
-+  asn1_get_length_der (const unsigned char *der, int der_len, int *len);
-+
-+extern ASN1_API long
-+  asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len);
-+
-+extern ASN1_API void
-+  asn1_length_der (unsigned long int len, unsigned char *der, int *der_len);
-+
-+/* Other utility functions. */
-+
-+extern ASN1_API
-+  int asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+				unsigned int _der_len,
-+				const unsigned char **str,
-+				unsigned int *str_len);
-+
-+extern ASN1_API
-+  int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+				unsigned int _der_len,
-+				unsigned char **str,
-+				unsigned int *str_len,
-+				unsigned int *ber_len);
-+
-+extern ASN1_API int
-+  asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
-+			    unsigned int str_len, unsigned char *tl,
-+			    unsigned int *tl_len);
-+
-+extern ASN1_API asn1_node
-+  asn1_find_node (asn1_node_const pointer, const char *name);
-+
-+extern ASN1_API int
-+  asn1_copy_node (asn1_node dst, const char *dst_name,
-+		    asn1_node_const src, const char *src_name);
-+extern ASN1_API asn1_node
-+  asn1_dup_node (asn1_node_const src, const char *src_name);
-+
-+/* Internal and low-level DER utility functions. */
-+
-+extern ASN1_API int
-+  asn1_get_tag_der (const unsigned char *der, int der_len,
-+		      unsigned char *cls, int *len, unsigned long *tag);
-+
-+extern ASN1_API void
-+  asn1_octet_der (const unsigned char *str, int str_len,
-+		    unsigned char *der, int *der_len);
-+
-+extern ASN1_API int
-+  asn1_get_octet_der (const unsigned char *der, int der_len,
-+			int *ret_len, unsigned char *str,
-+			int str_size, int *str_len);
-+
-+extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len,
-+				     unsigned char *der, int *der_len);
-+
-+extern ASN1_API int
-+  asn1_get_bit_der (const unsigned char *der, int der_len,
-+		      int *ret_len, unsigned char *str,
-+		      int str_size, int *bit_len);
-+
-+extern ASN1_API int
-+  asn1_get_object_id_der (const unsigned char *der,
-+                          int der_len, int *ret_len,
-+                          char *str, int str_size);
-+
-+extern ASN1_API int
-+  asn1_object_id_der (const char *str, unsigned char *der, int *der_len,
-+                      unsigned flags);
-+
-+/* Compatibility types */
-+
-+/**
-+ * asn1_retCode:
-+ *
-+ * Type formerly returned by libtasn1 functions.
-+ *
-+ * Deprecated: 3.0: Use int instead.
-+ */
-+typedef int asn1_retCode;
-+
-+/**
-+ * node_asn_struct:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_node instead.
-+ */
-+#define node_asn_struct asn1_node_st
-+
-+/**
-+ * node_asn:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_node instead.
-+ */
-+#define node_asn asn1_node_st
-+
-+/**
-+ * ASN1_TYPE:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_node instead.
-+ */
-+#define ASN1_TYPE asn1_node
-+
-+/**
-+ * ASN1_TYPE_EMPTY:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use NULL instead.
-+ */
-+#define ASN1_TYPE_EMPTY NULL
-+
-+/**
-+ * static_struct_asn:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_static_node instead.
-+ */
-+#define static_struct_asn asn1_static_node_st
-+
-+/**
-+ * ASN1_ARRAY_TYPE:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_static_node instead.
-+ */
-+#define ASN1_ARRAY_TYPE asn1_static_node
-+
-+/**
-+ * asn1_static_node_t:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_static_node instead.
-+ */
-+#define asn1_static_node_t asn1_static_node
-+
-+/**
-+ * node_data_struct:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_data_node_st instead.
-+ */
-+#define node_data_struct asn1_data_node_st
-+
-+/**
-+ * ASN1_DATA_NODE:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_data_node_st instead.
-+ */
-+#define ASN1_DATA_NODE asn1_data_node_st
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif				/* LIBTASN1_H */
-diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE
-new file mode 100644
-index 00000000000..e8b3628db9b
---- /dev/null
-+++ b/grub-core/lib/libtasn1/LICENSE
-@@ -0,0 +1,16 @@
-+LICENSING
-+=========
-+
-+The libtasn1 library is released under the GNU Lesser General Public
-+License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER)
-+for the license terms.
-+
-+The GNU LGPL applies to the main libtasn1 library, while the
-+included applications library are under the GNU GPL version 3.
-+The libtasn1 library is located in the lib directory, while the applications
-+in src/.
-+
-+The documentation in doc/ is under the GNU FDL license 1.3.
-+
-+For any copyright year range specified as YYYY-ZZZZ in this package
-+note that the range specifies every single year in that closed interval.
-diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md
-new file mode 100644
-index 00000000000..50a8642296c
---- /dev/null
-+++ b/grub-core/lib/libtasn1/README.md
-@@ -0,0 +1,91 @@
-+|Branch|CI system|Status|
-+|:----:|:-------:|-----:|
-+|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)|
-+
-+# libtasn1
-+
-+This is GNU Libtasn1, a small ASN.1 library.
-+
-+The C library (libtasn1.*) is licensed under the GNU Lesser General
-+Public License version 2.1 or later.  See the file COPYING.LIB.
-+
-+The command line tool, self tests, examples, and other auxilliary
-+files, are licensed under the GNU General Public License version 3.0
-+or later.  See the file COPYING.
-+
-+## Building the library
-+
-+We require several tools to build the software, including:
-+
-+* [Make](https://www.gnu.org/software/make/)
-+* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later)
-+* [Autoconf](https://www.gnu.org/software/autoconf/)
-+* [Libtool](https://www.gnu.org/software/libtool/)
-+* [Texinfo](https://www.gnu.org/software/texinfo/)
-+* [help2man](http://www.gnu.org/software/help2man/)
-+* [Tar](https://www.gnu.org/software/tar/)
-+* [Gzip](https://www.gnu.org/software/gzip/)
-+* [bison](https://www.gnu.org/software/bison/)
-+* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual)
-+* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual)
-+* [Git](https://git-scm.com/)
-+* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist)
-+* [Valgrind](https://valgrind.org/) (optional)
-+
-+The required software is typically distributed with your operating
-+system, and the instructions for installing them differ.  Here are
-+some hints:
-+
-+gNewSense/Debian/Ubuntu:
-+```
-+sudo apt-get install make git-core autoconf automake libtool
-+sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils
-+sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools
-+```
-+
-+The next step is to run autoreconf, ./configure, etc:
-+
-+```
-+$ ./bootstrap
-+```
-+
-+Then build the project normally:
-+
-+```
-+$ make
-+$ make check
-+```
-+
-+Happy hacking!
-+
-+
-+## Manual
-+
-+The manual is in the `doc/` directory of the release.  You can also browse
-+the manual online at:
-+
-+ - https://gnutls.gitlab.io/libtasn1/
-+
-+
-+## Code coverage report
-+
-+The coverage report is at:
-+
-+ - https://gnutls.gitlab.io/libtasn1/coverage
-+
-+
-+## Issue trackers
-+
-+ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues)
-+ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2)
-+
-+
-+## Homepage
-+
-+The project homepage at the gnu site is at:
-+
-+http://www.gnu.org/software/libtasn1/
-+
-+
-+For any copyright year range specified as YYYY-ZZZZ in this package
-+note that the range specifies every single year in that closed interval.
diff --git a/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch
new file mode 100644
index 0000000..9b2275c
--- /dev/null
+++ b/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch
@@ -0,0 +1,202 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 1 May 2020 20:44:29 +1000
+Subject: [PATCH] libtasn1: changes for grub compatibility
+
+Do a few things to make libtasn1 compile as part of grub:
+
+ - replace strcat. grub removed strcat so replace it with the appropriate
+   calls to memcpy and strlen.
+
+ - replace c_isdigit with grub_isdigit (and don't import c-ctype from
+   gnulib) grub_isdigit provides the same functionality as c_isdigit: it
+   determines if the input is an ASCII digit without regard for locale.
+
+ - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been
+   supported since gcc-2.96. This avoids messing around with gnulib.
+
+ - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our
+   modules. Unconditionally support const and pure attributes and adjust
+   header paths.
+
+ - adjust header paths to "grub/libtasn1.h".
+
+ - replace a 64 bit division with a call to grub_divmod64, preventing
+   creation of __udivdi3 calls on 32 bit platforms.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/libtasn1/lib/decoding.c   | 11 ++++++-----
+ grub-core/lib/libtasn1/lib/element.c    |  3 ++-
+ grub-core/lib/libtasn1/lib/gstr.c       |  4 ++--
+ grub-core/lib/libtasn1/lib/parser_aux.c |  7 ++++---
+ grub-core/lib/libtasn1/lib/int.h        |  4 ++--
+ include/grub/libtasn1.h                 | 26 ++++++--------------------
+ 6 files changed, 22 insertions(+), 33 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
+index 42f9a92b5d4..7856858b272 100644
+--- a/grub-core/lib/libtasn1/lib/decoding.c
++++ b/grub-core/lib/libtasn1/lib/decoding.c
+@@ -32,7 +32,8 @@
+ #include <element.h>
+ #include <limits.h>
+ #include <intprops.h>
+-#include <c-ctype.h>
++
++#define c_isdigit grub_isdigit
+ 
+ #ifdef DEBUG
+ # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
+@@ -2008,8 +2009,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ 	  (p2->type & CONST_ASSIGN))
+ 	{
+ 	  strcpy (name, definitions->name);
+-	  strcat (name, ".");
+-	  strcat (name, p2->name);
++	  memcpy (name + strlen(name), ".", sizeof(" . "));
++	  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
+ 
+ 	  len = sizeof (value);
+ 	  result = asn1_read_value (definitions, name, value, &len);
+@@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ 	      if (p2)
+ 		{
+ 		  strcpy (name, definitions->name);
+-		  strcat (name, ".");
+-		  strcat (name, p2->name);
++		  memcpy (name + strlen(name), ".", sizeof(" . "));
++		  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
+ 
+ 		  result = asn1_create_element (definitions, name, &aux);
+ 		  if (result == ASN1_SUCCESS)
+diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
+index 539008d8e94..ed761ff56bd 100644
+--- a/grub-core/lib/libtasn1/lib/element.c
++++ b/grub-core/lib/libtasn1/lib/element.c
+@@ -30,9 +30,10 @@
+ #include "parser_aux.h"
+ #include <gstr.h>
+ #include "structure.h"
+-#include "c-ctype.h"
+ #include "element.h"
+ 
++#define c_isdigit grub_isdigit
++
+ void
+ _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
+ {
+diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
+index e91a3a151c0..e33875c2c7c 100644
+--- a/grub-core/lib/libtasn1/lib/gstr.c
++++ b/grub-core/lib/libtasn1/lib/gstr.c
+@@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
+ 
+   if (dest_tot_size - dest_size > str_size)
+     {
+-      strcat (dest, src);
++      memcpy (dest + dest_size, src, str_size + 1);
+     }
+   else
+     {
+       if (dest_tot_size - dest_size > 0)
+ 	{
+-	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
++	  memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1);
+ 	  dest[dest_tot_size - 1] = 0;
+ 	}
+     }
+diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
+index d5dbbf8765d..89c9be69dc2 100644
+--- a/grub-core/lib/libtasn1/lib/parser_aux.c
++++ b/grub-core/lib/libtasn1/lib/parser_aux.c
+@@ -26,7 +26,8 @@
+ #include "gstr.h"
+ #include "structure.h"
+ #include "element.h"
+-#include "c-ctype.h"
++
++#define c_isdigit grub_isdigit
+ 
+ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
+ 
+@@ -40,7 +41,7 @@ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not fou
+ #ifdef __clang__
+ __attribute__((no_sanitize("integer")))
+ #endif
+-_GL_ATTRIBUTE_PURE
++__attribute__((__pure__))
+ static unsigned int
+ _asn1_hash_name (const char *x)
+ {
+@@ -634,7 +635,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
+   count = 0;
+   do
+     {
+-      d = val / 10;
++      d = grub_divmod64(val, 10, NULL);
+       r = val - d * 10;
+       temp[start + count] = '0' + (char) r;
+       count++;
+diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
+index ea1625786c1..4a568efee9c 100644
+--- a/grub-core/lib/libtasn1/lib/int.h
++++ b/grub-core/lib/libtasn1/lib/int.h
+@@ -35,7 +35,7 @@
+ #include <sys/types.h>
+ #endif
+ 
+-#include <libtasn1.h>
++#include "grub/libtasn1.h"
+ 
+ #define ASN1_SMALL_VALUE_SIZE 16
+ 
+@@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[];
+ #define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
+ #define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
+ #define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
+-#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
++#define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1)
+ 
+ #if SIZEOF_UNSIGNED_LONG_INT == 8
+ # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
+diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
+index 785eda2ae3f..28dbf16c4e0 100644
+--- a/include/grub/libtasn1.h
++++ b/include/grub/libtasn1.h
+@@ -38,29 +38,15 @@
+ #ifndef LIBTASN1_H
+ #define LIBTASN1_H
+ 
+-#ifndef ASN1_API
+-#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
+-#define ASN1_API __attribute__((__visibility__("default")))
+-#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
+-#define ASN1_API __declspec(dllexport)
+-#elif defined _MSC_VER && ! defined ASN1_STATIC
+-#define ASN1_API __declspec(dllimport)
+-#else
++/* grub: ASN1_API is not used */
+ #define ASN1_API
+-#endif
+-#endif
+ 
+-#ifdef __GNUC__
+-# define __LIBTASN1_CONST__  __attribute__((const))
+-# define __LIBTASN1_PURE__  __attribute__((pure))
+-#else
+-# define __LIBTASN1_CONST__
+-# define __LIBTASN1_PURE__
+-#endif
++/* grub: all our supported compilers support these attributes */
++#define __LIBTASN1_CONST__  __attribute__((const))
++#define __LIBTASN1_PURE__  __attribute__((pure))
+ 
+-#include <sys/types.h>
+-#include <time.h>
+-#include <stdio.h>		/* for FILE* */
++#include <grub/types.h>
++#include <grub/time.h>
+ 
+ #ifdef __cplusplus
+ extern "C"
diff --git a/SOURCES/0361-libtasn1-disable-code-not-needed-in-grub.patch b/SOURCES/0361-libtasn1-disable-code-not-needed-in-grub.patch
deleted file mode 100644
index 00f5588..0000000
--- a/SOURCES/0361-libtasn1-disable-code-not-needed-in-grub.patch
+++ /dev/null
@@ -1,307 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 1 May 2020 17:12:23 +1000
-Subject: [PATCH] libtasn1: disable code not needed in grub
-
-We don't expect to be able to write ASN.1, only read it,
-so we can disable some code.
-
-Do that with #if 0/#endif, rather than deletion. This means
-that the difference between upstream and grub is smaller,
-which should make updating libtasn1 easier in the future.
-
-With these exclusions we also avoid the need for minmax.h,
-which is convenient because it means we don't have to
-import it from gnulib.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/libtasn1/lib/coding.c    | 12 ++++++++++--
- grub-core/lib/libtasn1/lib/decoding.c  |  2 ++
- grub-core/lib/libtasn1/lib/element.c   |  4 ++--
- grub-core/lib/libtasn1/lib/errors.c    |  3 +++
- grub-core/lib/libtasn1/lib/structure.c | 10 ++++++----
- include/grub/libtasn1.h                | 15 +++++++++++++++
- 6 files changed, 38 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
-index 245ea64cf0a..52def598368 100644
---- a/grub-core/lib/libtasn1/lib/coding.c
-+++ b/grub-core/lib/libtasn1/lib/coding.c
-@@ -30,11 +30,11 @@
- #include "parser_aux.h"
- #include <gstr.h>
- #include "element.h"
--#include "minmax.h"
- #include <structure.h>
- 
- #define MAX_TAG_LEN 16
- 
-+#if 0
- /******************************************************/
- /* Function : _asn1_error_description_value_not_found */
- /* Description: creates the ErrorDescription string   */
-@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node,
-   Estrcat (ErrorDescription, "' not found");
- 
- }
-+#endif
- 
- /**
-  * asn1_length_der:
-@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
-   return ASN1_SUCCESS;
- }
- 
-+#if 0
- /******************************************************/
- /* Function : _asn1_time_der                          */
- /* Description: creates the DER coding for a TIME     */
-@@ -281,7 +283,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
- 
-   return ASN1_SUCCESS;
- }
--
-+#endif
- 
- /*
- void
-@@ -520,6 +522,7 @@ asn1_bit_der (const unsigned char *str, int bit_len,
- }
- 
- 
-+#if 0
- /******************************************************/
- /* Function : _asn1_complete_explicit_tag             */
- /* Description: add the length coding to the EXPLICIT */
-@@ -596,6 +599,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
- 
-   return ASN1_SUCCESS;
- }
-+#endif
- 
- const tag_and_class_st _asn1_tags[] = {
-   [ASN1_ETYPE_GENERALSTRING] =
-@@ -648,6 +652,8 @@ const tag_and_class_st _asn1_tags[] = {
- 
- unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
- 
-+
-+#if 0
- /******************************************************/
- /* Function : _asn1_insert_tag_der                    */
- /* Description: creates the DER coding of tags of one */
-@@ -1413,3 +1419,5 @@ error:
-   asn1_delete_structure (&node);
-   return err;
- }
-+
-+#endif
-\ No newline at end of file
-diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
-index ff04eb778cb..42f9a92b5d4 100644
---- a/grub-core/lib/libtasn1/lib/decoding.c
-+++ b/grub-core/lib/libtasn1/lib/decoding.c
-@@ -1613,6 +1613,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
-   return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
- }
- 
-+#if 0
- /**
-  * asn1_der_decoding_element:
-  * @structure: pointer to an ASN1 structure
-@@ -1643,6 +1644,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName,
- {
-   return asn1_der_decoding(structure, ider, len, errorDescription);
- }
-+#endif
- 
- /**
-  * asn1_der_decoding_startEnd:
-diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
-index 997eb2725dc..539008d8e94 100644
---- a/grub-core/lib/libtasn1/lib/element.c
-+++ b/grub-core/lib/libtasn1/lib/element.c
-@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
-   return ASN1_SUCCESS;
- }
- 
--
-+#if 0
- /**
-  * asn1_write_value:
-  * @node_root: pointer to a structure
-@@ -645,7 +645,7 @@ asn1_write_value (asn1_node node_root, const char *name,
- 
-   return ASN1_SUCCESS;
- }
--
-+#endif
- 
- #define PUT_VALUE( ptr, ptr_size, data, data_size) \
- 	*len = data_size; \
-diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
-index cee74daf795..42785e8622b 100644
---- a/grub-core/lib/libtasn1/lib/errors.c
-+++ b/grub-core/lib/libtasn1/lib/errors.c
-@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = {
-   {0, 0}
- };
- 
-+
-+#if 0
- /**
-  * asn1_perror:
-  * @error: is an error returned by a libtasn1 function.
-@@ -73,6 +75,7 @@ asn1_perror (int error)
-   const char *str = asn1_strerror (error);
-   fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
- }
-+#endif
- 
- /**
-  * asn1_strerror:
-diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
-index 8189c56a4c9..fcfde01a393 100644
---- a/grub-core/lib/libtasn1/lib/structure.c
-+++ b/grub-core/lib/libtasn1/lib/structure.c
-@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node)
-   return node->left;
- }
- 
--
-+#if 0
- int
- _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
- 			       char *vector_name)
-@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
- 
-   return ASN1_SUCCESS;
- }
--
-+#endif
- 
- /**
-  * asn1_array2tree:
-@@ -718,7 +718,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name,
-   return res;
- }
- 
--
-+#if 0
- /**
-  * asn1_print_structure:
-  * @out: pointer to the output file (e.g. stdout).
-@@ -1058,7 +1058,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
- 	}
-     }
- }
--
-+#endif
- 
- 
- /**
-@@ -1153,6 +1153,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
-   return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
- }
- 
-+#if 0
- /**
-  * asn1_copy_node:
-  * @dst: Destination asn1 node.
-@@ -1202,6 +1203,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name,
- 
-   return result;
- }
-+#endif
- 
- /**
-  * asn1_dup_node:
-diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
-index 6fd7a30dc35..785eda2ae3f 100644
---- a/include/grub/libtasn1.h
-+++ b/include/grub/libtasn1.h
-@@ -319,6 +319,8 @@ typedef struct asn1_data_node_st asn1_data_node_st;
- /*  Functions definitions          */
- /***********************************/
- 
-+/* These functions are not used in grub and should not be referenced. */
-+#if 0
- extern ASN1_API int
-   asn1_parser2tree (const char *file,
- 		      asn1_node * definitions, char *error_desc);
-@@ -327,14 +329,17 @@ extern ASN1_API int
-   asn1_parser2array (const char *inputFileName,
- 		       const char *outputFileName,
- 		       const char *vectorName, char *error_desc);
-+#endif
- 
- extern ASN1_API int
-   asn1_array2tree (const asn1_static_node * array,
- 		     asn1_node * definitions, char *errorDescription);
- 
-+#if 0
- extern ASN1_API void
-   asn1_print_structure (FILE * out, asn1_node_const structure,
- 			  const char *name, int mode);
-+#endif
- 
- extern ASN1_API int
-   asn1_create_element (asn1_node_const definitions,
-@@ -347,9 +352,11 @@ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int
- extern ASN1_API int
-   asn1_delete_element (asn1_node structure, const char *element_name);
- 
-+#if 0
- extern ASN1_API int
-   asn1_write_value (asn1_node node_root, const char *name,
- 		      const void *ivalue, int len);
-+#endif
- 
- extern ASN1_API int
-   asn1_read_value (asn1_node_const root, const char *name,
-@@ -365,9 +372,11 @@ extern ASN1_API int
- extern ASN1_API int
-   asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
- 
-+#if 0
- extern ASN1_API int
-   asn1_der_coding (asn1_node_const element, const char *name,
- 		     void *ider, int *len, char *ErrorDescription);
-+#endif
- 
- extern ASN1_API int
-   asn1_der_decoding2 (asn1_node *element, const void *ider,
-@@ -378,12 +387,14 @@ extern ASN1_API int
-   asn1_der_decoding (asn1_node * element, const void *ider,
- 		       int ider_len, char *errorDescription);
- 
-+#if 0
- /* Do not use. Use asn1_der_decoding() instead. */
- extern ASN1_API int
-   asn1_der_decoding_element (asn1_node * structure,
- 			       const char *elementName,
- 			       const void *ider, int len,
- 			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
-+#endif
- 
- extern ASN1_API int
-   asn1_der_decoding_startEnd (asn1_node element,
-@@ -408,13 +419,17 @@ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
- 							    const char
- 							    *oidValue);
- 
-+#if 0
- __LIBTASN1_PURE__
- extern ASN1_API const char *asn1_check_version (const char *req_version);
-+#endif
- 
- __LIBTASN1_PURE__
- extern ASN1_API const char *asn1_strerror (int error);
- 
-+#if 0
- extern ASN1_API void asn1_perror (int error);
-+#endif
- 
- #define ASN1_MAX_TAG_SIZE 4
- #define ASN1_MAX_LENGTH_SIZE 9
diff --git a/SOURCES/0362-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0362-libtasn1-changes-for-grub-compatibility.patch
deleted file mode 100644
index 9b2275c..0000000
--- a/SOURCES/0362-libtasn1-changes-for-grub-compatibility.patch
+++ /dev/null
@@ -1,202 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 1 May 2020 20:44:29 +1000
-Subject: [PATCH] libtasn1: changes for grub compatibility
-
-Do a few things to make libtasn1 compile as part of grub:
-
- - replace strcat. grub removed strcat so replace it with the appropriate
-   calls to memcpy and strlen.
-
- - replace c_isdigit with grub_isdigit (and don't import c-ctype from
-   gnulib) grub_isdigit provides the same functionality as c_isdigit: it
-   determines if the input is an ASCII digit without regard for locale.
-
- - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been
-   supported since gcc-2.96. This avoids messing around with gnulib.
-
- - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our
-   modules. Unconditionally support const and pure attributes and adjust
-   header paths.
-
- - adjust header paths to "grub/libtasn1.h".
-
- - replace a 64 bit division with a call to grub_divmod64, preventing
-   creation of __udivdi3 calls on 32 bit platforms.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/libtasn1/lib/decoding.c   | 11 ++++++-----
- grub-core/lib/libtasn1/lib/element.c    |  3 ++-
- grub-core/lib/libtasn1/lib/gstr.c       |  4 ++--
- grub-core/lib/libtasn1/lib/parser_aux.c |  7 ++++---
- grub-core/lib/libtasn1/lib/int.h        |  4 ++--
- include/grub/libtasn1.h                 | 26 ++++++--------------------
- 6 files changed, 22 insertions(+), 33 deletions(-)
-
-diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
-index 42f9a92b5d4..7856858b272 100644
---- a/grub-core/lib/libtasn1/lib/decoding.c
-+++ b/grub-core/lib/libtasn1/lib/decoding.c
-@@ -32,7 +32,8 @@
- #include <element.h>
- #include <limits.h>
- #include <intprops.h>
--#include <c-ctype.h>
-+
-+#define c_isdigit grub_isdigit
- 
- #ifdef DEBUG
- # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
-@@ -2008,8 +2009,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
- 	  (p2->type & CONST_ASSIGN))
- 	{
- 	  strcpy (name, definitions->name);
--	  strcat (name, ".");
--	  strcat (name, p2->name);
-+	  memcpy (name + strlen(name), ".", sizeof(" . "));
-+	  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
- 
- 	  len = sizeof (value);
- 	  result = asn1_read_value (definitions, name, value, &len);
-@@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
- 	      if (p2)
- 		{
- 		  strcpy (name, definitions->name);
--		  strcat (name, ".");
--		  strcat (name, p2->name);
-+		  memcpy (name + strlen(name), ".", sizeof(" . "));
-+		  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
- 
- 		  result = asn1_create_element (definitions, name, &aux);
- 		  if (result == ASN1_SUCCESS)
-diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
-index 539008d8e94..ed761ff56bd 100644
---- a/grub-core/lib/libtasn1/lib/element.c
-+++ b/grub-core/lib/libtasn1/lib/element.c
-@@ -30,9 +30,10 @@
- #include "parser_aux.h"
- #include <gstr.h>
- #include "structure.h"
--#include "c-ctype.h"
- #include "element.h"
- 
-+#define c_isdigit grub_isdigit
-+
- void
- _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
- {
-diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
-index e91a3a151c0..e33875c2c7c 100644
---- a/grub-core/lib/libtasn1/lib/gstr.c
-+++ b/grub-core/lib/libtasn1/lib/gstr.c
-@@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
- 
-   if (dest_tot_size - dest_size > str_size)
-     {
--      strcat (dest, src);
-+      memcpy (dest + dest_size, src, str_size + 1);
-     }
-   else
-     {
-       if (dest_tot_size - dest_size > 0)
- 	{
--	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
-+	  memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1);
- 	  dest[dest_tot_size - 1] = 0;
- 	}
-     }
-diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
-index d5dbbf8765d..89c9be69dc2 100644
---- a/grub-core/lib/libtasn1/lib/parser_aux.c
-+++ b/grub-core/lib/libtasn1/lib/parser_aux.c
-@@ -26,7 +26,8 @@
- #include "gstr.h"
- #include "structure.h"
- #include "element.h"
--#include "c-ctype.h"
-+
-+#define c_isdigit grub_isdigit
- 
- char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
- 
-@@ -40,7 +41,7 @@ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not fou
- #ifdef __clang__
- __attribute__((no_sanitize("integer")))
- #endif
--_GL_ATTRIBUTE_PURE
-+__attribute__((__pure__))
- static unsigned int
- _asn1_hash_name (const char *x)
- {
-@@ -634,7 +635,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
-   count = 0;
-   do
-     {
--      d = val / 10;
-+      d = grub_divmod64(val, 10, NULL);
-       r = val - d * 10;
-       temp[start + count] = '0' + (char) r;
-       count++;
-diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
-index ea1625786c1..4a568efee9c 100644
---- a/grub-core/lib/libtasn1/lib/int.h
-+++ b/grub-core/lib/libtasn1/lib/int.h
-@@ -35,7 +35,7 @@
- #include <sys/types.h>
- #endif
- 
--#include <libtasn1.h>
-+#include "grub/libtasn1.h"
- 
- #define ASN1_SMALL_VALUE_SIZE 16
- 
-@@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[];
- #define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
- #define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
- #define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
--#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
-+#define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1)
- 
- #if SIZEOF_UNSIGNED_LONG_INT == 8
- # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
-diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
-index 785eda2ae3f..28dbf16c4e0 100644
---- a/include/grub/libtasn1.h
-+++ b/include/grub/libtasn1.h
-@@ -38,29 +38,15 @@
- #ifndef LIBTASN1_H
- #define LIBTASN1_H
- 
--#ifndef ASN1_API
--#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
--#define ASN1_API __attribute__((__visibility__("default")))
--#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
--#define ASN1_API __declspec(dllexport)
--#elif defined _MSC_VER && ! defined ASN1_STATIC
--#define ASN1_API __declspec(dllimport)
--#else
-+/* grub: ASN1_API is not used */
- #define ASN1_API
--#endif
--#endif
- 
--#ifdef __GNUC__
--# define __LIBTASN1_CONST__  __attribute__((const))
--# define __LIBTASN1_PURE__  __attribute__((pure))
--#else
--# define __LIBTASN1_CONST__
--# define __LIBTASN1_PURE__
--#endif
-+/* grub: all our supported compilers support these attributes */
-+#define __LIBTASN1_CONST__  __attribute__((const))
-+#define __LIBTASN1_PURE__  __attribute__((pure))
- 
--#include <sys/types.h>
--#include <time.h>
--#include <stdio.h>		/* for FILE* */
-+#include <grub/types.h>
-+#include <grub/time.h>
- 
- #ifdef __cplusplus
- extern "C"
diff --git a/SOURCES/0362-libtasn1-compile-into-asn1-module.patch b/SOURCES/0362-libtasn1-compile-into-asn1-module.patch
new file mode 100644
index 0000000..8fbb427
--- /dev/null
+++ b/SOURCES/0362-libtasn1-compile-into-asn1-module.patch
@@ -0,0 +1,70 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 5 Jun 2020 17:47:25 +1000
+Subject: [PATCH] libtasn1: compile into asn1 module
+
+Create a wrapper file that specifies the module license.
+Set up the makefile so it is built.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def        | 15 +++++++++++++++
+ grub-core/lib/libtasn1_wrap/wrap.c | 26 ++++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+)
+ create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 99615c07b94..c2d922e6d48 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2436,3 +2436,18 @@ module = {
+   common = loader/i386/xen_file64.c;
+   extra_dist = loader/i386/xen_fileXX.c;
+ };
++
++module = {
++  name = asn1;
++  common = lib/libtasn1/lib/decoding.c;
++  common = lib/libtasn1/lib/coding.c;
++  common = lib/libtasn1/lib/element.c;
++  common = lib/libtasn1/lib/structure.c;
++  common = lib/libtasn1/lib/parser_aux.c;
++  common = lib/libtasn1/lib/gstr.c;
++  common = lib/libtasn1/lib/errors.c;
++  common = lib/libtasn1_wrap/wrap.c;
++  cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
++  // -Wno-type-limits comes from libtasn1's configure.ac
++  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
++};
+diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c
+new file mode 100644
+index 00000000000..622ba942e33
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/wrap.c
+@@ -0,0 +1,26 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020 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/dl.h>
++
++/*
++ * libtasn1 is provided under LGPL2.1+, which is compatible
++ * with GPL3+. As Grub as a whole is under GPL3+, this module
++ * is therefore under GPL3+ also.
++ */
++GRUB_MOD_LICENSE ("GPLv3+");
diff --git a/SOURCES/0363-libtasn1-compile-into-asn1-module.patch b/SOURCES/0363-libtasn1-compile-into-asn1-module.patch
deleted file mode 100644
index 8fbb427..0000000
--- a/SOURCES/0363-libtasn1-compile-into-asn1-module.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 5 Jun 2020 17:47:25 +1000
-Subject: [PATCH] libtasn1: compile into asn1 module
-
-Create a wrapper file that specifies the module license.
-Set up the makefile so it is built.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def        | 15 +++++++++++++++
- grub-core/lib/libtasn1_wrap/wrap.c | 26 ++++++++++++++++++++++++++
- 2 files changed, 41 insertions(+)
- create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 99615c07b94..c2d922e6d48 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2436,3 +2436,18 @@ module = {
-   common = loader/i386/xen_file64.c;
-   extra_dist = loader/i386/xen_fileXX.c;
- };
-+
-+module = {
-+  name = asn1;
-+  common = lib/libtasn1/lib/decoding.c;
-+  common = lib/libtasn1/lib/coding.c;
-+  common = lib/libtasn1/lib/element.c;
-+  common = lib/libtasn1/lib/structure.c;
-+  common = lib/libtasn1/lib/parser_aux.c;
-+  common = lib/libtasn1/lib/gstr.c;
-+  common = lib/libtasn1/lib/errors.c;
-+  common = lib/libtasn1_wrap/wrap.c;
-+  cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
-+  // -Wno-type-limits comes from libtasn1's configure.ac
-+  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c
-new file mode 100644
-index 00000000000..622ba942e33
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/wrap.c
-@@ -0,0 +1,26 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020 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/dl.h>
-+
-+/*
-+ * libtasn1 is provided under LGPL2.1+, which is compatible
-+ * with GPL3+. As Grub as a whole is under GPL3+, this module
-+ * is therefore under GPL3+ also.
-+ */
-+GRUB_MOD_LICENSE ("GPLv3+");
diff --git a/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch
new file mode 100644
index 0000000..d777fcd
--- /dev/null
+++ b/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch
@@ -0,0 +1,1455 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 10 Jun 2020 17:48:42 +1000
+Subject: [PATCH] test_asn1: test module for libtasn1
+
+Import tests from libtasn1 that don't use functionality we don't
+import. I have put them here rather than in the libtasn1 directory
+because:
+
+ -  They need much more significant changes to run in the grub
+    context.
+
+ -  I don't expect they will need to be changed when updating
+    libtasn1: I expect the old tests will usually continue to pass on
+    new versions.
+
+This doesn't test the full decoder but that will be exercised in
+test suites for coming patch sets.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ Makefile.util.def                                  |   6 +
+ grub-core/Makefile.core.def                        |  13 ++
+ .../lib/libtasn1_wrap/tests/CVE-2018-1000654.c     |  61 ++++++
+ grub-core/lib/libtasn1_wrap/tests/Test_overflow.c  | 138 ++++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/Test_simple.c    | 207 ++++++++++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/Test_strings.c   | 150 +++++++++++++++
+ .../lib/libtasn1_wrap/tests/object-id-decoding.c   | 116 +++++++++++
+ .../lib/libtasn1_wrap/tests/object-id-encoding.c   | 120 ++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/octet-string.c   | 211 +++++++++++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/reproducers.c    |  81 ++++++++
+ grub-core/lib/libtasn1_wrap/wrap_tests.c           |  75 ++++++++
+ .../tests/CVE-2018-1000654-1_asn1_tab.h            |  32 ++++
+ .../tests/CVE-2018-1000654-2_asn1_tab.h            |  36 ++++
+ grub-core/lib/libtasn1_wrap/wrap_tests.h           |  38 ++++
+ .gitignore                                         |   1 +
+ tests/test_asn1.in                                 |  12 ++
+ 16 files changed, 1297 insertions(+)
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
+ create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h
+ create mode 100644 tests/test_asn1.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 5062a0e50fa..3987d4cdacd 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1275,6 +1275,12 @@ script = {
+   common = tests/syslinux_test.in;
+ };
+ 
++script = {
++  testcase;
++  name = test_asn1;
++  common = tests/test_asn1.in;
++};
++
+ program = {
+   testcase;
+   name = example_unit_test;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index c2d922e6d48..fd1229c6328 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2451,3 +2451,16 @@ module = {
+   // -Wno-type-limits comes from libtasn1's configure.ac
+   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
+ };
++
++module = {
++  name = test_asn1;
++  common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c;
++  common = lib/libtasn1_wrap/tests/object-id-decoding.c;
++  common = lib/libtasn1_wrap/tests/object-id-encoding.c;
++  common = lib/libtasn1_wrap/tests/octet-string.c;
++  common = lib/libtasn1_wrap/tests/reproducers.c;
++  common = lib/libtasn1_wrap/tests/Test_overflow.c;
++  common = lib/libtasn1_wrap/tests/Test_simple.c;
++  common = lib/libtasn1_wrap/tests/Test_strings.c;
++  common = lib/libtasn1_wrap/wrap_tests.c;
++};
+diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
+new file mode 100644
+index 00000000000..534e304521e
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2002-2018 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/****************************************************************/
++/* Description: reproducer for CVE-2018-1000654			*/
++/****************************************************************/
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include "../wrap_tests.h"
++
++#include "CVE-2018-1000654-1_asn1_tab.h"
++#include "CVE-2018-1000654-2_asn1_tab.h"
++
++void
++test_CVE_2018_1000654 (void)
++{
++  int result;
++  asn1_node definitions = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++  result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription);
++  if (result != ASN1_RECURSION)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++
++  result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription);
++  if (result != ASN1_RECURSION)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
+new file mode 100644
+index 00000000000..f48aea0ef8b
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/* Written by Simon Josefsson */
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include "../wrap_tests.h"
++
++void
++test_overflow(void)
++{
++  /* Test that values larger than long are rejected.  This has worked
++     fine with all versions of libtasn1. */
++
++  {
++    unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
++    long l;
++    int len;
++
++    l = asn1_get_length_der (der, sizeof der, &len);
++
++    if (l != -2L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
++	return;
++      }
++  }
++
++  /* Test that values larger than int but smaller than long are
++     rejected.  This limitation was introduced with libtasn1 2.12. */
++#if (GRUB_LONG_MAX > GRUB_INT_MAX)
++    {
++      unsigned long num = ((long) GRUB_UINT_MAX) << 2;
++      unsigned char der[20];
++      int der_len;
++      long l;
++      int len;
++
++      asn1_length_der (num, der, &der_len);
++
++      l = asn1_get_length_der (der, der_len, &len);
++
++      if (l != -2L)
++	{
++	  grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
++		      len);
++	  return;
++	}
++    }
++#endif
++
++  /* Test that values larger than would fit in the input string are
++     rejected.  This problem was fixed in libtasn1 2.12. */
++  {
++    unsigned long num = 64;
++    unsigned char der[20];
++    int der_len;
++    long l;
++    int len;
++
++    asn1_length_der (num, der, &der_len);
++
++    der_len = sizeof (der);
++    l = asn1_get_length_der (der, der_len, &len);
++
++    if (l != -4L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
++		    l, len);
++	return;
++      }
++  }
++
++  /* Test that values larger than would fit in the input string are
++     rejected.  This problem was fixed in libtasn1 2.12. */
++  {
++    unsigned long num = 1073741824;
++    unsigned char der[20];
++    int der_len;
++    long l;
++    int len;
++
++    asn1_length_der (num, der, &der_len);
++
++    der_len = sizeof (der);
++    l = asn1_get_length_der (der, der_len, &len);
++
++    if (l != -4L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
++		    l, len);
++	return;
++      }
++  }
++
++  /* Test that values larger than would fit in the input string are
++     rejected.  This problem was fixed in libtasn1 2.12. */
++  {
++    unsigned long num = 2147483649;
++    unsigned char der[20];
++    int der_len;
++    long l;
++    int len;
++
++    asn1_length_der (num, der, &der_len);
++
++    der_len = sizeof (der);
++    l = asn1_get_length_der (der, der_len, &len);
++
++    if (l != -2L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
++		    l, len);
++	return;
++      }
++  }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
+new file mode 100644
+index 00000000000..9f01006ddf4
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
+@@ -0,0 +1,207 @@
++/*
++ * Copyright (C) 2011-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * Written by Simon Josefsson
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  int bitlen;
++  const char *bitstr;
++  int derlen;
++  const char *der;
++};
++
++static const struct tv tv[] = {
++  {0, "", 2, "\x01\x00"},
++  {1, "\x00", 3, "\x02\x07\x00"},
++  {2, "\x00", 3, "\x02\x06\x00"},
++  {3, "\x00", 3, "\x02\x05\x00"},
++  {4, "\x00", 3, "\x02\x04\x00"},
++  {5, "\x00", 3, "\x02\x03\x00"},
++  {6, "\x00", 3, "\x02\x02\x00"},
++  {7, "\x00", 3, "\x02\x01\x00"},
++  {8, "\x00\x00", 3, "\x02\x00\x00"},
++  {9, "\x00\x00", 4, "\x03\x07\x00\x00"},
++  {10, "\x00\x00", 4, "\x03\x06\x00\x00"},
++  {11, "\x00\x00", 4, "\x03\x05\x00\x00"},
++  {12, "\x00\x00", 4, "\x03\x04\x00\x00"},
++  {13, "\x00\x00", 4, "\x03\x03\x00\x00"},
++  {14, "\x00\x00", 4, "\x03\x02\x00\x00"},
++  {15, "\x00\x00", 4, "\x03\x01\x00\x00"},
++  {16, "\x00\x00", 4, "\x03\x00\x00\x00"},
++  {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"},
++  {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"},
++  {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"},
++  {1, "\xFF", 3, "\x02\x07\x80"},
++  {2, "\xFF", 3, "\x02\x06\xc0"},
++  {3, "\xFF", 3, "\x02\x05\xe0"},
++  {4, "\xFF", 3, "\x02\x04\xf0"},
++  {5, "\xFF", 3, "\x02\x03\xf8"},
++  {6, "\xFF", 3, "\x02\x02\xfc"},
++  {7, "\xFF", 3, "\x02\x01\xfe"},
++  {8, "\xFF\xFF", 3, "\x02\x00\xff"},
++  {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"},
++  {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"},
++  {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"},
++  {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"},
++  {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"},
++  {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"},
++  {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"},
++  {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"},
++  {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"},
++  {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"},
++  {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"},
++};
++
++void
++test_simple (void)
++{
++  int result;
++  unsigned char der[100];
++  unsigned char str[100];
++  int der_len = sizeof (der);
++  int str_size = sizeof (str);
++  int ret_len, bit_len;
++  grub_size_t i;
++
++  /* Dummy test */
++
++  asn1_bit_der (NULL, 0, der, &der_len);
++  result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len);
++  if (result != ASN1_GENERIC_ERROR)
++    {
++      grub_fatal ("asn1_get_bit_der zero\n");
++      return;
++    }
++
++  /* Encode short strings with increasing bit lengths */
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* Encode */
++
++      asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen,
++		    der, &der_len);
++
++#if 0
++      {
++	size_t j;
++	for (j = 0; j < der_len; j++)
++	  printf ("\\x%02x", der[j]);
++	printf ("\n");
++      }
++#endif
++
++      if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0)
++	{
++	  grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i);
++	  return;
++	}
++
++      /* Decode it */
++
++      result = asn1_get_bit_der (der, der_len, &ret_len, str,
++				 str_size, &bit_len);
++      if (result != ASN1_SUCCESS || ret_len != tv[i].derlen
++	  || bit_len != tv[i].bitlen)
++	{
++	  grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result);
++	  return;
++	}
++    }
++
++
++  /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER,
++     and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT
++     STRING value "011011100101110111" can be any of the following,
++     among others, depending on the choice of padding bits, the form
++     of length octets [...]".
++   */
++
++  /* 03 04 06 6e 5d c0  DER encoding */
++
++  grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
++  der_len = 5;
++
++  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
++  if (result != ASN1_SUCCESS || ret_len != 5
++      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
++    {
++      grub_fatal ("asn1_get_bit_der example\n");
++      return;
++    }
++
++  der_len = sizeof (der);
++  asn1_bit_der (str, bit_len, der, &der_len);
++  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++    {
++      grub_fatal ("asn1_bit_der example roundtrip\n");
++      return;
++    }
++
++  /* 03 04 06 6e 5d e0 padded with "100000" */
++
++  grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
++  der_len = 5;
++
++  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
++  if (result != ASN1_SUCCESS || ret_len != 5
++      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0)
++    {
++      grub_fatal ("asn1_get_bit_der example padded\n");
++      return;
++    }
++
++  der_len = sizeof (der);
++  asn1_bit_der (str, bit_len, der, &der_len);
++  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++    {
++      grub_fatal ("asn1_bit_der example roundtrip\n");
++      return;
++    }
++
++  /* 03 81 04 06 6e 5d c0 long form of length octets */
++
++  grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
++  der_len = 6;
++
++  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
++
++  if (result != ASN1_SUCCESS || ret_len != 6
++      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
++    {
++      grub_fatal ("asn1_get_bit_der example long form\n");
++      return;
++    }
++
++  der_len = sizeof (der);
++  asn1_bit_der (str, bit_len, der, &der_len);
++  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++    {
++      grub_fatal ("asn1_bit_der example roundtrip\n");
++      return;
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
+new file mode 100644
+index 00000000000..dbe1474b204
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * Written by Simon Josefsson
++ *
++ */
++
++#include <grub/mm.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/libtasn1.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  unsigned int etype;
++  unsigned int str_len;
++  const void *str;
++  unsigned int der_len;
++  const void *der;
++};
++
++static const struct tv tv[] = {
++  {ASN1_ETYPE_IA5_STRING, 20,
++   "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72",
++   22,
++   "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"},
++  {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73",
++   7, "\x13\x05\x4e\x69\x6b\x6f\x73"},
++  {ASN1_ETYPE_UTF8_STRING, 12, "Αττική",
++   14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"},
++  {ASN1_ETYPE_TELETEX_STRING, 15,
++   "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e",
++   17,
++   "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"},
++  {ASN1_ETYPE_OCTET_STRING, 36,
++   "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A",
++   38,
++   "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"}
++};
++
++#define SSTR(x) sizeof(x)-1,x
++static const struct tv ber[] = {
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")},
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0\xb0\xb0\xb0"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")},
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")},
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")},
++};
++
++void
++test_strings ()
++{
++  int ret;
++  unsigned char tl[ASN1_MAX_TL_SIZE];
++  unsigned int tl_len, der_len, str_len;
++  const unsigned char *str;
++  unsigned char *b;
++  unsigned int i;
++
++  /* Dummy test */
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* Encode */
++      tl_len = sizeof (tl);
++      ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len,
++				    tl, &tl_len);
++      if (ret != ASN1_SUCCESS)
++	{
++	  grub_fatal ("Encoding error in %u: %s\n", i,
++		   asn1_strerror (ret));
++	  return;
++	}
++      der_len = tl_len + tv[i].str_len;
++
++      if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0)
++	{
++	  grub_fatal (
++		   "DER encoding differs in %u! (size: %u, expected: %u)\n",
++		   i, der_len, tv[i].der_len);
++	  return;
++	}
++
++      /* decoding */
++      ret =
++	asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str,
++				&str_len);
++      if (ret != ASN1_SUCCESS)
++	{
++	  grub_fatal ("Decoding error in %u: %s\n", i,
++		   asn1_strerror (ret));
++	  return;
++	}
++
++      if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0)
++	{
++	  grub_fatal (
++		   "DER decoded data differ in %u! (size: %u, expected: %u)\n",
++		   i, der_len, tv[i].str_len);
++	  return;
++	}
++    }
++
++  /* BER decoding */
++  for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++)
++    {
++      /* decoding */
++      ret =
++	asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b,
++				&str_len, NULL);
++      if (ret != ASN1_SUCCESS)
++	{
++	  grub_fatal ("BER decoding error in %u: %s\n", i,
++		   asn1_strerror (ret));
++	  return;
++	}
++
++      if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0)
++	{
++	  grub_fatal (
++		   "BER decoded data differ in %u! (size: %u, expected: %u)\n",
++		   i, str_len, ber[i].str_len);
++	  return;
++	}
++      grub_free(b);
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
+new file mode 100644
+index 00000000000..d367bbfb5a7
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
+@@ -0,0 +1,116 @@
++/*
++ * Copyright (C) 2016 Red Hat, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  int der_len;
++  const unsigned char *der;
++  const char *oid;
++  int expected_error;
++};
++
++static const struct tv tv[] = {
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x80\x37\x03",
++   .oid = "2.999.3",
++   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
++  },
++  {.der_len = 12,
++   .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01",
++   .oid = "1.3.6.1.4.1.2312.9.5.1",
++   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
++  },
++  {.der_len = 6,
++   .der = (void *) "\x06\x04\x01\x02\x03\x04",
++   .oid = "0.1.2.3.4",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x51\x02\x03",
++   .oid = "2.1.2.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x88\x37\x03",
++   .oid = "2.999.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 12,
++   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
++   .oid = "1.3.6.1.4.1.2312.9.5.1",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
++   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der =
++   (void *)
++   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
++   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
++   .expected_error = ASN1_SUCCESS},
++};
++
++void
++test_object_id_decoding (void)
++{
++  char str[128];
++  int ret, ret_len;
++  grub_size_t i;
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* decode */
++      ret =
++	asn1_get_object_id_der (tv[i].der+1,
++				tv[i].der_len-1, &ret_len, str,
++				sizeof (str));
++      if (ret != tv[i].expected_error)
++	{
++	  grub_fatal (
++		   "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
++		   __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error);
++	  return;
++	}
++
++      if (tv[i].expected_error != ASN1_SUCCESS)
++        continue;
++
++      if (ret_len != tv[i].der_len-1)
++	{
++	  grub_fatal (
++		   "%d: iter %lu: error in DER, length returned is %d, had %d\n",
++		   __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1);
++	  return;
++	}
++
++      if (grub_strcmp (tv[i].oid, str) != 0)
++	{
++	  grub_fatal (
++		   "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
++		   __LINE__, (unsigned long) i, str, tv[i].oid);
++	  return;
++	}
++
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
+new file mode 100644
+index 00000000000..3a83b58c59f
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2019 Nikos Mavrogiannopoulos
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  int der_len;
++  const unsigned char *der;
++  const char *oid;
++  int expected_error;
++};
++
++static const struct tv tv[] = {
++  {.der_len = 0,
++   .der = (void *) "",
++   .oid = "5.999.3",
++   .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */
++  },
++  {.der_len = 0,
++   .der = (void *) "",
++   .oid = "0.48.9",
++   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */
++  },
++  {.der_len = 0,
++   .der = (void *) "",
++   .oid = "1.40.9",
++   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */
++  },
++  {.der_len = 4,
++   .der = (void *) "\x06\x02\x4f\x63",
++   .oid = "1.39.99",
++   .expected_error = ASN1_SUCCESS,
++  },
++  {.der_len = 6,
++   .der = (void *) "\x06\x04\x01\x02\x03\x04",
++   .oid = "0.1.2.3.4",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x51\x02\x03",
++   .oid = "2.1.2.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x88\x37\x03",
++   .oid = "2.999.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 12,
++   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
++   .oid = "1.3.6.1.4.1.2312.9.5.1",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
++   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der =
++   (void *)
++   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
++   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
++   .expected_error = ASN1_SUCCESS},
++};
++
++void
++test_object_id_encoding(void)
++{
++  unsigned char der[128];
++  int ret, der_len, i;
++
++  for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++)
++    {
++      der_len = sizeof(der);
++      ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0);
++      if (ret != ASN1_SUCCESS)
++	{
++	  if (ret == tv[i].expected_error)
++	    continue;
++	  grub_fatal (
++		   "%d: iter %lu, encoding of OID failed: %s\n",
++		   __LINE__, (unsigned long) i, asn1_strerror(ret));
++	  return;
++	}
++      else if (ret != tv[i].expected_error)
++        {
++	  grub_fatal (
++		   "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
++		   __LINE__, (unsigned long) i, tv[i].oid);
++          return;
++        }
++
++      if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0)
++	{
++	  grub_fatal (
++		   "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
++		   __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len);
++
++	  return;
++	}
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
+new file mode 100644
+index 00000000000..d8a049e8df0
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
+@@ -0,0 +1,211 @@
++/*
++ * Copyright (C) 2011-2020 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * Written by Simon Josefsson and Nikos Mavrogiannopoulos
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include "../wrap_tests.h"
++
++
++struct tv
++{
++  const char *name;
++  int der_len;
++  const unsigned char *der_str;
++  int len;
++  const unsigned char *string;
++  int expected_error;
++  int ber;
++};
++
++static const struct tv tv[] = {
++  {.name = "primitive octet strings",
++   .der_len = 10,
++   .der_str =
++   (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .len = 8,
++   .string =
++   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .ber = 0},
++  {.der_len = 22,
++   .der_str =
++   (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
++   .len = 20,
++   .string =
++   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"},
++
++  {.name = "long type of length",
++   .der_len = 23,
++   .der_str =
++   (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
++   .len = 20,
++   .string =
++   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27",
++   .ber = 1},
++  {.der_len = 11,
++   .der_str =
++   (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .len = 8,
++   .string =
++   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .ber = 1},
++
++  {.name = "constructed - indefinite",
++   .der_len = 11,
++   .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00",
++   .len = 5,
++   .string = (void*)"\x01\x02\x03\x04\x05",
++   .ber = 1,
++   },
++
++  {.name = "constructed - definite - concat",
++   .der_len = 12,
++   .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f",
++   .len = 6,
++   .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f",
++   .ber = 1,
++   },
++  {.name = "constructed - definite - recursive",
++   .der_len = 15,
++   .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f",
++   .len = 5,
++   .string = (void*)"\x0a\x0b\x0c\x0d\x0f",
++   .ber = 1,
++   },
++  {.name = "constructed - definite - single",
++   .der_len = 7,
++   .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03",
++   .len = 3,
++   .string = (void*)"\x01\x02\x03",
++   .ber = 1,
++   },
++
++  /* a large amount of recursive indefinite encoding */
++  {.name = "a large amount of recursive indefinite encoding",
++   .der_len = 29325,
++   .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80",
++   .len = 0,
++   .ber = 1,
++   .expected_error = ASN1_DER_ERROR
++   }
++};
++
++void
++test_octet_string (void)
++{
++  unsigned char str[100];
++  unsigned char der[100];
++  int der_len = sizeof (der);
++  int str_size = sizeof (str);
++  unsigned char *tmp = NULL;
++  int ret, ret_len;
++  grub_size_t i;
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* Decode */
++
++      if (tv[i].ber == 0)
++	{
++	  str_size = sizeof (str);
++	  ret =
++	    asn1_get_octet_der (tv[i].der_str + 1,
++				tv[i].der_len - 1, &ret_len, str,
++				sizeof (str), &str_size);
++	  if (ret != tv[i].expected_error)
++	    {
++	      grub_fatal (
++		       "%d: asn1_get_octet_der: %s: got %d expected %d\n",
++		       __LINE__, tv[i].name, ret,
++		       tv[i].expected_error);
++	      return;
++	    }
++	  if (tv[i].expected_error)
++	    continue;
++
++	  if (ret_len != tv[i].der_len - 1)
++	    {
++	      grub_fatal (
++		       "%d: error in DER, length returned is %d, had %d\n",
++		       __LINE__, ret_len, tv[i].der_len - 1);
++	      return;
++	    }
++
++	  if (str_size != tv[i].len
++	      || grub_memcmp (tv[i].string, str, tv[i].len) != 0)
++	    {
++	      grub_fatal (
++		       "%d: memcmp: %s: got invalid decoding\n",
++		       __LINE__, tv[i].name);
++
++              return;
++	    }
++
++	  /* Encode */
++	  der_len = sizeof (der);
++	  asn1_octet_der (str, str_size, der, &der_len);
++
++	  if (der_len != tv[i].der_len - 1
++	      || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
++	    {
++	      grub_fatal (
++		       "encoding: %s: got invalid encoding\n",
++		       tv[i].name);
++	      return;
++	    }
++	}
++
++      ret =
++	asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING,
++				tv[i].der_str, tv[i].der_len,
++				&tmp, (unsigned int*)&str_size, (unsigned int*)&der_len);
++      if (ret != tv[i].expected_error)
++	{
++	  grub_fatal (
++		   "%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
++		   __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error));
++	  return;
++	}
++      if (tv[i].expected_error)
++        continue;
++
++      if (der_len != tv[i].der_len)
++	{
++	  grub_fatal (
++		   "%d: error: %s: DER, length returned is %d, had %d\n",
++		   __LINE__, tv[i].name, der_len, tv[i].der_len);
++	  return;
++	}
++
++      if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0)
++	{
++	  grub_fatal (
++		   "%d: memcmp: %s: got invalid decoding\n",
++		   __LINE__, tv[i].name);
++          return;
++	}
++      grub_free (tmp);
++      tmp = NULL;
++
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
+new file mode 100644
+index 00000000000..dc7268d4c6c
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (C) 2019 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * This program 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.
++ *
++ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/****************************************************************/
++/* Description: run reproducers for several fixed issues        */
++/****************************************************************/
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include "../wrap_tests.h"
++
++#define CONST_DOWN        (1U<<29)
++
++/* produces endless loop (fixed by d4b624b2):
++ * The following translates into a single node with all pointers
++ * (right,left,down) set to NULL. */
++const asn1_static_node endless_asn1_tab[] = {
++  { "TEST_TREE", 536875024, NULL },
++  { NULL, 0, NULL }
++};
++
++/* produces memory leak (fixed by f16d1ff9):
++ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1
++ *    at 0x4837B65: calloc (vg_replace_malloc.c:762)
++ *    by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71)
++ *    by 0x4853AAC: asn1_array2tree (structure.c:200)
++ *    by 0x10923B: main (single_node.c:67)
++ */
++const asn1_static_node tab[] = {
++{ "a", CONST_DOWN, "" },
++{ "b", 0, "" },
++{ "c", 0, "" },
++{ NULL, 0, NULL }
++};
++
++void
++test_reproducers (void)
++{
++  int result;
++  asn1_node definitions = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++  result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
++  if (result != ASN1_SUCCESS)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++
++  definitions = NULL;
++  result = asn1_array2tree (tab, &definitions, errorDescription);
++  if (result != ASN1_SUCCESS)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++}
+diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c
+new file mode 100644
+index 00000000000..75fcd21f0d5
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c
+@@ -0,0 +1,75 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020 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/dl.h>
++#include <grub/command.h>
++#include <grub/mm.h>
++#include "wrap_tests.h"
++
++/*
++ * libtasn1 tests - from which this is derived - are provided under GPL3+.
++ */
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_command_t cmd;
++
++static grub_err_t
++grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)),
++		   int argc __attribute__((unused)),
++		   char **args __attribute__((unused)))
++{
++  grub_printf ("test_CVE_2018_1000654\n");
++  test_CVE_2018_1000654 ();
++
++  grub_printf ("test_object_id_decoding\n");
++  test_object_id_decoding ();
++
++  grub_printf ("test_object_id_encoding\n");
++  test_object_id_encoding ();
++
++  grub_printf ("test_octet_string\n");
++  test_octet_string ();
++
++  grub_printf ("test_overflow\n");
++  test_overflow ();
++
++  grub_printf ("test_reproducers\n");
++  test_overflow ();
++
++  grub_printf ("test_simple\n");
++  test_simple ();
++
++  grub_printf ("test_strings\n");
++  test_strings ();
++
++  grub_printf ("ASN.1 self-tests passed\n");
++
++  return GRUB_ERR_NONE;
++}
++
++
++GRUB_MOD_INIT(test_asn1)
++{
++  cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL,
++			       "Run self-tests for the ASN.1 parser.");
++}
++
++GRUB_MOD_FINI(test_asn1)
++{
++  grub_unregister_command (cmd);
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
+new file mode 100644
+index 00000000000..1e7d3d64f55
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
+@@ -0,0 +1,32 @@
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include <grub/libtasn1.h>
++
++const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = {
++  { "TEST_TREE", 536875024, NULL },
++  { NULL, 1610612748, NULL },
++  { "iso", 1073741825, "1"},
++  { "identified-organization", 1073741825, "3"},
++  { "dod", 1073741825, "6"},
++  { "internet", 1073741825, "1"},
++  { "security", 1073741825, "5"},
++  { "mechanisms", 1073741825, "5"},
++  { "pkix", 1073741825, "7"},
++  { "id-mod", 1073741825, "0"},
++  { "id-pkix1-implicit-88", 1, "2"},
++  { "id-xnyTest", 1879048204, NULL },
++  { NULL, 1073741825, "id-ix"},
++  { NULL, 1073741825, "29"},
++  { NULL, 1, "1"},
++  { "id-ix", 1880096780, "OBJECR"},
++  { NULL, 1073741825, "id-ix"},
++  { NULL, 1073741825, "29"},
++  { NULL, 1, "2"},
++  { "id-xnyTest", 805306380, NULL },
++  { NULL, 1073741825, "id-ix"},
++  { NULL, 1073741825, "29"},
++  { NULL, 1, "1"},
++  { NULL, 0, NULL }
++};
+diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
+new file mode 100644
+index 00000000000..e2561e5ec6d
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
+@@ -0,0 +1,36 @@
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include <grub/libtasn1.h>
++
++const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = {
++  { "TEST_TREE", 536875024, NULL },
++  { NULL, 1610612748, NULL },
++  { "iso", 1073741825, "1"},
++  { "identified-organization", 1073741825, "3"},
++  { "dod", 1073741825, "6"},
++  { "internet", 1073741825, "1"},
++  { "security", 1073741825, "5"},
++  { "mechanisms", 1073741825, "5"},
++  { "pkix", 1073741825, "7"},
++  { "id-mod", 1073741825, "0"},
++  { "id-pkix1-implicit-88", 1, "2"},
++  { "id-oneTest", 1879048204, NULL },
++  { NULL, 1073741825, "id-two"},
++  { NULL, 1073741825, "9"},
++  { NULL, 1, "1"},
++  { "id-two", 1879048204, NULL },
++  { NULL, 1073741825, "id-three"},
++  { NULL, 1073741825, "2"},
++  { NULL, 1, "2"},
++  { "id-three", 1879048204, NULL },
++  { NULL, 1073741825, "id-four"},
++  { NULL, 1073741825, "3"},
++  { NULL, 1, "3"},
++  { "id-four", 805306380, NULL },
++  { NULL, 1073741825, "id-two"},
++  { NULL, 1073741825, "3"},
++  { NULL, 1, "3"},
++  { NULL, 0, NULL }
++};
+diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h
+new file mode 100644
+index 00000000000..555e56dd202
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h
+@@ -0,0 +1,38 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020 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/>.
++ */
++
++#ifndef LIBTASN1_WRAP_TESTS_H
++#define LIBTASN1_WRAP_TESTS_H
++
++void test_CVE_2018_1000654 (void);
++
++void test_object_id_encoding (void);
++
++void test_object_id_decoding (void);
++
++void test_octet_string (void);
++
++void test_overflow (void);
++
++void test_reproducers (void);
++
++void test_simple (void);
++
++void test_strings (void);
++
++#endif
+diff --git a/.gitignore b/.gitignore
+index a999024652e..f8c5a51af4e 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -133,4 +133,5 @@ grub-*.tar.*
+ /libgrub_a_init.c
+ /libgrub_a_init.lst
+ /stamp-h.in
++/test_asn1
+ /widthspec.h
+diff --git a/tests/test_asn1.in b/tests/test_asn1.in
+new file mode 100644
+index 00000000000..8173c5c270e
+--- /dev/null
++++ b/tests/test_asn1.in
+@@ -0,0 +1,12 @@
++#! @BUILD_SHEBANG@
++set -e
++
++. "@builddir@/grub-core/modinfo.sh"
++
++out=`echo test_asn1 | @builddir@/grub-shell`
++
++if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then
++  echo "ASN.1 test failure: $out"
++  exit 1
++fi
++
diff --git a/SOURCES/0364-grub-install-support-embedding-x509-certificates.patch b/SOURCES/0364-grub-install-support-embedding-x509-certificates.patch
new file mode 100644
index 0000000..d8f73c2
--- /dev/null
+++ b/SOURCES/0364-grub-install-support-embedding-x509-certificates.patch
@@ -0,0 +1,255 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alastair D'Silva <alastair@d-silva.org>
+Date: Mon, 6 Jul 2020 13:33:04 +1000
+Subject: [PATCH] grub-install: support embedding x509 certificates
+
+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>
+---
+ grub-core/commands/pgp.c    |  2 +-
+ util/grub-install-common.c  | 23 ++++++++++++++++++++++-
+ util/grub-mkimage.c         | 15 +++++++++++++--
+ util/mkimage.c              | 41 ++++++++++++++++++++++++++++++++++++++---
+ include/grub/kernel.h       |  3 ++-
+ include/grub/util/install.h |  7 +++++--
+ 6 files changed, 81 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
+index 75de32c2a00..55d354be0ae 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/util/grub-install-common.c b/util/grub-install-common.c
+index 561e671ff34..fa6b65347ea 100644
+--- a/util/grub-install-common.c
++++ b/util/grub-install-common.c
+@@ -302,6 +302,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 grub_compression_t compression;
+ static size_t appsig_size;
+ 
+@@ -334,6 +336,12 @@ grub_install_parse (int key, char *arg)
+ 			  * (npubkeys + 1));
+       pubkeys[npubkeys++] = xstrdup (arg);
+       return 1;
++    case 'x':
++      x509keys = xrealloc (x509keys,
++			  sizeof (x509keys[0])
++			  * (nx509keys + 1));
++      x509keys[nx509keys++] = xstrdup (arg);
++      return 1;
+ 
+     case GRUB_INSTALL_OPTIONS_VERBOSITY:
+       verbosity++;
+@@ -460,6 +468,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
+     slen += 20 + grub_strlen (*pk);
+ 
++  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
++    slen += 10 + grub_strlen (*pk);
++
+   for (md = modules.entries; *md; md++)
+     {
+       slen += 10 + grub_strlen (*md);
+@@ -488,6 +499,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, "--x509 '");
++      p = grub_stpcpy (p, *pk);
++      *p++ = '\'';
++      *p++ = ' ';
++    }
++
+   for (md = modules.entries; *md; md++)
+     {
+       *p++ = '\'';
+@@ -515,7 +534,9 @@ 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);
+   while (dc--)
+     grub_install_pop_module ();
+diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
+index 9cc767088d3..b05fb827656 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},
++  {"x509",     '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},
+@@ -122,6 +123,8 @@ struct arguments
+   char *dtb;
+   char **pubkeys;
+   size_t npubkeys;
++  char **x509keys;
++  size_t nx509keys;
+   char *font;
+   char *config;
+   int note;
+@@ -202,6 +205,13 @@ 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);
+@@ -317,7 +327,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 a81120f26be..2529de4bb78 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -774,8 +774,10 @@ grub_install_get_image_targets_string (void)
+ 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,
++			     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, grub_compression_t comp, const char *dtb_path)
+ {
+@@ -819,6 +821,19 @@ 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);
+@@ -933,7 +948,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);
+ 
+@@ -942,6 +957,26 @@ 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;
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index 9548d552aad..75a057d4666 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -28,7 +28,8 @@ enum
+   OBJ_TYPE_MEMDISK,
+   OBJ_TYPE_CONFIG,
+   OBJ_TYPE_PREFIX,
+-  OBJ_TYPE_PUBKEY,
++  OBJ_TYPE_GPG_PUBKEY,
++  OBJ_TYPE_X509_PUBKEY,
+   OBJ_TYPE_DTB
+ };
+ 
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index ba5e6a2ea8f..95059285bd4 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -63,6 +63,8 @@
+     /* TRANSLATORS: "embed" is a verb (command description).  "*/	\
+   { "pubkey",   'k', N_("FILE"), 0,					\
+       N_("embed FILE as public key for signature checking"), 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},                                                                 \
+@@ -179,8 +181,9 @@ 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 *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/SOURCES/0364-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0364-test_asn1-test-module-for-libtasn1.patch
deleted file mode 100644
index d777fcd..0000000
--- a/SOURCES/0364-test_asn1-test-module-for-libtasn1.patch
+++ /dev/null
@@ -1,1455 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 10 Jun 2020 17:48:42 +1000
-Subject: [PATCH] test_asn1: test module for libtasn1
-
-Import tests from libtasn1 that don't use functionality we don't
-import. I have put them here rather than in the libtasn1 directory
-because:
-
- -  They need much more significant changes to run in the grub
-    context.
-
- -  I don't expect they will need to be changed when updating
-    libtasn1: I expect the old tests will usually continue to pass on
-    new versions.
-
-This doesn't test the full decoder but that will be exercised in
-test suites for coming patch sets.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- Makefile.util.def                                  |   6 +
- grub-core/Makefile.core.def                        |  13 ++
- .../lib/libtasn1_wrap/tests/CVE-2018-1000654.c     |  61 ++++++
- grub-core/lib/libtasn1_wrap/tests/Test_overflow.c  | 138 ++++++++++++++
- grub-core/lib/libtasn1_wrap/tests/Test_simple.c    | 207 ++++++++++++++++++++
- grub-core/lib/libtasn1_wrap/tests/Test_strings.c   | 150 +++++++++++++++
- .../lib/libtasn1_wrap/tests/object-id-decoding.c   | 116 +++++++++++
- .../lib/libtasn1_wrap/tests/object-id-encoding.c   | 120 ++++++++++++
- grub-core/lib/libtasn1_wrap/tests/octet-string.c   | 211 +++++++++++++++++++++
- grub-core/lib/libtasn1_wrap/tests/reproducers.c    |  81 ++++++++
- grub-core/lib/libtasn1_wrap/wrap_tests.c           |  75 ++++++++
- .../tests/CVE-2018-1000654-1_asn1_tab.h            |  32 ++++
- .../tests/CVE-2018-1000654-2_asn1_tab.h            |  36 ++++
- grub-core/lib/libtasn1_wrap/wrap_tests.h           |  38 ++++
- .gitignore                                         |   1 +
- tests/test_asn1.in                                 |  12 ++
- 16 files changed, 1297 insertions(+)
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c
- create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
- create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h
- create mode 100644 tests/test_asn1.in
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 5062a0e50fa..3987d4cdacd 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -1275,6 +1275,12 @@ script = {
-   common = tests/syslinux_test.in;
- };
- 
-+script = {
-+  testcase;
-+  name = test_asn1;
-+  common = tests/test_asn1.in;
-+};
-+
- program = {
-   testcase;
-   name = example_unit_test;
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index c2d922e6d48..fd1229c6328 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2451,3 +2451,16 @@ module = {
-   // -Wno-type-limits comes from libtasn1's configure.ac
-   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
- };
-+
-+module = {
-+  name = test_asn1;
-+  common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c;
-+  common = lib/libtasn1_wrap/tests/object-id-decoding.c;
-+  common = lib/libtasn1_wrap/tests/object-id-encoding.c;
-+  common = lib/libtasn1_wrap/tests/octet-string.c;
-+  common = lib/libtasn1_wrap/tests/reproducers.c;
-+  common = lib/libtasn1_wrap/tests/Test_overflow.c;
-+  common = lib/libtasn1_wrap/tests/Test_simple.c;
-+  common = lib/libtasn1_wrap/tests/Test_strings.c;
-+  common = lib/libtasn1_wrap/wrap_tests.c;
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
-new file mode 100644
-index 00000000000..534e304521e
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
-@@ -0,0 +1,61 @@
-+/*
-+ * Copyright (C) 2002-2018 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/****************************************************************/
-+/* Description: reproducer for CVE-2018-1000654			*/
-+/****************************************************************/
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/types.h>
-+#include "../wrap_tests.h"
-+
-+#include "CVE-2018-1000654-1_asn1_tab.h"
-+#include "CVE-2018-1000654-2_asn1_tab.h"
-+
-+void
-+test_CVE_2018_1000654 (void)
-+{
-+  int result;
-+  asn1_node definitions = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+  result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription);
-+  if (result != ASN1_RECURSION)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+
-+  result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription);
-+  if (result != ASN1_RECURSION)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
-new file mode 100644
-index 00000000000..f48aea0ef8b
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
-@@ -0,0 +1,138 @@
-+/*
-+ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/* Written by Simon Josefsson */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/types.h>
-+#include "../wrap_tests.h"
-+
-+void
-+test_overflow(void)
-+{
-+  /* Test that values larger than long are rejected.  This has worked
-+     fine with all versions of libtasn1. */
-+
-+  {
-+    unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
-+    long l;
-+    int len;
-+
-+    l = asn1_get_length_der (der, sizeof der, &len);
-+
-+    if (l != -2L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
-+	return;
-+      }
-+  }
-+
-+  /* Test that values larger than int but smaller than long are
-+     rejected.  This limitation was introduced with libtasn1 2.12. */
-+#if (GRUB_LONG_MAX > GRUB_INT_MAX)
-+    {
-+      unsigned long num = ((long) GRUB_UINT_MAX) << 2;
-+      unsigned char der[20];
-+      int der_len;
-+      long l;
-+      int len;
-+
-+      asn1_length_der (num, der, &der_len);
-+
-+      l = asn1_get_length_der (der, der_len, &len);
-+
-+      if (l != -2L)
-+	{
-+	  grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
-+		      len);
-+	  return;
-+	}
-+    }
-+#endif
-+
-+  /* Test that values larger than would fit in the input string are
-+     rejected.  This problem was fixed in libtasn1 2.12. */
-+  {
-+    unsigned long num = 64;
-+    unsigned char der[20];
-+    int der_len;
-+    long l;
-+    int len;
-+
-+    asn1_length_der (num, der, &der_len);
-+
-+    der_len = sizeof (der);
-+    l = asn1_get_length_der (der, der_len, &len);
-+
-+    if (l != -4L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
-+		    l, len);
-+	return;
-+      }
-+  }
-+
-+  /* Test that values larger than would fit in the input string are
-+     rejected.  This problem was fixed in libtasn1 2.12. */
-+  {
-+    unsigned long num = 1073741824;
-+    unsigned char der[20];
-+    int der_len;
-+    long l;
-+    int len;
-+
-+    asn1_length_der (num, der, &der_len);
-+
-+    der_len = sizeof (der);
-+    l = asn1_get_length_der (der, der_len, &len);
-+
-+    if (l != -4L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
-+		    l, len);
-+	return;
-+      }
-+  }
-+
-+  /* Test that values larger than would fit in the input string are
-+     rejected.  This problem was fixed in libtasn1 2.12. */
-+  {
-+    unsigned long num = 2147483649;
-+    unsigned char der[20];
-+    int der_len;
-+    long l;
-+    int len;
-+
-+    asn1_length_der (num, der, &der_len);
-+
-+    der_len = sizeof (der);
-+    l = asn1_get_length_der (der, der_len, &len);
-+
-+    if (l != -2L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
-+		    l, len);
-+	return;
-+      }
-+  }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
-new file mode 100644
-index 00000000000..9f01006ddf4
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
-@@ -0,0 +1,207 @@
-+/*
-+ * Copyright (C) 2011-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Written by Simon Josefsson
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/err.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  int bitlen;
-+  const char *bitstr;
-+  int derlen;
-+  const char *der;
-+};
-+
-+static const struct tv tv[] = {
-+  {0, "", 2, "\x01\x00"},
-+  {1, "\x00", 3, "\x02\x07\x00"},
-+  {2, "\x00", 3, "\x02\x06\x00"},
-+  {3, "\x00", 3, "\x02\x05\x00"},
-+  {4, "\x00", 3, "\x02\x04\x00"},
-+  {5, "\x00", 3, "\x02\x03\x00"},
-+  {6, "\x00", 3, "\x02\x02\x00"},
-+  {7, "\x00", 3, "\x02\x01\x00"},
-+  {8, "\x00\x00", 3, "\x02\x00\x00"},
-+  {9, "\x00\x00", 4, "\x03\x07\x00\x00"},
-+  {10, "\x00\x00", 4, "\x03\x06\x00\x00"},
-+  {11, "\x00\x00", 4, "\x03\x05\x00\x00"},
-+  {12, "\x00\x00", 4, "\x03\x04\x00\x00"},
-+  {13, "\x00\x00", 4, "\x03\x03\x00\x00"},
-+  {14, "\x00\x00", 4, "\x03\x02\x00\x00"},
-+  {15, "\x00\x00", 4, "\x03\x01\x00\x00"},
-+  {16, "\x00\x00", 4, "\x03\x00\x00\x00"},
-+  {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"},
-+  {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"},
-+  {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"},
-+  {1, "\xFF", 3, "\x02\x07\x80"},
-+  {2, "\xFF", 3, "\x02\x06\xc0"},
-+  {3, "\xFF", 3, "\x02\x05\xe0"},
-+  {4, "\xFF", 3, "\x02\x04\xf0"},
-+  {5, "\xFF", 3, "\x02\x03\xf8"},
-+  {6, "\xFF", 3, "\x02\x02\xfc"},
-+  {7, "\xFF", 3, "\x02\x01\xfe"},
-+  {8, "\xFF\xFF", 3, "\x02\x00\xff"},
-+  {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"},
-+  {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"},
-+  {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"},
-+  {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"},
-+  {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"},
-+  {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"},
-+  {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"},
-+  {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"},
-+  {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"},
-+  {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"},
-+  {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"},
-+};
-+
-+void
-+test_simple (void)
-+{
-+  int result;
-+  unsigned char der[100];
-+  unsigned char str[100];
-+  int der_len = sizeof (der);
-+  int str_size = sizeof (str);
-+  int ret_len, bit_len;
-+  grub_size_t i;
-+
-+  /* Dummy test */
-+
-+  asn1_bit_der (NULL, 0, der, &der_len);
-+  result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len);
-+  if (result != ASN1_GENERIC_ERROR)
-+    {
-+      grub_fatal ("asn1_get_bit_der zero\n");
-+      return;
-+    }
-+
-+  /* Encode short strings with increasing bit lengths */
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* Encode */
-+
-+      asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen,
-+		    der, &der_len);
-+
-+#if 0
-+      {
-+	size_t j;
-+	for (j = 0; j < der_len; j++)
-+	  printf ("\\x%02x", der[j]);
-+	printf ("\n");
-+      }
-+#endif
-+
-+      if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0)
-+	{
-+	  grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i);
-+	  return;
-+	}
-+
-+      /* Decode it */
-+
-+      result = asn1_get_bit_der (der, der_len, &ret_len, str,
-+				 str_size, &bit_len);
-+      if (result != ASN1_SUCCESS || ret_len != tv[i].derlen
-+	  || bit_len != tv[i].bitlen)
-+	{
-+	  grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result);
-+	  return;
-+	}
-+    }
-+
-+
-+  /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER,
-+     and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT
-+     STRING value "011011100101110111" can be any of the following,
-+     among others, depending on the choice of padding bits, the form
-+     of length octets [...]".
-+   */
-+
-+  /* 03 04 06 6e 5d c0  DER encoding */
-+
-+  grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
-+  der_len = 5;
-+
-+  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
-+  if (result != ASN1_SUCCESS || ret_len != 5
-+      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
-+    {
-+      grub_fatal ("asn1_get_bit_der example\n");
-+      return;
-+    }
-+
-+  der_len = sizeof (der);
-+  asn1_bit_der (str, bit_len, der, &der_len);
-+  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
-+    {
-+      grub_fatal ("asn1_bit_der example roundtrip\n");
-+      return;
-+    }
-+
-+  /* 03 04 06 6e 5d e0 padded with "100000" */
-+
-+  grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
-+  der_len = 5;
-+
-+  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
-+  if (result != ASN1_SUCCESS || ret_len != 5
-+      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0)
-+    {
-+      grub_fatal ("asn1_get_bit_der example padded\n");
-+      return;
-+    }
-+
-+  der_len = sizeof (der);
-+  asn1_bit_der (str, bit_len, der, &der_len);
-+  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
-+    {
-+      grub_fatal ("asn1_bit_der example roundtrip\n");
-+      return;
-+    }
-+
-+  /* 03 81 04 06 6e 5d c0 long form of length octets */
-+
-+  grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
-+  der_len = 6;
-+
-+  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
-+
-+  if (result != ASN1_SUCCESS || ret_len != 6
-+      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
-+    {
-+      grub_fatal ("asn1_get_bit_der example long form\n");
-+      return;
-+    }
-+
-+  der_len = sizeof (der);
-+  asn1_bit_der (str, bit_len, der, &der_len);
-+  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
-+    {
-+      grub_fatal ("asn1_bit_der example roundtrip\n");
-+      return;
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
-new file mode 100644
-index 00000000000..dbe1474b204
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
-@@ -0,0 +1,150 @@
-+/*
-+ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Written by Simon Josefsson
-+ *
-+ */
-+
-+#include <grub/mm.h>
-+#include <grub/err.h>
-+#include <grub/misc.h>
-+#include <grub/libtasn1.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  unsigned int etype;
-+  unsigned int str_len;
-+  const void *str;
-+  unsigned int der_len;
-+  const void *der;
-+};
-+
-+static const struct tv tv[] = {
-+  {ASN1_ETYPE_IA5_STRING, 20,
-+   "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72",
-+   22,
-+   "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"},
-+  {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73",
-+   7, "\x13\x05\x4e\x69\x6b\x6f\x73"},
-+  {ASN1_ETYPE_UTF8_STRING, 12, "Αττική",
-+   14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"},
-+  {ASN1_ETYPE_TELETEX_STRING, 15,
-+   "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e",
-+   17,
-+   "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"},
-+  {ASN1_ETYPE_OCTET_STRING, 36,
-+   "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A",
-+   38,
-+   "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"}
-+};
-+
-+#define SSTR(x) sizeof(x)-1,x
-+static const struct tv ber[] = {
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")},
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0\xb0\xb0\xb0"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")},
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")},
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")},
-+};
-+
-+void
-+test_strings ()
-+{
-+  int ret;
-+  unsigned char tl[ASN1_MAX_TL_SIZE];
-+  unsigned int tl_len, der_len, str_len;
-+  const unsigned char *str;
-+  unsigned char *b;
-+  unsigned int i;
-+
-+  /* Dummy test */
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* Encode */
-+      tl_len = sizeof (tl);
-+      ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len,
-+				    tl, &tl_len);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  grub_fatal ("Encoding error in %u: %s\n", i,
-+		   asn1_strerror (ret));
-+	  return;
-+	}
-+      der_len = tl_len + tv[i].str_len;
-+
-+      if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "DER encoding differs in %u! (size: %u, expected: %u)\n",
-+		   i, der_len, tv[i].der_len);
-+	  return;
-+	}
-+
-+      /* decoding */
-+      ret =
-+	asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str,
-+				&str_len);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  grub_fatal ("Decoding error in %u: %s\n", i,
-+		   asn1_strerror (ret));
-+	  return;
-+	}
-+
-+      if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "DER decoded data differ in %u! (size: %u, expected: %u)\n",
-+		   i, der_len, tv[i].str_len);
-+	  return;
-+	}
-+    }
-+
-+  /* BER decoding */
-+  for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++)
-+    {
-+      /* decoding */
-+      ret =
-+	asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b,
-+				&str_len, NULL);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  grub_fatal ("BER decoding error in %u: %s\n", i,
-+		   asn1_strerror (ret));
-+	  return;
-+	}
-+
-+      if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "BER decoded data differ in %u! (size: %u, expected: %u)\n",
-+		   i, str_len, ber[i].str_len);
-+	  return;
-+	}
-+      grub_free(b);
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
-new file mode 100644
-index 00000000000..d367bbfb5a7
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
-@@ -0,0 +1,116 @@
-+/*
-+ * Copyright (C) 2016 Red Hat, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/types.h>
-+#include <grub/misc.h>
-+#include <grub/err.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  int der_len;
-+  const unsigned char *der;
-+  const char *oid;
-+  int expected_error;
-+};
-+
-+static const struct tv tv[] = {
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x80\x37\x03",
-+   .oid = "2.999.3",
-+   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
-+  },
-+  {.der_len = 12,
-+   .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01",
-+   .oid = "1.3.6.1.4.1.2312.9.5.1",
-+   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
-+  },
-+  {.der_len = 6,
-+   .der = (void *) "\x06\x04\x01\x02\x03\x04",
-+   .oid = "0.1.2.3.4",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x51\x02\x03",
-+   .oid = "2.1.2.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x88\x37\x03",
-+   .oid = "2.999.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 12,
-+   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
-+   .oid = "1.3.6.1.4.1.2312.9.5.1",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
-+   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der =
-+   (void *)
-+   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
-+   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
-+   .expected_error = ASN1_SUCCESS},
-+};
-+
-+void
-+test_object_id_decoding (void)
-+{
-+  char str[128];
-+  int ret, ret_len;
-+  grub_size_t i;
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* decode */
-+      ret =
-+	asn1_get_object_id_der (tv[i].der+1,
-+				tv[i].der_len-1, &ret_len, str,
-+				sizeof (str));
-+      if (ret != tv[i].expected_error)
-+	{
-+	  grub_fatal (
-+		   "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
-+		   __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error);
-+	  return;
-+	}
-+
-+      if (tv[i].expected_error != ASN1_SUCCESS)
-+        continue;
-+
-+      if (ret_len != tv[i].der_len-1)
-+	{
-+	  grub_fatal (
-+		   "%d: iter %lu: error in DER, length returned is %d, had %d\n",
-+		   __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1);
-+	  return;
-+	}
-+
-+      if (grub_strcmp (tv[i].oid, str) != 0)
-+	{
-+	  grub_fatal (
-+		   "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
-+		   __LINE__, (unsigned long) i, str, tv[i].oid);
-+	  return;
-+	}
-+
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
-new file mode 100644
-index 00000000000..3a83b58c59f
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
-@@ -0,0 +1,120 @@
-+/*
-+ * Copyright (C) 2019 Nikos Mavrogiannopoulos
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/types.h>
-+#include <grub/misc.h>
-+#include <grub/err.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  int der_len;
-+  const unsigned char *der;
-+  const char *oid;
-+  int expected_error;
-+};
-+
-+static const struct tv tv[] = {
-+  {.der_len = 0,
-+   .der = (void *) "",
-+   .oid = "5.999.3",
-+   .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */
-+  },
-+  {.der_len = 0,
-+   .der = (void *) "",
-+   .oid = "0.48.9",
-+   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */
-+  },
-+  {.der_len = 0,
-+   .der = (void *) "",
-+   .oid = "1.40.9",
-+   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */
-+  },
-+  {.der_len = 4,
-+   .der = (void *) "\x06\x02\x4f\x63",
-+   .oid = "1.39.99",
-+   .expected_error = ASN1_SUCCESS,
-+  },
-+  {.der_len = 6,
-+   .der = (void *) "\x06\x04\x01\x02\x03\x04",
-+   .oid = "0.1.2.3.4",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x51\x02\x03",
-+   .oid = "2.1.2.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x88\x37\x03",
-+   .oid = "2.999.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 12,
-+   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
-+   .oid = "1.3.6.1.4.1.2312.9.5.1",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
-+   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der =
-+   (void *)
-+   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
-+   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
-+   .expected_error = ASN1_SUCCESS},
-+};
-+
-+void
-+test_object_id_encoding(void)
-+{
-+  unsigned char der[128];
-+  int ret, der_len, i;
-+
-+  for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++)
-+    {
-+      der_len = sizeof(der);
-+      ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  if (ret == tv[i].expected_error)
-+	    continue;
-+	  grub_fatal (
-+		   "%d: iter %lu, encoding of OID failed: %s\n",
-+		   __LINE__, (unsigned long) i, asn1_strerror(ret));
-+	  return;
-+	}
-+      else if (ret != tv[i].expected_error)
-+        {
-+	  grub_fatal (
-+		   "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
-+		   __LINE__, (unsigned long) i, tv[i].oid);
-+          return;
-+        }
-+
-+      if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
-+		   __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len);
-+
-+	  return;
-+	}
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
-new file mode 100644
-index 00000000000..d8a049e8df0
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
-@@ -0,0 +1,211 @@
-+/*
-+ * Copyright (C) 2011-2020 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Written by Simon Josefsson and Nikos Mavrogiannopoulos
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include "../wrap_tests.h"
-+
-+
-+struct tv
-+{
-+  const char *name;
-+  int der_len;
-+  const unsigned char *der_str;
-+  int len;
-+  const unsigned char *string;
-+  int expected_error;
-+  int ber;
-+};
-+
-+static const struct tv tv[] = {
-+  {.name = "primitive octet strings",
-+   .der_len = 10,
-+   .der_str =
-+   (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .len = 8,
-+   .string =
-+   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .ber = 0},
-+  {.der_len = 22,
-+   .der_str =
-+   (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
-+   .len = 20,
-+   .string =
-+   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"},
-+
-+  {.name = "long type of length",
-+   .der_len = 23,
-+   .der_str =
-+   (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
-+   .len = 20,
-+   .string =
-+   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27",
-+   .ber = 1},
-+  {.der_len = 11,
-+   .der_str =
-+   (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .len = 8,
-+   .string =
-+   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .ber = 1},
-+
-+  {.name = "constructed - indefinite",
-+   .der_len = 11,
-+   .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00",
-+   .len = 5,
-+   .string = (void*)"\x01\x02\x03\x04\x05",
-+   .ber = 1,
-+   },
-+
-+  {.name = "constructed - definite - concat",
-+   .der_len = 12,
-+   .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f",
-+   .len = 6,
-+   .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f",
-+   .ber = 1,
-+   },
-+  {.name = "constructed - definite - recursive",
-+   .der_len = 15,
-+   .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f",
-+   .len = 5,
-+   .string = (void*)"\x0a\x0b\x0c\x0d\x0f",
-+   .ber = 1,
-+   },
-+  {.name = "constructed - definite - single",
-+   .der_len = 7,
-+   .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03",
-+   .len = 3,
-+   .string = (void*)"\x01\x02\x03",
-+   .ber = 1,
-+   },
-+
-+  /* a large amount of recursive indefinite encoding */
-+  {.name = "a large amount of recursive indefinite encoding",
-+   .der_len = 29325,
-+   .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80",
-+   .len = 0,
-+   .ber = 1,
-+   .expected_error = ASN1_DER_ERROR
-+   }
-+};
-+
-+void
-+test_octet_string (void)
-+{
-+  unsigned char str[100];
-+  unsigned char der[100];
-+  int der_len = sizeof (der);
-+  int str_size = sizeof (str);
-+  unsigned char *tmp = NULL;
-+  int ret, ret_len;
-+  grub_size_t i;
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* Decode */
-+
-+      if (tv[i].ber == 0)
-+	{
-+	  str_size = sizeof (str);
-+	  ret =
-+	    asn1_get_octet_der (tv[i].der_str + 1,
-+				tv[i].der_len - 1, &ret_len, str,
-+				sizeof (str), &str_size);
-+	  if (ret != tv[i].expected_error)
-+	    {
-+	      grub_fatal (
-+		       "%d: asn1_get_octet_der: %s: got %d expected %d\n",
-+		       __LINE__, tv[i].name, ret,
-+		       tv[i].expected_error);
-+	      return;
-+	    }
-+	  if (tv[i].expected_error)
-+	    continue;
-+
-+	  if (ret_len != tv[i].der_len - 1)
-+	    {
-+	      grub_fatal (
-+		       "%d: error in DER, length returned is %d, had %d\n",
-+		       __LINE__, ret_len, tv[i].der_len - 1);
-+	      return;
-+	    }
-+
-+	  if (str_size != tv[i].len
-+	      || grub_memcmp (tv[i].string, str, tv[i].len) != 0)
-+	    {
-+	      grub_fatal (
-+		       "%d: memcmp: %s: got invalid decoding\n",
-+		       __LINE__, tv[i].name);
-+
-+              return;
-+	    }
-+
-+	  /* Encode */
-+	  der_len = sizeof (der);
-+	  asn1_octet_der (str, str_size, der, &der_len);
-+
-+	  if (der_len != tv[i].der_len - 1
-+	      || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
-+	    {
-+	      grub_fatal (
-+		       "encoding: %s: got invalid encoding\n",
-+		       tv[i].name);
-+	      return;
-+	    }
-+	}
-+
-+      ret =
-+	asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING,
-+				tv[i].der_str, tv[i].der_len,
-+				&tmp, (unsigned int*)&str_size, (unsigned int*)&der_len);
-+      if (ret != tv[i].expected_error)
-+	{
-+	  grub_fatal (
-+		   "%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
-+		   __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error));
-+	  return;
-+	}
-+      if (tv[i].expected_error)
-+        continue;
-+
-+      if (der_len != tv[i].der_len)
-+	{
-+	  grub_fatal (
-+		   "%d: error: %s: DER, length returned is %d, had %d\n",
-+		   __LINE__, tv[i].name, der_len, tv[i].der_len);
-+	  return;
-+	}
-+
-+      if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0)
-+	{
-+	  grub_fatal (
-+		   "%d: memcmp: %s: got invalid decoding\n",
-+		   __LINE__, tv[i].name);
-+          return;
-+	}
-+      grub_free (tmp);
-+      tmp = NULL;
-+
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
-new file mode 100644
-index 00000000000..dc7268d4c6c
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
-@@ -0,0 +1,81 @@
-+/*
-+ * Copyright (C) 2019 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * This program 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.
-+ *
-+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/****************************************************************/
-+/* Description: run reproducers for several fixed issues        */
-+/****************************************************************/
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include "../wrap_tests.h"
-+
-+#define CONST_DOWN        (1U<<29)
-+
-+/* produces endless loop (fixed by d4b624b2):
-+ * The following translates into a single node with all pointers
-+ * (right,left,down) set to NULL. */
-+const asn1_static_node endless_asn1_tab[] = {
-+  { "TEST_TREE", 536875024, NULL },
-+  { NULL, 0, NULL }
-+};
-+
-+/* produces memory leak (fixed by f16d1ff9):
-+ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1
-+ *    at 0x4837B65: calloc (vg_replace_malloc.c:762)
-+ *    by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71)
-+ *    by 0x4853AAC: asn1_array2tree (structure.c:200)
-+ *    by 0x10923B: main (single_node.c:67)
-+ */
-+const asn1_static_node tab[] = {
-+{ "a", CONST_DOWN, "" },
-+{ "b", 0, "" },
-+{ "c", 0, "" },
-+{ NULL, 0, NULL }
-+};
-+
-+void
-+test_reproducers (void)
-+{
-+  int result;
-+  asn1_node definitions = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+  result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+
-+  definitions = NULL;
-+  result = asn1_array2tree (tab, &definitions, errorDescription);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c
-new file mode 100644
-index 00000000000..75fcd21f0d5
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c
-@@ -0,0 +1,75 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020 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/dl.h>
-+#include <grub/command.h>
-+#include <grub/mm.h>
-+#include "wrap_tests.h"
-+
-+/*
-+ * libtasn1 tests - from which this is derived - are provided under GPL3+.
-+ */
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+static grub_command_t cmd;
-+
-+static grub_err_t
-+grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)),
-+		   int argc __attribute__((unused)),
-+		   char **args __attribute__((unused)))
-+{
-+  grub_printf ("test_CVE_2018_1000654\n");
-+  test_CVE_2018_1000654 ();
-+
-+  grub_printf ("test_object_id_decoding\n");
-+  test_object_id_decoding ();
-+
-+  grub_printf ("test_object_id_encoding\n");
-+  test_object_id_encoding ();
-+
-+  grub_printf ("test_octet_string\n");
-+  test_octet_string ();
-+
-+  grub_printf ("test_overflow\n");
-+  test_overflow ();
-+
-+  grub_printf ("test_reproducers\n");
-+  test_overflow ();
-+
-+  grub_printf ("test_simple\n");
-+  test_simple ();
-+
-+  grub_printf ("test_strings\n");
-+  test_strings ();
-+
-+  grub_printf ("ASN.1 self-tests passed\n");
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+
-+GRUB_MOD_INIT(test_asn1)
-+{
-+  cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL,
-+			       "Run self-tests for the ASN.1 parser.");
-+}
-+
-+GRUB_MOD_FINI(test_asn1)
-+{
-+  grub_unregister_command (cmd);
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
-new file mode 100644
-index 00000000000..1e7d3d64f55
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
-@@ -0,0 +1,32 @@
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include <grub/libtasn1.h>
-+
-+const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = {
-+  { "TEST_TREE", 536875024, NULL },
-+  { NULL, 1610612748, NULL },
-+  { "iso", 1073741825, "1"},
-+  { "identified-organization", 1073741825, "3"},
-+  { "dod", 1073741825, "6"},
-+  { "internet", 1073741825, "1"},
-+  { "security", 1073741825, "5"},
-+  { "mechanisms", 1073741825, "5"},
-+  { "pkix", 1073741825, "7"},
-+  { "id-mod", 1073741825, "0"},
-+  { "id-pkix1-implicit-88", 1, "2"},
-+  { "id-xnyTest", 1879048204, NULL },
-+  { NULL, 1073741825, "id-ix"},
-+  { NULL, 1073741825, "29"},
-+  { NULL, 1, "1"},
-+  { "id-ix", 1880096780, "OBJECR"},
-+  { NULL, 1073741825, "id-ix"},
-+  { NULL, 1073741825, "29"},
-+  { NULL, 1, "2"},
-+  { "id-xnyTest", 805306380, NULL },
-+  { NULL, 1073741825, "id-ix"},
-+  { NULL, 1073741825, "29"},
-+  { NULL, 1, "1"},
-+  { NULL, 0, NULL }
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
-new file mode 100644
-index 00000000000..e2561e5ec6d
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
-@@ -0,0 +1,36 @@
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include <grub/libtasn1.h>
-+
-+const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = {
-+  { "TEST_TREE", 536875024, NULL },
-+  { NULL, 1610612748, NULL },
-+  { "iso", 1073741825, "1"},
-+  { "identified-organization", 1073741825, "3"},
-+  { "dod", 1073741825, "6"},
-+  { "internet", 1073741825, "1"},
-+  { "security", 1073741825, "5"},
-+  { "mechanisms", 1073741825, "5"},
-+  { "pkix", 1073741825, "7"},
-+  { "id-mod", 1073741825, "0"},
-+  { "id-pkix1-implicit-88", 1, "2"},
-+  { "id-oneTest", 1879048204, NULL },
-+  { NULL, 1073741825, "id-two"},
-+  { NULL, 1073741825, "9"},
-+  { NULL, 1, "1"},
-+  { "id-two", 1879048204, NULL },
-+  { NULL, 1073741825, "id-three"},
-+  { NULL, 1073741825, "2"},
-+  { NULL, 1, "2"},
-+  { "id-three", 1879048204, NULL },
-+  { NULL, 1073741825, "id-four"},
-+  { NULL, 1073741825, "3"},
-+  { NULL, 1, "3"},
-+  { "id-four", 805306380, NULL },
-+  { NULL, 1073741825, "id-two"},
-+  { NULL, 1073741825, "3"},
-+  { NULL, 1, "3"},
-+  { NULL, 0, NULL }
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h
-new file mode 100644
-index 00000000000..555e56dd202
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h
-@@ -0,0 +1,38 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020 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/>.
-+ */
-+
-+#ifndef LIBTASN1_WRAP_TESTS_H
-+#define LIBTASN1_WRAP_TESTS_H
-+
-+void test_CVE_2018_1000654 (void);
-+
-+void test_object_id_encoding (void);
-+
-+void test_object_id_decoding (void);
-+
-+void test_octet_string (void);
-+
-+void test_overflow (void);
-+
-+void test_reproducers (void);
-+
-+void test_simple (void);
-+
-+void test_strings (void);
-+
-+#endif
-diff --git a/.gitignore b/.gitignore
-index a999024652e..f8c5a51af4e 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -133,4 +133,5 @@ grub-*.tar.*
- /libgrub_a_init.c
- /libgrub_a_init.lst
- /stamp-h.in
-+/test_asn1
- /widthspec.h
-diff --git a/tests/test_asn1.in b/tests/test_asn1.in
-new file mode 100644
-index 00000000000..8173c5c270e
---- /dev/null
-+++ b/tests/test_asn1.in
-@@ -0,0 +1,12 @@
-+#! @BUILD_SHEBANG@
-+set -e
-+
-+. "@builddir@/grub-core/modinfo.sh"
-+
-+out=`echo test_asn1 | @builddir@/grub-shell`
-+
-+if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then
-+  echo "ASN.1 test failure: $out"
-+  exit 1
-+fi
-+
diff --git a/SOURCES/0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/SOURCES/0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
new file mode 100644
index 0000000..7b7d70c
--- /dev/null
+++ b/SOURCES/0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
@@ -0,0 +1,639 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:35:10 +1000
+Subject: [PATCH] appended signatures: import GNUTLS's ASN.1 description files
+
+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 license is LGPLv2.1+, which is GPLv3 compatible, allowing
+us to import it without issue.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/appendedsig/gnutls_asn1_tab.c | 121 ++++++
+ grub-core/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 00000000000..ddd1314e63b
+--- /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 00000000000..adef69d95ce
+--- /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 }
++};
diff --git a/SOURCES/0365-grub-install-support-embedding-x509-certificates.patch b/SOURCES/0365-grub-install-support-embedding-x509-certificates.patch
deleted file mode 100644
index d8f73c2..0000000
--- a/SOURCES/0365-grub-install-support-embedding-x509-certificates.patch
+++ /dev/null
@@ -1,255 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Alastair D'Silva <alastair@d-silva.org>
-Date: Mon, 6 Jul 2020 13:33:04 +1000
-Subject: [PATCH] grub-install: support embedding x509 certificates
-
-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>
----
- grub-core/commands/pgp.c    |  2 +-
- util/grub-install-common.c  | 23 ++++++++++++++++++++++-
- util/grub-mkimage.c         | 15 +++++++++++++--
- util/mkimage.c              | 41 ++++++++++++++++++++++++++++++++++++++---
- include/grub/kernel.h       |  3 ++-
- include/grub/util/install.h |  7 +++++--
- 6 files changed, 81 insertions(+), 10 deletions(-)
-
-diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
-index 75de32c2a00..55d354be0ae 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/util/grub-install-common.c b/util/grub-install-common.c
-index 561e671ff34..fa6b65347ea 100644
---- a/util/grub-install-common.c
-+++ b/util/grub-install-common.c
-@@ -302,6 +302,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 grub_compression_t compression;
- static size_t appsig_size;
- 
-@@ -334,6 +336,12 @@ grub_install_parse (int key, char *arg)
- 			  * (npubkeys + 1));
-       pubkeys[npubkeys++] = xstrdup (arg);
-       return 1;
-+    case 'x':
-+      x509keys = xrealloc (x509keys,
-+			  sizeof (x509keys[0])
-+			  * (nx509keys + 1));
-+      x509keys[nx509keys++] = xstrdup (arg);
-+      return 1;
- 
-     case GRUB_INSTALL_OPTIONS_VERBOSITY:
-       verbosity++;
-@@ -460,6 +468,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
-   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
-     slen += 20 + grub_strlen (*pk);
- 
-+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
-+    slen += 10 + grub_strlen (*pk);
-+
-   for (md = modules.entries; *md; md++)
-     {
-       slen += 10 + grub_strlen (*md);
-@@ -488,6 +499,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, "--x509 '");
-+      p = grub_stpcpy (p, *pk);
-+      *p++ = '\'';
-+      *p++ = ' ';
-+    }
-+
-   for (md = modules.entries; *md; md++)
-     {
-       *p++ = '\'';
-@@ -515,7 +534,9 @@ 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);
-   while (dc--)
-     grub_install_pop_module ();
-diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
-index 9cc767088d3..b05fb827656 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},
-+  {"x509",     '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},
-@@ -122,6 +123,8 @@ struct arguments
-   char *dtb;
-   char **pubkeys;
-   size_t npubkeys;
-+  char **x509keys;
-+  size_t nx509keys;
-   char *font;
-   char *config;
-   int note;
-@@ -202,6 +205,13 @@ 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);
-@@ -317,7 +327,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 a81120f26be..2529de4bb78 100644
---- a/util/mkimage.c
-+++ b/util/mkimage.c
-@@ -774,8 +774,10 @@ grub_install_get_image_targets_string (void)
- 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,
-+			     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, grub_compression_t comp, const char *dtb_path)
- {
-@@ -819,6 +821,19 @@ 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);
-@@ -933,7 +948,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);
- 
-@@ -942,6 +957,26 @@ 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;
-diff --git a/include/grub/kernel.h b/include/grub/kernel.h
-index 9548d552aad..75a057d4666 100644
---- a/include/grub/kernel.h
-+++ b/include/grub/kernel.h
-@@ -28,7 +28,8 @@ enum
-   OBJ_TYPE_MEMDISK,
-   OBJ_TYPE_CONFIG,
-   OBJ_TYPE_PREFIX,
--  OBJ_TYPE_PUBKEY,
-+  OBJ_TYPE_GPG_PUBKEY,
-+  OBJ_TYPE_X509_PUBKEY,
-   OBJ_TYPE_DTB
- };
- 
-diff --git a/include/grub/util/install.h b/include/grub/util/install.h
-index ba5e6a2ea8f..95059285bd4 100644
---- a/include/grub/util/install.h
-+++ b/include/grub/util/install.h
-@@ -63,6 +63,8 @@
-     /* TRANSLATORS: "embed" is a verb (command description).  "*/	\
-   { "pubkey",   'k', N_("FILE"), 0,					\
-       N_("embed FILE as public key for signature checking"), 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},                                                                 \
-@@ -179,8 +181,9 @@ 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 *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/SOURCES/0366-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/SOURCES/0366-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
deleted file mode 100644
index 7b7d70c..0000000
--- a/SOURCES/0366-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
+++ /dev/null
@@ -1,639 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:35:10 +1000
-Subject: [PATCH] appended signatures: import GNUTLS's ASN.1 description files
-
-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 license is LGPLv2.1+, which is GPLv3 compatible, allowing
-us to import it without issue.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/appendedsig/gnutls_asn1_tab.c | 121 ++++++
- grub-core/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 00000000000..ddd1314e63b
---- /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 00000000000..adef69d95ce
---- /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 }
-+};
diff --git a/SOURCES/0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/SOURCES/0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
new file mode 100644
index 0000000..c638457
--- /dev/null
+++ b/SOURCES/0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
@@ -0,0 +1,1542 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:33:46 +1000
+Subject: [PATCH] appended signatures: parse PKCS#7 signedData and X.509
+ certificates
+
+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.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/appendedsig/asn1util.c    | 102 +++
+ grub-core/commands/appendedsig/pkcs7.c       | 305 +++++++++
+ grub-core/commands/appendedsig/x509.c        | 972 +++++++++++++++++++++++++++
+ grub-core/commands/appendedsig/appendedsig.h | 110 +++
+ 4 files changed, 1489 insertions(+)
+ 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
+ create mode 100644 grub-core/commands/appendedsig/appendedsig.h
+
+diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
+new file mode 100644
+index 00000000000..eff095a9df2
+--- /dev/null
++++ b/grub-core/commands/appendedsig/asn1util.c
+@@ -0,0 +1,102 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  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/gcrypt/gcrypt.h>
++
++#include "appendedsig.h"
++
++asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY;
++asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY;
++
++extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[];
++extern const ASN1_ARRAY_TYPE 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 00000000000..dc6afe203f7
+--- /dev/null
++++ b/grub-core/commands/appendedsig/pkcs7.c
+@@ -0,0 +1,305 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  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>
++
++
++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++/*
++ * RFC 5652 s 5.1
++ */
++const char *signedData_oid = "1.2.840.113549.1.7.2";
++
++/*
++ * RFC 4055 s 2.1
++ */
++const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
++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;
++  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;
++
++  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 != 1)
++    {
++      err =
++	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		    "Only 1 digest algorithm is supported");
++      goto cleanup_signed_part;
++    }
++
++  res =
++    asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid,
++		     &algo_oid_size);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error reading digest algorithm: %s",
++		    asn1_strerror (res));
++      goto cleanup_signed_part;
++    }
++
++  if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
++    {
++      msg->hash = grub_crypto_lookup_md_by_name ("sha512");
++    }
++  else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
++    {
++      msg->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_signed_part;
++    }
++
++  if (!msg->hash)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Hash algorithm for OID %s not loaded", algo_oid);
++      goto cleanup_signed_part;
++    }
++
++  /*
++   * 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 signature */
++  result_buf =
++    grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature",
++				 "signature data", &result_size);
++  if (!result_buf)
++    {
++      err = grub_errno;
++      goto cleanup_signed_part;
++    }
++
++  gcry_err =
++    gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size,
++		   NULL);
++  if (gcry_err != GPG_ERR_NO_ERROR)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error loading signature into MPI structure: %d",
++		    gcry_err);
++      goto cleanup_result;
++    }
++
++cleanup_result:
++  grub_free (result_buf);
++cleanup_signed_part:
++  asn1_delete_structure (&signed_part);
++
++  return err;
++}
++
++grub_err_t
++parse_pkcs7_signedData (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_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)
++{
++  gcry_mpi_release (msg->sig_mpi);
++}
+diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
+new file mode 100644
+index 00000000000..652e4f16870
+--- /dev/null
++++ b/grub-core/commands/appendedsig/x509.c
+@@ -0,0 +1,972 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  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/gcrypt/gcrypt.h>
++
++#include "appendedsig.h"
++
++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++/*
++ * RFC 3279 2.3.1  RSA Keys
++ */
++const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
++
++/*
++ * RFC 5280 Appendix A
++ */
++const char *commonName_oid = "2.5.4.3";
++
++/*
++ * RFC 5280 4.2.1.3 Key Usage
++ */
++const char *keyUsage_oid = "2.5.29.15";
++
++/*
++ * RFC 5280 4.2.1.9 Basic Constraints
++ */
++const char *basicConstraints_oid = "2.5.29.19";
++
++/*
++ * 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 = ASN1_TYPE_EMPTY;
++  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 = 1;
++
++  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;
++    }
++
++  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;
++}
++
++/*
++ * details here
++ */
++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 = 1;
++
++  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;
++    }
++
++  /* Only the first bit is permitted to be set */
++  if (usage != 0x80)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x",
++		    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;
++}
++
++
++/*
++ * 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
++ * }
++ *
++ * We require that a certificate:
++ *  - contain the Digital Signature usage only
++ *  - not be a CA
++ *  - MUST 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;
++  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 != GRUB_ERR_NONE)
++	{
++	  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 ("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);
++    }
++  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
++certificate_import (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_name;
++
++
++  /*
++   * 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_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]);
++}
+diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
+new file mode 100644
+index 00000000000..9792ef3901e
+--- /dev/null
++++ b/grub-core/commands/appendedsig/appendedsig.h
+@@ -0,0 +1,110 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  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 message.
++ *
++ * We make no attempt to match intelligently, so we don't save any info about
++ * the signer. We also support only 1 signerInfo, so we only store a single
++ * MPI for the signature.
++ */
++struct pkcs7_signedData
++{
++  const gcry_md_spec_t *hash;
++  gcry_mpi_t sig_mpi;
++};
++
++
++/* 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
++certificate_import (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 (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/SOURCES/0367-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/SOURCES/0367-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
deleted file mode 100644
index c638457..0000000
--- a/SOURCES/0367-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
+++ /dev/null
@@ -1,1542 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:33:46 +1000
-Subject: [PATCH] appended signatures: parse PKCS#7 signedData and X.509
- certificates
-
-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.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/appendedsig/asn1util.c    | 102 +++
- grub-core/commands/appendedsig/pkcs7.c       | 305 +++++++++
- grub-core/commands/appendedsig/x509.c        | 972 +++++++++++++++++++++++++++
- grub-core/commands/appendedsig/appendedsig.h | 110 +++
- 4 files changed, 1489 insertions(+)
- 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
- create mode 100644 grub-core/commands/appendedsig/appendedsig.h
-
-diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
-new file mode 100644
-index 00000000000..eff095a9df2
---- /dev/null
-+++ b/grub-core/commands/appendedsig/asn1util.c
-@@ -0,0 +1,102 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  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/gcrypt/gcrypt.h>
-+
-+#include "appendedsig.h"
-+
-+asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY;
-+asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY;
-+
-+extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[];
-+extern const ASN1_ARRAY_TYPE 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 00000000000..dc6afe203f7
---- /dev/null
-+++ b/grub-core/commands/appendedsig/pkcs7.c
-@@ -0,0 +1,305 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  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>
-+
-+
-+static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+/*
-+ * RFC 5652 s 5.1
-+ */
-+const char *signedData_oid = "1.2.840.113549.1.7.2";
-+
-+/*
-+ * RFC 4055 s 2.1
-+ */
-+const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
-+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;
-+  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;
-+
-+  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 != 1)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-+		    "Only 1 digest algorithm is supported");
-+      goto cleanup_signed_part;
-+    }
-+
-+  res =
-+    asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid,
-+		     &algo_oid_size);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error reading digest algorithm: %s",
-+		    asn1_strerror (res));
-+      goto cleanup_signed_part;
-+    }
-+
-+  if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
-+    {
-+      msg->hash = grub_crypto_lookup_md_by_name ("sha512");
-+    }
-+  else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
-+    {
-+      msg->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_signed_part;
-+    }
-+
-+  if (!msg->hash)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Hash algorithm for OID %s not loaded", algo_oid);
-+      goto cleanup_signed_part;
-+    }
-+
-+  /*
-+   * 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 signature */
-+  result_buf =
-+    grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature",
-+				 "signature data", &result_size);
-+  if (!result_buf)
-+    {
-+      err = grub_errno;
-+      goto cleanup_signed_part;
-+    }
-+
-+  gcry_err =
-+    gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size,
-+		   NULL);
-+  if (gcry_err != GPG_ERR_NO_ERROR)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error loading signature into MPI structure: %d",
-+		    gcry_err);
-+      goto cleanup_result;
-+    }
-+
-+cleanup_result:
-+  grub_free (result_buf);
-+cleanup_signed_part:
-+  asn1_delete_structure (&signed_part);
-+
-+  return err;
-+}
-+
-+grub_err_t
-+parse_pkcs7_signedData (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_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)
-+{
-+  gcry_mpi_release (msg->sig_mpi);
-+}
-diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
-new file mode 100644
-index 00000000000..652e4f16870
---- /dev/null
-+++ b/grub-core/commands/appendedsig/x509.c
-@@ -0,0 +1,972 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  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/gcrypt/gcrypt.h>
-+
-+#include "appendedsig.h"
-+
-+static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+/*
-+ * RFC 3279 2.3.1  RSA Keys
-+ */
-+const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
-+
-+/*
-+ * RFC 5280 Appendix A
-+ */
-+const char *commonName_oid = "2.5.4.3";
-+
-+/*
-+ * RFC 5280 4.2.1.3 Key Usage
-+ */
-+const char *keyUsage_oid = "2.5.29.15";
-+
-+/*
-+ * RFC 5280 4.2.1.9 Basic Constraints
-+ */
-+const char *basicConstraints_oid = "2.5.29.19";
-+
-+/*
-+ * 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 = ASN1_TYPE_EMPTY;
-+  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 = 1;
-+
-+  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;
-+    }
-+
-+  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;
-+}
-+
-+/*
-+ * details here
-+ */
-+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 = 1;
-+
-+  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;
-+    }
-+
-+  /* Only the first bit is permitted to be set */
-+  if (usage != 0x80)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x",
-+		    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;
-+}
-+
-+
-+/*
-+ * 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
-+ * }
-+ *
-+ * We require that a certificate:
-+ *  - contain the Digital Signature usage only
-+ *  - not be a CA
-+ *  - MUST 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;
-+  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 != GRUB_ERR_NONE)
-+	{
-+	  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 ("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);
-+    }
-+  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
-+certificate_import (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_name;
-+
-+
-+  /*
-+   * 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_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]);
-+}
-diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
-new file mode 100644
-index 00000000000..9792ef3901e
---- /dev/null
-+++ b/grub-core/commands/appendedsig/appendedsig.h
-@@ -0,0 +1,110 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  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 message.
-+ *
-+ * We make no attempt to match intelligently, so we don't save any info about
-+ * the signer. We also support only 1 signerInfo, so we only store a single
-+ * MPI for the signature.
-+ */
-+struct pkcs7_signedData
-+{
-+  const gcry_md_spec_t *hash;
-+  gcry_mpi_t sig_mpi;
-+};
-+
-+
-+/* 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
-+certificate_import (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 (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/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch b/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch
new file mode 100644
index 0000000..52a057c
--- /dev/null
+++ b/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch
@@ -0,0 +1,719 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:35:43 +1000
+Subject: [PATCH] appended signatures: support verifying appended signatures
+
+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 kernels and grub modules have appended
+   signatures. It shares lots of logic with shim-lock verifier about what
+   files need to be verified and what modules are unsafe to have loaded.
+
+ - commands to manage the list of trusted certificates for verification.
+
+Similar to the PGP verifier, if a certificate is embedded in the core
+image, verification will be enforced unless disabled on the the grub
+command line or by load_env.
+
+Thus, as with the PGP verifier, it is not a complete secure-boot solution:
+other mechanisms 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>
+---
+ grub-core/Makefile.core.def                  |  12 +
+ grub-core/commands/appendedsig/appendedsig.c | 644 +++++++++++++++++++++++++++
+ include/grub/file.h                          |   2 +
+ 3 files changed, 658 insertions(+)
+ create mode 100644 grub-core/commands/appendedsig/appendedsig.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index fd1229c6328..1cf6b60f82e 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -921,6 +921,18 @@ 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;
++  cflags = '$(CFLAGS_POSIX)';
++  cppflags = '-I$(srcdir)/lib/posix_wrap';
++};
++
+ module = {
+   name = verifiers;
+   common = commands/verifiers.c;
+diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
+new file mode 100644
+index 00000000000..5d8897be5c8
+--- /dev/null
++++ b/grub-core/commands/appendedsig/appendedsig.c
+@@ -0,0 +1,644 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  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 <grub/libtasn1.h>
++#include <grub/env.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 int check_sigs = 0;
++
++static char *
++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)),
++		    const char *val)
++{
++  check_sigs = (*val == '1') || (*val == 'e');
++  return grub_strdup (check_sigs ? "enforce" : "no");
++}
++
++static grub_err_t
++read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
++{
++  grub_err_t err;
++  grub_uint8_t *buf = NULL;
++  grub_ssize_t read_size;
++  grub_off_t total_read_size = 0;
++  grub_off_t file_size = grub_file_size (f);
++
++
++  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		       N_("Cannot parse a certificate file of unknown size"));
++
++  buf = grub_zalloc (file_size);
++  if (!buf)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("Could not allocate buffer for certificate file contents"));
++
++  while (total_read_size < file_size)
++    {
++      read_size =
++	grub_file_read (f, &buf[total_read_size],
++			file_size - total_read_size);
++      if (read_size < 0)
++	{
++	  err = grub_error (GRUB_ERR_READ_ERROR,
++			    N_("Error reading certificate file"));
++	  goto cleanup_buf;
++	}
++      total_read_size += read_size;
++    }
++
++  err = certificate_import (buf, total_read_size, certificate);
++  if (err != GRUB_ERR_NONE)
++    goto cleanup_buf;
++
++  return GRUB_ERR_NONE;
++
++cleanup_buf:
++  grub_free (buf);
++  return err;
++}
++
++static grub_err_t
++extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize,
++			    struct grub_appended_signature *sig)
++{
++  grub_err_t err;
++  grub_size_t pkcs7_size;
++  grub_size_t remaining_len;
++  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"));
++
++#ifdef GRUB_TARGET_WORDS_BIGENDIAN
++  pkcs7_size = sig->sig_metadata.sig_len;
++#else
++  pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len);
++#endif
++
++  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;
++
++  err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_verify_appended_signature (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;
++
++  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;
++
++  context = grub_zalloc (sig.pkcs7.hash->contextsize);
++  if (!context)
++    return grub_errno;
++
++  sig.pkcs7.hash->init (context);
++  sig.pkcs7.hash->write (context, buf, datasize);
++  sig.pkcs7.hash->final (context);
++  hash = sig.pkcs7.hash->read (context);
++  grub_dprintf ("appendedsig",
++		"data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n",
++		datasize, 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, sig.pkcs7.hash, pk->mpis[0]);
++      if (rc)
++	{
++	  err = grub_error (GRUB_ERR_BAD_SIGNATURE,
++			    N_("Error padding hash for RSA verification: %d"),
++			    rc);
++	  goto cleanup;
++	}
++
++      rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi,
++					 pk->mpis, NULL, NULL);
++      gcry_mpi_release (hashmpi);
++
++      if (rc == 0)
++	{
++	  grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n",
++			pk->subject);
++	  err = GRUB_ERR_NONE;
++	  break;
++	}
++
++      grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n",
++		    pk->subject, rc);
++    }
++
++  /* 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:
++  grub_free (context);
++  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_ssize_t read_size;
++  grub_off_t file_size, total_read_size = 0;
++
++  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;
++    }
++
++  file_size = grub_file_size (f);
++  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		       N_("Cannot verify the signature of a file of unknown size"));
++
++  data = grub_malloc (file_size);
++  if (!data)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("Could not allocate data buffer size "
++		       PRIuGRUB_UINT64_T " for verification"), file_size);
++
++  while (total_read_size < file_size)
++    {
++      read_size =
++	grub_file_read (f, &data[total_read_size],
++			file_size - total_read_size);
++      if (read_size < 0)
++	{
++	  err = grub_error (GRUB_ERR_READ_ERROR,
++			    N_("Error reading file to verify"));
++	  goto cleanup_data;
++	}
++      total_read_size += read_size;
++    }
++
++  err = grub_verify_appended_signature (data, file_size);
++
++cleanup_data:
++  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 %d found - only %d 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, enum grub_file_type type,
++		  void **context __attribute__((unused)),
++		  enum grub_verify_flags *flags)
++{
++  const char *dangerous_mod;
++
++  if (!check_sigs)
++    {
++      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
++      return GRUB_ERR_NONE;
++    }
++
++  switch (type & GRUB_FILE_TYPE_MASK)
++    {
++    case GRUB_FILE_TYPE_GRUB_MODULE:
++      if (grub_is_dangerous_module (io))
++	return grub_error (GRUB_ERR_ACCESS_DENIED,
++			   N_("module cannot be loaded in appended signature mode: %s"),
++			   io->name);
++
++      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
++      return GRUB_ERR_NONE;
++
++    case GRUB_FILE_TYPE_ACPI_TABLE:
++    case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
++      *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
++      return GRUB_ERR_NONE;
++
++    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_MULTIBOOT_KERNEL:
++    case GRUB_FILE_TYPE_BSD_KERNEL:
++    case GRUB_FILE_TYPE_XNU_KERNEL:
++    case GRUB_FILE_TYPE_PLAN9_KERNEL:
++
++      dangerous_mod = grub_dangerous_module_loaded ();
++      if (dangerous_mod)
++	return grub_error (GRUB_ERR_ACCESS_DENIED,
++			   N_("cannot proceed due to dangerous module in memory: %s"),
++			   dangerous_mod);
++
++      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
++      return GRUB_ERR_NONE;
++
++    default:
++      /*
++       * powerpc only supports the linux loader. If you support more,
++       * (especially chain loaded binaries) make sure they're checked!
++       */
++      *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",
++  .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;
++  const char *val;
++
++  val = grub_env_get ("check_appended_signatures");
++  grub_dprintf ("appendedsig", "check_appended_signatures='%s'\n", val);
++
++  if (val && (val[0] == '1' || val[0] == 'e'))
++    check_sigs = 1;
++  else
++    check_sigs = 0;
++
++  grub_trusted_key = NULL;
++
++  grub_register_variable_hook ("check_appended_signatures", 0,
++			       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 ELF module, 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;
++  }
++
++  if (!val || val[0] == '\0')
++    {
++      grub_env_set ("check_appended_signatures",
++		    grub_trusted_key ? "enforce" : "no");
++    }
++
++  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/include/grub/file.h b/include/grub/file.h
+index cbbd294655b..2e337dbd68d 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -82,6 +82,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.  */
diff --git a/SOURCES/0368-appended-signatures-support-verifying-appended-signa.patch b/SOURCES/0368-appended-signatures-support-verifying-appended-signa.patch
deleted file mode 100644
index 52a057c..0000000
--- a/SOURCES/0368-appended-signatures-support-verifying-appended-signa.patch
+++ /dev/null
@@ -1,719 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:35:43 +1000
-Subject: [PATCH] appended signatures: support verifying appended signatures
-
-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 kernels and grub modules have appended
-   signatures. It shares lots of logic with shim-lock verifier about what
-   files need to be verified and what modules are unsafe to have loaded.
-
- - commands to manage the list of trusted certificates for verification.
-
-Similar to the PGP verifier, if a certificate is embedded in the core
-image, verification will be enforced unless disabled on the the grub
-command line or by load_env.
-
-Thus, as with the PGP verifier, it is not a complete secure-boot solution:
-other mechanisms 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>
----
- grub-core/Makefile.core.def                  |  12 +
- grub-core/commands/appendedsig/appendedsig.c | 644 +++++++++++++++++++++++++++
- include/grub/file.h                          |   2 +
- 3 files changed, 658 insertions(+)
- create mode 100644 grub-core/commands/appendedsig/appendedsig.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index fd1229c6328..1cf6b60f82e 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -921,6 +921,18 @@ 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;
-+  cflags = '$(CFLAGS_POSIX)';
-+  cppflags = '-I$(srcdir)/lib/posix_wrap';
-+};
-+
- module = {
-   name = verifiers;
-   common = commands/verifiers.c;
-diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
-new file mode 100644
-index 00000000000..5d8897be5c8
---- /dev/null
-+++ b/grub-core/commands/appendedsig/appendedsig.c
-@@ -0,0 +1,644 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  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 <grub/libtasn1.h>
-+#include <grub/env.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 int check_sigs = 0;
-+
-+static char *
-+grub_env_write_sec (struct grub_env_var *var __attribute__((unused)),
-+		    const char *val)
-+{
-+  check_sigs = (*val == '1') || (*val == 'e');
-+  return grub_strdup (check_sigs ? "enforce" : "no");
-+}
-+
-+static grub_err_t
-+read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
-+{
-+  grub_err_t err;
-+  grub_uint8_t *buf = NULL;
-+  grub_ssize_t read_size;
-+  grub_off_t total_read_size = 0;
-+  grub_off_t file_size = grub_file_size (f);
-+
-+
-+  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		       N_("Cannot parse a certificate file of unknown size"));
-+
-+  buf = grub_zalloc (file_size);
-+  if (!buf)
-+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		       N_("Could not allocate buffer for certificate file contents"));
-+
-+  while (total_read_size < file_size)
-+    {
-+      read_size =
-+	grub_file_read (f, &buf[total_read_size],
-+			file_size - total_read_size);
-+      if (read_size < 0)
-+	{
-+	  err = grub_error (GRUB_ERR_READ_ERROR,
-+			    N_("Error reading certificate file"));
-+	  goto cleanup_buf;
-+	}
-+      total_read_size += read_size;
-+    }
-+
-+  err = certificate_import (buf, total_read_size, certificate);
-+  if (err != GRUB_ERR_NONE)
-+    goto cleanup_buf;
-+
-+  return GRUB_ERR_NONE;
-+
-+cleanup_buf:
-+  grub_free (buf);
-+  return err;
-+}
-+
-+static grub_err_t
-+extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize,
-+			    struct grub_appended_signature *sig)
-+{
-+  grub_err_t err;
-+  grub_size_t pkcs7_size;
-+  grub_size_t remaining_len;
-+  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"));
-+
-+#ifdef GRUB_TARGET_WORDS_BIGENDIAN
-+  pkcs7_size = sig->sig_metadata.sig_len;
-+#else
-+  pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len);
-+#endif
-+
-+  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;
-+
-+  err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
-+  if (err != GRUB_ERR_NONE)
-+    return err;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_verify_appended_signature (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;
-+
-+  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;
-+
-+  context = grub_zalloc (sig.pkcs7.hash->contextsize);
-+  if (!context)
-+    return grub_errno;
-+
-+  sig.pkcs7.hash->init (context);
-+  sig.pkcs7.hash->write (context, buf, datasize);
-+  sig.pkcs7.hash->final (context);
-+  hash = sig.pkcs7.hash->read (context);
-+  grub_dprintf ("appendedsig",
-+		"data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n",
-+		datasize, 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, sig.pkcs7.hash, pk->mpis[0]);
-+      if (rc)
-+	{
-+	  err = grub_error (GRUB_ERR_BAD_SIGNATURE,
-+			    N_("Error padding hash for RSA verification: %d"),
-+			    rc);
-+	  goto cleanup;
-+	}
-+
-+      rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi,
-+					 pk->mpis, NULL, NULL);
-+      gcry_mpi_release (hashmpi);
-+
-+      if (rc == 0)
-+	{
-+	  grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n",
-+			pk->subject);
-+	  err = GRUB_ERR_NONE;
-+	  break;
-+	}
-+
-+      grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n",
-+		    pk->subject, rc);
-+    }
-+
-+  /* 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:
-+  grub_free (context);
-+  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_ssize_t read_size;
-+  grub_off_t file_size, total_read_size = 0;
-+
-+  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;
-+    }
-+
-+  file_size = grub_file_size (f);
-+  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		       N_("Cannot verify the signature of a file of unknown size"));
-+
-+  data = grub_malloc (file_size);
-+  if (!data)
-+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		       N_("Could not allocate data buffer size "
-+		       PRIuGRUB_UINT64_T " for verification"), file_size);
-+
-+  while (total_read_size < file_size)
-+    {
-+      read_size =
-+	grub_file_read (f, &data[total_read_size],
-+			file_size - total_read_size);
-+      if (read_size < 0)
-+	{
-+	  err = grub_error (GRUB_ERR_READ_ERROR,
-+			    N_("Error reading file to verify"));
-+	  goto cleanup_data;
-+	}
-+      total_read_size += read_size;
-+    }
-+
-+  err = grub_verify_appended_signature (data, file_size);
-+
-+cleanup_data:
-+  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 %d found - only %d 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, enum grub_file_type type,
-+		  void **context __attribute__((unused)),
-+		  enum grub_verify_flags *flags)
-+{
-+  const char *dangerous_mod;
-+
-+  if (!check_sigs)
-+    {
-+      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
-+      return GRUB_ERR_NONE;
-+    }
-+
-+  switch (type & GRUB_FILE_TYPE_MASK)
-+    {
-+    case GRUB_FILE_TYPE_GRUB_MODULE:
-+      if (grub_is_dangerous_module (io))
-+	return grub_error (GRUB_ERR_ACCESS_DENIED,
-+			   N_("module cannot be loaded in appended signature mode: %s"),
-+			   io->name);
-+
-+      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
-+      return GRUB_ERR_NONE;
-+
-+    case GRUB_FILE_TYPE_ACPI_TABLE:
-+    case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
-+      *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
-+      return GRUB_ERR_NONE;
-+
-+    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_MULTIBOOT_KERNEL:
-+    case GRUB_FILE_TYPE_BSD_KERNEL:
-+    case GRUB_FILE_TYPE_XNU_KERNEL:
-+    case GRUB_FILE_TYPE_PLAN9_KERNEL:
-+
-+      dangerous_mod = grub_dangerous_module_loaded ();
-+      if (dangerous_mod)
-+	return grub_error (GRUB_ERR_ACCESS_DENIED,
-+			   N_("cannot proceed due to dangerous module in memory: %s"),
-+			   dangerous_mod);
-+
-+      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
-+      return GRUB_ERR_NONE;
-+
-+    default:
-+      /*
-+       * powerpc only supports the linux loader. If you support more,
-+       * (especially chain loaded binaries) make sure they're checked!
-+       */
-+      *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",
-+  .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;
-+  const char *val;
-+
-+  val = grub_env_get ("check_appended_signatures");
-+  grub_dprintf ("appendedsig", "check_appended_signatures='%s'\n", val);
-+
-+  if (val && (val[0] == '1' || val[0] == 'e'))
-+    check_sigs = 1;
-+  else
-+    check_sigs = 0;
-+
-+  grub_trusted_key = NULL;
-+
-+  grub_register_variable_hook ("check_appended_signatures", 0,
-+			       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 ELF module, 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;
-+  }
-+
-+  if (!val || val[0] == '\0')
-+    {
-+      grub_env_set ("check_appended_signatures",
-+		    grub_trusted_key ? "enforce" : "no");
-+    }
-+
-+  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/include/grub/file.h b/include/grub/file.h
-index cbbd294655b..2e337dbd68d 100644
---- a/include/grub/file.h
-+++ b/include/grub/file.h
-@@ -82,6 +82,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.  */
diff --git a/SOURCES/0368-appended-signatures-verification-tests.patch b/SOURCES/0368-appended-signatures-verification-tests.patch
new file mode 100644
index 0000000..db1aa9b
--- /dev/null
+++ b/SOURCES/0368-appended-signatures-verification-tests.patch
@@ -0,0 +1,897 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:31:02 +1000
+Subject: [PATCH] appended signatures: verification tests
+
+These tests are run through all_functional_test and test a range
+of commands and behaviours.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def               |   6 +
+ grub-core/tests/appended_signature_test.c | 281 +++++++++++++++
+ grub-core/tests/lib/functional_test.c     |   1 +
+ grub-core/tests/appended_signatures.h     | 557 ++++++++++++++++++++++++++++++
+ 4 files changed, 845 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 1cf6b60f82e..8914083d13f 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2040,6 +2040,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 00000000000..88a485200d8
+--- /dev/null
++++ b/grub-core/tests/appended_signature_test.c
+@@ -0,0 +1,281 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  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 DEFINE_TEST_CASE(case_name) \
++static char * \
++get_ ## case_name (grub_size_t *sz) \
++{ \
++  char *ret; \
++  *sz = case_name ## _len; \
++  ret = grub_malloc (*sz); \
++  if (ret) \
++    grub_memcpy (ret, case_name, *sz); \
++  return ret; \
++} \
++\
++static struct grub_procfs_entry case_name ## _entry = \
++{ \
++  .name = #case_name, \
++  .get_contents = get_ ## 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);
++
++static char *
++get_certificate_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate_der_entry = {
++  .name = "certificate.der",
++  .get_contents = get_certificate_der
++};
++
++static char *
++get_certificate2_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate2_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate2_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate2_der_entry = {
++  .name = "certificate2.der",
++  .get_contents = get_certificate2_der
++};
++
++static char *
++get_certificate_printable_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate_printable_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate_printable_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate_printable_der_entry = {
++  .name = "certificate_printable.der",
++  .get_contents = get_certificate_printable_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 *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);
++
++  cmd_trust = grub_command_find ("trust_certificate");
++  if (!cmd_trust)
++    {
++      grub_test_assert (0, "can't find command `%s'", "trust_certificate");
++      return;
++    }
++  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");
++
++  DO_TEST (hi_signed, 1);
++  DO_TEST (hi_signed_sha256, 1);
++  DO_TEST (hj_signed, 0);
++  DO_TEST (short_msg, 0);
++  DO_TEST (unsigned_msg, 0);
++
++  /*
++   * 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);
++
++  /*
++   * 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);
++
++  /*
++   * 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);
++
++  /*
++   * Lastly, check a certificate that uses printableString rather than
++   * utf8String loads properly.
++   */
++  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "distrusting printable certificate 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_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
+diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
+index 96781fb39b5..403fa5c789a 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");
+diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
+new file mode 100644
+index 00000000000..aa3dc6278e3
+--- /dev/null
++++ b/grub-core/tests/appended_signatures.h
+@@ -0,0 +1,557 @@
++unsigned char certificate_der[] = {
++  0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01,
++  0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
++  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
++  0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04,
++  0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d,
++  0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
++  0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e,
++  0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30,
++  0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f,
++  0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32,
++  0x30, 0x37, 0x5a, 0x30, 0x52, 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, 0x31, 0x1d, 0x30, 0x1b,
++  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
++  0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e,
++  0x6e, 0x65, 0x74, 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,
++  0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61,
++  0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72,
++  0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d,
++  0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98,
++  0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e,
++  0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b,
++  0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12,
++  0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78,
++  0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c,
++  0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9,
++  0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97,
++  0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e,
++  0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c,
++  0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3,
++  0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f,
++  0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc,
++  0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64,
++  0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93,
++  0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d,
++  0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72,
++  0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2,
++  0x32, 0x38, 0x11, 0xb1, 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, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf,
++  0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30,
++  0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
++  0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4,
++  0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
++  0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47,
++  0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf,
++  0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49,
++  0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13,
++  0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4,
++  0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00,
++  0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1,
++  0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79,
++  0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e,
++  0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83,
++  0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3,
++  0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d,
++  0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97,
++  0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d,
++  0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf,
++  0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3,
++  0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b,
++  0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9,
++  0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e,
++  0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46,
++  0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49,
++  0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07
++};
++unsigned int certificate_der_len = 908;
++
++unsigned char hi_signed[] = {
++  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
++  0x01, 0xad, 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, 0x01,
++  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
++  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
++  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
++  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
++  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
++  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
++  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
++  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
++  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
++  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
++  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
++  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
++  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
++  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
++  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
++  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
++  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
++  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
++  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
++  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
++  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
++  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
++  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
++  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
++  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
++  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495;
++
++unsigned char hj_signed[] = {
++  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
++  0x01, 0xad, 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, 0x01,
++  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
++  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
++  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
++  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
++  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
++  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
++  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
++  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
++  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
++  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
++  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
++  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
++  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
++  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
++  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
++  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
++  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
++  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
++  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
++  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
++  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
++  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
++  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
++  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
++  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
++  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495;
++
++unsigned char hi_signed_sha256[] = {
++  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
++  0x01, 0xad, 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, 0x01,
++  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
++  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
++  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
++  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21,
++  0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26,
++  0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3,
++  0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4,
++  0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80,
++  0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f,
++  0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f,
++  0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73,
++  0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0,
++  0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d,
++  0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47,
++  0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b,
++  0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf,
++  0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0,
++  0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a,
++  0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f,
++  0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09,
++  0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2,
++  0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b,
++  0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44,
++  0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93,
++  0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00,
++  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495;
++
++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 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;
diff --git a/SOURCES/0369-appended-signatures-documentation.patch b/SOURCES/0369-appended-signatures-documentation.patch
new file mode 100644
index 0000000..82f50de
--- /dev/null
+++ b/SOURCES/0369-appended-signatures-documentation.patch
@@ -0,0 +1,329 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 1 Oct 2020 13:02:09 +1000
+Subject: [PATCH] appended signatures: documentation
+
+This explains how appended signatures can be used to form part of
+a secure boot chain, and documents the commands and variables
+introduced.
+
+(docs: s/grub/grub2/)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 172 insertions(+), 13 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index a833364d5ff..97f0f47e082 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -3160,6 +3160,7 @@ These variables have special meaning to GRUB.
+ 
+ @menu
+ * biosnum::
++* check_appended_signatures::
+ * check_signatures::
+ * chosen::
+ * cmdpath::
+@@ -3219,11 +3220,18 @@ 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
+@@ -3937,6 +3945,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
+ * eval::                        Evaluate agruments as GRUB commands
+@@ -3953,6 +3962,7 @@ you forget a command, you can run the command @command{help}
+ * keystatus::                   Check key modifier status
+ * linux::                       Load a Linux kernel
+ * linux16::                     Load a Linux kernel (16-bit mode)
++* 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
+@@ -3989,9 +3999,11 @@ you forget a command, you can run the command @command{help}
+ * test::                        Check file types and compare values
+ * 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
+ * uppermem::                    Set the upper memory size
+ @comment * vbeinfo::                     List available video modes
++* verify_appended::             Verify appended digital signature
+ * verify_detached::             Verify detached digital signature
+ * videoinfo::                   List available video modes
+ @comment * xen_*::              Xen boot commands for AArch64
+@@ -4282,9 +4294,28 @@ 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
+ @subsection drivemap
+ 
+@@ -4542,6 +4573,21 @@ This command is only available on x86 systems.
+ @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
+ 
+@@ -4561,7 +4607,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
+ 
+@@ -4596,8 +4642,12 @@ 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
+ 
+ 
+@@ -4883,7 +4933,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
+ 
+ 
+@@ -5208,11 +5258,31 @@ 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 an 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
+ 
+@@ -5237,6 +5307,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
+@@ -5255,7 +5337,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
+@@ -5601,9 +5683,10 @@ 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
+-* 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
++* Signing GRUB itself::                Ensuring the integrity of the GRUB core image
+ @end menu
+ 
+ @node Authentication and authorisation
+@@ -5676,8 +5759,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.
+@@ -5760,6 +5843,82 @@ 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 Signing GRUB itself
+ @section Signing GRUB itself
+ 
diff --git a/SOURCES/0369-appended-signatures-verification-tests.patch b/SOURCES/0369-appended-signatures-verification-tests.patch
deleted file mode 100644
index db1aa9b..0000000
--- a/SOURCES/0369-appended-signatures-verification-tests.patch
+++ /dev/null
@@ -1,897 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:31:02 +1000
-Subject: [PATCH] appended signatures: verification tests
-
-These tests are run through all_functional_test and test a range
-of commands and behaviours.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def               |   6 +
- grub-core/tests/appended_signature_test.c | 281 +++++++++++++++
- grub-core/tests/lib/functional_test.c     |   1 +
- grub-core/tests/appended_signatures.h     | 557 ++++++++++++++++++++++++++++++
- 4 files changed, 845 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 1cf6b60f82e..8914083d13f 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2040,6 +2040,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 00000000000..88a485200d8
---- /dev/null
-+++ b/grub-core/tests/appended_signature_test.c
-@@ -0,0 +1,281 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  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 DEFINE_TEST_CASE(case_name) \
-+static char * \
-+get_ ## case_name (grub_size_t *sz) \
-+{ \
-+  char *ret; \
-+  *sz = case_name ## _len; \
-+  ret = grub_malloc (*sz); \
-+  if (ret) \
-+    grub_memcpy (ret, case_name, *sz); \
-+  return ret; \
-+} \
-+\
-+static struct grub_procfs_entry case_name ## _entry = \
-+{ \
-+  .name = #case_name, \
-+  .get_contents = get_ ## 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);
-+
-+static char *
-+get_certificate_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate_der_entry = {
-+  .name = "certificate.der",
-+  .get_contents = get_certificate_der
-+};
-+
-+static char *
-+get_certificate2_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate2_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate2_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate2_der_entry = {
-+  .name = "certificate2.der",
-+  .get_contents = get_certificate2_der
-+};
-+
-+static char *
-+get_certificate_printable_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate_printable_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate_printable_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate_printable_der_entry = {
-+  .name = "certificate_printable.der",
-+  .get_contents = get_certificate_printable_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 *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);
-+
-+  cmd_trust = grub_command_find ("trust_certificate");
-+  if (!cmd_trust)
-+    {
-+      grub_test_assert (0, "can't find command `%s'", "trust_certificate");
-+      return;
-+    }
-+  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");
-+
-+  DO_TEST (hi_signed, 1);
-+  DO_TEST (hi_signed_sha256, 1);
-+  DO_TEST (hj_signed, 0);
-+  DO_TEST (short_msg, 0);
-+  DO_TEST (unsigned_msg, 0);
-+
-+  /*
-+   * 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);
-+
-+  /*
-+   * 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);
-+
-+  /*
-+   * 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);
-+
-+  /*
-+   * Lastly, check a certificate that uses printableString rather than
-+   * utf8String loads properly.
-+   */
-+  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "distrusting printable certificate 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_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
-diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
-index 96781fb39b5..403fa5c789a 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");
-diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
-new file mode 100644
-index 00000000000..aa3dc6278e3
---- /dev/null
-+++ b/grub-core/tests/appended_signatures.h
-@@ -0,0 +1,557 @@
-+unsigned char certificate_der[] = {
-+  0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01,
-+  0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
-+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
-+  0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04,
-+  0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d,
-+  0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
-+  0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e,
-+  0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30,
-+  0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f,
-+  0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32,
-+  0x30, 0x37, 0x5a, 0x30, 0x52, 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, 0x31, 0x1d, 0x30, 0x1b,
-+  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-+  0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e,
-+  0x6e, 0x65, 0x74, 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,
-+  0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61,
-+  0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72,
-+  0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d,
-+  0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98,
-+  0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e,
-+  0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b,
-+  0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12,
-+  0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78,
-+  0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c,
-+  0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9,
-+  0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97,
-+  0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e,
-+  0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c,
-+  0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3,
-+  0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f,
-+  0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc,
-+  0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64,
-+  0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93,
-+  0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d,
-+  0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72,
-+  0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2,
-+  0x32, 0x38, 0x11, 0xb1, 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, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf,
-+  0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30,
-+  0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
-+  0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4,
-+  0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
-+  0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47,
-+  0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf,
-+  0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49,
-+  0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13,
-+  0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4,
-+  0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00,
-+  0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1,
-+  0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79,
-+  0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e,
-+  0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83,
-+  0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3,
-+  0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d,
-+  0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97,
-+  0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d,
-+  0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf,
-+  0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3,
-+  0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b,
-+  0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9,
-+  0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e,
-+  0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46,
-+  0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49,
-+  0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07
-+};
-+unsigned int certificate_der_len = 908;
-+
-+unsigned char hi_signed[] = {
-+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
-+  0x01, 0xad, 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, 0x01,
-+  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
-+  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
-+  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
-+  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
-+  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
-+  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
-+  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
-+  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
-+  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
-+  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
-+  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
-+  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
-+  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
-+  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
-+  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
-+  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
-+  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
-+  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
-+  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
-+  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
-+  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
-+  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
-+  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
-+  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
-+  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
-+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495;
-+
-+unsigned char hj_signed[] = {
-+  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
-+  0x01, 0xad, 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, 0x01,
-+  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
-+  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
-+  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
-+  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
-+  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
-+  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
-+  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
-+  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
-+  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
-+  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
-+  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
-+  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
-+  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
-+  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
-+  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
-+  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
-+  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
-+  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
-+  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
-+  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
-+  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
-+  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
-+  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
-+  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
-+  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
-+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495;
-+
-+unsigned char hi_signed_sha256[] = {
-+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
-+  0x01, 0xad, 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, 0x01,
-+  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
-+  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
-+  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
-+  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21,
-+  0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26,
-+  0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3,
-+  0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4,
-+  0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80,
-+  0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f,
-+  0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f,
-+  0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73,
-+  0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0,
-+  0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d,
-+  0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47,
-+  0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b,
-+  0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf,
-+  0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0,
-+  0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a,
-+  0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f,
-+  0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09,
-+  0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2,
-+  0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b,
-+  0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44,
-+  0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93,
-+  0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00,
-+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495;
-+
-+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 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;
diff --git a/SOURCES/0370-appended-signatures-documentation.patch b/SOURCES/0370-appended-signatures-documentation.patch
deleted file mode 100644
index 82f50de..0000000
--- a/SOURCES/0370-appended-signatures-documentation.patch
+++ /dev/null
@@ -1,329 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 1 Oct 2020 13:02:09 +1000
-Subject: [PATCH] appended signatures: documentation
-
-This explains how appended signatures can be used to form part of
-a secure boot chain, and documents the commands and variables
-introduced.
-
-(docs: s/grub/grub2/)
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
- 1 file changed, 172 insertions(+), 13 deletions(-)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index a833364d5ff..97f0f47e082 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -3160,6 +3160,7 @@ These variables have special meaning to GRUB.
- 
- @menu
- * biosnum::
-+* check_appended_signatures::
- * check_signatures::
- * chosen::
- * cmdpath::
-@@ -3219,11 +3220,18 @@ 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
-@@ -3937,6 +3945,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
- * eval::                        Evaluate agruments as GRUB commands
-@@ -3953,6 +3962,7 @@ you forget a command, you can run the command @command{help}
- * keystatus::                   Check key modifier status
- * linux::                       Load a Linux kernel
- * linux16::                     Load a Linux kernel (16-bit mode)
-+* 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
-@@ -3989,9 +3999,11 @@ you forget a command, you can run the command @command{help}
- * test::                        Check file types and compare values
- * 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
- * uppermem::                    Set the upper memory size
- @comment * vbeinfo::                     List available video modes
-+* verify_appended::             Verify appended digital signature
- * verify_detached::             Verify detached digital signature
- * videoinfo::                   List available video modes
- @comment * xen_*::              Xen boot commands for AArch64
-@@ -4282,9 +4294,28 @@ 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
- @subsection drivemap
- 
-@@ -4542,6 +4573,21 @@ This command is only available on x86 systems.
- @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
- 
-@@ -4561,7 +4607,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
- 
-@@ -4596,8 +4642,12 @@ 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
- 
- 
-@@ -4883,7 +4933,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
- 
- 
-@@ -5208,11 +5258,31 @@ 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 an 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
- 
-@@ -5237,6 +5307,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
-@@ -5255,7 +5337,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
-@@ -5601,9 +5683,10 @@ 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
--* 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
-+* Signing GRUB itself::                Ensuring the integrity of the GRUB core image
- @end menu
- 
- @node Authentication and authorisation
-@@ -5676,8 +5759,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.
-@@ -5760,6 +5843,82 @@ 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 Signing GRUB itself
- @section Signing GRUB itself
- 
diff --git a/SOURCES/0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch b/SOURCES/0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch
new file mode 100644
index 0000000..219d181
--- /dev/null
+++ b/SOURCES/0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch
@@ -0,0 +1,137 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Sep 2020 11:11:17 +1000
+Subject: [PATCH] ieee1275: link appended-signature enforcement to
+ /ibm,secure-boot
+
+If the 'ibm,secure-boot' property of the root node is 2 or greater,
+require that the kernel pass appended-signature verification.
+
+Do not consider the presence of a certificate to enforce verification.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/appendedsig/appendedsig.c | 44 +++++++++++++++++++++-------
+ grub-core/kern/ieee1275/init.c               | 26 ++++++++++++++++
+ 2 files changed, 60 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
+index 5d8897be5c8..4ef2ec2893c 100644
+--- a/grub-core/commands/appendedsig/appendedsig.c
++++ b/grub-core/commands/appendedsig/appendedsig.c
+@@ -95,10 +95,24 @@ static char *
+ grub_env_write_sec (struct grub_env_var *var __attribute__((unused)),
+ 		    const char *val)
+ {
++  if (check_sigs == 2)
++    return grub_strdup ("forced");
+   check_sigs = (*val == '1') || (*val == 'e');
+   return grub_strdup (check_sigs ? "enforce" : "no");
+ }
+ 
++static const char *
++grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
++                         const char *val __attribute__ ((unused)))
++{
++  if (check_sigs == 2)
++    return "forced";
++  else if (check_sigs == 1)
++    return "enforce";
++  else
++    return "no";
++}
++
+ static grub_err_t
+ read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
+ {
+@@ -552,14 +566,20 @@ GRUB_MOD_INIT (appendedsig)
+   val = grub_env_get ("check_appended_signatures");
+   grub_dprintf ("appendedsig", "check_appended_signatures='%s'\n", val);
+ 
+-  if (val && (val[0] == '1' || val[0] == 'e'))
+-    check_sigs = 1;
+-  else
+-    check_sigs = 0;
++  if (val)
++  {
++    if (val[0] == '2' || val[0] == 'f')
++      check_sigs = 2;
++    else if (val[0] == '1' || val[0] == 'e')
++      check_sigs = 1;
++    else
++      check_sigs = 0;
++  }
+ 
+   grub_trusted_key = NULL;
+ 
+-  grub_register_variable_hook ("check_appended_signatures", 0,
++  grub_register_variable_hook ("check_appended_signatures",
++  			       grub_env_read_sec,
+ 			       grub_env_write_sec);
+   grub_env_export ("check_appended_signatures");
+ 
+@@ -603,11 +623,15 @@ GRUB_MOD_INIT (appendedsig)
+     grub_trusted_key = pk;
+   }
+ 
+-  if (!val || val[0] == '\0')
+-    {
+-      grub_env_set ("check_appended_signatures",
+-		    grub_trusted_key ? "enforce" : "no");
+-    }
++  /*
++   * When controlled by ibm,secure-boot, we don't want the presence of
++   * a certificate to enforce secure boot.
++   * if (!val || val[0] == '\0')
++   * {
++   *    grub_env_set ("check_appended_signatures",
++   *		      grub_trusted_key ? "enforce" : "no");
++   * }
++   */
+ 
+   cmd_trust =
+     grub_register_command ("trust_certificate", grub_cmd_trust,
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index e731a57a47b..22dc3013d86 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -268,6 +268,30 @@ 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_env_set("check_appended_signatures", "forced");
++}
++
+ grub_addr_t grub_modbase;
+ 
+ void
+@@ -290,6 +314,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/SOURCES/0371-ieee1275-link-appended-signature-enforcement-to-ibm-.patch b/SOURCES/0371-ieee1275-link-appended-signature-enforcement-to-ibm-.patch
deleted file mode 100644
index ae1689b..0000000
--- a/SOURCES/0371-ieee1275-link-appended-signature-enforcement-to-ibm-.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 28 Sep 2020 11:11:17 +1000
-Subject: [PATCH] ieee1275: link appended-signature enforcement to
- /ibm,secure-boot
-
-If the 'ibm,secure-boot' property of the root node is 2 or greater,
-require that the kernel pass appended-signature verification.
-
-Do not consider the presence of a certificate to enforce verification.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/appendedsig/appendedsig.c | 44 +++++++++++++++++++++-------
- grub-core/kern/ieee1275/init.c               | 26 ++++++++++++++++
- 2 files changed, 60 insertions(+), 10 deletions(-)
-
-diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
-index 5d8897be5c8..4ef2ec2893c 100644
---- a/grub-core/commands/appendedsig/appendedsig.c
-+++ b/grub-core/commands/appendedsig/appendedsig.c
-@@ -95,10 +95,24 @@ static char *
- grub_env_write_sec (struct grub_env_var *var __attribute__((unused)),
- 		    const char *val)
- {
-+  if (check_sigs == 2)
-+    return grub_strdup ("forced");
-   check_sigs = (*val == '1') || (*val == 'e');
-   return grub_strdup (check_sigs ? "enforce" : "no");
- }
- 
-+static const char *
-+grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
-+                         const char *val __attribute__ ((unused)))
-+{
-+  if (check_sigs == 2)
-+    return "forced";
-+  else if (check_sigs == 1)
-+    return "enforce";
-+  else
-+    return "no";
-+}
-+
- static grub_err_t
- read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
- {
-@@ -552,14 +566,20 @@ GRUB_MOD_INIT (appendedsig)
-   val = grub_env_get ("check_appended_signatures");
-   grub_dprintf ("appendedsig", "check_appended_signatures='%s'\n", val);
- 
--  if (val && (val[0] == '1' || val[0] == 'e'))
--    check_sigs = 1;
--  else
--    check_sigs = 0;
-+  if (val)
-+  {
-+    if (val[0] == '2' || val[0] == 'f')
-+      check_sigs = 2;
-+    else if (val[0] == '1' || val[0] == 'e')
-+      check_sigs = 1;
-+    else
-+      check_sigs = 0;
-+  }
- 
-   grub_trusted_key = NULL;
- 
--  grub_register_variable_hook ("check_appended_signatures", 0,
-+  grub_register_variable_hook ("check_appended_signatures",
-+  			       grub_env_read_sec,
- 			       grub_env_write_sec);
-   grub_env_export ("check_appended_signatures");
- 
-@@ -603,11 +623,15 @@ GRUB_MOD_INIT (appendedsig)
-     grub_trusted_key = pk;
-   }
- 
--  if (!val || val[0] == '\0')
--    {
--      grub_env_set ("check_appended_signatures",
--		    grub_trusted_key ? "enforce" : "no");
--    }
-+  /*
-+   * When controlled by ibm,secure-boot, we don't want the presence of
-+   * a certificate to enforce secure boot.
-+   * if (!val || val[0] == '\0')
-+   * {
-+   *    grub_env_set ("check_appended_signatures",
-+   *		      grub_trusted_key ? "enforce" : "no");
-+   * }
-+   */
- 
-   cmd_trust =
-     grub_register_command ("trust_certificate", grub_cmd_trust,
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index f8a4f8f4214..137a343bca7 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -266,6 +266,30 @@ 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_env_set("check_appended_signatures", "forced");
-+}
-+
- grub_addr_t grub_modbase;
- 
- void
-@@ -288,6 +312,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/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch b/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch
new file mode 100644
index 0000000..d757ffd
--- /dev/null
+++ b/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leif Lindholm <leif.lindholm@linaro.org>
+Date: Wed, 14 Nov 2018 19:29:15 +0000
+Subject: [PATCH] include/grub/verify.h: Add include guard
+
+verify.h was added without include guards. This means compiling anything
+including both include/grub/verify.h and include/grub/lib/cmdline.h fails
+(at least grub-core/loader/arm64/linux.c.
+
+Add the necessary include guard.
+
+Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ include/grub/verify.h | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+index 60c13e7ea8e..ace72d74663 100644
+--- a/include/grub/verify.h
++++ b/include/grub/verify.h
+@@ -16,6 +16,9 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
++#ifndef GRUB_VERIFY_HEADER
++#define GRUB_VERIFY_HEADER 1
++
+ #include <grub/file.h>
+ #include <grub/list.h>
+ 
+@@ -89,3 +92,5 @@ char grub_is_dangerous_module (grub_file_t io);
+  * Returns the name if one is loaded, otherwise NULL.
+  */
+ const char *grub_dangerous_module_loaded (void);
++
++#endif /* ! GRUB_VERIFY_HEADER */
diff --git a/SOURCES/0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch b/SOURCES/0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch
new file mode 100644
index 0000000..e472215
--- /dev/null
+++ b/SOURCES/0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Lee Jones <lee.jones@linaro.org>
+Date: Tue, 20 Nov 2018 10:45:04 +0000
+Subject: [PATCH] arm64/xen: Fix too few arguments to function
+ grub_create_loader_cmdline()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Without this fix, building xen_boot.c omits:
+
+loader/arm64/xen_boot.c: In function ‘xen_boot_binary_load’:
+loader/arm64/xen_boot.c:370:7: error: too few arguments to function ‘grub_create_loader_cmdline’
+       grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline,
+       ^~~~~~~~~~~~~~~~~~~~~~~~~~
+In file included from loader/arm64/xen_boot.c:36:0:
+../include/grub/lib/cmdline.h:29:12: note: declared here
+ grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Reviewed-by: Julien Grall <julien.grall@arm.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/loader/arm64/xen_boot.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
+index 318c833de57..1a337866f08 100644
+--- a/grub-core/loader/arm64/xen_boot.c
++++ b/grub-core/loader/arm64/xen_boot.c
+@@ -367,7 +367,8 @@ xen_boot_binary_load (struct xen_boot_binary *binary, grub_file_t file,
+ 	  return;
+ 	}
+       grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline,
+-				  binary->cmdline_size);
++				  binary->cmdline_size,
++				  GRUB_VERIFY_KERNEL_CMDLINE);
+       grub_dprintf ("xen_loader",
+ 		    "Xen_boot cmdline @ %p %s, size: %d\n",
+ 		    binary->cmdline, binary->cmdline, binary->cmdline_size);
diff --git a/SOURCES/0372-include-grub-verify.h-Add-include-guard.patch b/SOURCES/0372-include-grub-verify.h-Add-include-guard.patch
deleted file mode 100644
index d757ffd..0000000
--- a/SOURCES/0372-include-grub-verify.h-Add-include-guard.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Leif Lindholm <leif.lindholm@linaro.org>
-Date: Wed, 14 Nov 2018 19:29:15 +0000
-Subject: [PATCH] include/grub/verify.h: Add include guard
-
-verify.h was added without include guards. This means compiling anything
-including both include/grub/verify.h and include/grub/lib/cmdline.h fails
-(at least grub-core/loader/arm64/linux.c.
-
-Add the necessary include guard.
-
-Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
----
- include/grub/verify.h | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/include/grub/verify.h b/include/grub/verify.h
-index 60c13e7ea8e..ace72d74663 100644
---- a/include/grub/verify.h
-+++ b/include/grub/verify.h
-@@ -16,6 +16,9 @@
-  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
-  */
- 
-+#ifndef GRUB_VERIFY_HEADER
-+#define GRUB_VERIFY_HEADER 1
-+
- #include <grub/file.h>
- #include <grub/list.h>
- 
-@@ -89,3 +92,5 @@ char grub_is_dangerous_module (grub_file_t io);
-  * Returns the name if one is loaded, otherwise NULL.
-  */
- const char *grub_dangerous_module_loaded (void);
-+
-+#endif /* ! GRUB_VERIFY_HEADER */
diff --git a/SOURCES/0373-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch b/SOURCES/0373-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch
deleted file mode 100644
index e472215..0000000
--- a/SOURCES/0373-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Lee Jones <lee.jones@linaro.org>
-Date: Tue, 20 Nov 2018 10:45:04 +0000
-Subject: [PATCH] arm64/xen: Fix too few arguments to function
- grub_create_loader_cmdline()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Without this fix, building xen_boot.c omits:
-
-loader/arm64/xen_boot.c: In function ‘xen_boot_binary_load’:
-loader/arm64/xen_boot.c:370:7: error: too few arguments to function ‘grub_create_loader_cmdline’
-       grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline,
-       ^~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from loader/arm64/xen_boot.c:36:0:
-../include/grub/lib/cmdline.h:29:12: note: declared here
- grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf,
-
-Signed-off-by: Lee Jones <lee.jones@linaro.org>
-Reviewed-by: Julien Grall <julien.grall@arm.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
----
- grub-core/loader/arm64/xen_boot.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
-index 318c833de57..1a337866f08 100644
---- a/grub-core/loader/arm64/xen_boot.c
-+++ b/grub-core/loader/arm64/xen_boot.c
-@@ -367,7 +367,8 @@ xen_boot_binary_load (struct xen_boot_binary *binary, grub_file_t file,
- 	  return;
- 	}
-       grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline,
--				  binary->cmdline_size);
-+				  binary->cmdline_size,
-+				  GRUB_VERIFY_KERNEL_CMDLINE);
-       grub_dprintf ("xen_loader",
- 		    "Xen_boot cmdline @ %p %s, size: %d\n",
- 		    binary->cmdline, binary->cmdline, binary->cmdline_size);
diff --git a/SOURCES/centos-ca-secureboot.der b/SOURCES/centos-ca-secureboot.der
deleted file mode 100644
index 44a2563..0000000
Binary files a/SOURCES/centos-ca-secureboot.der and /dev/null differ
diff --git a/SOURCES/centossecureboot001.der b/SOURCES/centossecureboot001.der
deleted file mode 100644
index e8216b1..0000000
Binary files a/SOURCES/centossecureboot001.der and /dev/null differ
diff --git a/SOURCES/centossecureboot202.der b/SOURCES/centossecureboot202.der
deleted file mode 100644
index ab8213c..0000000
Binary files a/SOURCES/centossecureboot202.der and /dev/null differ
diff --git a/SOURCES/centossecurebootca2.der b/SOURCES/centossecurebootca2.der
deleted file mode 100644
index 42bdfcf..0000000
Binary files a/SOURCES/centossecurebootca2.der and /dev/null differ
diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches
index 504969a..1f4dab1 100644
--- a/SOURCES/grub.patches
+++ b/SOURCES/grub.patches
@@ -346,28 +346,27 @@ Patch0345: 0345-verifiers-MIPS-fallout-cleanup.patch
 Patch0346: 0346-verifiers-Fix-calling-uninitialized-function-pointer.patch
 Patch0347: 0347-rhel-extra-file-type-fixes.patch
 Patch0348: 0348-dl-Add-support-for-persistent-modules.patch
-Patch0349: 0349-ieee1275-claim-up-to-256MB-memory.patch
-Patch0350: 0350-Add-suport-for-signing-grub-with-an-appended-signatu.patch
-Patch0351: 0351-docs-grub-Document-signing-grub-under-UEFI.patch
-Patch0352: 0352-docs-grub-Document-signing-grub-with-an-appended-sig.patch
-Patch0353: 0353-docs-grub-grub-install-is-no-longer-a-shell-script.patch
-Patch0354: 0354-docs-grub-pubkey-has-been-supported-for-some-time.patch
-Patch0355: 0355-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
-Patch0356: 0356-verifiers-provide-unsafe-module-list.patch
-Patch0357: 0357-pgp-factor-out-rsa_pad.patch
-Patch0358: 0358-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
-Patch0359: 0359-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
-Patch0360: 0360-libtasn1-import-libtasn1-4.16.0.patch
-Patch0361: 0361-libtasn1-disable-code-not-needed-in-grub.patch
-Patch0362: 0362-libtasn1-changes-for-grub-compatibility.patch
-Patch0363: 0363-libtasn1-compile-into-asn1-module.patch
-Patch0364: 0364-test_asn1-test-module-for-libtasn1.patch
-Patch0365: 0365-grub-install-support-embedding-x509-certificates.patch
-Patch0366: 0366-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
-Patch0367: 0367-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
-Patch0368: 0368-appended-signatures-support-verifying-appended-signa.patch
-Patch0369: 0369-appended-signatures-verification-tests.patch
-Patch0370: 0370-appended-signatures-documentation.patch
-Patch0371: 0371-ieee1275-link-appended-signature-enforcement-to-ibm-.patch
-Patch0372: 0372-include-grub-verify.h-Add-include-guard.patch
-Patch0373: 0373-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch
+Patch0349: 0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch
+Patch0350: 0350-docs-grub-Document-signing-grub-under-UEFI.patch
+Patch0351: 0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch
+Patch0352: 0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch
+Patch0353: 0353-docs-grub-pubkey-has-been-supported-for-some-time.patch
+Patch0354: 0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
+Patch0355: 0355-verifiers-provide-unsafe-module-list.patch
+Patch0356: 0356-pgp-factor-out-rsa_pad.patch
+Patch0357: 0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
+Patch0358: 0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
+Patch0359: 0359-libtasn1-import-libtasn1-4.16.0.patch
+Patch0360: 0360-libtasn1-disable-code-not-needed-in-grub.patch
+Patch0361: 0361-libtasn1-changes-for-grub-compatibility.patch
+Patch0362: 0362-libtasn1-compile-into-asn1-module.patch
+Patch0363: 0363-test_asn1-test-module-for-libtasn1.patch
+Patch0364: 0364-grub-install-support-embedding-x509-certificates.patch
+Patch0365: 0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
+Patch0366: 0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
+Patch0367: 0367-appended-signatures-support-verifying-appended-signa.patch
+Patch0368: 0368-appended-signatures-verification-tests.patch
+Patch0369: 0369-appended-signatures-documentation.patch
+Patch0370: 0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch
+Patch0371: 0371-include-grub-verify.h-Add-include-guard.patch
+Patch0372: 0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch
diff --git a/SOURCES/redhatsecureboot301.cer b/SOURCES/redhatsecureboot301.cer
new file mode 100644
index 0000000..4ff8b79
Binary files /dev/null and b/SOURCES/redhatsecureboot301.cer differ
diff --git a/SOURCES/redhatsecureboot502.cer b/SOURCES/redhatsecureboot502.cer
new file mode 100644
index 0000000..be0b5e2
Binary files /dev/null and b/SOURCES/redhatsecureboot502.cer differ
diff --git a/SOURCES/redhatsecurebootca3.cer b/SOURCES/redhatsecurebootca3.cer
new file mode 100644
index 0000000..b235400
Binary files /dev/null and b/SOURCES/redhatsecurebootca3.cer differ
diff --git a/SOURCES/redhatsecurebootca5.cer b/SOURCES/redhatsecurebootca5.cer
new file mode 100644
index 0000000..dfb0284
Binary files /dev/null and b/SOURCES/redhatsecurebootca5.cer differ
diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec
index 8aa696a..7fc7831 100644
--- a/SPECS/grub2.spec
+++ b/SPECS/grub2.spec
@@ -7,7 +7,7 @@
 Name:		grub2
 Epoch:		1
 Version:	2.02
-Release:	95%{?dist}
+Release:	97%{?dist}
 Summary:	Bootloader with support for Linux, Multiboot and more
 Group:		System Environment/Base
 License:	GPLv3+
@@ -24,10 +24,10 @@ Source6:	gitignore
 Source8:	strtoull_test.c
 Source9:	20-grub.install
 Source12:	99-grub-mkconfig.install
-Source13:	centos-ca-secureboot.der
-Source14:	centossecureboot001.der
-Source15:	centossecurebootca2.der
-Source16:	centossecureboot202.der
+Source13:	redhatsecurebootca3.cer
+Source14:	redhatsecureboot301.cer
+Source15:	redhatsecurebootca5.cer
+Source16:	redhatsecureboot502.cer
 
 %include %{SOURCE1}
 
@@ -54,11 +54,7 @@ BuildRequires:	pesign >= 0.99-8
 BuildRequires:	ccache
 %endif
 
-%if 0%{?centos}
-%global efidir centos
-%endif
-
-ExcludeArch:	s390 s390x
+ExcludeArch:	s390 s390x %{arm}
 Obsoletes:	%{name} <= %{evr}
 
 %if 0%{with_legacy_arch}
@@ -170,10 +166,10 @@ git commit -m "After making subdirs"
 
 %build
 %if 0%{with_efi_arch}
-%{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{SOURCE13} %{SOURCE14} centossecureboot001 %{SOURCE15} %{SOURCE16} centossecureboot202}
+%{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{SOURCE13} %{SOURCE14} redhatsecureboot301 %{SOURCE15} %{SOURCE16} redhatsecureboot502}
 %endif
 %if 0%{with_alt_efi_arch}
-%{expand:%do_alt_efi_build %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname} %%{_alt_target_platform} %%{alt_efi_target_cflags} %%{alt_efi_host_cflags} %{SOURCE13} %{SOURCE14} centossecureboot001 %{SOURCE15} %{SOURCE16} centossecureboot202}
+%{expand:%do_alt_efi_build %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname} %%{_alt_target_platform} %%{alt_efi_target_cflags} %%{alt_efi_host_cflags} %{SOURCE13} %{SOURCE14} redhatsecureboot301 %{SOURCE15} %{SOURCE16} redhatsecureboot502}
 %endif
 %if 0%{with_legacy_arch}
 %{expand:%do_legacy_build %%{grublegacyarch}}
@@ -504,6 +500,16 @@ fi
 %endif
 
 %changelog
+* Tue Feb 23 2021 Javier Martinez Canillas <javierm@redhat.com> - 2.02-97
+- Fix keylayouts module listed twice in GRUB_MODULES variable
+  Related: rhbz#1897587
+
+* Tue Feb 23 2021 Javier Martinez Canillas <javierm@redhat.com> - 2.02-96
+- Fix "Add 'at_keyboard_fallback_set' var to force the set manually"
+  Related: rhbz#1897587
+- Fix a boot failure due patch "ieee1275: claim up to 256MB memory"
+  Resolves: rhbz#1929111
+
 * Tue Jan 26 2021 Javier Martinez Canillas <javierm@redhat.com> - 2.02-95
 - Add appended signatures support for ppc64le LPAR Secure Boot (daxtens)
   Resolves: rhbz#1853410