diff --git a/SOURCES/0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/SOURCES/0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..047b07ba935785fb854c74e764a9a2fa57059839
--- /dev/null
+++ b/SOURCES/0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
@@ -0,0 +1,121 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Thu, 3 Dec 2020 09:13:24 +0100
+Subject: [PATCH] at_keyboard: use set 1 when keyboard is in Translate mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When keyboard controller acts in Translate mode (0x40 mask), then use
+set 1 since translation is done.
+Otherwise use the mode queried from the controller (usually set 2).
+
+Added "atkeyb" debugging messages in at_keyboard module as well.
+
+Resolves: rhbz#1897587
+
+Tested on:
+- Asus N53SN (set 1 used)
+- Dell Precision (set 1 used)
+- HP Elitebook (set 2 used)
+- HP G5430 (set 1 used, keyboard in XT mode!)
+- Lenovo P71 & Lenovo T460s (set 2 used)
+- QEMU/KVM (set 1 used)
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/term/at_keyboard.c | 29 ++++++++++++++++++++++++-----
+ include/grub/at_keyboard.h   |  4 ++++
+ 2 files changed, 28 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index f0a986eb176..69d99b61df5 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -135,20 +135,28 @@ query_mode (void)
+   int e;
+ 
+   e = write_mode (0);
+-  if (!e)
++  if (!e) {
++    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
+     return 0;
++  }
+ 
+   do {
+     keyboard_controller_wait_until_ready ();
+     ret = grub_inb (KEYBOARD_REG_DATA);
+   } while (ret == GRUB_AT_ACK);
+   /* QEMU translates the set even in no-translate mode.  */
+-  if (ret == 0x43 || ret == 1)
++  if (ret == 0x43 || ret == 1) {
++    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
+     return 1;
+-  if (ret == 0x41 || ret == 2)
++  }
++  if (ret == 0x41 || ret == 2) {
++    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
+     return 2;
+-  if (ret == 0x3f || ret == 3)
++  }
++  if (ret == 0x3f || ret == 3) {
++    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
+     return 3;
++  }
+   return 0;
+ }
+ 
+@@ -165,7 +173,13 @@ set_scancodes (void)
+     }
+ 
+ #if !USE_SCANCODE_SET
+-  ps2_state.current_set = 1;
++  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;
++  } else {
++    grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set);
++    ps2_state.current_set = grub_keyboard_orig_set;
++  }
+   return;
+ #else
+ 
+@@ -266,6 +280,7 @@ grub_keyboard_controller_init (void)
+   grub_keyboard_orig_set = 2;
+ #else
+   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 ();
+ #endif
+   set_scancodes ();
+@@ -275,11 +290,15 @@ grub_keyboard_controller_init (void)
+ static grub_err_t
+ grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused)))
+ {
++/* In !USE_SCANCODE_SET mode, we didn't change anything, so nothing to restore */
++#if USE_SCANCODE_SET
+   if (ps2_state.current_set == 0)
+     return GRUB_ERR_NONE;
++  grub_dprintf ("atkeyb", "restoring set %d, controller 0x%x\n", grub_keyboard_orig_set, grub_keyboard_controller_orig);
+   if (grub_keyboard_orig_set)
+     write_mode (grub_keyboard_orig_set);
+   grub_keyboard_controller_write (grub_keyboard_controller_orig);
++#endif
+   return GRUB_ERR_NONE;
+ }
+ 
+diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h
+index bcb4d9ba78f..9414dc1b996 100644
+--- a/include/grub/at_keyboard.h
++++ b/include/grub/at_keyboard.h
+@@ -19,6 +19,10 @@
+ #ifndef GRUB_AT_KEYBOARD_HEADER
+ #define GRUB_AT_KEYBOARD_HEADER	1
+ 
++/*
++ * Refer to https://wiki.osdev.org/%228042%22_PS/2_Controller for details.
++ */
++
+ /* Used for sending commands to the controller.  */
+ #define KEYBOARD_COMMAND_ISREADY(x)	!((x) & 0x02)
+ #define KEYBOARD_COMMAND_READ		0x20
diff --git a/SOURCES/0319-grub-install-disable-support-for-EFI-platforms.patch b/SOURCES/0319-grub-install-disable-support-for-EFI-platforms.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2591b60e104a6ac8ffee1a1f4e6870dadf738740
--- /dev/null
+++ b/SOURCES/0319-grub-install-disable-support-for-EFI-platforms.patch
@@ -0,0 +1,118 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jan Hlavac <jhlavac@redhat.com>
+Date: Fri, 20 Nov 2020 23:51:47 +0100
+Subject: [PATCH] grub-install: disable support for EFI platforms
+
+For each platform, GRUB is shipped as a kernel image and a set of
+modules. These files are then used by the grub-install utility to
+install GRUB on a specific device. However, in order to support UEFI
+Secure Boot, the resulting EFI binary must be signed by a recognized
+private key. For this reason, for EFI platforms, most distributions also
+ship prebuilt EFI binaries signed by a distribution-specific private
+key. In this case, however, the grub-install utility should not be used
+because it would overwrite the signed EFI binary.
+
+The current fix is suboptimal because it preserves all EFI-related code.
+A better solution could be to modularize the code and provide a
+build-time option.
+
+Resolves: rhbz#1737444
+
+Signed-off-by: Jan Hlavac <jhlavac@redhat.com>
+---
+ util/grub-install.c | 35 ++++++++++++++++-------------------
+ docs/grub.texi      |  7 +++++++
+ util/grub-install.8 |  4 +++-
+ 3 files changed, 26 insertions(+), 20 deletions(-)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 3bf0e063a86..65bb2f99ef1 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -888,6 +888,22 @@ main (int argc, char *argv[])
+ 
+   platform = grub_install_get_target (grub_install_source_directory);
+ 
++  switch (platform)
++    {
++    case GRUB_INSTALL_PLATFORM_ARM_EFI:
++    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
++    case GRUB_INSTALL_PLATFORM_I386_EFI:
++    case GRUB_INSTALL_PLATFORM_IA64_EFI:
++    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
++      is_efi = 1;
++      grub_util_error (_("this utility cannot be used for EFI platforms"
++                         " because it does not support UEFI Secure Boot"));
++      break;
++    default:
++      is_efi = 0;
++      break;
++    }
++
+   {
+     char *platname = grub_install_get_platform_name (platform);
+     fprintf (stderr, _("Installing for %s platform.\n"), platname);
+@@ -994,26 +1010,7 @@ main (int argc, char *argv[])
+   grub_hostfs_init ();
+   grub_host_init ();
+ 
+-  switch (platform)
+-    {
+-    case GRUB_INSTALL_PLATFORM_I386_EFI:
+-    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+-    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+-    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+-    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+-      is_efi = 1;
+-      break;
+-    default:
+-      is_efi = 0;
+-      break;
+-
+-      /* pacify warning.  */
+-    case GRUB_INSTALL_PLATFORM_MAX:
+-      break;
+-    }
+-
+   /* Find the EFI System Partition.  */
+-
+   if (is_efi)
+     {
+       grub_fs_t fs;
+diff --git a/docs/grub.texi b/docs/grub.texi
+index c54bee31679..fa11cc0aff7 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -6185,6 +6185,13 @@ grub2-install @var{install_device}
+ The device name @var{install_device} is an OS device name or a GRUB
+ device name.
+ 
++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must
++be signed by a recognized private key. For this reason, for EFI
++platforms, most distributions also ship prebuilt GRUB EFI binaries
++signed by a distribution-specific private key. In this case, however,
++@command{grub2-install} should not be used because it would overwrite
++the signed EFI binary.
++
+ @command{grub2-install} accepts the following options:
+ 
+ @table @option
+diff --git a/util/grub-install.8 b/util/grub-install.8
+index 76272a39d2e..02371930fa1 100644
+--- a/util/grub-install.8
++++ b/util/grub-install.8
+@@ -1,4 +1,4 @@
+-.TH GRUB-INSTALL 1 "Wed Feb 26 2014"
++.TH GRUB-INSTALL 1 "Fri Nov 20 2020"
+ .SH NAME
+ \fBgrub-install\fR \(em Install GRUB on a device.
+ 
+@@ -31,6 +31,8 @@
+ .SH DESCRIPTION
+ \fBgrub-install\fR installs GRUB onto a device.  This includes copying GRUB images into the target directory (generally \fI/boot/grub\fR), and on some platforms may also include installing GRUB onto a boot sector.
+ 
++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must be signed by a recognized private key. For this reason, for EFI platforms, most distributions also ship prebuilt GRUB EFI binaries signed by a distribution-specific private key. In this case, however, the \fBgrub-install\fR utility should not be used because it would overwrite the signed EFI binary.
++
+ .SH OPTIONS
+ .TP
+ \fB--modules\fR=\fIMODULES\fR\!
diff --git a/SOURCES/0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/SOURCES/0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..62d61b97efb3f9e2840548e14766335c3ea8fa02
--- /dev/null
+++ b/SOURCES/0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch
@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Sat, 23 Nov 2019 14:57:41 +0100
+Subject: [PATCH] New --with-debug-timestamps configure flag to prepend debug
+ traces with absolute and relative timestamp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ configure.ac          | 18 ++++++++++++++++++
+ grub-core/kern/misc.c | 20 ++++++++++++++++++++
+ config.h.in           |  1 +
+ 3 files changed, 39 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 9323c125469..0059b938a3a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1514,6 +1514,17 @@ else
+ fi
+ AC_SUBST([BOOT_TIME_STATS])
+ 
++AC_ARG_WITH([debug-timestamps],
++	   AS_HELP_STRING([--with-debug-timestamps],
++                          [prepend debug traces with absolute and relative timestamps]))
++
++if test x$with_debug_timestamps = xyes; then
++  DEBUG_WITH_TIMESTAMPS=1
++else
++  DEBUG_WITH_TIMESTAMPS=0
++fi
++AC_SUBST([DEBUG_WITH_TIMESTAMPS])
++
+ AC_ARG_ENABLE([grub-emu-sdl],
+ 	      [AS_HELP_STRING([--enable-grub-emu-sdl],
+                              [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])])
+@@ -2092,6 +2103,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1])
+ AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes])
+ AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1])
+ AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1])
++AM_CONDITIONAL([COND_DEBUG_WITH_TIMESTAMPS], [test x$DEBUG_WITH_TIMESTAMPS = x1])
+ 
+ AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes])
+ 
+@@ -2187,6 +2199,12 @@ else
+ echo With boot time statistics: No
+ fi
+ 
++if [ x"$with_debug_timestamps" = xyes ]; then
++echo Debug traces with timestamps: Yes
++else
++echo Debug traces with timestamps: No
++fi
++
+ if [ x"$efiemu_excuse" = x ]; then
+ echo efiemu runtime: Yes
+ else
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index c034f49f97c..11f2974fce5 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -25,6 +25,9 @@
+ #include <grub/env.h>
+ #include <grub/i18n.h>
+ #include <grub/backtrace.h>
++#if DEBUG_WITH_TIMESTAMPS
++#include <grub/time.h>
++#endif
+ 
+ union printf_arg
+ {
+@@ -179,9 +182,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
+ 		   const char *fmt, ...)
+ {
+   va_list args;
++#if DEBUG_WITH_TIMESTAMPS
++  static long unsigned int last_time = 0;
++  static int last_had_cr = 1;
++#endif
+ 
+   if (grub_debug_enabled (condition))
+     {
++#if DEBUG_WITH_TIMESTAMPS
++      /* Don't print timestamp if last printed message isn't terminated yet */
++      if (last_had_cr) {
++        long unsigned int tmabs = (long unsigned int) grub_get_time_ms();
++        long unsigned int tmrel = tmabs - last_time;
++        last_time = tmabs;
++        grub_printf ("%3lu.%03lus +%2lu.%03lus ", tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000);
++      }
++      if (fmt[grub_strlen(fmt)-1] == '\n')
++        last_had_cr = 1;
++      else
++        last_had_cr = 0;
++#endif
+       grub_printf ("%s:%d: ", file, line);
+       va_start (args, fmt);
+       grub_vprintf (fmt, args);
+diff --git a/config.h.in b/config.h.in
+index 9e8f9911b18..d15480b4163 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -12,6 +12,7 @@
+ /* Define to 1 to enable disk cache statistics.  */
+ #define DISK_CACHE_STATS @DISK_CACHE_STATS@
+ #define BOOT_TIME_STATS @BOOT_TIME_STATS@
++#define DEBUG_WITH_TIMESTAMPS @DEBUG_WITH_TIMESTAMPS@
+ 
+ /* We don't need those.  */
+ #define MINILZO_CFG_SKIP_LZO_PTR 1
diff --git a/SOURCES/0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/SOURCES/0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6edbdbdde1608743619299cc993cc3fe7d5119bf
--- /dev/null
+++ b/SOURCES/0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Sat, 23 Nov 2019 15:22:16 +0100
+Subject: [PATCH] Added debug statements to grub_disk_open() and
+ grub_disk_close() on success
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/kern/disk.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
+index 789f8c05233..7f58c561472 100644
+--- a/grub-core/kern/disk.c
++++ b/grub-core/kern/disk.c
+@@ -285,6 +285,8 @@ grub_disk_open (const char *name)
+       return 0;
+     }
+ 
++  grub_dprintf ("disk", "Opening `%s' succeeded.\n", name);
++
+   return disk;
+ }
+ 
+@@ -292,7 +294,7 @@ void
+ grub_disk_close (grub_disk_t disk)
+ {
+   grub_partition_t part;
+-  grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
++  grub_dprintf ("disk", "Closing `%s'...\n", disk->name);
+ 
+   if (disk->dev && disk->dev->close)
+     (disk->dev->close) (disk);
+@@ -306,8 +308,10 @@ grub_disk_close (grub_disk_t disk)
+       grub_free (disk->partition);
+       disk->partition = part;
+     }
++  grub_dprintf ("disk", "Closing `%s' succeeded.\n", disk->name);
+   grub_free ((void *) disk->name);
+   grub_free (disk);
++
+ }
+ 
+ /* Small read (less than cache size and not pass across cache unit boundaries).
diff --git a/SOURCES/0322-Introduce-function-grub_debug_is_enabled-void-return.patch b/SOURCES/0322-Introduce-function-grub_debug_is_enabled-void-return.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e73e302512bd27ae2d4ce99061f937c1a6d7941c
--- /dev/null
+++ b/SOURCES/0322-Introduce-function-grub_debug_is_enabled-void-return.patch
@@ -0,0 +1,51 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Mon, 25 Nov 2019 09:29:53 +0100
+Subject: [PATCH] Introduce function grub_debug_is_enabled(void) returning 1 if
+ 'debug' is in the environment and not empty
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/kern/misc.c | 13 +++++++++++++
+ include/grub/misc.h   |  1 +
+ 2 files changed, 14 insertions(+)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 11f2974fce5..97378c48b22 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -162,6 +162,19 @@ int grub_err_printf (const char *fmt, ...)
+ __attribute__ ((alias("grub_printf")));
+ #endif
+ 
++/* Return 1 if 'debug' is set and not empty */
++int
++grub_debug_is_enabled (void)
++{
++  const char *debug;
++
++  debug = grub_env_get ("debug");
++  if (!debug || debug[0] == '\0')
++    return 0;
++
++  return 1;
++}
++
+ int
+ grub_debug_enabled (const char * condition)
+ {
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 1258ec6bbf3..6ca03c4d692 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -367,6 +367,7 @@ grub_puts (const char *s)
+ }
+ 
+ int EXPORT_FUNC(grub_puts_) (const char *s);
++int EXPORT_FUNC(grub_debug_is_enabled) (void);
+ int EXPORT_FUNC(grub_debug_enabled) (const char *condition);
+ void EXPORT_FUNC(grub_real_dprintf) (const char *file,
+                                      const int line,
diff --git a/SOURCES/0323-Don-t-clear-screen-when-debugging-is-enabled.patch b/SOURCES/0323-Don-t-clear-screen-when-debugging-is-enabled.patch
new file mode 100644
index 0000000000000000000000000000000000000000..20abbf35befabb3474cb562461dfc7f0655e9384
--- /dev/null
+++ b/SOURCES/0323-Don-t-clear-screen-when-debugging-is-enabled.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Sat, 23 Nov 2019 16:23:54 +0100
+Subject: [PATCH] Don't clear screen when debugging is enabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/normal/main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 04ae9ed02f6..59fd54eb0f1 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -204,7 +204,8 @@ void
+ grub_normal_init_page (struct grub_term_output *term,
+ 		       int y __attribute__((__unused__)))
+ {
+-  grub_term_cls (term);
++  if (! grub_debug_is_enabled ())
++    grub_term_cls (term);
+ 
+ #if 0
+   grub_ssize_t msg_len;
diff --git a/SOURCES/0324-grub_file_-instrumentation-new-file-debug-tag.patch b/SOURCES/0324-grub_file_-instrumentation-new-file-debug-tag.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e0f515a5c469ed84e82c6202a2ef8a9da134bc6e
--- /dev/null
+++ b/SOURCES/0324-grub_file_-instrumentation-new-file-debug-tag.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Fri, 29 Nov 2019 11:02:00 +0100
+Subject: [PATCH] grub_file_* instrumentation (new 'file' debug tag)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/kern/file.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index 668f8930b19..c2d9a550007 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -67,6 +67,8 @@ grub_file_open (const char *name)
+   const char *file_name;
+   grub_file_filter_id_t filter;
+ 
++  grub_dprintf ("file", "Opening `%s' ...\n", name);
++
+   device_name = grub_file_get_device_name (name);
+   if (grub_errno)
+     goto fail;
+@@ -127,6 +129,8 @@ grub_file_open (const char *name)
+   grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
+ 	       sizeof (grub_file_filters_enabled));
+ 
++  grub_dprintf ("file", "Opening `%s' succeeded.\n", name);
++
+   return file;
+ 
+  fail:
+@@ -140,6 +144,8 @@ grub_file_open (const char *name)
+   grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
+ 	       sizeof (grub_file_filters_enabled));
+ 
++  grub_dprintf ("file", "Opening `%s' failed.\n", name);
++
+   return 0;
+ }
+ 
+@@ -171,6 +177,7 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
+ 
+   if (len == 0)
+     return 0;
++
+   read_hook = file->read_hook;
+   read_hook_data = file->read_hook_data;
+   if (!file->read_hook)
+@@ -191,11 +198,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
+ grub_err_t
+ grub_file_close (grub_file_t file)
+ {
++  grub_dprintf ("file", "Closing `%s' ...\n", file->name);
+   if (file->fs->close)
+     (file->fs->close) (file);
+ 
+   if (file->device)
+     grub_device_close (file->device);
++
++  if (grub_errno == GRUB_ERR_NONE)
++    grub_dprintf ("file", "Closing `%s' succeeded.\n", file->name);
++  else
++    grub_dprintf ("file", "Closing `%s' failed with %d.\n", file->name, grub_errno);
++
+   grub_free (file->name);
+   grub_free (file);
+   return grub_errno;
diff --git a/SOURCES/0325-ieee1275-Avoiding-many-unecessary-open-close.patch b/SOURCES/0325-ieee1275-Avoiding-many-unecessary-open-close.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c92467de50bb11a981715acd0f7a07df04c03d7a
--- /dev/null
+++ b/SOURCES/0325-ieee1275-Avoiding-many-unecessary-open-close.patch
@@ -0,0 +1,136 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Mon, 14 Dec 2020 17:42:45 +0100
+Subject: [PATCH] ieee1275: Avoiding many unecessary open/close
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/disk/ieee1275/ofdisk.c | 64 ++++++++++++++++++++++------------------
+ 1 file changed, 35 insertions(+), 29 deletions(-)
+
+diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
+index d887d4b6eee..f3a6ecd797f 100644
+--- a/grub-core/disk/ieee1275/ofdisk.c
++++ b/grub-core/disk/ieee1275/ofdisk.c
+@@ -44,7 +44,7 @@ struct ofdisk_hash_ent
+ };
+ 
+ static grub_err_t
+-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
++grub_ofdisk_get_block_size (grub_uint32_t *block_size,
+ 			    struct ofdisk_hash_ent *op);
+ 
+ #define OFDISK_HASH_SZ	8
+@@ -461,6 +461,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+   grub_ssize_t actual;
+   grub_uint32_t block_size = 0;
+   grub_err_t err;
++  struct ofdisk_hash_ent *op;
+ 
+   if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0)
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+@@ -471,6 +472,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+ 
+   grub_dprintf ("disk", "Opening `%s'.\n", devpath);
+ 
++  op = ofdisk_hash_find (devpath);
++  if (!op)
++    op = ofdisk_hash_add (devpath, NULL);
++  if (!op)
++    {
++      grub_free (devpath);
++      return grub_errno;
++    }
++
++  /* Check if the call to open is the same to the last disk already opened */
++  if (last_devpath && !grub_strcmp(op->open_path,last_devpath))
++  {
++      goto finish;
++  }
++
++ /* If not, we need to close the previous disk and open the new one */
++  else {
++    if (last_ihandle){
++        grub_ieee1275_close (last_ihandle);
++    }
++    last_ihandle = 0;
++    last_devpath = NULL;
++
++    grub_ieee1275_open (op->open_path, &last_ihandle);
++    if (! last_ihandle)
++      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
++    last_devpath = op->open_path;
++  }
++
+   if (grub_ieee1275_finddevice (devpath, &dev))
+     {
+       grub_free (devpath);
+@@ -491,25 +521,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device");
+     }
+ 
++
++  finish:
+   /* XXX: There is no property to read the number of blocks.  There
+      should be a property `#blocks', but it is not there.  Perhaps it
+      is possible to use seek for this.  */
+   disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
+ 
+   {
+-    struct ofdisk_hash_ent *op;
+-    op = ofdisk_hash_find (devpath);
+-    if (!op)
+-      op = ofdisk_hash_add (devpath, NULL);
+-    if (!op)
+-      {
+-        grub_free (devpath);
+-        return grub_errno;
+-      }
+     disk->id = (unsigned long) op;
+     disk->data = op->open_path;
+ 
+-    err = grub_ofdisk_get_block_size (devpath, &block_size, op);
++    err = grub_ofdisk_get_block_size (&block_size, op);
+     if (err)
+       {
+         grub_free (devpath);
+@@ -532,13 +555,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+ static void
+ grub_ofdisk_close (grub_disk_t disk)
+ {
+-  if (disk->data == last_devpath)
+-    {
+-      if (last_ihandle)
+-	grub_ieee1275_close (last_ihandle);
+-      last_ihandle = 0;
+-      last_devpath = NULL;
+-    }
+   disk->data = 0;
+ }
+ 
+@@ -685,7 +701,7 @@ grub_ofdisk_init (void)
+ }
+ 
+ static grub_err_t
+-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
++grub_ofdisk_get_block_size (grub_uint32_t *block_size,
+ 			    struct ofdisk_hash_ent *op)
+ {
+   struct size_args_ieee1275
+@@ -698,16 +714,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
+       grub_ieee1275_cell_t size2;
+     } args_ieee1275;
+ 
+-  if (last_ihandle)
+-    grub_ieee1275_close (last_ihandle);
+-
+-  last_ihandle = 0;
+-  last_devpath = NULL;
+-
+-  grub_ieee1275_open (device, &last_ihandle);
+-  if (! last_ihandle)
+-    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+-
+   *block_size = 0;
+ 
+   if (op->block_size_fails >= 2)
diff --git a/SOURCES/0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/SOURCES/0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9fa02bb1748cd09b8bc33e536d1736bca49b5c96
--- /dev/null
+++ b/SOURCES/0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
@@ -0,0 +1,90 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Mon, 14 Dec 2020 17:45:28 +0100
+Subject: [PATCH] ieee1275/powerpc: implements fibre channel discovery for
+ ofpathname
+
+grub-ofpathname doesn't work with fibre channel because there is no
+function currently implemented for it.
+This patch enables it by prividing a function that looks for the port
+name, building the entire path for OF devices.
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/osdep/linux/ofpath.c | 49 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
+index a6153d35954..0f5d54e9f2d 100644
+--- a/grub-core/osdep/linux/ofpath.c
++++ b/grub-core/osdep/linux/ofpath.c
+@@ -350,6 +350,38 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi
+   return ret;
+ }
+ 
++
++static void
++of_fc_port_name(const char *path, const char *subpath, char *port_name)
++{
++  char *bname, *basepath, *p;
++  int fd;
++
++  bname = xmalloc(sizeof(char)*150);
++  basepath = xmalloc(strlen(path));
++
++  /* Generate the path to get port name information from the drive */
++  strncpy(basepath,path,subpath-path);
++  basepath[subpath-path-1] = '\0';
++  p = get_basename(basepath);
++  snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p);
++
++  /* Read the information from the port name */
++  fd = open (bname, O_RDONLY);
++  if (fd < 0)
++    grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno));
++
++  if (read(fd,port_name,sizeof(char)*19) < 0)
++    grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno));
++
++  sscanf(port_name,"0x%s",port_name);
++  
++  close(fd);
++
++  free(bname);
++  free(basepath);
++}
++
+ #ifdef __sparc__
+ static char *
+ of_path_of_nvme(const char *sys_devname __attribute__((unused)),
+@@ -577,6 +609,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+   digit_string = trailing_digits (device);
+   if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0)
+     {
++      if(strstr(of_path,"vfc-client"))
++      {
++	char * port_name = xmalloc(sizeof(char)*17);
++	of_fc_port_name(sysfs_path, p, port_name);
++	
++	snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
++	free(port_name);
++      }
++      else
++      {
+       unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun;
+       if (*digit_string == '\0')
+ 	{
+@@ -590,6 +632,13 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+ 	  snprintf(disk, sizeof (disk),
+ 		   "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1));
+ 	}
++	}
++    } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){
++	char * port_name = xmalloc(sizeof(char)*17);
++	of_fc_port_name(sysfs_path, p, port_name);
++	
++	snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
++	free(port_name);
+     }
+   else
+     {
diff --git a/SOURCES/0327-ieee1275-powerpc-enables-device-mapper-discovery.patch b/SOURCES/0327-ieee1275-powerpc-enables-device-mapper-discovery.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6f1c21b383fd252e4854dc3887291f85548cb242
--- /dev/null
+++ b/SOURCES/0327-ieee1275-powerpc-enables-device-mapper-discovery.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Mon, 14 Dec 2020 17:47:16 +0100
+Subject: [PATCH] ieee1275/powerpc: enables device mapper discovery
+
+this patch enables the device mapper discovery on ofpath.c. Currently,
+when we are dealing with a device like /dev/dm-* the ofpath returns null
+since there is no function implemented to handle this case.
+
+This patch implements a function that will look into /sys/block/dm-*
+devices and search recursively inside slaves directory to find the root
+disk.
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/osdep/linux/ofpath.c | 64 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 63 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
+index 0f5d54e9f2d..cc849d9c94c 100644
+--- a/grub-core/osdep/linux/ofpath.c
++++ b/grub-core/osdep/linux/ofpath.c
+@@ -37,6 +37,7 @@
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <ctype.h>
++#include <dirent.h>
+ 
+ #ifdef __sparc__
+ typedef enum
+@@ -755,13 +756,74 @@ strip_trailing_digits (const char *p)
+   return new;
+ }
+ 
++static char *
++get_slave_from_dm(const char * device){
++  char *curr_device, *tmp;
++  char *directory;
++  char *ret = NULL;
++
++  directory = grub_strdup (device);
++  tmp = get_basename(directory);
++  curr_device = grub_strdup (tmp);
++  *tmp = '\0';
++
++  /* Recursively check for slaves devices so we can find the root device */
++  while ((curr_device[0] == 'd') && (curr_device[1] == 'm') && (curr_device[2] == '-')){
++    DIR *dp;
++    struct dirent *ep;
++    char* device_path;
++
++    device_path = grub_xasprintf ("/sys/block/%s/slaves", curr_device);
++    dp = opendir(device_path);
++    free(device_path);
++
++    if (dp != NULL)
++    {
++      ep = readdir (dp);
++      while (ep != NULL){
++
++	/* avoid some system directories */
++        if (!strcmp(ep->d_name,"."))
++            goto next_dir;
++        if (!strcmp(ep->d_name,".."))
++            goto next_dir;
++
++	free (curr_device);
++	free (ret);
++	curr_device = grub_strdup (ep->d_name);
++	ret = grub_xasprintf ("%s%s", directory, curr_device);
++	break;
++
++        next_dir:
++         ep = readdir (dp);
++         continue;
++      }
++      closedir (dp);
++    }
++    else
++      grub_util_warn (_("cannot open directory `%s'"), device_path);
++  }
++
++  free (directory);
++  free (curr_device);
++
++  return ret;
++}
++
+ char *
+ grub_util_devname_to_ofpath (const char *sys_devname)
+ {
+-  char *name_buf, *device, *devnode, *devicenode, *ofpath;
++  char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname;
+ 
+   name_buf = xrealpath (sys_devname);
+ 
++  realname = get_slave_from_dm (name_buf);
++  if (realname)
++    {
++      free (name_buf);
++      name_buf = realname;
++    }
++
+   device = get_basename (name_buf);
+   devnode = strip_trailing_digits (name_buf);
+   devicenode = strip_trailing_digits (device);
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
new file mode 100644
index 0000000000000000000000000000000000000000..2f053c84c6cf1382530ae6e7c5e04cb6ecb3ff8c
--- /dev/null
+++ b/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
@@ -0,0 +1,239 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Fri, 18 Dec 2020 15:39:26 +0100
+Subject: [PATCH] Add 'at_keyboard_fallback_set' var to force the set manually
+
+This seems required with HP DL380p Gen 8 systems.
+Indeed, with this system, we can see the following sequence:
+
+1. controller is queried to get current configuration (returns 0x30 which is quite standard)
+2. controller is queried to get the current keyboard set in used, using code 0xf0 (first part)
+3. controller answers with 0xfa which means "ACK" (== ok)
+4. then we send "0" to tell "we want to know which set your are supporting"
+5. controller answers with 0xfa ("ACK")
+6. controller should then give us 1, 2, 3 or 0x43, 0x41, 0x3f, but here it gives us 0xfe which means "NACK"
+
+Since there seems no way to determine the current set, and in fact the
+controller expects set2 to be used, we need to rely on an environment
+variable.
+Everything has been tested on this system: using 0xFE (resend command),
+making sure we wait for ACK in the 2 steps "write_mode", etc.
+
+Below is litterature I used to come up with "there is no other
+solution":
+- https://wiki.osdev.org/%228042%22_PS/2_Controller
+- 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 | 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..c805cccbdde 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ static grub_uint8_t grub_keyboard_controller_orig;
+ static grub_uint8_t grub_keyboard_orig_set;
+ struct grub_ps2_state ps2_state;
++static int fallback_set;
+ 
+ static int ping_sent;
+ 
+@@ -76,6 +77,8 @@ at_command (grub_uint8_t data)
+ 	break;
+       return 0;
+     }
++  if (i == GRUB_AT_TRIES)
++    grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i);
+   return (i != GRUB_AT_TRIES);
+ }
+ 
+@@ -105,6 +108,21 @@ grub_keyboard_controller_read (void)
+ 
+ #endif
+ 
++static int
++resend_last_result (void)
++{
++  grub_uint8_t ret;
++  keyboard_controller_wait_until_ready ();
++  grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n");
++  grub_outb (0xfe, KEYBOARD_REG_DATA);
++  ret = wait_ack ();
++  grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret);
++  keyboard_controller_wait_until_ready ();
++  ret = grub_inb (KEYBOARD_REG_DATA);
++  grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret);
++  return ret;
++}
++
+ static int
+ 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);
+       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 ();
+       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 +146,9 @@ write_mode (int mode)
+       return 0;
+     }
+ 
++  if (i == GRUB_AT_TRIES)
++    grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i);
++
+   return (i != GRUB_AT_TRIES);
+ }
+ 
+@@ -132,31 +156,66 @@ static int
+ query_mode (void)
+ {
+   grub_uint8_t ret;
++  grub_uint64_t endtime;
++  unsigned i;
+   int e;
++  char *envvar;
+ 
+-  e = write_mode (0);
+-  if (!e) {
+-    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
+-    return 0;
+-  }
++  for (i = 0; i < GRUB_AT_TRIES; i++) {
++    grub_dprintf ("atkeyb", "query_mode: sending command to controller\n");
++    e = write_mode (0);
++    if (!e) {
++      grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n");
++      return 0;
++    }
+ 
+-  do {
+-    keyboard_controller_wait_until_ready ();
+-    ret = grub_inb (KEYBOARD_REG_DATA);
+-  } while (ret == GRUB_AT_ACK);
+-  /* QEMU translates the set even in no-translate mode.  */
+-  if (ret == 0x43 || ret == 1) {
+-    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
+-    return 1;
+-  }
+-  if (ret == 0x41 || ret == 2) {
+-    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
+-    return 2;
++    endtime = grub_get_time_ms () + 20;
++    do {
++      keyboard_controller_wait_until_ready ();
++      ret = grub_inb (KEYBOARD_REG_DATA);
++      grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret);
++    } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime);
++    if (ret == 0xfe) {
++      grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n");
++      ret = resend_last_result();
++      grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret);
++    }
++    /* QEMU translates the set even in no-translate mode.  */
++    if (ret == 0x43 || ret == 1) {
++      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret);
++      return 1;
++    }
++    if (ret == 0x41 || ret == 2) {
++      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret);
++      return 2;
++    }
++    if (ret == 0x3f || ret == 3) {
++      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret);
++      return 3;
++    }
++    grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret);
+   }
+-  if (ret == 0x3f || ret == 3) {
+-    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
+-    return 3;
++
++  /*
++   * Falling here means we tried querying and the controller returned something
++   * we don't understand, try to use 'at_keyboard_fallback_set' if it exists,
++   * otherwise return 0.
++   */
++  envvar = grub_env_get ("at_keyboard_fallback_set");
++  if (envvar) {
++    fallback_set = grub_strtoul (envvar, 0, 10);
++    if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) {
++      grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n",
++		    envvar, "at_keyboard_fallback_set");
++      fallback_set = 0;
++    } else {
++      grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n",
++		    "at_keyboard_fallback_set", fallback_set);
++    }
++    return fallback_set;
+   }
++  grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n",
++		"at_keyboard_fallback_set");
+   return 0;
+ }
+ 
+@@ -165,14 +224,25 @@ set_scancodes (void)
+ {
+   /* You must have visited computer museum. Keyboard without scancode set
+      knowledge. Assume XT. */
+-  if (!grub_keyboard_orig_set)
+-    {
+-      grub_dprintf ("atkeyb", "No sets support assumed\n");
+-      ps2_state.current_set = 1;
++  if (!grub_keyboard_orig_set) {
++    if (fallback_set) {
++      grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set);
++      ps2_state.current_set = fallback_set;
+       return;
+     }
++    grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n");
++    ps2_state.current_set = 1;
++    return;
++  }
+ 
+ #if !USE_SCANCODE_SET
++  if (fallback_set) {
++    grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n",
++		  grub_keyboard_orig_set, fallback_set);
++    ps2_state.current_set = fallback_set;
++    return;
++  }
++
+   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;
+@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
+ static void
+ grub_keyboard_controller_init (void)
+ {
++  grub_dprintf ("atkeyb", "initializing the controller\n");
+   ps2_state.at_keyboard_status = 0;
+   /* Drain input buffer. */
+   while (1)
+@@ -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 ();
++  grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set);
+ #endif
+   set_scancodes ();
+   keyboard_controller_led (ps2_state.led_status);
+@@ -329,7 +401,6 @@ grub_at_restore_hw (void)
+   return GRUB_ERR_NONE;
+ }
+ 
+-
+ static struct grub_term_input grub_at_keyboard_term =
+   {
+     .name = "at_keyboard",
diff --git a/SOURCES/0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch b/SOURCES/0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2d35cc8ac22e9617efe9a4d99bd2784bac73fbbc
--- /dev/null
+++ b/SOURCES/0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch
@@ -0,0 +1,60 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Mon, 29 Oct 2018 13:25:25 +0100
+Subject: [PATCH] bufio: Use grub_size_t instead of plain int for size
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+(cherry picked from commit f3f8347569383e7f483f37ca70d41eb1af9f990f)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/io/bufio.c | 6 +++---
+ include/grub/bufio.h | 4 ++--
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
+index 6118bade50d..2781afe0515 100644
+--- a/grub-core/io/bufio.c
++++ b/grub-core/io/bufio.c
+@@ -43,7 +43,7 @@ typedef struct grub_bufio *grub_bufio_t;
+ static struct grub_fs grub_bufio_fs;
+ 
+ grub_file_t
+-grub_bufio_open (grub_file_t io, int size)
++grub_bufio_open (grub_file_t io, grub_size_t size)
+ {
+   grub_file_t file;
+   grub_bufio_t bufio = 0;
+@@ -57,7 +57,7 @@ grub_bufio_open (grub_file_t io, int size)
+   else if (size > GRUB_BUFIO_MAX_SIZE)
+     size = GRUB_BUFIO_MAX_SIZE;
+ 
+-  if ((size < 0) || ((unsigned) size > io->size))
++  if (size > io->size)
+     size = ((io->size > GRUB_BUFIO_MAX_SIZE) ? GRUB_BUFIO_MAX_SIZE :
+             io->size);
+ 
+@@ -88,7 +88,7 @@ grub_bufio_open (grub_file_t io, int size)
+ }
+ 
+ grub_file_t
+-grub_buffile_open (const char *name, int size)
++grub_buffile_open (const char *name, grub_size_t size)
+ {
+   grub_file_t io, file;
+ 
+diff --git a/include/grub/bufio.h b/include/grub/bufio.h
+index acdd0c882c6..77eb8ee5672 100644
+--- a/include/grub/bufio.h
++++ b/include/grub/bufio.h
+@@ -22,7 +22,7 @@
+ 
+ #include <grub/file.h>
+ 
+-grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, int size);
+-grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, int size);
++grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, grub_size_t size);
++grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, grub_size_t size);
+ 
+ #endif /* ! GRUB_BUFIO_H */
diff --git a/SOURCES/0330-verifiers-File-type-for-fine-grained-signature-verif.patch b/SOURCES/0330-verifiers-File-type-for-fine-grained-signature-verif.patch
new file mode 100644
index 0000000000000000000000000000000000000000..12baee27fef538f461d70561e33e5c83e38ad5fd
--- /dev/null
+++ b/SOURCES/0330-verifiers-File-type-for-fine-grained-signature-verif.patch
@@ -0,0 +1,1738 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Vladimir Serbinenko <phcoder@gmail.com>
+Date: Wed, 20 Nov 2013 02:28:29 +0100
+Subject: [PATCH] verifiers: File type for fine-grained signature-verification
+ controlling
+
+Let's provide file type info to the I/O layer. This way verifiers
+framework and its users will be able to differentiate files and verify
+only required ones.
+
+This is preparatory patch.
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+(backported from commit ca0a4f689a02c2c5a5e385f874aaaa38e151564e)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/acpi.c                    |   2 +-
+ grub-core/commands/blocklist.c               |   4 +-
+ grub-core/commands/cat.c                     |   2 +-
+ grub-core/commands/cmp.c                     |   4 +-
+ grub-core/commands/efi/loadbios.c            |   4 +-
+ grub-core/commands/file.c                    |   5 +-
+ grub-core/commands/hashsum.c                 |  22 ++--
+ grub-core/commands/hexdump.c                 |   2 +-
+ grub-core/commands/i386/pc/play.c            |   2 +-
+ grub-core/commands/keylayouts.c              |   2 +-
+ grub-core/commands/legacycfg.c               |   2 +-
+ grub-core/commands/loadenv.c                 |  24 +++--
+ grub-core/commands/ls.c                      |   8 +-
+ grub-core/commands/minicmd.c                 |   2 +-
+ grub-core/commands/nativedisk.c              |   3 +-
+ grub-core/commands/parttool.c                |   2 +-
+ grub-core/commands/search.c                  |   4 +-
+ grub-core/commands/test.c                    |   4 +-
+ grub-core/commands/testload.c                |   2 +-
+ grub-core/commands/testspeed.c               |   2 +-
+ grub-core/commands/verify.c                  |  51 ++++-----
+ grub-core/disk/loopback.c                    |   3 +-
+ grub-core/efiemu/main.c                      |   2 +-
+ grub-core/font/font.c                        |   4 +-
+ grub-core/fs/zfs/zfscrypt.c                  |   2 +-
+ grub-core/gettext/gettext.c                  |   2 +-
+ grub-core/gfxmenu/theme_loader.c             |   2 +-
+ grub-core/io/bufio.c                         |   4 +-
+ grub-core/io/gzio.c                          |   5 +-
+ grub-core/io/lzopio.c                        |   6 +-
+ grub-core/io/offset.c                        |   7 +-
+ grub-core/io/xzio.c                          |   6 +-
+ grub-core/kern/dl.c                          |   2 +-
+ grub-core/kern/elf.c                         |   4 +-
+ grub-core/kern/file.c                        |  22 ++--
+ grub-core/lib/syslinux_parse.c               |   2 +-
+ grub-core/loader/efi/chainloader.c           |   2 +-
+ grub-core/loader/i386/bsd.c                  |  16 +--
+ grub-core/loader/i386/coreboot/chainloader.c |   2 +-
+ grub-core/loader/i386/linux.c                |   2 +-
+ grub-core/loader/i386/pc/chainloader.c       |   4 +-
+ grub-core/loader/i386/pc/freedos.c           |   2 +-
+ grub-core/loader/i386/pc/linux.c             |   2 +-
+ grub-core/loader/i386/pc/ntldr.c             |   2 +-
+ grub-core/loader/i386/pc/plan9.c             |   2 +-
+ grub-core/loader/i386/pc/pxechainloader.c    |   2 +-
+ grub-core/loader/i386/pc/truecrypt.c         |   2 +-
+ grub-core/loader/i386/xen.c                  |   7 +-
+ grub-core/loader/i386/xen_file.c             |   2 +-
+ grub-core/loader/i386/xnu.c                  |   2 +-
+ grub-core/loader/linux.c                     |   6 +-
+ grub-core/loader/macho.c                     |   4 +-
+ grub-core/loader/mips/linux.c                |   2 +-
+ grub-core/loader/multiboot.c                 |   8 +-
+ grub-core/loader/xnu.c                       |  16 +--
+ grub-core/loader/xnu_resume.c                |   4 +-
+ grub-core/normal/autofs.c                    |  11 +-
+ grub-core/normal/crypto.c                    |   2 +-
+ grub-core/normal/dyncmd.c                    |   2 +-
+ grub-core/normal/main.c                      |   2 +-
+ grub-core/normal/term.c                      |   2 +-
+ grub-core/video/readers/jpeg.c               |   2 +-
+ grub-core/video/readers/png.c                |   2 +-
+ grub-core/video/readers/tga.c                |   2 +-
+ util/grub-fstest.c                           |   6 +-
+ util/grub-mount.c                            |   6 +-
+ include/grub/bufio.h                         |   4 +-
+ include/grub/elfload.h                       |   2 +-
+ include/grub/file.h                          | 152 +++++++++++++++++++--------
+ include/grub/machoload.h                     |   3 +-
+ 70 files changed, 292 insertions(+), 221 deletions(-)
+
+diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c
+index 9f02f22019a..5a1499aa0e3 100644
+--- a/grub-core/commands/acpi.c
++++ b/grub-core/commands/acpi.c
+@@ -635,7 +635,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
+       grub_size_t size;
+       char *buf;
+ 
+-      file = grub_file_open (args[i]);
++      file = grub_file_open (args[i], GRUB_FILE_TYPE_ACPI_TABLE);
+       if (! file)
+ 	{
+ 	  free_tables ();
+diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c
+index d1a47b504bf..944449b77d4 100644
+--- a/grub-core/commands/blocklist.c
++++ b/grub-core/commands/blocklist.c
+@@ -121,8 +121,8 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
+   if (argc < 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  grub_file_filter_disable_compression ();
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_PRINT_BLOCKLIST
++			 | GRUB_FILE_TYPE_NO_DECOMPRESS);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c
+index 88d90443602..ba5f0061aa5 100644
+--- a/grub-core/commands/cat.c
++++ b/grub-core/commands/cat.c
+@@ -56,7 +56,7 @@ grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (argc != 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_CAT);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c
+index cc23ee67ea3..e9c3b25d34c 100644
+--- a/grub-core/commands/cmp.c
++++ b/grub-core/commands/cmp.c
+@@ -45,8 +45,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
+   grub_printf_ (N_("Compare file `%s' with `%s':\n"), args[0],
+ 		args[1]);
+ 
+-  file1 = grub_file_open (args[0]);
+-  file2 = grub_file_open (args[1]);
++  file1 = grub_file_open (args[0], GRUB_FILE_TYPE_CMP);
++  file2 = grub_file_open (args[1], GRUB_FILE_TYPE_CMP);
+   if (! file1 || ! file2)
+     goto cleanup;
+ 
+diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c
+index 132cadbc764..d41d521a4ae 100644
+--- a/grub-core/commands/efi/loadbios.c
++++ b/grub-core/commands/efi/loadbios.c
+@@ -169,7 +169,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)),
+ 
+   if (argc > 1)
+     {
+-      file = grub_file_open (argv[1]);
++      file = grub_file_open (argv[1], GRUB_FILE_TYPE_VBE_DUMP);
+       if (! file)
+ 	return grub_errno;
+ 
+@@ -183,7 +183,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)),
+ 	return grub_errno;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_VBE_DUMP);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/commands/file.c b/grub-core/commands/file.c
+index 3ff6d5522d2..4f81aa1f9e1 100644
+--- a/grub-core/commands/file.c
++++ b/grub-core/commands/file.c
+@@ -165,7 +165,7 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (type == -1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no type specified");
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL);
+   if (!file)
+     return grub_errno;
+   switch (type)
+@@ -546,7 +546,8 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+     case IS_XNU64:
+     case IS_XNU32:
+       {
+-	macho = grub_macho_open (args[0], (type == IS_XNU64));
++	macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL,
++				 (type == IS_XNU64));
+ 	if (!macho)
+ 	  break;
+ 	/* FIXME: more checks?  */
+diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c
+index d18687351a5..456ba908b6f 100644
+--- a/grub-core/commands/hashsum.c
++++ b/grub-core/commands/hashsum.c
+@@ -113,7 +113,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
+   if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN)
+     return grub_error (GRUB_ERR_BUG, "mdlen is too long");
+ 
+-  hashlist = grub_file_open (hashfilename);
++  hashlist = grub_file_open (hashfilename, GRUB_FILE_TYPE_HASHLIST);
+   if (!hashlist)
+     return grub_errno;
+   
+@@ -141,17 +141,15 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
+ 	  filename = grub_xasprintf ("%s/%s", prefix, p);
+ 	  if (!filename)
+ 	    return grub_errno;
+-	  if (!uncompress)
+-	    grub_file_filter_disable_compression ();
+-	  file = grub_file_open (filename);
++	  file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH
++				 | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
++				    : GRUB_FILE_TYPE_NONE));
+ 	  grub_free (filename);
+ 	}
+       else
+-	{
+-	  if (!uncompress)
+-	    grub_file_filter_disable_compression ();
+-	  file = grub_file_open (p);
+-	}
++	file = grub_file_open (p, GRUB_FILE_TYPE_TO_HASH
++			       | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
++				  : GRUB_FILE_TYPE_NONE));
+       if (!file)
+ 	{
+ 	  grub_file_close (hashlist);
+@@ -242,9 +240,9 @@ grub_cmd_hashsum (struct grub_extcmd_context *ctxt,
+       grub_file_t file;
+       grub_err_t err;
+       unsigned j;
+-      if (!uncompress)
+-	grub_file_filter_disable_compression ();
+-      file = grub_file_open (args[i]);
++      file = grub_file_open (args[i], GRUB_FILE_TYPE_TO_HASH
++			     | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
++				: GRUB_FILE_TYPE_NONE));
+       if (!file)
+ 	{
+ 	  if (!keep)
+diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c
+index 4c884b3a19a..eaa12465bb3 100644
+--- a/grub-core/commands/hexdump.c
++++ b/grub-core/commands/hexdump.c
+@@ -90,7 +90,7 @@ grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args)
+     {
+       grub_file_t file;
+ 
+-      file = grub_file_open (args[0]);
++      file = grub_file_open (args[0], GRUB_FILE_TYPE_HEXCAT);
+       if (! file)
+ 	return 0;
+ 
+diff --git a/grub-core/commands/i386/pc/play.c b/grub-core/commands/i386/pc/play.c
+index 7712e2a36a1..c8181310515 100644
+--- a/grub-core/commands/i386/pc/play.c
++++ b/grub-core/commands/i386/pc/play.c
+@@ -93,7 +93,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)),
+       grub_uint32_t tempo;
+       grub_file_t file;
+ 
+-      file = grub_file_open (args[0]);
++      file = grub_file_open (args[0], GRUB_FILE_TYPE_AUDIO);
+ 
+       if (! file)
+         return grub_errno;
+diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
+index f35d3a369ba..c05d6128a6d 100644
+--- a/grub-core/commands/keylayouts.c
++++ b/grub-core/commands/keylayouts.c
+@@ -220,7 +220,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)),
+   else
+     filename = argv[0];
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_KEYBOARD_LAYOUT);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c
+index 0de070eacc4..f5696a51a75 100644
+--- a/grub-core/commands/legacycfg.c
++++ b/grub-core/commands/legacycfg.c
+@@ -56,7 +56,7 @@ legacy_file (const char *filename)
+   if (!suffix)
+     return grub_errno;
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG);
+   if (! file)
+     {
+       grub_free (suffix);
+diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
+index 91c99456091..163b9a09042 100644
+--- a/grub-core/commands/loadenv.c
++++ b/grub-core/commands/loadenv.c
+@@ -46,7 +46,8 @@ static const struct grub_arg_option options[] =
+    PUBKEY filter (that insists upon properly signed files) as well.  PUBKEY
+    filter is restored before the function returns. */
+ static grub_file_t
+-open_envblk_file (char *filename, int untrusted)
++open_envblk_file (char *filename,
++		  enum grub_file_type type)
+ {
+   grub_file_t file;
+   char *buf = 0;
+@@ -74,13 +75,7 @@ open_envblk_file (char *filename, int untrusted)
+       grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
+     }
+ 
+-  /* The filters that are disabled will be re-enabled by the call to
+-     grub_file_open() after this particular file is opened. */
+-  grub_file_filter_disable_compression ();
+-  if (untrusted)
+-    grub_file_filter_disable_pubkey ();
+-
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, type);
+ 
+   grub_free (buf);
+   return file;
+@@ -98,7 +93,10 @@ grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
+   whitelist.list = args;
+ 
+   /* state[0] is the -f flag; state[1] is the --skip-sig flag */
+-  file = open_envblk_file ((state[0].set) ? state[0].arg : 0, state[1].set);
++  file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
++			   GRUB_FILE_TYPE_LOADENV
++			   | (state[1].set
++			      ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE));
+   if (! file)
+     return grub_errno;
+ 
+@@ -133,7 +131,10 @@ grub_cmd_list_env (grub_extcmd_context_t ctxt,
+   grub_file_t file;
+   grub_envblk_t envblk;
+ 
+-  file = open_envblk_file ((state[0].set) ? state[0].arg : 0, 0);
++  file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
++			   GRUB_FILE_TYPE_LOADENV
++			   | (state[1].set
++			      ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE));
+   if (! file)
+     return grub_errno;
+ 
+@@ -317,7 +318,8 @@ grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified");
+ 
+   file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+-                           1 /* allow untrusted */);
++			   GRUB_FILE_TYPE_SAVEENV
++			   | GRUB_FILE_TYPE_SKIP_SIGNATURE);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c
+index c25161cc4f2..2cdb2acc552 100644
+--- a/grub-core/commands/ls.c
++++ b/grub-core/commands/ls.c
+@@ -129,8 +129,8 @@ print_files_long (const char *filename, const struct grub_dirhook_info *info,
+ 
+       /* XXX: For ext2fs symlinks are detected as files while they
+ 	 should be reported as directories.  */
+-      grub_file_filter_disable_compression ();
+-      file = grub_file_open (pathname);
++      file = grub_file_open (pathname, GRUB_FILE_TYPE_GET_SIZE
++			     | GRUB_FILE_TYPE_NO_DECOMPRESS);
+       if (! file)
+ 	{
+ 	  grub_errno = 0;
+@@ -234,8 +234,8 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
+ 	  struct grub_dirhook_info info;
+ 	  grub_errno = 0;
+ 
+-	  grub_file_filter_disable_compression ();
+-	  file = grub_file_open (dirname);
++	  file = grub_file_open (dirname, GRUB_FILE_TYPE_GET_SIZE
++				 | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ 	  if (! file)
+ 	    goto fail;
+ 
+diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
+index b25ca4b9f17..46bf135e8f0 100644
+--- a/grub-core/commands/minicmd.c
++++ b/grub-core/commands/minicmd.c
+@@ -43,7 +43,7 @@ grub_mini_cmd_cat (struct grub_command *cmd __attribute__ ((unused)),
+   if (argc < 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_CAT);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c
+index d69214f6de0..f200a5ce092 100644
+--- a/grub-core/commands/nativedisk.c
++++ b/grub-core/commands/nativedisk.c
+@@ -242,7 +242,8 @@ grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)),
+       if (! filename)
+ 	goto fail;
+ 
+-      file = grub_file_open (filename);
++      file = grub_file_open (filename,
++			     GRUB_FILE_TYPE_GRUB_MODULE);
+       grub_free (filename);
+       if (! file)
+ 	goto fail;
+diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c
+index 36dadc0b1db..051e31320e9 100644
+--- a/grub-core/commands/parttool.c
++++ b/grub-core/commands/parttool.c
+@@ -199,7 +199,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)),
+ 	  {
+ 	    grub_file_t file;
+ 
+-	    file = grub_file_open (filename);
++	    file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST);
+ 	    if (file)
+ 	      {
+ 		char *buf = 0;
+diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
+index 7dd32e445c9..ddda6e7c590 100644
+--- a/grub-core/commands/search.c
++++ b/grub-core/commands/search.c
+@@ -81,8 +81,8 @@ iterate_device (const char *name, void *data)
+       if (! buf)
+ 	return 1;
+ 
+-      grub_file_filter_disable_compression ();
+-      file = grub_file_open (buf);
++      file = grub_file_open (buf, GRUB_FILE_TYPE_FS_SEARCH
++			     | GRUB_FILE_TYPE_NO_DECOMPRESS);
+       if (file)
+ 	{
+ 	  found = 1;
+diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c
+index 5f06642f6c6..13c6ed9534a 100644
+--- a/grub-core/commands/test.c
++++ b/grub-core/commands/test.c
+@@ -355,8 +355,8 @@ test_parse (char **args, int *argn, int argc)
+ 	  if (grub_strcmp (args[*argn], "-s") == 0)
+ 	    {
+ 	      grub_file_t file;
+-	      grub_file_filter_disable_compression ();
+-	      file = grub_file_open (args[*argn + 1]);
++	      file = grub_file_open (args[*argn + 1], GRUB_FILE_TYPE_GET_SIZE
++				     | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ 	      update_val (file && (grub_file_size (file) != 0), &ctx);
+ 	      if (file)
+ 		grub_file_close (file);
+diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c
+index cfab6763dc3..ff01a0516dd 100644
+--- a/grub-core/commands/testload.c
++++ b/grub-core/commands/testload.c
+@@ -57,7 +57,7 @@ grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)),
+   if (argc < 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_TESTLOAD);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/commands/testspeed.c b/grub-core/commands/testspeed.c
+index 042645f8d26..c13a9b8d8d2 100644
+--- a/grub-core/commands/testspeed.c
++++ b/grub-core/commands/testspeed.c
+@@ -61,7 +61,7 @@ grub_cmd_testspeed (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (buffer == NULL)
+     return grub_errno;
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_TESTLOAD);
+   if (file == NULL)
+     goto quit;
+ 
+diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
+index 67cb1c78509..f0dfeceebd4 100644
+--- a/grub-core/commands/verify.c
++++ b/grub-core/commands/verify.c
+@@ -680,10 +680,12 @@ grub_cmd_trust (grub_extcmd_context_t ctxt,
+   if (argc < 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ 
+-  grub_file_filter_disable_compression ();
+-  if (ctxt->state[OPTION_SKIP_SIG].set)
+-    grub_file_filter_disable_pubkey ();
+-  pkf = grub_file_open (args[0]);
++  pkf = grub_file_open (args[0],
++			GRUB_FILE_TYPE_PUBLIC_KEY_TRUST
++			| GRUB_FILE_TYPE_NO_DECOMPRESS
++			| (ctxt->state[OPTION_SKIP_SIG].set
++			   ? GRUB_FILE_TYPE_SKIP_SIGNATURE
++			   : GRUB_FILE_TYPE_NONE));
+   if (!pkf)
+     return grub_errno;
+   pk = grub_load_public_key (pkf);
+@@ -771,10 +773,12 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+   if (argc > 2)
+     {
+       grub_file_t pkf;
+-      grub_file_filter_disable_compression ();
+-      if (ctxt->state[OPTION_SKIP_SIG].set)
+-	grub_file_filter_disable_pubkey ();
+-      pkf = grub_file_open (args[2]);
++      pkf = grub_file_open (args[2],
++			    GRUB_FILE_TYPE_PUBLIC_KEY
++			    | GRUB_FILE_TYPE_NO_DECOMPRESS
++			    | (ctxt->state[OPTION_SKIP_SIG].set
++			       ? GRUB_FILE_TYPE_SKIP_SIGNATURE
++			       : GRUB_FILE_TYPE_NONE));
+       if (!pkf)
+ 	return grub_errno;
+       pk = grub_load_public_key (pkf);
+@@ -786,16 +790,16 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+       grub_file_close (pkf);
+     }
+ 
+-  grub_file_filter_disable_all ();
+-  f = grub_file_open (args[0]);
++  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+   if (!f)
+     {
+       err = grub_errno;
+       goto fail;
+     }
+ 
+-  grub_file_filter_disable_all ();
+-  sig = grub_file_open (args[1]);
++  sig = grub_file_open (args[1],
++			GRUB_FILE_TYPE_SIGNATURE
++			| GRUB_FILE_TYPE_NO_DECOMPRESS);
+   if (!sig)
+     {
+       err = grub_errno;
+@@ -858,33 +862,32 @@ struct grub_fs verified_fs =
+ };
+ 
+ static grub_file_t
+-grub_pubkey_open (grub_file_t io, const char *filename)
++grub_pubkey_open (grub_file_t io, enum grub_file_type type)
+ {
+   grub_file_t sig;
+   char *fsuf, *ptr;
+   grub_err_t err;
+-  grub_file_filter_t curfilt[GRUB_FILE_FILTER_MAX];
+   grub_file_t ret;
+   grub_verified_t verified;
+ 
++  if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
++      || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
++      || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
++    return io;
++
+   if (!sec)
+     return io;
+   if (io->device->disk && 
+       (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
+        || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
+     return io;
+-  fsuf = grub_malloc (grub_strlen (filename) + sizeof (".sig"));
++  fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
+   if (!fsuf)
+     return NULL;
+-  ptr = grub_stpcpy (fsuf, filename);
++  ptr = grub_stpcpy (fsuf, io->name);
+   grub_memcpy (ptr, ".sig", sizeof (".sig"));
+ 
+-  grub_memcpy (curfilt, grub_file_filters_enabled,
+-	       sizeof (curfilt));
+-  grub_file_filter_disable_all ();
+-  sig = grub_file_open (fsuf);
+-  grub_memcpy (grub_file_filters_enabled, curfilt,
+-	       sizeof (curfilt));
++  sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE);
+   grub_free (fsuf);
+   if (!sig)
+     return NULL;
+@@ -918,7 +921,7 @@ grub_pubkey_open (grub_file_t io, const char *filename)
+   if (!verified->buf)
+     {
+       grub_file_close (sig);
+-      grub_free (verified);
++      verified_free (verified);
+       grub_free (ret);
+       return NULL;
+     }
+@@ -926,7 +929,7 @@ grub_pubkey_open (grub_file_t io, const char *filename)
+     {
+       if (!grub_errno)
+ 	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+-		    filename);
++		    io->name);
+       grub_file_close (sig);
+       verified_free (verified);
+       grub_free (ret);
+diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c
+index 2d8deaeafbd..9406d931cdd 100644
+--- a/grub-core/disk/loopback.c
++++ b/grub-core/disk/loopback.c
+@@ -92,7 +92,8 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (argc < 2)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (args[1]);
++  file = grub_file_open (args[1], GRUB_FILE_TYPE_LOOPBACK
++			 | GRUB_FILE_TYPE_NO_DECOMPRESS);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c
+index f6813b1ed15..a81934725be 100644
+--- a/grub-core/efiemu/main.c
++++ b/grub-core/efiemu/main.c
+@@ -187,7 +187,7 @@ grub_efiemu_load_file (const char *filename)
+   grub_file_t file;
+   grub_err_t err;
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index b36a099b856..b67507fcc82 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -422,7 +422,7 @@ grub_font_load (const char *filename)
+ #endif
+ 
+   if (filename[0] == '(' || filename[0] == '/' || filename[0] == '+')
+-    file = grub_buffile_open (filename, 1024);
++    file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024);
+   else
+     {
+       const char *prefix = grub_env_get ("prefix");
+@@ -442,7 +442,7 @@ grub_font_load (const char *filename)
+       ptr = grub_stpcpy (ptr, filename);
+       ptr = grub_stpcpy (ptr, ".pf2");
+       *ptr = 0;
+-      file = grub_buffile_open (fullname, 1024);
++      file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024);
+       grub_free (fullname);
+     }
+   if (!file)
+diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c
+index f8488c35344..de3b015f582 100644
+--- a/grub-core/fs/zfs/zfscrypt.c
++++ b/grub-core/fs/zfs/zfscrypt.c
+@@ -430,7 +430,7 @@ grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (argc > 0)
+     {
+       grub_file_t file;
+-      file = grub_file_open (args[0]);
++      file = grub_file_open (args[0], GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY);
+       if (!file)
+ 	return grub_errno;
+       real_size = grub_file_read (file, buf, 1024);
+diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
+index b22e1bcc94b..84d520cd494 100644
+--- a/grub-core/gettext/gettext.c
++++ b/grub-core/gettext/gettext.c
+@@ -291,7 +291,7 @@ grub_mofile_open (struct grub_gettext_context *ctx,
+   /* Using fd_mo and not another variable because
+      it's needed for grub_gettext_get_info.  */
+ 
+-  fd = grub_file_open (filename);
++  fd = grub_file_open (filename, GRUB_FILE_TYPE_GETTEXT_CATALOG);
+ 
+   if (!fd)
+     return grub_errno;
+diff --git a/grub-core/gfxmenu/theme_loader.c b/grub-core/gfxmenu/theme_loader.c
+index 02978392ccc..d6829bb5e90 100644
+--- a/grub-core/gfxmenu/theme_loader.c
++++ b/grub-core/gfxmenu/theme_loader.c
+@@ -743,7 +743,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
+   p.view = view;
+   p.theme_dir = grub_get_dirname (theme_path);
+ 
+-  file = grub_file_open (theme_path);
++  file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME);
+   if (! file)
+     {
+       grub_free (p.theme_dir);
+diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
+index 2781afe0515..0dbac1b3a1e 100644
+--- a/grub-core/io/bufio.c
++++ b/grub-core/io/bufio.c
+@@ -88,11 +88,11 @@ grub_bufio_open (grub_file_t io, grub_size_t size)
+ }
+ 
+ grub_file_t
+-grub_buffile_open (const char *name, grub_size_t size)
++grub_buffile_open (const char *name, enum grub_file_type type, grub_size_t size)
+ {
+   grub_file_t io, file;
+ 
+-  io = grub_file_open (name);
++  io = grub_file_open (name, type);
+   if (! io)
+     return 0;
+ 
+diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
+index 7024cda84ea..2ecf076dd5e 100644
+--- a/grub-core/io/gzio.c
++++ b/grub-core/io/gzio.c
+@@ -1156,11 +1156,14 @@ initialize_tables (grub_gzio_t gzio)
+    even if IO does not contain data compressed by gzip, return a valid file
+    object. Note that this function won't close IO, even if an error occurs.  */
+ static grub_file_t
+-grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused)))
++grub_gzio_open (grub_file_t io, enum grub_file_type type)
+ {
+   grub_file_t file;
+   grub_gzio_t gzio = 0;
+ 
++  if (type & GRUB_FILE_TYPE_NO_DECOMPRESS)
++    return io;
++
+   file = (grub_file_t) grub_zalloc (sizeof (*file));
+   if (! file)
+     return 0;
+diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c
+index 7559c6c9cab..84edf6dd2dc 100644
+--- a/grub-core/io/lzopio.c
++++ b/grub-core/io/lzopio.c
+@@ -407,12 +407,14 @@ CORRUPTED:
+ }
+ 
+ static grub_file_t
+-grub_lzopio_open (grub_file_t io,
+-		  const char *name __attribute__ ((unused)))
++grub_lzopio_open (grub_file_t io, enum grub_file_type type)
+ {
+   grub_file_t file;
+   grub_lzopio_t lzopio;
+ 
++  if (type & GRUB_FILE_TYPE_NO_DECOMPRESS)
++    return io;
++
+   file = (grub_file_t) grub_zalloc (sizeof (*file));
+   if (!file)
+     return 0;
+diff --git a/grub-core/io/offset.c b/grub-core/io/offset.c
+index ebed0ebe63e..ec8e2320871 100644
+--- a/grub-core/io/offset.c
++++ b/grub-core/io/offset.c
+@@ -69,7 +69,8 @@ grub_file_offset_close (grub_file_t file)
+ }
+ 
+ grub_file_t
+-grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size)
++grub_file_offset_open (grub_file_t parent, enum grub_file_type type,
++		       grub_off_t start, grub_off_t size)
+ {
+   struct grub_offset_file *off_data;
+   grub_file_t off_file, last_off_file;
+@@ -95,10 +96,10 @@ grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size)
+   last_off_file = NULL;
+   for (filter = GRUB_FILE_FILTER_COMPRESSION_FIRST;
+        off_file && filter <= GRUB_FILE_FILTER_COMPRESSION_LAST; filter++)
+-    if (grub_file_filters_enabled[filter])
++    if (grub_file_filters[filter])
+       {
+ 	last_off_file = off_file;
+-	off_file = grub_file_filters_enabled[filter] (off_file, parent->name);
++	off_file = grub_file_filters[filter] (off_file, type);
+       }
+ 
+   if (!off_file)
+diff --git a/grub-core/io/xzio.c b/grub-core/io/xzio.c
+index a3536ad73b1..42afeedcd64 100644
+--- a/grub-core/io/xzio.c
++++ b/grub-core/io/xzio.c
+@@ -169,12 +169,14 @@ ERROR:
+ }
+ 
+ static grub_file_t
+-grub_xzio_open (grub_file_t io,
+-		const char *name __attribute__ ((unused)))
++grub_xzio_open (grub_file_t io, enum grub_file_type type)
+ {
+   grub_file_t file;
+   grub_xzio_t xzio;
+ 
++  if (type & GRUB_FILE_TYPE_NO_DECOMPRESS)
++    return io;
++
+   file = (grub_file_t) grub_zalloc (sizeof (*file));
+   if (!file)
+     return 0;
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 91105bc4677..d7a7c8f97b0 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -806,7 +806,7 @@ grub_dl_load_file (const char *filename)
+ 
+   grub_boot_time ("Loading module %s", filename);
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE);
+   if (! file)
+     return 0;
+ 
+diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c
+index 4f282c9cf43..9d7149b3892 100644
+--- a/grub-core/kern/elf.c
++++ b/grub-core/kern/elf.c
+@@ -136,12 +136,12 @@ fail:
+ }
+ 
+ grub_elf_t
+-grub_elf_open (const char *name)
++grub_elf_open (const char *name, enum grub_file_type type)
+ {
+   grub_file_t file;
+   grub_elf_t elf;
+ 
+-  file = grub_file_open (name);
++  file = grub_file_open (name, type);
+   if (! file)
+     return 0;
+ 
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index c2d9a550007..2efc31da94f 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -28,8 +28,7 @@
+ 
+ void (*EXPORT_VAR (grub_grubnet_fini)) (void);
+ 
+-grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
+-grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX];
++grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX];
+ 
+ /* Get the device part of the filename NAME. It is enclosed by parentheses.  */
+ char *
+@@ -59,7 +58,7 @@ grub_file_get_device_name (const char *name)
+ }
+ 
+ grub_file_t
+-grub_file_open (const char *name)
++grub_file_open (const char *name, enum grub_file_type type)
+ {
+   grub_device_t device = 0;
+   grub_file_t file = 0, last_file = 0;
+@@ -116,18 +115,20 @@ grub_file_open (const char *name)
+   file->name = grub_strdup (name);
+   grub_errno = GRUB_ERR_NONE;
+ 
+-  for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters_enabled);
++  for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters);
+        filter++)
+-    if (grub_file_filters_enabled[filter])
++    if (grub_file_filters[filter])
+       {
+ 	last_file = file;
+-	file = grub_file_filters_enabled[filter] (file, name);
++	file = grub_file_filters[filter] (file, type);
++	if (file && file != last_file)
++	  {
++	    file->name = grub_strdup (name);
++	    grub_errno = GRUB_ERR_NONE;
++	  }
+       }
+   if (!file)
+     grub_file_close (last_file);
+-    
+-  grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
+-	       sizeof (grub_file_filters_enabled));
+ 
+   grub_dprintf ("file", "Opening `%s' succeeded.\n", name);
+ 
+@@ -141,9 +142,6 @@ grub_file_open (const char *name)
+ 
+   grub_free (file);
+ 
+-  grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
+-	       sizeof (grub_file_filters_enabled));
+-
+   grub_dprintf ("file", "Opening `%s' failed.\n", name);
+ 
+   return 0;
+diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c
+index 21ca040ada7..83e7bdb9161 100644
+--- a/grub-core/lib/syslinux_parse.c
++++ b/grub-core/lib/syslinux_parse.c
+@@ -696,7 +696,7 @@ syslinux_parse_real (struct syslinux_menu *menu)
+   char *buf = NULL;
+   grub_err_t err = GRUB_ERR_NONE;
+ 
+-  file = grub_file_open (menu->filename);
++  file = grub_file_open (menu->filename, GRUB_FILE_TYPE_CONFIG);
+   if (!file)
+     return grub_errno;
+   while ((grub_free (buf), buf = grub_file_getline (file)))
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index a93edc975cd..29663f71801 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -941,7 +941,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+       *(--p16) = 0;
+     }
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
+index 0f317632a3b..8306b415abd 100644
+--- a/grub-core/loader/i386/bsd.c
++++ b/grub-core/loader/i386/bsd.c
+@@ -1464,7 +1464,7 @@ grub_bsd_load (int argc, char *argv[])
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL);
+   if (!file)
+     goto fail;
+ 
+@@ -1541,7 +1541,7 @@ grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
+ 	  if (err)
+ 	    return err;
+ 
+-	  file = grub_file_open (argv[0]);
++	  file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL);
+ 	  if (! file)
+ 	    return grub_errno;
+ 
+@@ -1700,7 +1700,7 @@ grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
+ 	{
+ 	  grub_file_t file;
+ 
+-	  file = grub_file_open (argv[0]);
++	  file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL);
+ 	  if (! file)
+ 	    return grub_errno;
+ 
+@@ -1809,7 +1809,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_ENV);
+   if ((!file) || (!file->size))
+     goto fail;
+ 
+@@ -1914,7 +1914,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)),
+       return 0;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_MODULE);
+   if ((!file) || (!file->size))
+     goto fail;
+ 
+@@ -1965,7 +1965,7 @@ grub_netbsd_module_load (char *filename, grub_uint32_t type)
+   void *src;
+   grub_err_t err;
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_NETBSD_MODULE);
+   if ((!file) || (!file->size))
+     goto fail;
+ 
+@@ -2055,7 +2055,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)),
+       return 0;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_MODULE_ELF);
+   if (!file)
+     return grub_errno;
+   if (!file->size)
+@@ -2095,7 +2095,7 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)),
+   if (!openbsd_ramdisk.max_size)
+     return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk");
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_OPENBSD_RAMDISK);
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c
+index 2cb78eee090..0a19ebb9c3e 100644
+--- a/grub-core/loader/i386/coreboot/chainloader.c
++++ b/grub-core/loader/i386/coreboot/chainloader.c
+@@ -439,7 +439,7 @@ grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_loader_unset ();
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_COREBOOT_CHAINLOADER);
+   if (!file)
+     return grub_errno;
+ 
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 191f1631e88..aa2cbc4e7eb 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -709,7 +709,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c
+index ef3a322b78c..976fea73ab5 100644
+--- a/grub-core/loader/i386/pc/chainloader.c
++++ b/grub-core/loader/i386/pc/chainloader.c
+@@ -172,8 +172,8 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
+ 
+   grub_dl_ref (my_mod);
+ 
+-  grub_file_filter_disable_compression ();
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_PCCHAINLOADER
++			 | GRUB_FILE_TYPE_NO_DECOMPRESS);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/freedos.c b/grub-core/loader/i386/pc/freedos.c
+index 478f3c5139d..aac6c9715f6 100644
+--- a/grub-core/loader/i386/pc/freedos.c
++++ b/grub-core/loader/i386/pc/freedos.c
+@@ -110,7 +110,7 @@ grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)),
+   if (!rel)
+     goto fail;
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEDOS);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index 63736fae950..b5c28c6580e 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -142,7 +142,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c
+index 1b88f40d871..f0d74145b38 100644
+--- a/grub-core/loader/i386/pc/ntldr.c
++++ b/grub-core/loader/i386/pc/ntldr.c
+@@ -90,7 +90,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)),
+   if (!rel)
+     goto fail;
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_NTLDR);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c
+index 814a49d5071..0351090daf8 100644
+--- a/grub-core/loader/i386/pc/plan9.c
++++ b/grub-core/loader/i386/pc/plan9.c
+@@ -413,7 +413,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
+   if (!rel)
+     goto fail;
+ 
+-  fill_ctx.file = grub_file_open (argv[0]);
++  fill_ctx.file = grub_file_open (argv[0], GRUB_FILE_TYPE_PLAN9_KERNEL);
+   if (! fill_ctx.file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/pxechainloader.c b/grub-core/loader/i386/pc/pxechainloader.c
+index e60c62b1bad..acb061169b9 100644
+--- a/grub-core/loader/i386/pc/pxechainloader.c
++++ b/grub-core/loader/i386/pc/pxechainloader.c
+@@ -99,7 +99,7 @@ grub_cmd_pxechain (grub_command_t cmd __attribute__ ((unused)),
+   if (!rel)
+     goto fail;
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_PXECHAINLOADER);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/pc/truecrypt.c b/grub-core/loader/i386/pc/truecrypt.c
+index 9ea4fde42a5..cbeeec7beae 100644
+--- a/grub-core/loader/i386/pc/truecrypt.c
++++ b/grub-core/loader/i386/pc/truecrypt.c
+@@ -99,7 +99,7 @@ grub_cmd_truecrypt (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dl_ref (my_mod);
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_TRUECRYPT);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
+index 85b93347b25..82350d3a178 100644
+--- a/grub-core/loader/i386/xen.c
++++ b/grub-core/loader/i386/xen.c
+@@ -650,7 +650,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
+ 			      (char *) xen_state.next_start.cmd_line,
+ 			      sizeof (xen_state.next_start.cmd_line) - 1);
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (!file)
+     return grub_errno;
+ 
+@@ -901,9 +901,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+ 
+   xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE);
+ 
+-  if (nounzip)
+-    grub_file_filter_disable_compression ();
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_INITRD |
++			 (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE));
+   if (!file)
+     return grub_errno;
+   size = grub_file_size (file);
+diff --git a/grub-core/loader/i386/xen_file.c b/grub-core/loader/i386/xen_file.c
+index 77a93e7b228..9af5d66dfcd 100644
+--- a/grub-core/loader/i386/xen_file.c
++++ b/grub-core/loader/i386/xen_file.c
+@@ -78,7 +78,7 @@ grub_xen_file (grub_file_t file)
+      Trim it.  */
+   if (grub_memcmp (magic, XZ_MAGIC, sizeof (XZ_MAGIC) - 1) == 0)
+     payload_length -= 4;
+-  off_file = grub_file_offset_open (file, payload_offset,
++  off_file = grub_file_offset_open (file, GRUB_FILE_TYPE_LINUX_KERNEL, payload_offset,
+ 				    payload_length);
+   if (!off_file)
+     goto fail;
+diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c
+index 44f7ebfa2b6..a7009360732 100644
+--- a/grub-core/loader/i386/xnu.c
++++ b/grub-core/loader/i386/xnu.c
+@@ -486,7 +486,7 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
+   if (argc != 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_XNU_DEVPROP);
+   if (! file)
+     return grub_errno;
+   size = grub_file_size (file);
+diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
+index 0953f6d3266..2b2f798e754 100644
+--- a/grub-core/loader/linux.c
++++ b/grub-core/loader/linux.c
+@@ -183,7 +183,6 @@ grub_initrd_init (int argc, char *argv[],
+ 	  eptr = grub_strchr (ptr, ':');
+ 	  if (eptr)
+ 	    {
+-	      grub_file_filter_disable_compression ();
+ 	      grub_size_t dir_size, name_len;
+ 
+ 	      initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
+@@ -215,8 +214,9 @@ grub_initrd_init (int argc, char *argv[],
+ 	  root = 0;
+ 	  newc = 0;
+ 	}
+-      grub_file_filter_disable_compression ();
+-      initrd_ctx->components[i].file = grub_file_open (fname);
++      initrd_ctx->components[i].file = grub_file_open (fname,
++						       GRUB_FILE_TYPE_LINUX_INITRD
++						       | GRUB_FILE_TYPE_NO_DECOMPRESS);
+       if (!initrd_ctx->components[i].file)
+ 	{
+ 	  grub_initrd_close (initrd_ctx);
+diff --git a/grub-core/loader/macho.c b/grub-core/loader/macho.c
+index f61341af515..05710c48e06 100644
+--- a/grub-core/loader/macho.c
++++ b/grub-core/loader/macho.c
+@@ -188,12 +188,12 @@ fail:
+ }
+ 
+ grub_macho_t
+-grub_macho_open (const char *name, int is_64bit)
++grub_macho_open (const char *name, enum grub_file_type type, int is_64bit)
+ {
+   grub_file_t file;
+   grub_macho_t macho;
+ 
+-  file = grub_file_open (name);
++  file = grub_file_open (name, type);
+   if (! file)
+     return 0;
+ 
+diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c
+index 27c1db84a44..10358854458 100644
+--- a/grub-core/loader/mips/linux.c
++++ b/grub-core/loader/mips/linux.c
+@@ -237,7 +237,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  elf = grub_elf_open (argv[0]);
++  elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (! elf)
+     return grub_errno;
+ 
+diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
+index f455e803910..e8963d7cdb3 100644
+--- a/grub-core/loader/multiboot.c
++++ b/grub-core/loader/multiboot.c
+@@ -323,7 +323,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_KERNEL);
+   if (! file)
+     return grub_errno;
+ 
+@@ -389,10 +389,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+     return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ 		       N_("you need to load the kernel first"));
+ 
+-  if (nounzip)
+-    grub_file_filter_disable_compression ();
+-
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_MODULE
++			 | (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE));
+   if (! file)
+     return grub_errno;
+ 
+diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
+index 2bf02489bad..9f78abb05f9 100644
+--- a/grub-core/loader/xnu.c
++++ b/grub-core/loader/xnu.c
+@@ -355,7 +355,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_xnu_unload ();
+ 
+-  macho = grub_macho_open (args[0], 0);
++  macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 0);
+   if (! macho)
+     return grub_errno;
+ 
+@@ -460,7 +460,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_xnu_unload ();
+ 
+-  macho = grub_macho_open (args[0], 1);
++  macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 1);
+   if (! macho)
+     return grub_errno;
+ 
+@@ -678,7 +678,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
+     macho = 0;
+ 
+   if (infoplistname)
+-    infoplist = grub_file_open (infoplistname);
++    infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
+   else
+     infoplist = 0;
+   grub_errno = GRUB_ERR_NONE;
+@@ -775,7 +775,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
+   if (! grub_xnu_heap_size)
+     return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_MKEXT);
+   if (! file)
+     return grub_errno;
+ 
+@@ -889,7 +889,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
+   if (! grub_xnu_heap_size)
+     return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
+ 
+-  file = grub_file_open (args[0]);
++  file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_RAMDISK);
+   if (! file)
+     return grub_errno;
+ 
+@@ -929,7 +929,7 @@ grub_xnu_check_os_bundle_required (char *plistname,
+   if (binname)
+     *binname = 0;
+ 
+-  file = grub_file_open (plistname);
++  file = grub_file_open (plistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
+   if (! file)
+     return 0;
+ 
+@@ -1214,7 +1214,7 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
+ 		grub_strcpy (binname + grub_strlen (binname), "/");
+ 	      grub_strcpy (binname + grub_strlen (binname), binsuffix);
+ 	      grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname);
+-	      binfile = grub_file_open (binname);
++	      binfile = grub_file_open (binname, GRUB_FILE_TYPE_XNU_KEXT);
+ 	      if (! binfile)
+ 		grub_errno = GRUB_ERR_NONE;
+ 
+@@ -1257,7 +1257,7 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
+       /* User explicitly specified plist and binary. */
+       if (grub_strcmp (args[1], "-") != 0)
+ 	{
+-	  binfile = grub_file_open (args[1]);
++	  binfile = grub_file_open (args[1], GRUB_FILE_TYPE_XNU_KEXT);
+ 	  if (! binfile)
+ 	    return grub_errno;
+ 	}
+diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c
+index 99119558d21..d648ef0cd3a 100644
+--- a/grub-core/loader/xnu_resume.c
++++ b/grub-core/loader/xnu_resume.c
+@@ -53,8 +53,8 @@ grub_xnu_resume (char *imagename)
+   grub_addr_t target_image;
+   grub_err_t err;
+ 
+-  grub_file_filter_disable_compression ();
+-  file = grub_file_open (imagename);
++  file = grub_file_open (imagename, GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE
++			 | GRUB_FILE_TYPE_NO_DECOMPRESS);
+   if (! file)
+     return 0;
+ 
+diff --git a/grub-core/normal/autofs.c b/grub-core/normal/autofs.c
+index 721b9c3256d..7a7cf2b0f7e 100644
+--- a/grub-core/normal/autofs.c
++++ b/grub-core/normal/autofs.c
+@@ -33,12 +33,6 @@ autoload_fs_module (void)
+ {
+   grub_named_list_t p;
+   int ret = 0;
+-  grub_file_filter_t grub_file_filters_was[GRUB_FILE_FILTER_MAX];
+-
+-  grub_memcpy (grub_file_filters_was, grub_file_filters_enabled,
+-	       sizeof (grub_file_filters_enabled));
+-  grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
+-	       sizeof (grub_file_filters_enabled));
+ 
+   while ((p = fs_module_list) != NULL)
+     {
+@@ -56,9 +50,6 @@ autoload_fs_module (void)
+       grub_free (p);
+     }
+ 
+-  grub_memcpy (grub_file_filters_enabled, grub_file_filters_was,
+-	       sizeof (grub_file_filters_enabled));
+-
+   return ret;
+ }
+ 
+@@ -82,7 +73,7 @@ read_fs_list (const char *prefix)
+ 	  tmp_autoload_hook = grub_fs_autoload_hook;
+ 	  grub_fs_autoload_hook = NULL;
+ 
+-	  file = grub_file_open (filename);
++	  file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST);
+ 	  if (file)
+ 	    {
+ 	      /* Override previous fs.lst.  */
+diff --git a/grub-core/normal/crypto.c b/grub-core/normal/crypto.c
+index e6d345f3345..d01e6f271e1 100644
+--- a/grub-core/normal/crypto.c
++++ b/grub-core/normal/crypto.c
+@@ -94,7 +94,7 @@ read_crypto_list (const char *prefix)
+       return;
+     }
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST);
+   grub_free (filename);
+   if (!file)
+     {
+diff --git a/grub-core/normal/dyncmd.c b/grub-core/normal/dyncmd.c
+index 169c126f508..719ebf477f2 100644
+--- a/grub-core/normal/dyncmd.c
++++ b/grub-core/normal/dyncmd.c
+@@ -106,7 +106,7 @@ read_command_list (const char *prefix)
+ 	{
+ 	  grub_file_t file;
+ 
+-	  file = grub_file_open (filename);
++	  file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST);
+ 	  if (file)
+ 	    {
+ 	      char *buf = NULL;
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 59fd54eb0f1..cee71a4c2ab 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -127,7 +127,7 @@ read_config_file (const char *config)
+     }
+ 
+   /* Try to open the config file.  */
+-  rawfile = grub_file_open (config);
++  rawfile = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+   if (! rawfile)
+     return 0;
+ 
+diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c
+index 93a3a0d912e..cc8c173b6e8 100644
+--- a/grub-core/normal/term.c
++++ b/grub-core/normal/term.c
+@@ -331,7 +331,7 @@ read_terminal_list (const char *prefix)
+       return;
+     }
+ 
+-  file = grub_file_open (filename);
++  file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST);
+   grub_free (filename);
+   if (!file)
+     {
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index 21b0d9ded67..31359a4c9c8 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -772,7 +772,7 @@ grub_video_reader_jpeg (struct grub_video_bitmap **bitmap,
+   grub_file_t file;
+   struct grub_jpeg_data *data;
+ 
+-  file = grub_buffile_open (filename, 0);
++  file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0);
+   if (!file)
+     return grub_errno;
+ 
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index 719e647e44f..0157ff7420b 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -1095,7 +1095,7 @@ grub_video_reader_png (struct grub_video_bitmap **bitmap,
+   grub_file_t file;
+   struct grub_png_data *data;
+ 
+-  file = grub_buffile_open (filename, 0);
++  file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0);
+   if (!file)
+     return grub_errno;
+ 
+diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c
+index c7a16fa9cc4..7cb9d1d2a0c 100644
+--- a/grub-core/video/readers/tga.c
++++ b/grub-core/video/readers/tga.c
+@@ -297,7 +297,7 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap,
+ 
+   grub_memset (&data, 0, sizeof (data));
+ 
+-  data.file = grub_buffile_open (filename, 0);
++  data.file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0);
+   if (! data.file)
+     return grub_errno;
+ 
+diff --git a/util/grub-fstest.c b/util/grub-fstest.c
+index 793aefa02b1..fe5982220d0 100644
+--- a/util/grub-fstest.c
++++ b/util/grub-fstest.c
+@@ -120,9 +120,9 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len, void
+       return;
+     }
+ 
+-  if (uncompress == 0)
+-    grub_file_filter_disable_compression ();
+-  file = grub_file_open (pathname);
++  file = grub_file_open (pathname, ((uncompress == 0)
++				    ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)
++			 | GRUB_FILE_TYPE_FSTEST);
+   if (!file)
+     {
+       grub_util_error (_("cannot open `%s': %s"), pathname,
+diff --git a/util/grub-mount.c b/util/grub-mount.c
+index a25db8a7181..e32b502e7e4 100644
+--- a/util/grub-mount.c
++++ b/util/grub-mount.c
+@@ -208,7 +208,7 @@ fuse_getattr (const char *path, struct stat *st)
+   if (!ctx.file_info.dir)
+     {
+       grub_file_t file;
+-      file = grub_file_open (path);
++      file = grub_file_open (path, GRUB_FILE_TYPE_GET_SIZE);
+       if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+@@ -244,7 +244,7 @@ static int
+ fuse_open (const char *path, struct fuse_file_info *fi __attribute__ ((unused)))
+ {
+   grub_file_t file;
+-  file = grub_file_open (path);
++  file = grub_file_open (path, GRUB_FILE_TYPE_MOUNT);
+   if (! file)
+     return translate_error ();
+   files[first_fd++] = file;
+@@ -308,7 +308,7 @@ fuse_readdir_call_fill (const char *filename,
+       grub_file_t file;
+       char *tmp;
+       tmp = xasprintf ("%s/%s", ctx->path, filename);
+-      file = grub_file_open (tmp);
++      file = grub_file_open (tmp, GRUB_FILE_TYPE_GET_SIZE);
+       free (tmp);
+       /* Symlink to directory.  */
+       if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE)
+diff --git a/include/grub/bufio.h b/include/grub/bufio.h
+index 77eb8ee5672..0ff72d1033c 100644
+--- a/include/grub/bufio.h
++++ b/include/grub/bufio.h
+@@ -23,6 +23,8 @@
+ #include <grub/file.h>
+ 
+ grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, grub_size_t size);
+-grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, grub_size_t size);
++grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name,
++					     enum grub_file_type type,
++					     grub_size_t size);
+ 
+ #endif /* ! GRUB_BUFIO_H */
+diff --git a/include/grub/elfload.h b/include/grub/elfload.h
+index 9a7ae4ebb30..dbb609c9b20 100644
+--- a/include/grub/elfload.h
++++ b/include/grub/elfload.h
+@@ -42,7 +42,7 @@ typedef int (*grub_elf32_phdr_iterate_hook_t)
+ typedef int (*grub_elf64_phdr_iterate_hook_t)
+   (grub_elf_t elf, Elf64_Phdr *phdr, void *arg);
+ 
+-grub_elf_t grub_elf_open (const char *);
++grub_elf_t grub_elf_open (const char *, enum grub_file_type type);
+ grub_elf_t grub_elf_file (grub_file_t file, const char *filename);
+ grub_err_t grub_elf_close (grub_elf_t);
+ 
+diff --git a/include/grub/file.h b/include/grub/file.h
+index 739488cbe59..5b47c5f91f9 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -25,6 +25,109 @@
+ #include <grub/fs.h>
+ #include <grub/disk.h>
+ 
++enum grub_file_type
++  {
++    GRUB_FILE_TYPE_NONE = 0,
++    /* GRUB module to be loaded.  */
++    GRUB_FILE_TYPE_GRUB_MODULE,
++    /* Loopback file to be represented as disk.  */
++    GRUB_FILE_TYPE_LOOPBACK,
++    /* Linux kernel to be loaded.  */
++    GRUB_FILE_TYPE_LINUX_KERNEL,
++    /* Linux initrd.  */
++    GRUB_FILE_TYPE_LINUX_INITRD,
++
++    /* Multiboot kernel.  */
++    GRUB_FILE_TYPE_MULTIBOOT_KERNEL,
++    /* Multiboot module.  */
++    GRUB_FILE_TYPE_MULTIBOOT_MODULE,
++
++    GRUB_FILE_TYPE_BSD_KERNEL,
++    GRUB_FILE_TYPE_FREEBSD_ENV,
++    GRUB_FILE_TYPE_FREEBSD_MODULE,
++    GRUB_FILE_TYPE_FREEBSD_MODULE_ELF,
++    GRUB_FILE_TYPE_NETBSD_MODULE,
++    GRUB_FILE_TYPE_OPENBSD_RAMDISK,
++
++    GRUB_FILE_TYPE_XNU_INFO_PLIST,
++    GRUB_FILE_TYPE_XNU_MKEXT,
++    GRUB_FILE_TYPE_XNU_KEXT,
++    GRUB_FILE_TYPE_XNU_KERNEL,
++    GRUB_FILE_TYPE_XNU_RAMDISK,
++    GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE,
++    GRUB_FILE_XNU_DEVPROP,
++
++    GRUB_FILE_TYPE_PLAN9_KERNEL,
++
++    GRUB_FILE_TYPE_NTLDR,
++    GRUB_FILE_TYPE_TRUECRYPT,
++    GRUB_FILE_TYPE_FREEDOS,
++    GRUB_FILE_TYPE_PXECHAINLOADER,
++    GRUB_FILE_TYPE_PCCHAINLOADER,
++
++    GRUB_FILE_TYPE_COREBOOT_CHAINLOADER,
++
++    GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE,
++
++    /* File holding signature.  */
++    GRUB_FILE_TYPE_SIGNATURE,
++    /* File holding public key to verify signature once.  */
++    GRUB_FILE_TYPE_PUBLIC_KEY,
++    /* File holding public key to add to trused keys.  */
++    GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
++    /* File of which we intend to print a blocklist to the user.  */
++    GRUB_FILE_TYPE_PRINT_BLOCKLIST,
++    /* File we intend to use for test loading or testing speed.  */
++    GRUB_FILE_TYPE_TESTLOAD,
++    /* File we open only to get its size. E.g. in ls output.  */
++    GRUB_FILE_TYPE_GET_SIZE,
++    /* Font file.  */
++    GRUB_FILE_TYPE_FONT,
++    /* File holding encryption key for encrypted ZFS.  */
++    GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY,
++    /* File we open n grub-fstest.  */
++    GRUB_FILE_TYPE_FSTEST,
++    /* File we open n grub-mount.  */
++    GRUB_FILE_TYPE_MOUNT,
++    /* File which we attempt to identify the type of.  */
++    GRUB_FILE_TYPE_FILE_ID,
++    /* File holding ACPI table.  */
++    GRUB_FILE_TYPE_ACPI_TABLE,
++    /* File we intend show to user.  */
++    GRUB_FILE_TYPE_CAT,
++    GRUB_FILE_TYPE_HEXCAT,
++    /* One of pair of files we intend to compare.  */
++    GRUB_FILE_TYPE_CMP,
++    /* List of hashes for hashsum.  */
++    GRUB_FILE_TYPE_HASHLIST,
++    /* File hashed by hashsum.  */
++    GRUB_FILE_TYPE_TO_HASH,
++    /* Keyboard layout.  */
++    GRUB_FILE_TYPE_KEYBOARD_LAYOUT,
++    /* Picture file.  */
++    GRUB_FILE_TYPE_PIXMAP,
++    /* *.lst shipped by GRUB.  */
++    GRUB_FILE_TYPE_GRUB_MODULE_LIST,
++    /* config file.  */
++    GRUB_FILE_TYPE_CONFIG,
++    GRUB_FILE_TYPE_THEME,
++    GRUB_FILE_TYPE_GETTEXT_CATALOG,
++    GRUB_FILE_TYPE_FS_SEARCH,
++    GRUB_FILE_TYPE_AUDIO,
++    GRUB_FILE_TYPE_VBE_DUMP,
++
++    GRUB_FILE_TYPE_LOADENV,
++    GRUB_FILE_TYPE_SAVEENV,
++
++    GRUB_FILE_TYPE_VERIFY_SIGNATURE,
++
++    GRUB_FILE_TYPE_MASK = 0xffff,
++
++    /* --skip-sig is specified.  */
++    GRUB_FILE_TYPE_SKIP_SIGNATURE = 0x10000,
++    GRUB_FILE_TYPE_NO_DECOMPRESS = 0x20000
++  };
++
+ /* File description.  */
+ struct grub_file
+ {
+@@ -77,61 +180,26 @@ typedef enum grub_file_filter_id
+     GRUB_FILE_FILTER_COMPRESSION_LAST = GRUB_FILE_FILTER_LZOPIO,
+   } grub_file_filter_id_t;
+ 
+-typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, const char *filename);
++typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, enum grub_file_type type);
+ 
+-extern grub_file_filter_t EXPORT_VAR(grub_file_filters_all)[GRUB_FILE_FILTER_MAX];
+-extern grub_file_filter_t EXPORT_VAR(grub_file_filters_enabled)[GRUB_FILE_FILTER_MAX];
++extern grub_file_filter_t EXPORT_VAR(grub_file_filters)[GRUB_FILE_FILTER_MAX];
+ 
+ static inline void
+ grub_file_filter_register (grub_file_filter_id_t id, grub_file_filter_t filter)
+ {
+-  grub_file_filters_all[id] = filter;
+-  grub_file_filters_enabled[id] = filter;
++  grub_file_filters[id] = filter;
+ }
+ 
+ static inline void
+ grub_file_filter_unregister (grub_file_filter_id_t id)
+ {
+-  grub_file_filters_all[id] = 0;
+-  grub_file_filters_enabled[id] = 0;
+-}
+-
+-static inline void
+-grub_file_filter_disable (grub_file_filter_id_t id)
+-{
+-  grub_file_filters_enabled[id] = 0;
+-}
+-
+-static inline void
+-grub_file_filter_disable_compression (void)
+-{
+-  grub_file_filter_id_t id;
+-
+-  for (id = GRUB_FILE_FILTER_COMPRESSION_FIRST;
+-       id <= GRUB_FILE_FILTER_COMPRESSION_LAST; id++)
+-    grub_file_filters_enabled[id] = 0;
+-}
+-
+-static inline void
+-grub_file_filter_disable_all (void)
+-{
+-  grub_file_filter_id_t id;
+-
+-  for (id = 0;
+-       id < GRUB_FILE_FILTER_MAX; id++)
+-    grub_file_filters_enabled[id] = 0;
+-}
+-
+-static inline void
+-grub_file_filter_disable_pubkey (void)
+-{
+-  grub_file_filters_enabled[GRUB_FILE_FILTER_PUBKEY] = 0;
++  grub_file_filters[id] = 0;
+ }
+ 
+ /* Get a device name from NAME.  */
+ char *EXPORT_FUNC(grub_file_get_device_name) (const char *name);
+ 
+-grub_file_t EXPORT_FUNC(grub_file_open) (const char *name);
++grub_file_t EXPORT_FUNC(grub_file_open) (const char *name, enum grub_file_type type);
+ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf,
+ 					  grub_size_t len);
+ grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset);
+@@ -159,8 +227,8 @@ grub_file_seekable (const grub_file_t file)
+ }
+ 
+ grub_file_t
+-grub_file_offset_open (grub_file_t parent, grub_off_t start,
+-		       grub_off_t size);
++grub_file_offset_open (grub_file_t parent, enum grub_file_type type,
++		       grub_off_t start, grub_off_t size);
+ void
+ grub_file_offset_close (grub_file_t file);
+ 
+diff --git a/include/grub/machoload.h b/include/grub/machoload.h
+index 1eec118f15f..f1157f4105b 100644
+--- a/include/grub/machoload.h
++++ b/include/grub/machoload.h
+@@ -49,7 +49,8 @@ struct grub_macho_file
+ };
+ typedef struct grub_macho_file *grub_macho_t;
+ 
+-grub_macho_t grub_macho_open (const char *, int is_64bit);
++grub_macho_t grub_macho_open (const char *, enum grub_file_type type,
++			      int is_64bit);
+ grub_macho_t grub_macho_file (grub_file_t file, const char *filename,
+ 			      int is_64bit);
+ grub_err_t grub_macho_close (grub_macho_t);
diff --git a/SOURCES/0331-verifiers-Framework-core.patch b/SOURCES/0331-verifiers-Framework-core.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b830048306730171121ede7342b80c83b777780d
--- /dev/null
+++ b/SOURCES/0331-verifiers-Framework-core.patch
@@ -0,0 +1,1026 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Vladimir Serbinenko <phcoder@gmail.com>
+Date: Sun, 5 Feb 2017 14:25:47 +0100
+Subject: [PATCH] verifiers: Framework core
+
+Verifiers framework provides core file verification functionality which
+can be used by various security mechanisms, e.g., UEFI secure boot, TPM,
+PGP signature verification, etc.
+
+The patch contains PGP code changes and probably they should be extracted
+to separate patch for the sake of clarity.
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+(cherry picked from commit 75a919e334f8514b6adbc024743cfcd9b88fa394)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def    |   5 +
+ grub-core/commands/verifiers.c | 197 ++++++++++++++
+ grub-core/commands/verify.c    | 566 ++++++++++++++++++++---------------------
+ include/grub/file.h            |   2 +-
+ include/grub/list.h            |   1 +
+ include/grub/verify.h          |  65 +++++
+ 6 files changed, 539 insertions(+), 297 deletions(-)
+ create mode 100644 grub-core/commands/verifiers.c
+ create mode 100644 include/grub/verify.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index c8a50b4fcfa..29c3bf6cd66 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -921,6 +921,11 @@ module = {
+   cppflags = '-I$(srcdir)/lib/posix_wrap';
+ };
+ 
++module = {
++  name = verifiers;
++  common = commands/verifiers.c;
++};
++
+ module = {
+   name = hdparm;
+   common = commands/hdparm.c;
+diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
+new file mode 100644
+index 00000000000..fde88318d4c
+--- /dev/null
++++ b/grub-core/commands/verifiers.c
+@@ -0,0 +1,197 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2017  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/>.
++ *
++ *  Verifiers helper.
++ */
++
++#include <grub/file.h>
++#include <grub/verify.h>
++#include <grub/dl.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++struct grub_file_verifier *grub_file_verifiers;
++
++struct grub_verified
++{
++  grub_file_t file;
++  void *buf;
++};
++typedef struct grub_verified *grub_verified_t;
++
++static void
++verified_free (grub_verified_t verified)
++{
++  if (verified)
++    {
++      grub_free (verified->buf);
++      grub_free (verified);
++    }
++}
++
++static grub_ssize_t
++verified_read (struct grub_file *file, char *buf, grub_size_t len)
++{
++  grub_verified_t verified = file->data;
++
++  grub_memcpy (buf, (char *) verified->buf + file->offset, len);
++  return len;
++}
++
++static grub_err_t
++verified_close (struct grub_file *file)
++{
++  grub_verified_t verified = file->data;
++
++  grub_file_close (verified->file);
++  verified_free (verified);
++  file->data = 0;
++
++  /* Device and name are freed by parent. */
++  file->device = 0;
++  file->name = 0;
++
++  return grub_errno;
++}
++
++struct grub_fs verified_fs =
++{
++  .name = "verified_read",
++  .read = verified_read,
++  .close = verified_close
++};
++
++static grub_file_t
++grub_verifiers_open (grub_file_t io, enum grub_file_type type)
++{
++  grub_verified_t verified = NULL;
++  struct grub_file_verifier *ver;
++  void *context;
++  grub_file_t ret = 0;
++  grub_err_t err;
++
++  grub_dprintf ("verify", "file: %s type: %d\n", io->name, type);
++
++  if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
++      || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
++      || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
++    return io;
++
++  if (io->device->disk &&
++      (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
++       || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
++    return io;
++
++  FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
++    {
++      enum grub_verify_flags flags = 0;
++      err = ver->init (io, type, &context, &flags);
++      if (err)
++	goto fail_noclose;
++      if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION))
++	break;
++    }
++
++  if (!ver)
++    /* No verifiers wanted to verify. Just return underlying file. */
++    return io;
++
++  ret = grub_malloc (sizeof (*ret));
++  if (!ret)
++    {
++      goto fail;
++    }
++  *ret = *io;
++
++  ret->fs = &verified_fs;
++  ret->not_easily_seekable = 0;
++  if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
++    {
++      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		  N_("big file signature isn't implemented yet"));
++      goto fail;
++    }
++  verified = grub_malloc (sizeof (*verified));
++  if (!verified)
++    {
++      goto fail;
++    }
++  verified->buf = grub_malloc (ret->size);
++  if (!verified->buf)
++    {
++      goto fail;
++    }
++  if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
++    {
++      if (!grub_errno)
++	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
++		    io->name);
++      goto fail;
++    }
++
++  err = ver->write (context, verified->buf, ret->size);
++  if (err)
++    goto fail;
++
++  err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE;
++  if (err)
++    goto fail;
++
++  if (ver->close)
++    ver->close (context);
++
++  FOR_LIST_ELEMENTS_NEXT(ver, grub_file_verifiers)
++    {
++      enum grub_verify_flags flags = 0;
++      err = ver->init (io, type, &context, &flags);
++      if (err)
++	goto fail_noclose;
++      if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION)
++	continue;
++      err = ver->write (context, verified->buf, ret->size);
++      if (err)
++	goto fail;
++
++      err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE;
++      if (err)
++	goto fail;
++
++      if (ver->close)
++	ver->close (context);
++    }
++
++  verified->file = io;
++  ret->data = verified;
++  return ret;
++
++ fail:
++  ver->close (context);
++ fail_noclose:
++  verified_free (verified);
++  grub_free (ret);
++  return NULL;
++}
++
++GRUB_MOD_INIT(verifiers)
++{
++  grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
++}
++
++GRUB_MOD_FINI(verifiers)
++{
++  grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY);
++}
+diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c
+index f0dfeceebd4..29e74a64004 100644
+--- a/grub-core/commands/verify.c
++++ b/grub-core/commands/verify.c
+@@ -30,16 +30,10 @@
+ #include <grub/env.h>
+ #include <grub/kernel.h>
+ #include <grub/extcmd.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+-struct grub_verified
+-{
+-  grub_file_t file;
+-  void *buf;
+-};
+-typedef struct grub_verified *grub_verified_t;
+-
+ enum
+   {
+     OPTION_SKIP_SIG = 0
+@@ -445,23 +439,27 @@ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+   return ret;
+ }
+ 
+-static grub_err_t
+-grub_verify_signature_real (char *buf, grub_size_t size,
+-			    grub_file_t f, grub_file_t sig,
+-			    struct grub_public_key *pkey)
++struct grub_pubkey_context
+ {
+-  grub_size_t len;
++  grub_file_t sig;
++  struct signature_v4_header v4;
+   grub_uint8_t v;
++  const gcry_md_spec_t *hash;
++  void *hash_context;
++};
++
++static grub_err_t
++grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
++{
++  grub_size_t len;
+   grub_uint8_t h;
+   grub_uint8_t t;
+   grub_uint8_t pk;
+-  const gcry_md_spec_t *hash;
+-  struct signature_v4_header v4;
+   grub_err_t err;
+-  grub_size_t i;
+-  gcry_mpi_t mpis[10];
+   grub_uint8_t type = 0;
+ 
++  grub_memset (ctxt, 0, sizeof (*ctxt));
++
+   err = read_packet_header (sig, &type, &len);
+   if (err)
+     return err;
+@@ -469,18 +467,18 @@ grub_verify_signature_real (char *buf, grub_size_t size,
+   if (type != 0x2)
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ 
+-  if (grub_file_read (sig, &v, sizeof (v)) != sizeof (v))
++  if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ 
+-  if (v != 4)
++  if (ctxt->v != 4)
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ 
+-  if (grub_file_read (sig, &v4, sizeof (v4)) != sizeof (v4))
++  if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ 
+-  h = v4.hash;
+-  t = v4.type;
+-  pk = v4.pkeyalgo;
++  h = ctxt->v4.hash;
++  t = ctxt->v4.type;
++  pk = ctxt->v4.pkeyalgo;
+   
+   if (t != 0)
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+@@ -491,183 +489,233 @@ grub_verify_signature_real (char *buf, grub_size_t size,
+   if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ 
+-  hash = grub_crypto_lookup_md_by_name (hashes[h]);
+-  if (!hash)
++  ctxt->hash = grub_crypto_lookup_md_by_name (hashes[h]);
++  if (!ctxt->hash)
+     return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded", hashes[h]);
+ 
+   grub_dprintf ("crypt", "alive\n");
+ 
+-  {
+-    void *context = NULL;
+-    unsigned char *hval;
+-    grub_ssize_t rem = grub_be_to_cpu16 (v4.hashed_sub);
+-    grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6);
+-    grub_uint8_t s;
+-    grub_uint16_t unhashed_sub;
+-    grub_ssize_t r;
+-    grub_uint8_t hash_start[2];
+-    gcry_mpi_t hmpi;
+-    grub_uint64_t keyid = 0;
+-    struct grub_public_subkey *sk;
+-    grub_uint8_t *readbuf = NULL;
++  ctxt->sig = sig;
+ 
+-    context = grub_zalloc (hash->contextsize);
+-    readbuf = grub_zalloc (READBUF_SIZE);
+-    if (!context || !readbuf)
+-      goto fail;
+-
+-    hash->init (context);
+-    if (buf)
+-      hash->write (context, buf, size);
+-    else 
+-      while (1)
+-	{
+-	  r = grub_file_read (f, readbuf, READBUF_SIZE);
+-	  if (r < 0)
+-	    goto fail;
+-	  if (r == 0)
+-	    break;
+-	  hash->write (context, readbuf, r);
+-	}
+-
+-    hash->write (context, &v, sizeof (v));
+-    hash->write (context, &v4, sizeof (v4));
+-    while (rem)
+-      {
+-	r = grub_file_read (sig, readbuf,
+-			    rem < READBUF_SIZE ? rem : READBUF_SIZE);
+-	if (r < 0)
+-	  goto fail;
+-	if (r == 0)
+-	  break;
+-	hash->write (context, readbuf, r);
+-	rem -= r;
+-      }
+-    hash->write (context, &v, sizeof (v));
+-    s = 0xff;
+-    hash->write (context, &s, sizeof (s));
+-    hash->write (context, &headlen, sizeof (headlen));
+-    r = grub_file_read (sig, &unhashed_sub, sizeof (unhashed_sub));
+-    if (r != sizeof (unhashed_sub))
+-      goto fail;
+-    {
+-      grub_uint8_t *ptr;
+-      grub_uint32_t l;
+-      rem = grub_be_to_cpu16 (unhashed_sub);
+-      if (rem > READBUF_SIZE)
+-	goto fail;
+-      r = grub_file_read (sig, readbuf, rem);
+-      if (r != rem)
+-	goto fail;
+-      for (ptr = readbuf; ptr < readbuf + rem; ptr += l)
+-	{
+-	  if (*ptr < 192)
+-	    l = *ptr++;
+-	  else if (*ptr < 255)
+-	    {
+-	      if (ptr + 1 >= readbuf + rem)
+-		break;
+-	      l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
+-	      ptr += 2;
+-	    }
+-	  else
+-	    {
+-	      if (ptr + 5 >= readbuf + rem)
+-		break;
+-	      l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1));
+-	      ptr += 5;
+-	    }
+-	  if (*ptr == 0x10 && l >= 8)
+-	    keyid = grub_get_unaligned64 (ptr + 1);
+-	}
+-    }
+-
+-    hash->final (context);
+-
+-    grub_dprintf ("crypt", "alive\n");
+-
+-    hval = hash->read (context);
+-
+-    if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
+-      goto fail;
+-    if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
+-      goto fail;
+-
+-    grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (sig));
+-
+-    for (i = 0; i < pkalgos[pk].nmpisig; i++)
+-      {
+-	grub_uint16_t l;
+-	grub_size_t lb;
+-	grub_dprintf ("crypt", "alive\n");
+-	if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
+-	  goto fail;
+-	grub_dprintf ("crypt", "alive\n");
+-	lb = (grub_be_to_cpu16 (l) + 7) / 8;
+-	grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l));
+-	if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
+-	  goto fail;
+-	grub_dprintf ("crypt", "alive\n");
+-	if (grub_file_read (sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
+-	  goto fail;
+-	grub_dprintf ("crypt", "alive\n");
+-	grub_memcpy (readbuf, &l, sizeof (l));
+-	grub_dprintf ("crypt", "alive\n");
+-
+-	if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
+-			   readbuf, lb + sizeof (grub_uint16_t), 0))
+-	  goto fail;
+-	grub_dprintf ("crypt", "alive\n");
+-      }
+-
+-    if (pkey)
+-      sk = grub_crypto_pk_locate_subkey (keyid, pkey);
+-    else
+-      sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid);
+-    if (!sk)
+-      {
+-	/* TRANSLATORS: %08x is 32-bit key id.  */
+-	grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
+-		    keyid);
+-	goto fail;
+-      }
+-
+-    if (pkalgos[pk].pad (&hmpi, hval, hash, sk))
+-      goto fail;
+-    if (!*pkalgos[pk].algo)
+-      {
+-	grub_dl_load (pkalgos[pk].module);
+-	grub_errno = GRUB_ERR_NONE;
+-      }
+-
+-    if (!*pkalgos[pk].algo)
+-      {
+-	grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
+-		    pkalgos[pk].module);
+-	goto fail;
+-      }
+-    if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
+-      goto fail;
+-
+-    grub_free (context);
+-    grub_free (readbuf);
+-
+-    return GRUB_ERR_NONE;
+-
+-  fail:
+-    grub_free (context);
+-    grub_free (readbuf);
+-    if (!grub_errno)
+-      return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
++  ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
++  if (!ctxt->hash_context)
+     return grub_errno;
++
++  ctxt->hash->init (ctxt->hash_context);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_pubkey_write (void *ctxt_, void *buf, grub_size_t size)
++{
++  struct grub_pubkey_context *ctxt = ctxt_;
++  ctxt->hash->write (ctxt->hash_context, buf, size);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_verify_signature_real (struct grub_pubkey_context *ctxt,
++			    struct grub_public_key *pkey)
++{
++  gcry_mpi_t mpis[10];
++  grub_uint8_t pk = ctxt->v4.pkeyalgo;
++  grub_size_t i;
++  grub_uint8_t *readbuf = NULL;
++  unsigned char *hval;
++  grub_ssize_t rem = grub_be_to_cpu16 (ctxt->v4.hashed_sub);
++  grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6);
++  grub_uint8_t s;
++  grub_uint16_t unhashed_sub;
++  grub_ssize_t r;
++  grub_uint8_t hash_start[2];
++  gcry_mpi_t hmpi;
++  grub_uint64_t keyid = 0;
++  struct grub_public_subkey *sk;
++
++  readbuf = grub_malloc (READBUF_SIZE);
++  if (!readbuf)
++    goto fail;
++
++  ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
++  ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4));
++  while (rem)
++    {
++      r = grub_file_read (ctxt->sig, readbuf,
++			  rem < READBUF_SIZE ? rem : READBUF_SIZE);
++      if (r < 0)
++	goto fail;
++      if (r == 0)
++	break;
++      ctxt->hash->write (ctxt->hash_context, readbuf, r);
++      rem -= r;
++    }
++  ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
++  s = 0xff;
++  ctxt->hash->write (ctxt->hash_context, &s, sizeof (s));
++  ctxt->hash->write (ctxt->hash_context, &headlen, sizeof (headlen));
++  r = grub_file_read (ctxt->sig, &unhashed_sub, sizeof (unhashed_sub));
++  if (r != sizeof (unhashed_sub))
++    goto fail;
++  {
++    grub_uint8_t *ptr;
++    grub_uint32_t l;
++    rem = grub_be_to_cpu16 (unhashed_sub);
++    if (rem > READBUF_SIZE)
++      goto fail;
++    r = grub_file_read (ctxt->sig, readbuf, rem);
++    if (r != rem)
++      goto fail;
++    for (ptr = readbuf; ptr < readbuf + rem; ptr += l)
++      {
++	if (*ptr < 192)
++	  l = *ptr++;
++	else if (*ptr < 255)
++	  {
++	    if (ptr + 1 >= readbuf + rem)
++	      break;
++	    l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
++	    ptr += 2;
++	  }
++	else
++	  {
++	    if (ptr + 5 >= readbuf + rem)
++	      break;
++	    l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1));
++	    ptr += 5;
++	  }
++	if (*ptr == 0x10 && l >= 8)
++	  keyid = grub_get_unaligned64 (ptr + 1);
++      }
+   }
++
++  ctxt->hash->final (ctxt->hash_context);
++
++  grub_dprintf ("crypt", "alive\n");
++
++  hval = ctxt->hash->read (ctxt->hash_context);
++
++  if (grub_file_read (ctxt->sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
++    goto fail;
++  if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
++    goto fail;
++
++  grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (ctxt->sig));
++
++  for (i = 0; i < pkalgos[pk].nmpisig; i++)
++    {
++      grub_uint16_t l;
++      grub_size_t lb;
++      grub_dprintf ("crypt", "alive\n");
++      if (grub_file_read (ctxt->sig, &l, sizeof (l)) != sizeof (l))
++	goto fail;
++      grub_dprintf ("crypt", "alive\n");
++      lb = (grub_be_to_cpu16 (l) + 7) / 8;
++      grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l));
++      if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
++	goto fail;
++      grub_dprintf ("crypt", "alive\n");
++      if (grub_file_read (ctxt->sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
++	goto fail;
++      grub_dprintf ("crypt", "alive\n");
++      grub_memcpy (readbuf, &l, sizeof (l));
++      grub_dprintf ("crypt", "alive\n");
++
++      if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
++			 readbuf, lb + sizeof (grub_uint16_t), 0))
++	goto fail;
++      grub_dprintf ("crypt", "alive\n");
++    }
++
++  if (pkey)
++    sk = grub_crypto_pk_locate_subkey (keyid, pkey);
++  else
++    sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid);
++  if (!sk)
++    {
++      /* TRANSLATORS: %08x is 32-bit key id.  */
++      grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"),
++		  keyid);
++      goto fail;
++    }
++
++  if (pkalgos[pk].pad (&hmpi, hval, ctxt->hash, sk))
++    goto fail;
++  if (!*pkalgos[pk].algo)
++    {
++      grub_dl_load (pkalgos[pk].module);
++      grub_errno = GRUB_ERR_NONE;
++    }
++
++  if (!*pkalgos[pk].algo)
++    {
++      grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
++		  pkalgos[pk].module);
++      goto fail;
++    }
++  if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
++    goto fail;
++
++  grub_free (readbuf);
++
++  return GRUB_ERR_NONE;
++
++ fail:
++  grub_free (readbuf);
++  if (!grub_errno)
++    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
++  return grub_errno;
++}
++
++static void
++grub_pubkey_close_real (struct grub_pubkey_context *ctxt)
++{
++  if (ctxt->sig)
++    grub_file_close (ctxt->sig);
++  if (ctxt->hash_context)
++    grub_free (ctxt->hash_context);
++}
++
++static void
++grub_pubkey_close (void *ctxt)
++{
++  grub_pubkey_close_real (ctxt);
++  grub_free (ctxt);
+ }
+ 
+ grub_err_t
+ grub_verify_signature (grub_file_t f, grub_file_t sig,
+ 		       struct grub_public_key *pkey)
+ {
+-  return grub_verify_signature_real (0, 0, f, sig, pkey);
++  grub_err_t err;
++  struct grub_pubkey_context ctxt;
++  grub_uint8_t *readbuf = NULL;
++
++  err = grub_verify_signature_init (&ctxt, sig);
++  if (err)
++    return err;
++
++  readbuf = grub_zalloc (READBUF_SIZE);
++  if (!readbuf)
++    goto fail;
++
++  while (1)
++    {
++      grub_ssize_t r;
++      r = grub_file_read (f, readbuf, READBUF_SIZE);
++      if (r < 0)
++	goto fail;
++      if (r == 0)
++	break;
++      err = grub_pubkey_write (&ctxt, readbuf, r);
++      if (err)
++	return err;
++    }
++
++  grub_verify_signature_real (&ctxt, pkey);
++ fail:
++  grub_pubkey_close_real (&ctxt);
++  return grub_errno;
+ }
+ 
+ static grub_err_t
+@@ -819,134 +867,52 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+ 
+ static int sec = 0;
+ 
+-static void
+-verified_free (grub_verified_t verified)
+-{
+-  if (verified)
+-    {
+-      grub_free (verified->buf);
+-      grub_free (verified);
+-    }
+-}
+-
+-static grub_ssize_t
+-verified_read (struct grub_file *file, char *buf, grub_size_t len)
+-{
+-  grub_verified_t verified = file->data;
+-
+-  grub_memcpy (buf, (char *) verified->buf + file->offset, len);
+-  return len;
+-}
+-
+ static grub_err_t
+-verified_close (struct grub_file *file)
+-{
+-  grub_verified_t verified = file->data;
+-
+-  grub_file_close (verified->file);
+-  verified_free (verified);
+-  file->data = 0;
+-
+-  /* device and name are freed by parent */
+-  file->device = 0;
+-  file->name = 0;
+-
+-  return grub_errno;
+-}
+-
+-struct grub_fs verified_fs =
+-{
+-  .name = "verified_read",
+-  .read = verified_read,
+-  .close = verified_close
+-};
+-
+-static grub_file_t
+-grub_pubkey_open (grub_file_t io, enum grub_file_type type)
++grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__ ((unused)),
++		  void **context, enum grub_verify_flags *flags)
+ {
+   grub_file_t sig;
+   char *fsuf, *ptr;
+   grub_err_t err;
+-  grub_file_t ret;
+-  grub_verified_t verified;
+-
+-  if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
+-      || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
+-      || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
+-    return io;
++  struct grub_pubkey_context *ctxt;
+ 
+   if (!sec)
+-    return io;
+-  if (io->device->disk && 
+-      (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
+-       || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
+-    return io;
++    {
++      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
++      return GRUB_ERR_NONE;
++    }
++
+   fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
+   if (!fsuf)
+-    return NULL;
++    return grub_errno;
+   ptr = grub_stpcpy (fsuf, io->name);
+   grub_memcpy (ptr, ".sig", sizeof (".sig"));
+ 
+   sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE);
+   grub_free (fsuf);
+   if (!sig)
+-    return NULL;
++    return grub_errno;
+ 
+-  ret = grub_malloc (sizeof (*ret));
+-  if (!ret)
++  ctxt = grub_malloc (sizeof (*ctxt));
++  if (!ctxt)
+     {
+       grub_file_close (sig);
+-      return NULL;
++      return grub_errno;
+     }
+-  *ret = *io;
+-
+-  ret->fs = &verified_fs;
+-  ret->not_easily_seekable = 0;
+-  if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
+-    {
+-      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+-		  "big file signature isn't implemented yet");
+-      grub_file_close (sig);
+-      grub_free (ret);
+-      return NULL;
+-    }
+-  verified = grub_malloc (sizeof (*verified));
+-  if (!verified)
+-    {
+-      grub_file_close (sig);
+-      grub_free (ret);
+-      return NULL;
+-    }
+-  verified->buf = grub_malloc (ret->size);
+-  if (!verified->buf)
+-    {
+-      grub_file_close (sig);
+-      verified_free (verified);
+-      grub_free (ret);
+-      return NULL;
+-    }
+-  if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
+-    {
+-      if (!grub_errno)
+-	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+-		    io->name);
+-      grub_file_close (sig);
+-      verified_free (verified);
+-      grub_free (ret);
+-      return NULL;
+-    }
+-
+-  err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL);
+-  grub_file_close (sig);
++  err = grub_verify_signature_init (ctxt, sig);
+   if (err)
+     {
+-      verified_free (verified);
+-      grub_free (ret);
+-      return NULL;
++      grub_pubkey_close (ctxt);
++      return err;
+     }
+-  verified->file = io;
+-  ret->data = verified;
+-  return ret;
++  *context = ctxt;
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_pubkey_fini (void *ctxt)
++{
++  return grub_verify_signature_real (ctxt, NULL);
+ }
+ 
+ static char *
+@@ -970,8 +936,16 @@ struct grub_fs pseudo_fs =
+   {
+     .name = "pseudo",
+     .read = pseudo_read
+-};
++  };
+ 
++struct grub_file_verifier grub_pubkey_verifier =
++  {
++    .name = "pgp",
++    .init = grub_pubkey_init,
++    .fini = grub_pubkey_fini,
++    .write = grub_pubkey_write,
++    .close = grub_pubkey_close,
++  };
+ 
+ static grub_extcmd_t cmd, cmd_trust;
+ static grub_command_t cmd_distrust, cmd_list;
+@@ -986,8 +960,6 @@ GRUB_MOD_INIT(verify)
+     sec = 1;
+   else
+     sec = 0;
+-    
+-  grub_file_filter_register (GRUB_FILE_FILTER_PUBKEY, grub_pubkey_open);
+ 
+   grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
+   grub_env_export ("check_signatures");
+@@ -1033,11 +1005,13 @@ GRUB_MOD_INIT(verify)
+   cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
+ 					N_("PUBKEY_ID"),
+ 					N_("Remove PUBKEY_ID from trusted keys."));
++
++  grub_verifier_register (&grub_pubkey_verifier);
+ }
+ 
+ GRUB_MOD_FINI(verify)
+ {
+-  grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
++  grub_verifier_unregister (&grub_pubkey_verifier);
+   grub_unregister_extcmd (cmd);
+   grub_unregister_extcmd (cmd_trust);
+   grub_unregister_command (cmd_list);
+diff --git a/include/grub/file.h b/include/grub/file.h
+index 5b47c5f91f9..19dda67f68b 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -171,7 +171,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook);
+ /* Filters with lower ID are executed first.  */
+ typedef enum grub_file_filter_id
+   {
+-    GRUB_FILE_FILTER_PUBKEY,
++    GRUB_FILE_FILTER_VERIFY,
+     GRUB_FILE_FILTER_GZIO,
+     GRUB_FILE_FILTER_XZIO,
+     GRUB_FILE_FILTER_LZOPIO,
+diff --git a/include/grub/list.h b/include/grub/list.h
+index d170ff6da02..b13acb96243 100644
+--- a/include/grub/list.h
++++ b/include/grub/list.h
+@@ -35,6 +35,7 @@ void EXPORT_FUNC(grub_list_push) (grub_list_t *head, grub_list_t item);
+ void EXPORT_FUNC(grub_list_remove) (grub_list_t item);
+ 
+ #define FOR_LIST_ELEMENTS(var, list) for ((var) = (list); (var); (var) = (var)->next)
++#define FOR_LIST_ELEMENTS_NEXT(var, list) for ((var) = (var)->next; (var); (var) = (var)->next)
+ #define FOR_LIST_ELEMENTS_SAFE(var, nxt, list) for ((var) = (list), (nxt) = ((var) ? (var)->next : 0); (var); (var) = (nxt), ((nxt) = (var) ? (var)->next : 0))
+ 
+ static inline void *
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+new file mode 100644
+index 00000000000..298120f5776
+--- /dev/null
++++ b/include/grub/verify.h
+@@ -0,0 +1,65 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2017  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/file.h>
++#include <grub/list.h>
++
++enum grub_verify_flags
++  {
++    GRUB_VERIFY_FLAGS_SKIP_VERIFICATION	= 1,
++    GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2
++  };
++
++struct grub_file_verifier
++{
++  struct grub_file_verifier *next;
++  struct grub_file_verifier **prev;
++
++  const char *name;
++
++  /*
++   * Check if file needs to be verified and set up context.
++   * init/read/fini is structured in the same way as hash interface.
++   */
++  grub_err_t (*init) (grub_file_t io, enum grub_file_type type,
++		      void **context, enum grub_verify_flags *flags);
++
++  /*
++   * Right now we pass the whole file in one call but it may
++   * change in the future. If you insist on single buffer you
++   * need to set GRUB_VERIFY_FLAGS_SINGLE_CHUNK in verify_flags.
++   */
++  grub_err_t (*write) (void *context, void *buf, grub_size_t size);
++
++  grub_err_t (*fini) (void *context);
++  void (*close) (void *context);
++};
++
++extern struct grub_file_verifier *grub_file_verifiers;
++
++static inline void
++grub_verifier_register (struct grub_file_verifier *ver)
++{
++  grub_list_push (GRUB_AS_LIST_P (&grub_file_verifiers), GRUB_AS_LIST (ver));
++}
++
++static inline void
++grub_verifier_unregister (struct grub_file_verifier *ver)
++{
++  grub_list_remove (GRUB_AS_LIST (ver));
++}
diff --git a/SOURCES/0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch b/SOURCES/0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b6265b20a1b050574a772f7fede3f504344af617
--- /dev/null
+++ b/SOURCES/0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch
@@ -0,0 +1,520 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Vladimir Serbinenko <phcoder@gmail.com>
+Date: Tue, 7 Feb 2017 02:10:14 +0100
+Subject: [PATCH] verifiers: Add possibility to verify kernel and modules
+ command lines
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+(backported from 4d4a8c96e3593d76fe7b025665ccdecc70a53c1f)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/verifiers.c            | 14 ++++++++++++++
+ grub-core/lib/cmdline.c                   |  7 ++++---
+ grub-core/loader/arm/linux.c              |  8 ++++++--
+ grub-core/loader/arm64/linux.c            | 10 +++++++---
+ grub-core/loader/i386/bsd.c               |  6 ++++++
+ grub-core/loader/i386/linux.c             | 16 +++++++++++-----
+ grub-core/loader/i386/multiboot_mbi.c     | 16 ++++++++++------
+ grub-core/loader/i386/pc/linux.c          | 13 ++++++++-----
+ grub-core/loader/i386/pc/plan9.c          | 11 +++++++++++
+ grub-core/loader/i386/xen.c               |  7 +++++++
+ grub-core/loader/ia64/efi/linux.c         |  7 +++++++
+ grub-core/loader/mips/linux.c             |  8 ++++++++
+ grub-core/loader/multiboot_mbi2.c         |  8 +++-----
+ grub-core/loader/powerpc/ieee1275/linux.c |  5 +++--
+ grub-core/loader/sparc64/ieee1275/linux.c |  5 +++--
+ grub-core/loader/xnu.c                    |  9 +++++++++
+ include/grub/lib/cmdline.h                |  5 +++--
+ include/grub/verify.h                     | 11 +++++++++++
+ 18 files changed, 131 insertions(+), 35 deletions(-)
+
+diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
+index fde88318d4c..59ea418a2d9 100644
+--- a/grub-core/commands/verifiers.c
++++ b/grub-core/commands/verifiers.c
+@@ -186,6 +186,20 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
+   return NULL;
+ }
+ 
++grub_err_t
++grub_verify_string (char *str, enum grub_verify_string_type type)
++{
++  struct grub_file_verifier *ver;
++  FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
++    {
++      grub_err_t err;
++      err = ver->verify_string ? ver->verify_string (str, type) : GRUB_ERR_NONE;
++      if (err)
++	return err;
++    }
++  return GRUB_ERR_NONE;
++}
++
+ GRUB_MOD_INIT(verifiers)
+ {
+   grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
+diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
+index d5c12957cad..463c3c65c79 100644
+--- a/grub-core/lib/cmdline.c
++++ b/grub-core/lib/cmdline.c
+@@ -75,8 +75,9 @@ unsigned int grub_loader_cmdline_size (int argc, char *argv[])
+   return size;
+ }
+ 
+-int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+-				grub_size_t size)
++grub_err_t
++grub_create_loader_cmdline (int argc, char *argv[], char *buf,
++			    grub_size_t size, enum grub_verify_string_type type)
+ {
+   int i, space;
+   unsigned int arg_size;
+@@ -130,5 +131,5 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ 		    "grub_kernel_cmdline", orig);
+   grub_print_error();
+ 
+-  return i;
++  return grub_verify_string (orig, type);
+ }
+diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c
+index ea29d7a724a..beceda52030 100644
+--- a/grub-core/loader/arm/linux.c
++++ b/grub-core/loader/arm/linux.c
+@@ -28,6 +28,7 @@
+ #include <grub/cpu/linux.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/linux.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -383,8 +384,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   /* Create kernel command line.  */
+   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+-  grub_create_loader_cmdline (argc, argv,
+-			      linux_args + sizeof (LINUX_IMAGE) - 1, size);
++  err = grub_create_loader_cmdline (argc, argv,
++				    linux_args + sizeof (LINUX_IMAGE) - 1, size,
++				    GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    goto fail;
+ 
+   return GRUB_ERR_NONE;
+ 
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 7a076c13171..48ea66596ad 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -33,6 +33,7 @@
+ #include <grub/efi/pe32.h>
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -403,9 +404,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+-  grub_create_loader_cmdline (argc, argv,
+-			      linux_args + sizeof (LINUX_IMAGE) - 1,
+-			      cmdline_size);
++  err = grub_create_loader_cmdline (argc, argv,
++				    linux_args + sizeof (LINUX_IMAGE) - 1,
++				    cmdline_size,
++				    GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    goto fail;
+ 
+   if (grub_errno == GRUB_ERR_NONE)
+     {
+diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
+index 8306b415abd..45a71509956 100644
+--- a/grub-core/loader/i386/bsd.c
++++ b/grub-core/loader/i386/bsd.c
+@@ -36,6 +36,7 @@
+ #include <grub/bsdlabel.h>
+ #include <grub/crypto.h>
+ #include <grub/safemath.h>
++#include <grub/verify.h>
+ #ifdef GRUB_MACHINE_PCBIOS
+ #include <grub/machine/int.h>
+ #endif
+@@ -418,6 +419,8 @@ grub_freebsd_add_meta_module (const char *filename, const char *type,
+ 			      grub_addr_t addr, grub_uint32_t size)
+ {
+   const char *name;
++  grub_err_t err;
++
+   name = grub_strrchr (filename, '/');
+   if (name)
+     name++;
+@@ -471,6 +474,9 @@ grub_freebsd_add_meta_module (const char *filename, const char *type,
+ 	      *(p++) = ' ';
+ 	    }
+ 	  *p = 0;
++	  err = grub_verify_string (cmdline, GRUB_VERIFY_MODULE_CMDLINE);
++	  if (err)
++	    return err;
+ 	}
+     }
+ 
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index aa2cbc4e7eb..ef8fcb9e1b6 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -1039,11 +1039,17 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (!linux_cmdline)
+     goto fail;
+   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+-  grub_create_loader_cmdline (argc, argv,
+-			      linux_cmdline
+-			      + sizeof (LINUX_IMAGE) - 1,
+-			      maximal_cmdline_size
+-			      - (sizeof (LINUX_IMAGE) - 1));
++  {
++    grub_err_t err;
++    err = grub_create_loader_cmdline (argc, argv,
++				      linux_cmdline
++				      + sizeof (LINUX_IMAGE) - 1,
++				      maximal_cmdline_size
++				      - (sizeof (LINUX_IMAGE) - 1),
++				      GRUB_VERIFY_KERNEL_CMDLINE);
++    if (err)
++      goto fail;
++  }
+ 
+   len = prot_file_size;
+   grub_memcpy (prot_mode_mem, kernel + kernel_offset, len);
+diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
+index 9d3466d6ace..525446b5687 100644
+--- a/grub-core/loader/i386/multiboot_mbi.c
++++ b/grub-core/loader/i386/multiboot_mbi.c
+@@ -676,10 +676,8 @@ grub_multiboot_init_mbi (int argc, char *argv[])
+     return grub_errno;
+   cmdline_size = len;
+ 
+-  grub_create_loader_cmdline (argc, argv, cmdline,
+-			      cmdline_size);
+-
+-  return GRUB_ERR_NONE;
++  return grub_create_loader_cmdline (argc, argv, cmdline,
++				     cmdline_size, GRUB_VERIFY_KERNEL_CMDLINE);
+ }
+ 
+ grub_err_t
+@@ -688,6 +686,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
+ {
+   struct module *newmod;
+   grub_size_t len = 0;
++  grub_err_t err;
+ 
+   newmod = grub_malloc (sizeof (*newmod));
+   if (!newmod)
+@@ -707,8 +706,13 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
+   newmod->cmdline_size = len;
+   total_modcmd += ALIGN_UP (len, 4);
+ 
+-  grub_create_loader_cmdline (argc, argv, newmod->cmdline,
+-			      newmod->cmdline_size);
++  err = grub_create_loader_cmdline (argc, argv, newmod->cmdline,
++				    newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE);
++  if (err)
++    {
++      grub_free (newmod);
++      return grub_errno;
++    }
+ 
+   if (modules_last)
+     modules_last->next = newmod;
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index b5c28c6580e..f631225f59b 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -348,11 +348,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   /* Create kernel command line.  */
+   grub_memcpy ((char *)grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET,
+ 		LINUX_IMAGE, sizeof (LINUX_IMAGE));
+-  grub_create_loader_cmdline (argc, argv,
+-			      (char *)grub_linux_real_chunk
+-			      + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1,
+-			      maximal_cmdline_size
+-			      - (sizeof (LINUX_IMAGE) - 1));
++  err = grub_create_loader_cmdline (argc, argv,
++				    (char *)grub_linux_real_chunk
++				    + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1,
++				    maximal_cmdline_size
++				    - (sizeof (LINUX_IMAGE) - 1),
++				    GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    goto fail;
+ 
+   if (grub_linux_is_bzimage)
+     grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR;
+diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c
+index 0351090daf8..37550155df7 100644
+--- a/grub-core/loader/i386/pc/plan9.c
++++ b/grub-core/loader/i386/pc/plan9.c
+@@ -33,6 +33,7 @@
+ #include <grub/mm.h>
+ #include <grub/cpu/relocator.h>
+ #include <grub/extcmd.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -505,6 +506,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
+   configptr = grub_stpcpy (configptr, "bootfile=");
+   configptr = grub_stpcpy (configptr, bootpath);
+   *configptr++ = '\n';
++  char *cmdline = configptr;
+   {
+     int i;
+     for (i = 1; i < argc; i++)
+@@ -513,6 +515,15 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
+ 	*configptr++ = '\n';
+       }
+   }
++
++  {
++    grub_err_t err;
++    *configptr = '\0';
++    err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
++    if (err)
++      goto fail;
++  }
++
+   configptr = grub_stpcpy (configptr, fill_ctx.pmap);
+ 
+   {
+diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
+index 82350d3a178..07a4837c532 100644
+--- a/grub-core/loader/i386/xen.c
++++ b/grub-core/loader/i386/xen.c
+@@ -41,6 +41,7 @@
+ #include <grub/linux.h>
+ #include <grub/i386/memory.h>
+ #include <grub/safemath.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -649,6 +650,9 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
+   grub_create_loader_cmdline (argc - 1, argv + 1,
+ 			      (char *) xen_state.next_start.cmd_line,
+ 			      sizeof (xen_state.next_start.cmd_line) - 1);
++  err = grub_verify_string (xen_state.next_start.cmd_line, GRUB_VERIFY_MODULE_CMDLINE);
++  if (err)
++    return err;
+ 
+   file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (!file)
+@@ -916,6 +920,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_create_loader_cmdline (argc - 1, argv + 1,
+ 			      get_virtual_current_address (ch), cmdline_len);
++  err = grub_verify_string (get_virtual_current_address (ch), GRUB_VERIFY_MODULE_CMDLINE);
++  if (err)
++    goto fail;
+ 
+   xen_state.module_info_page[xen_state.n_modules].cmdline =
+     xen_state.max_addr - xen_state.modules_target_start;
+diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c
+index 750330d4572..e325fe0ee83 100644
+--- a/grub-core/loader/ia64/efi/linux.c
++++ b/grub-core/loader/ia64/efi/linux.c
+@@ -33,6 +33,7 @@
+ #include <grub/i18n.h>
+ #include <grub/env.h>
+ #include <grub/linux.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -543,6 +544,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       p = grub_stpcpy (p, argv[i]);
+     }
+   cmdline[10] = '=';
++
++  *p = '\0';
++
++  err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    goto fail;
+   
+   boot_param->command_line = (grub_uint64_t) cmdline;
+   boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table;
+diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c
+index 10358854458..20135ce253d 100644
+--- a/grub-core/loader/mips/linux.c
++++ b/grub-core/loader/mips/linux.c
+@@ -327,6 +327,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   linux_argv++;
+   linux_args += ALIGN_UP (sizeof ("a0"), 4);
+ 
++  char *params = linux_args;
++
+ #ifdef GRUB_MACHINE_MIPS_LOONGSON
+   {
+     unsigned mtype = grub_arch_machine;
+@@ -352,6 +354,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
+     }
+ 
++  *linux_args = '\0';
++
++  err = grub_verify_string (params, GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    return err;
++
+   /* Reserve space for rd arguments.  */
+   rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground;
+   linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
+diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
+index 3cfb47650a0..f64a857e394 100644
+--- a/grub-core/loader/multiboot_mbi2.c
++++ b/grub-core/loader/multiboot_mbi2.c
+@@ -1077,10 +1077,8 @@ grub_multiboot2_init_mbi (int argc, char *argv[])
+     return grub_errno;
+   cmdline_size = len;
+ 
+-  grub_create_loader_cmdline (argc, argv, cmdline,
+-			      cmdline_size);
+-
+-  return GRUB_ERR_NONE;
++  return grub_create_loader_cmdline (argc, argv, cmdline, cmdline_size,
++				     GRUB_VERIFY_KERNEL_CMDLINE);
+ }
+ 
+ grub_err_t
+@@ -1109,7 +1107,7 @@ grub_multiboot2_add_module (grub_addr_t start, grub_size_t size,
+   total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN);
+ 
+   err = grub_create_loader_cmdline (argc, argv, newmod->cmdline,
+-				    newmod->cmdline_size);
++				    newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE);
+   if (err)
+     {
+       grub_free (newmod->cmdline);
+diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c
+index 6e814649f31..c114e7df4fb 100644
+--- a/grub-core/loader/powerpc/ieee1275/linux.c
++++ b/grub-core/loader/powerpc/ieee1275/linux.c
+@@ -302,8 +302,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   /* Create kernel command line.  */
+   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+-  grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
+-			      size);
++  if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
++				  size))
++    goto out;
+ 
+ out:
+ 
+diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c
+index 67ef0488324..abe46faa012 100644
+--- a/grub-core/loader/sparc64/ieee1275/linux.c
++++ b/grub-core/loader/sparc64/ieee1275/linux.c
+@@ -340,8 +340,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   /* Create kernel command line.  */
+   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+-  grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
+-			      size);
++  if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
++				  size, GRUB_VERIFY_KERNEL_CMDLINE))
++    goto out;
+ 
+ out:
+   if (elf)
+diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
+index 9f78abb05f9..5944dc5eafc 100644
+--- a/grub-core/loader/xnu.c
++++ b/grub-core/loader/xnu.c
+@@ -35,6 +35,7 @@
+ #include <grub/i18n.h>
+ #include <grub/efi/sb.h>
+ #include <grub/safemath.h>
++#include <grub/verify.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -429,6 +430,10 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
+   if (ptr != grub_xnu_cmdline)
+     *(ptr - 1) = 0;
+ 
++  err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    return err;
++
+ #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
+   err = grub_efiemu_autocore ();
+   if (err)
+@@ -538,6 +543,10 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
+   if (ptr != grub_xnu_cmdline)
+     *(ptr - 1) = 0;
+ 
++  err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
++  if (err)
++    return err;
++
+ #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
+   err = grub_efiemu_autocore ();
+   if (err)
+diff --git a/include/grub/lib/cmdline.h b/include/grub/lib/cmdline.h
+index 1fe8d017971..cdca09b7a16 100644
+--- a/include/grub/lib/cmdline.h
++++ b/include/grub/lib/cmdline.h
+@@ -21,11 +21,12 @@
+ #define GRUB_CMDLINE_HEADER	1
+ 
+ #include <grub/types.h>
++#include <grub/verify.h>
+ 
+ #define LINUX_IMAGE "BOOT_IMAGE="
+ 
+ unsigned int grub_loader_cmdline_size (int argc, char *argv[]);
+-int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+-				grub_size_t size);
++grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf,
++				       grub_size_t size, enum grub_verify_string_type type);
+ 
+ #endif /* ! GRUB_CMDLINE_HEADER */
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+index 298120f5776..9f892d8fedb 100644
+--- a/include/grub/verify.h
++++ b/include/grub/verify.h
+@@ -25,6 +25,12 @@ enum grub_verify_flags
+     GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2
+   };
+ 
++enum grub_verify_string_type
++  {
++    GRUB_VERIFY_KERNEL_CMDLINE,
++    GRUB_VERIFY_MODULE_CMDLINE,
++  };
++
+ struct grub_file_verifier
+ {
+   struct grub_file_verifier *next;
+@@ -48,6 +54,8 @@ struct grub_file_verifier
+ 
+   grub_err_t (*fini) (void *context);
+   void (*close) (void *context);
++
++  grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type);
+ };
+ 
+ extern struct grub_file_verifier *grub_file_verifiers;
+@@ -63,3 +71,6 @@ grub_verifier_unregister (struct grub_file_verifier *ver)
+ {
+   grub_list_remove (GRUB_AS_LIST (ver));
+ }
++
++grub_err_t
++grub_verify_string (char *str, enum grub_verify_string_type type);
diff --git a/SOURCES/0333-verifiers-Add-possibility-to-defer-verification-to-o.patch b/SOURCES/0333-verifiers-Add-possibility-to-defer-verification-to-o.patch
new file mode 100644
index 0000000000000000000000000000000000000000..bddb30e0fd590b93a2da869369fb7c2d9c7306f2
--- /dev/null
+++ b/SOURCES/0333-verifiers-Add-possibility-to-defer-verification-to-o.patch
@@ -0,0 +1,91 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Wed, 26 Sep 2018 13:17:52 +0200
+Subject: [PATCH] verifiers: Add possibility to defer verification to other
+ verifiers
+
+This way if a verifier requires verification of a given file it can defer task
+to another verifier (another authority) if it is not able to do it itself. E.g.
+shim_lock verifier, posted as a subsequent patch, is able to verify only PE
+files. This means that it is not able to verify any of GRUB2 modules which have
+to be trusted on UEFI systems with secure boot enabled. So, it can defer
+verification to other verifier, e.g. PGP one.
+
+I silently assume that other verifiers are trusted and will do good job for us.
+Or at least they will not do any harm.
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+---
+ grub-core/commands/verifiers.c | 23 ++++++++++++++++++++---
+ include/grub/verify.h          |  4 +++-
+ 2 files changed, 23 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
+index 59ea418a2d9..c638d5f43e0 100644
+--- a/grub-core/commands/verifiers.c
++++ b/grub-core/commands/verifiers.c
+@@ -83,6 +83,7 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
+   void *context;
+   grub_file_t ret = 0;
+   grub_err_t err;
++  int defer = 0;
+ 
+   grub_dprintf ("verify", "file: %s type: %d\n", io->name, type);
+ 
+@@ -102,13 +103,27 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
+       err = ver->init (io, type, &context, &flags);
+       if (err)
+ 	goto fail_noclose;
++      if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
++	{
++	  defer = 1;
++	  continue;
++	}
+       if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION))
+ 	break;
+     }
+ 
+   if (!ver)
+-    /* No verifiers wanted to verify. Just return underlying file. */
+-    return io;
++    {
++      if (defer)
++	{
++	  grub_error (GRUB_ERR_ACCESS_DENIED,
++		      N_("verification requested but nobody cares: %s"), io->name);
++	  goto fail_noclose;
++	}
++
++      /* No verifiers wanted to verify. Just return underlying file. */
++      return io;
++    }
+ 
+   ret = grub_malloc (sizeof (*ret));
+   if (!ret)
+@@ -160,7 +175,9 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
+       err = ver->init (io, type, &context, &flags);
+       if (err)
+ 	goto fail_noclose;
+-      if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION)
++      if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION ||
++	  /* Verification done earlier. So, we are happy here. */
++	  flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
+ 	continue;
+       err = ver->write (context, verified->buf, ret->size);
+       if (err)
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+index 9f892d8fedb..79022b42258 100644
+--- a/include/grub/verify.h
++++ b/include/grub/verify.h
+@@ -22,7 +22,9 @@
+ enum grub_verify_flags
+   {
+     GRUB_VERIFY_FLAGS_SKIP_VERIFICATION	= 1,
+-    GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2
++    GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2,
++    /* Defer verification to another authority. */
++    GRUB_VERIFY_FLAGS_DEFER_AUTH	= 4
+   };
+ 
+ enum grub_verify_string_type
diff --git a/SOURCES/0334-verifiers-Rename-verify-module-to-pgp-module.patch b/SOURCES/0334-verifiers-Rename-verify-module-to-pgp-module.patch
new file mode 100644
index 0000000000000000000000000000000000000000..40363f2271f60412247f0286665ec11fe86bd4e1
--- /dev/null
+++ b/SOURCES/0334-verifiers-Rename-verify-module-to-pgp-module.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Tue, 2 Oct 2018 22:36:43 +0200
+Subject: [PATCH] verifiers: Rename verify module to pgp module
+
+Just for clarity. No functional change.
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+(cherry picked from commit b07feb8746c3bb845e3f0d33d37c0bded704d14d)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def            | 4 ++--
+ grub-core/commands/{verify.c => pgp.c} | 0
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+ rename grub-core/commands/{verify.c => pgp.c} (100%)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 29c3bf6cd66..809f11feaef 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -915,8 +915,8 @@ module = {
+ };
+ 
+ module = {
+-  name = verify;
+-  common = commands/verify.c;
++  name = pgp;
++  common = commands/pgp.c;
+   cflags = '$(CFLAGS_POSIX)';
+   cppflags = '-I$(srcdir)/lib/posix_wrap';
+ };
+diff --git a/grub-core/commands/verify.c b/grub-core/commands/pgp.c
+similarity index 100%
+rename from grub-core/commands/verify.c
+rename to grub-core/commands/pgp.c
diff --git a/SOURCES/0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch b/SOURCES/0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5813141d5bde21d889708b9a528f8b2362801855
--- /dev/null
+++ b/SOURCES/0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch
@@ -0,0 +1,55 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Wed, 9 Jan 2019 14:54:39 +0000
+Subject: [PATCH] pgp: Fix emu build and tests after pgp module renaming
+
+Commit b07feb8746c3bb845e3f0d33d37c0bded704d14d (verifiers: Rename
+verify module to pgp module) renamed the "verify" module to "pgp", but
+the GRUB_MOD_INIT and GRUB_MOD_FINI macros were left as "verify", which
+broke the emu target build; and file_filter_test still referred to the
+now non-existent "verify" module. Fix both of these.
+
+Signed-off-by: Colin Watson <cjwatson@ubuntu.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit ed087f0460516737e174222f01e2bf6ccbd45674)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/pgp.c  | 4 ++--
+ tests/file_filter_test.in | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
+index 29e74a64004..5c913c2e2fe 100644
+--- a/grub-core/commands/pgp.c
++++ b/grub-core/commands/pgp.c
+@@ -950,7 +950,7 @@ struct grub_file_verifier grub_pubkey_verifier =
+ static grub_extcmd_t cmd, cmd_trust;
+ static grub_command_t cmd_distrust, cmd_list;
+ 
+-GRUB_MOD_INIT(verify)
++GRUB_MOD_INIT(pgp)
+ {
+   const char *val;
+   struct grub_module_header *header;
+@@ -1009,7 +1009,7 @@ GRUB_MOD_INIT(verify)
+   grub_verifier_register (&grub_pubkey_verifier);
+ }
+ 
+-GRUB_MOD_FINI(verify)
++GRUB_MOD_FINI(pgp)
+ {
+   grub_verifier_unregister (&grub_pubkey_verifier);
+   grub_unregister_extcmd (cmd);
+diff --git a/tests/file_filter_test.in b/tests/file_filter_test.in
+index bfb6382274e..ed6abcb5af4 100644
+--- a/tests/file_filter_test.in
++++ b/tests/file_filter_test.in
+@@ -19,7 +19,7 @@ grubshell=@builddir@/grub-shell
+ 
+ . "@builddir@/grub-core/modinfo.sh"
+ 
+-filters="gzio xzio lzopio verify"
++filters="gzio xzio lzopio pgp"
+ modules="cat mpi"
+ 
+ for mod in $(cut -d ' ' -f 2 "@builddir@/grub-core/crypto.lst"  | sort -u); do
diff --git a/SOURCES/0336-include-grub-file.h-Add-device-tree-file-type.patch b/SOURCES/0336-include-grub-file.h-Add-device-tree-file-type.patch
new file mode 100644
index 0000000000000000000000000000000000000000..04e16fcb1df2f1b586c9a2efd15fdd5b1559addf
--- /dev/null
+++ b/SOURCES/0336-include-grub-file.h-Add-device-tree-file-type.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leif Lindholm <leif.lindholm@linaro.org>
+Date: Wed, 14 Nov 2018 19:29:16 +0000
+Subject: [PATCH] include/grub/file.h: Add device tree file type
+
+The API change of grub_file_open() for adding verifiers did not include
+a type for device tree blobs. Add GRUB_FILE_TYPE_DEVICE_TREE_IMAGE to
+the grub_file_type enum.
+
+Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 7453c2cc32525a5eebe3b268433d0dfc73622917)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ include/grub/file.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/grub/file.h b/include/grub/file.h
+index 19dda67f68b..9aae463557a 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -69,6 +69,8 @@ enum grub_file_type
+ 
+     GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE,
+ 
++    GRUB_FILE_TYPE_DEVICE_TREE_IMAGE,
++
+     /* File holding signature.  */
+     GRUB_FILE_TYPE_SIGNATURE,
+     /* File holding public key to verify signature once.  */
diff --git a/SOURCES/0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch b/SOURCES/0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch
new file mode 100644
index 0000000000000000000000000000000000000000..73d1cda25f3b4f5d9f94e94596bdb00e7e9323cb
--- /dev/null
+++ b/SOURCES/0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leif Lindholm <leif.lindholm@linaro.org>
+Date: Wed, 14 Nov 2018 19:29:17 +0000
+Subject: [PATCH] grub-core/loader/efi/fdt.c: Fixup grub_file_open() call
+
+The verifiers framework changed the API of grub_file_open(), but did not
+fix up all users. Add the file type GRUB_FILE_TYPE_DEVICE_TREE_IMAGE
+to the "devicetree" command handler call.
+
+Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/loader/efi/fdt.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
+index a9dbcfdfeaf..e3ee3ad79d6 100644
+--- a/grub-core/loader/efi/fdt.c
++++ b/grub-core/loader/efi/fdt.c
+@@ -125,7 +125,7 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
+       return GRUB_ERR_NONE;
+     }
+ 
+-  dtb = grub_file_open (argv[0]);
++  dtb = grub_file_open (argv[0], GRUB_FILE_TYPE_DEVICE_TREE_IMAGE);
+   if (!dtb)
+     goto out;
+ 
diff --git a/SOURCES/0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch b/SOURCES/0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch
new file mode 100644
index 0000000000000000000000000000000000000000..debb2c6ff83c50263bc421704309e351ee63f80b
--- /dev/null
+++ b/SOURCES/0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leif Lindholm <leif.lindholm@linaro.org>
+Date: Wed, 14 Nov 2018 19:29:18 +0000
+Subject: [PATCH] arm64/efi: Fix breakage caused by verifiers
+
+  - add variable "err" (used but not defined),
+  - add GRUB_FILE_TYPE_LINUX_KERNEL to grub_file_open() call.
+
+Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+Conflicts:
+	grub-core/loader/arm64/linux.c
+---
+ grub-core/loader/arm64/linux.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 48ea66596ad..864724dd4fa 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -338,6 +338,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   struct linux_armxx_kernel_header lh;
+   struct grub_armxx_linux_pe_header *pe;
+   int rc;
++  grub_err_t err;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -347,7 +348,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (!file)
+     goto fail;
+ 
diff --git a/SOURCES/0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch b/SOURCES/0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8cd768570ecb29ee88847a86baaf46abb1069760
--- /dev/null
+++ b/SOURCES/0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch
@@ -0,0 +1,74 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leif Lindholm <leif.lindholm@linaro.org>
+Date: Wed, 14 Nov 2018 19:29:19 +0000
+Subject: [PATCH] arm-uboot, ia64, sparc64: Fix up grub_file_open() calls
+
+The verifiers framework changed the grub_file_open() interface, breaking all
+non-x86 linux loaders. Add file types to the grub_file_open() calls to make
+them build again.
+
+Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/loader/arm/linux.c              | 6 +++---
+ grub-core/loader/ia64/efi/linux.c         | 2 +-
+ grub-core/loader/sparc64/ieee1275/linux.c | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c
+index beceda52030..1e944a2b671 100644
+--- a/grub-core/loader/arm/linux.c
++++ b/grub-core/loader/arm/linux.c
+@@ -363,7 +363,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (!file)
+     goto fail;
+ 
+@@ -408,7 +408,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_INITRD);
+   if (!file)
+     return grub_errno;
+ 
+@@ -471,7 +471,7 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
+   if (argc != 1)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  dtb = grub_file_open (argv[0]);
++  dtb = grub_file_open (argv[0], GRUB_FILE_TYPE_DEVICE_TREE_IMAGE);
+   if (!dtb)
+     return grub_errno;
+ 
+diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c
+index e325fe0ee83..2ad0b0c0407 100644
+--- a/grub-core/loader/ia64/efi/linux.c
++++ b/grub-core/loader/ia64/efi/linux.c
+@@ -502,7 +502,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (! file)
+     goto fail;
+ 
+diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c
+index abe46faa012..bb47ee0cc64 100644
+--- a/grub-core/loader/sparc64/ieee1275/linux.c
++++ b/grub-core/loader/sparc64/ieee1275/linux.c
+@@ -306,7 +306,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto out;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (!file)
+     goto out;
+ 
diff --git a/SOURCES/0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch b/SOURCES/0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4704137330a3b92a44a1f57fb07cce82139a70db
--- /dev/null
+++ b/SOURCES/0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch
@@ -0,0 +1,146 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Tue, 20 Nov 2018 19:15:37 +0800
+Subject: [PATCH] verifiers: fix double close on pgp's sig file descriptor
+
+An error emerged as when I was testing the verifiers branch, so instead
+of putting it in pgp prefix, the verifiers is used to reflect what the
+patch is based on.
+
+While running verify_detached, grub aborts with error.
+
+verify_detached /@/.snapshots/1/snapshot/boot/grub/grub.cfg
+/@/.snapshots/1/snapshot/boot/grub/grub.cfg.sig
+
+alloc magic is broken at 0x7beea660: 0
+Aborted. Press any key to exit.
+
+The error is caused by sig file descriptor been closed twice, first time
+in grub_verify_signature() to which it is passed as parameter. Second in
+grub_cmd_verify_signature() or in whichever opens the sig file
+descriptor. The second close is not consider as bug to me either, as in
+common rule of what opens a file has to close it to avoid file
+descriptor leakage.
+
+After all the design of grub_verify_signature() makes it difficult to keep
+a good trace on opened file descriptor from it's caller. Let's refine
+the application interface to accept file path rather than descriptor, in
+this way the caller doesn't have to care about closing the descriptor by
+delegating it to grub_verify_signature() with full tracing to opened
+file descriptor by itself.
+
+Also making it clear that sig descriptor is not referenced in error
+returning path of grub_verify_signature_init(), so it can be closed
+directly by it's caller. This also makes delegating it to
+grub_pubkey_close() infeasible to help in relieving file descriptor
+leakage as it has to depend on uncertainty of ctxt fields in error
+returning path.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/commands/pgp.c | 35 +++++++++++++++++------------------
+ include/grub/pubkey.h    |  2 +-
+ 2 files changed, 18 insertions(+), 19 deletions(-)
+
+diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
+index 5c913c2e2fe..d39846d8cfe 100644
+--- a/grub-core/commands/pgp.c
++++ b/grub-core/commands/pgp.c
+@@ -495,13 +495,12 @@ grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
+ 
+   grub_dprintf ("crypt", "alive\n");
+ 
+-  ctxt->sig = sig;
+-
+   ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+   if (!ctxt->hash_context)
+     return grub_errno;
+ 
+   ctxt->hash->init (ctxt->hash_context);
++  ctxt->sig = sig;
+ 
+   return GRUB_ERR_NONE;
+ }
+@@ -684,16 +683,26 @@ grub_pubkey_close (void *ctxt)
+ }
+ 
+ grub_err_t
+-grub_verify_signature (grub_file_t f, grub_file_t sig,
++grub_verify_signature (grub_file_t f, const char *fsig,
+ 		       struct grub_public_key *pkey)
+ {
++  grub_file_t sig;
+   grub_err_t err;
+   struct grub_pubkey_context ctxt;
+   grub_uint8_t *readbuf = NULL;
+ 
++  sig = grub_file_open (fsig,
++			GRUB_FILE_TYPE_SIGNATURE
++			| GRUB_FILE_TYPE_NO_DECOMPRESS);
++  if (!sig)
++    return grub_errno;
++
+   err = grub_verify_signature_init (&ctxt, sig);
+   if (err)
+-    return err;
++    {
++      grub_file_close (sig);
++      return err;
++    }
+ 
+   readbuf = grub_zalloc (READBUF_SIZE);
+   if (!readbuf)
+@@ -807,7 +816,7 @@ static grub_err_t
+ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+ 			   int argc, char **args)
+ {
+-  grub_file_t f = NULL, sig = NULL;
++  grub_file_t f = NULL;
+   grub_err_t err = GRUB_ERR_NONE;
+   struct grub_public_key *pk = NULL;
+ 
+@@ -845,19 +854,8 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+       goto fail;
+     }
+ 
+-  sig = grub_file_open (args[1],
+-			GRUB_FILE_TYPE_SIGNATURE
+-			| GRUB_FILE_TYPE_NO_DECOMPRESS);
+-  if (!sig)
+-    {
+-      err = grub_errno;
+-      goto fail;
+-    }
+-
+-  err = grub_verify_signature (f, sig, pk);
++  err = grub_verify_signature (f, args[1], pk);
+  fail:
+-  if (sig)
+-    grub_file_close (sig);
+   if (f)
+     grub_file_close (f);
+   if (pk)
+@@ -902,7 +900,8 @@ grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__ ((unuse
+   err = grub_verify_signature_init (ctxt, sig);
+   if (err)
+     {
+-      grub_pubkey_close (ctxt);
++      grub_free (ctxt);
++      grub_file_close (sig);
+       return err;
+     }
+   *context = ctxt;
+diff --git a/include/grub/pubkey.h b/include/grub/pubkey.h
+index 4a9d04b4305..fb8be9cbb73 100644
+--- a/include/grub/pubkey.h
++++ b/include/grub/pubkey.h
+@@ -25,7 +25,7 @@ struct grub_public_key *
+ grub_load_public_key (grub_file_t f);
+ 
+ grub_err_t
+-grub_verify_signature (grub_file_t f, grub_file_t sig,
++grub_verify_signature (grub_file_t f, const char *fsig,
+ 		       struct grub_public_key *pk);
+ 
+ 
diff --git a/SOURCES/0341-verifiers-Xen-fallout-cleanup.patch b/SOURCES/0341-verifiers-Xen-fallout-cleanup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7270f3e7242a9b8a6dfeb6dd64be178868b05e31
--- /dev/null
+++ b/SOURCES/0341-verifiers-Xen-fallout-cleanup.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Thu, 6 Dec 2018 13:38:15 +0100
+Subject: [PATCH] verifiers: Xen fallout cleanup
+
+Xen fallout cleanup after commit ca0a4f689 (verifiers: File type for
+fine-grained signature-verification controlling).
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+---
+ grub-core/loader/i386/xen.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
+index 07a4837c532..071b530d744 100644
+--- a/grub-core/loader/i386/xen.c
++++ b/grub-core/loader/i386/xen.c
+@@ -647,10 +647,10 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_xen_reset ();
+ 
+-  grub_create_loader_cmdline (argc - 1, argv + 1,
+-			      (char *) xen_state.next_start.cmd_line,
+-			      sizeof (xen_state.next_start.cmd_line) - 1);
+-  err = grub_verify_string (xen_state.next_start.cmd_line, GRUB_VERIFY_MODULE_CMDLINE);
++  err = grub_create_loader_cmdline (argc - 1, argv + 1,
++				    (char *) xen_state.next_start.cmd_line,
++				    sizeof (xen_state.next_start.cmd_line) - 1,
++				    GRUB_VERIFY_KERNEL_CMDLINE);
+   if (err)
+     return err;
+ 
+@@ -918,9 +918,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+   if (err)
+     goto fail;
+ 
+-  grub_create_loader_cmdline (argc - 1, argv + 1,
+-			      get_virtual_current_address (ch), cmdline_len);
+-  err = grub_verify_string (get_virtual_current_address (ch), GRUB_VERIFY_MODULE_CMDLINE);
++  err = grub_create_loader_cmdline (argc - 1, argv + 1,
++				    get_virtual_current_address (ch), cmdline_len,
++				    GRUB_VERIFY_MODULE_CMDLINE);
+   if (err)
+     goto fail;
+ 
diff --git a/SOURCES/0342-verifiers-ARM-Xen-fallout-cleanup.patch b/SOURCES/0342-verifiers-ARM-Xen-fallout-cleanup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..cc1bfea1d212526e157298f594ea080da656f08c
--- /dev/null
+++ b/SOURCES/0342-verifiers-ARM-Xen-fallout-cleanup.patch
@@ -0,0 +1,63 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Thu, 6 Dec 2018 13:43:05 +0100
+Subject: [PATCH] verifiers: ARM Xen fallout cleanup
+
+ARM Xen fallout cleanup after commit ca0a4f689 (verifiers: File type for
+fine-grained signature-verification controlling).
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+[javierm: remove grub_file_filter_disable_compression() call leftovers]
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+
+Conflicts:
+	grub-core/loader/arm64/xen_boot.c
+---
+ grub-core/loader/arm64/xen_boot.c | 9 +++++----
+ include/grub/file.h               | 5 +++++
+ 2 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
+index f35b16caa92..318c833de57 100644
+--- a/grub-core/loader/arm64/xen_boot.c
++++ b/grub-core/loader/arm64/xen_boot.c
+@@ -427,9 +427,10 @@ grub_cmd_xen_module (grub_command_t cmd __attribute__((unused)),
+ 
+   grub_dprintf ("xen_loader", "Init module and node info\n");
+ 
+-  if (nounzip)
+-    grub_file_filter_disable_compression ();
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_XEN_MODULE
++                        | (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS
++                           : GRUB_FILE_TYPE_NONE));
++
+   if (!file)
+     goto fail;
+ 
+@@ -461,7 +462,7 @@ grub_cmd_xen_hypervisor (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_XEN_HYPERVISOR);
+   if (!file)
+     goto fail;
+ 
+diff --git a/include/grub/file.h b/include/grub/file.h
+index 9aae463557a..cbbd294655b 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -42,6 +42,11 @@ enum grub_file_type
+     /* Multiboot module.  */
+     GRUB_FILE_TYPE_MULTIBOOT_MODULE,
+ 
++    /* Xen hypervisor - used on ARM only. */
++    GRUB_FILE_TYPE_XEN_HYPERVISOR,
++    /* Xen module - used on ARM only. */
++    GRUB_FILE_TYPE_XEN_MODULE,
++
+     GRUB_FILE_TYPE_BSD_KERNEL,
+     GRUB_FILE_TYPE_FREEBSD_ENV,
+     GRUB_FILE_TYPE_FREEBSD_MODULE,
diff --git a/SOURCES/0343-verifiers-IA-64-fallout-cleanup.patch b/SOURCES/0343-verifiers-IA-64-fallout-cleanup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..005a324412f23135d851d3aaaf2d9b00f99564b0
--- /dev/null
+++ b/SOURCES/0343-verifiers-IA-64-fallout-cleanup.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Thu, 14 Mar 2019 16:18:31 +0100
+Subject: [PATCH] verifiers: IA-64 fallout cleanup
+
+IA-64 fallout cleanup after commit 4d4a8c96e (verifiers: Add possibility
+to verify kernel and modules command lines).
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+---
+ grub-core/loader/ia64/efi/linux.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c
+index 2ad0b0c0407..cfeb2c145bb 100644
+--- a/grub-core/loader/ia64/efi/linux.c
++++ b/grub-core/loader/ia64/efi/linux.c
+@@ -547,8 +547,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   *p = '\0';
+ 
+-  err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
+-  if (err)
++  if (grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE))
+     goto fail;
+   
+   boot_param->command_line = (grub_uint64_t) cmdline;
diff --git a/SOURCES/0344-verifiers-PowerPC-fallout-cleanup.patch b/SOURCES/0344-verifiers-PowerPC-fallout-cleanup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..451e5f69d6b664f997a26c08a321d156729b57c5
--- /dev/null
+++ b/SOURCES/0344-verifiers-PowerPC-fallout-cleanup.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Thu, 14 Mar 2019 19:45:17 +0100
+Subject: [PATCH] verifiers: PowerPC fallout cleanup
+
+PowerPC fallout cleanup after commit 4d4a8c96e (verifiers: Add possibility
+to verify kernel and modules command lines) and ca0a4f689 (verifiers: File
+type for fine-grained signature-verification controlling).
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+---
+ grub-core/loader/powerpc/ieee1275/linux.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c
+index c114e7df4fb..818b2a86d1a 100644
+--- a/grub-core/loader/powerpc/ieee1275/linux.c
++++ b/grub-core/loader/powerpc/ieee1275/linux.c
+@@ -270,7 +270,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto out;
+     }
+ 
+-  elf = grub_elf_open (argv[0]);
++  elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (! elf)
+     goto out;
+ 
+@@ -303,7 +303,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   /* Create kernel command line.  */
+   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
+-				  size))
++				  size, GRUB_VERIFY_KERNEL_CMDLINE))
+     goto out;
+ 
+ out:
diff --git a/SOURCES/0345-verifiers-MIPS-fallout-cleanup.patch b/SOURCES/0345-verifiers-MIPS-fallout-cleanup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9fe0c4039d0fd3ec4cd0ccea44a4114a3521fd8a
--- /dev/null
+++ b/SOURCES/0345-verifiers-MIPS-fallout-cleanup.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Mon, 18 Mar 2019 13:09:22 +0100
+Subject: [PATCH] verifiers: MIPS fallout cleanup
+
+MIPS fallout cleanup after commit 4d4a8c96e (verifiers: Add possibility
+to verify kernel and modules command lines).
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+---
+ grub-core/loader/mips/linux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c
+index 20135ce253d..e4ed95921df 100644
+--- a/grub-core/loader/mips/linux.c
++++ b/grub-core/loader/mips/linux.c
+@@ -314,7 +314,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_memcpy (params, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   grub_create_loader_cmdline (argc, argv, params + sizeof (LINUX_IMAGE) - 1,
+-			      size);
++			      size, GRUB_VERIFY_KERNEL_CMDLINE);
+ #else
+   linux_argv = extra;
+   argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground;
diff --git a/SOURCES/0346-verifiers-Fix-calling-uninitialized-function-pointer.patch b/SOURCES/0346-verifiers-Fix-calling-uninitialized-function-pointer.patch
new file mode 100644
index 0000000000000000000000000000000000000000..19d383a08b40932bae10370f6cf1fcd40ea0821c
--- /dev/null
+++ b/SOURCES/0346-verifiers-Fix-calling-uninitialized-function-pointer.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Tue, 18 Feb 2020 18:08:18 +0800
+Subject: [PATCH] verifiers: Fix calling uninitialized function pointer
+
+The necessary check for NULL before use of function ver->close is not
+taking place in the failure path. This patch simply adds the missing
+check and fixes the problem that GRUB hangs indefinitely after booting
+rogue image without valid signature if secure boot is turned on.
+
+Now it displays like this for booting rogue UEFI image:
+
+  error: bad shim signature
+  error: you need to load the kernel first
+
+  Press any key to continue...
+
+and then you can go back to boot menu by pressing any key or after a few
+seconds expired.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/commands/verifiers.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
+index c638d5f43e0..599d79b757e 100644
+--- a/grub-core/commands/verifiers.c
++++ b/grub-core/commands/verifiers.c
+@@ -196,7 +196,8 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
+   return ret;
+ 
+  fail:
+-  ver->close (context);
++  if (ver->close)
++    ver->close (context);
+  fail_noclose:
+   verified_free (verified);
+   grub_free (ret);
diff --git a/SOURCES/0347-rhel-extra-file-type-fixes.patch b/SOURCES/0347-rhel-extra-file-type-fixes.patch
new file mode 100644
index 0000000000000000000000000000000000000000..aa7544328b0179c8c771e097efa3785a9b0e74ec
--- /dev/null
+++ b/SOURCES/0347-rhel-extra-file-type-fixes.patch
@@ -0,0 +1,124 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 12 May 2020 17:26:26 +1000
+Subject: [PATCH] rhel: extra file type fixes
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+[javierm: fix a couple of build errors caused by mismerges]
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c         | 2 +-
+ grub-core/loader/arm64/linux.c      | 1 +
+ grub-core/loader/i386/efi/linux.c   | 9 +++++----
+ grub-core/net/net.c                 | 2 +-
+ grub-core/normal/main.c             | 2 +-
+ grub-core/osdep/generic/blocklist.c | 4 ++--
+ 6 files changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 70ce5c7bf6f..795a9f9f178 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -463,7 +463,7 @@ static int read_entry (
+ 
+   p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
+ 
+-  f = grub_file_open (p);
++  f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
+   if (!f)
+     goto finish;
+ 
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 864724dd4fa..e1923cf7257 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -31,6 +31,7 @@
+ #include <grub/efi/memory.h>
+ #include <grub/efi/linux.h>
+ #include <grub/efi/pe32.h>
++#include <grub/efi/sb.h>
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/verify.h>
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 361e503cb52..576f8c07eaf 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -101,8 +101,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ 
+   for (i = 0; i < argc; i++)
+     {
+-      grub_file_filter_disable_compression ();
+-      files[i] = grub_file_open (argv[i]);
++      files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD |
++				 GRUB_FILE_TYPE_NO_DECOMPRESS);
+       if (! files[i])
+         goto fail;
+       nfiles++;
+@@ -182,7 +182,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  file = grub_file_open (argv[0]);
++  file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+   if (! file)
+     goto fail;
+ 
+@@ -302,7 +302,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   grub_create_loader_cmdline (argc, argv,
+                               linux_cmdline + sizeof (LINUX_IMAGE) - 1,
+-			      lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1));
++			      lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1),
++			      GRUB_VERIFY_KERNEL_CMDLINE);
+ 
+   grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
+   grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 0e72bbb9b39..1fd104aeaf2 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1907,7 +1907,7 @@ grub_net_search_configfile (char *config)
+ 	  grub_dprintf ("net", "probe %s\n", config);
+ 
+           grub_file_t file;
+-          file = grub_file_open (config);
++          file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+ 
+           if (file)
+             {
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index cee71a4c2ab..49141039f8f 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -363,7 +363,7 @@ grub_try_normal (const char *variable)
+ 	if (config)
+ 	  {
+ 	    grub_file_t file;
+-	    file = grub_file_open (config);
++	    file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+ 	    if (file)
+ 	      {
+ 		grub_file_close (file);
+diff --git a/grub-core/osdep/generic/blocklist.c b/grub-core/osdep/generic/blocklist.c
+index 74024fd06f3..ab1f96da62d 100644
+--- a/grub-core/osdep/generic/blocklist.c
++++ b/grub-core/osdep/generic/blocklist.c
+@@ -60,7 +60,7 @@ grub_install_get_blocklist (grub_device_t root_dev,
+       grub_disk_cache_invalidate_all ();
+ 
+       grub_file_filter_disable_compression ();
+-      file = grub_file_open (core_path_dev);
++      file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE);
+       if (file)
+ 	{
+ 	  if (grub_file_size (file) != core_size)
+@@ -118,7 +118,7 @@ grub_install_get_blocklist (grub_device_t root_dev,
+   grub_file_t file;
+   /* Now read the core image to determine where the sectors are.  */
+   grub_file_filter_disable_compression ();
+-  file = grub_file_open (core_path_dev);
++  file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE);
+   if (! file)
+     grub_util_error ("%s", grub_errmsg);
+ 
diff --git a/SOURCES/0348-dl-Add-support-for-persistent-modules.patch b/SOURCES/0348-dl-Add-support-for-persistent-modules.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e534415503746a0ee504aecc1c176e05f4a773ce
--- /dev/null
+++ b/SOURCES/0348-dl-Add-support-for-persistent-modules.patch
@@ -0,0 +1,65 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Kiper <daniel.kiper@oracle.com>
+Date: Tue, 2 Oct 2018 18:49:26 +0200
+Subject: [PATCH] dl: Add support for persistent modules
+
+This type of modules cannot be unloaded. This is useful if a given
+functionality, e.g. UEFI secure boot shim signature verification, should
+not be disabled if it was enabled at some point in time. Somebody may
+say that we can use standalone GRUB2 here. That is true. However, the
+code is not so big nor complicated hence it make sense to support
+modularized configs too.
+
+Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
+(cherry picked from commit ee7808e2197cbf5e8515d90ecbd81c9d0dd6fc15)
+---
+ grub-core/commands/minicmd.c |  3 +++
+ include/grub/dl.h            | 13 +++++++++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
+index 46bf135e8f0..6d66b7c453a 100644
+--- a/grub-core/commands/minicmd.c
++++ b/grub-core/commands/minicmd.c
+@@ -137,6 +137,9 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
+   if (! mod)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module");
+ 
++  if (grub_dl_is_persistent (mod))
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module");
++
+   if (grub_dl_unref (mod) <= 0)
+     grub_dl_unload (mod);
+ 
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 7b5bfb07ce6..f7cfe64823c 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -177,6 +177,7 @@ struct grub_dl
+ {
+   char *name;
+   int ref_count;
++  int persistent;
+   grub_dl_dep_t dep;
+   grub_dl_segment_t segment;
+   Elf_Sym *symtab;
+@@ -242,6 +243,18 @@ grub_dl_get (const char *name)
+   return 0;
+ }
+ 
++static inline void
++grub_dl_set_persistent (grub_dl_t mod)
++{
++  mod->persistent = 1;
++}
++
++static inline int
++grub_dl_is_persistent (grub_dl_t mod)
++{
++  return mod->persistent;
++}
++
+ #endif
+ 
+ void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
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 0000000000000000000000000000000000000000..538e9160b3d95c5e3d5257a709b26f55cba5d223
--- /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..65a015d8a04 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 0000000000000000000000000000000000000000..dee54cee29282a947fcf7d977e3003cf916c2f39
--- /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-with-an-appended-sig.patch b/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6e65133e6b6eb42fe991dd11e9f8e7e1f295c61c
--- /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-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 0000000000000000000000000000000000000000..2e5823f5674d010128b2a79d46be806559f3b05e
--- /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-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 0000000000000000000000000000000000000000..f8a2e9ec3c4f1eca421f9a5794d8e00cae2eafac
--- /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 0000000000000000000000000000000000000000..859472d7700a1861e8909c26a1c0f8afb26659fe
--- /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/0355-verifiers-provide-unsafe-module-list.patch b/SOURCES/0355-verifiers-provide-unsafe-module-list.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5a6148fa1fdb4bc793d3d9d1357c6b0edb435996
--- /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 0000000000000000000000000000000000000000..79a73ec0165713057af999aa57b509cd554c8ae0
--- /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/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 0000000000000000000000000000000000000000..e8004d279c1cc610175cf33bfbb94658a1e8def3
--- /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/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 0000000000000000000000000000000000000000..2db2a84144856aa2c2caa4f4e5b0afcf4c03583f
--- /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 0000000000000000000000000000000000000000..89552c884536b70ec7b130ee81660c985908119c
--- /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/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 0000000000000000000000000000000000000000..00f55888d7e83c744e28b78c162d97169c1d324e
--- /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/0361-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9b2275cab19dc1ab55a3e30380e5c2654da263b9
--- /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/0362-libtasn1-compile-into-asn1-module.patch b/SOURCES/0362-libtasn1-compile-into-asn1-module.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8fbb4274817f540918be53dde042e9a8176efd91
--- /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-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d777fcdbfd1ea9b89008dba199279434cc60e283
--- /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 0000000000000000000000000000000000000000..3413d7e649d71dadabc6a56c4f81d9f1c99624ad
--- /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 65a015d8a04..394d2dc5fc9 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/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 0000000000000000000000000000000000000000..7b7d70c48a5f2d9286e7c1afbe4cc44a7375ac94
--- /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/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 0000000000000000000000000000000000000000..c638457f165ae755333bac491cb8564d46373ffd
--- /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-support-verifying-appended-signa.patch b/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch
new file mode 100644
index 0000000000000000000000000000000000000000..52a057c713271705006c3fdec1d5050a226a6940
--- /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-verification-tests.patch b/SOURCES/0368-appended-signatures-verification-tests.patch
new file mode 100644
index 0000000000000000000000000000000000000000..db1aa9b15bd177cf88e1cd04f5b7f67118d72ba1
--- /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 0000000000000000000000000000000000000000..82f50de42416958a07b739eb0c73bbf182829d20
--- /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/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 0000000000000000000000000000000000000000..219d181440ae9ff046fe55e3c81284f2640d0c2f
--- /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-include-grub-verify.h-Add-include-guard.patch b/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d757ffdb9a09f01401cea25ba9e3a41a97112262
--- /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 0000000000000000000000000000000000000000..e472215dbbd5110bb2050e5df122fdedef72c172
--- /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/0318-kern-Add-lockdown-support.patch b/SOURCES/0373-kern-Add-lockdown-support.patch
similarity index 96%
rename from SOURCES/0318-kern-Add-lockdown-support.patch
rename to SOURCES/0373-kern-Add-lockdown-support.patch
index 1fa686b7959fb65a6d409b00793182c586584c40..b1d50131d0bf56103571869b06f408910735907a 100644
--- a/SOURCES/0318-kern-Add-lockdown-support.patch
+++ b/SOURCES/0373-kern-Add-lockdown-support.patch
@@ -45,14 +45,14 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  include/grub/lockdown.h     | 44 +++++++++++++++++++++
  conf/Makefile.common        |  2 +
  docs/grub-dev.texi          | 27 +++++++++++++
- docs/grub.texi              |  9 +++++
+ docs/grub.texi              |  8 ++++
  grub-core/Makefile.am       |  5 ++-
- 11 files changed, 239 insertions(+), 1 deletion(-)
+ 11 files changed, 238 insertions(+), 1 deletion(-)
  create mode 100644 grub-core/kern/lockdown.c
  create mode 100644 include/grub/lockdown.h
 
 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index c8a50b4fcfa..0eb7f312b29 100644
+index 8914083d13f..02fbecd4b81 100644
 --- a/grub-core/Makefile.core.def
 +++ b/grub-core/Makefile.core.def
 @@ -197,6 +197,7 @@ kernel = {
@@ -389,21 +389,20 @@ index 3ce827ab726..421dd410e50 100644
  @appendix Copying This Manual
  
 diff --git a/docs/grub.texi b/docs/grub.texi
-index c54bee31679..0a53c28ee88 100644
+index 97f0f47e082..f957535dbea 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -5610,6 +5610,8 @@ 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
+@@ -5687,6 +5687,7 @@ environment variables and commands are listed in the same order.
+ * 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
 +* Lockdown::                           Lockdown when booting on a secure setup
-+
  @end menu
  
  @node Authentication and authorisation
-@@ -5772,6 +5774,13 @@ 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.
+@@ -5977,6 +5978,13 @@ As with UEFI secure boot, it is necessary to build in the required modules,
+ or sign them separately.
+ 
  
 +@node Lockdown
 +@section Lockdown when booting on a secure setup
diff --git a/SOURCES/0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch b/SOURCES/0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
similarity index 93%
rename from SOURCES/0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
rename to SOURCES/0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
index 91021f0b76c9ffb97688220d954dffebc480f1d8..cccd2136466b7c8f96f7de1b1b573b8881023c41 100644
--- a/SOURCES/0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
+++ b/SOURCES/0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
@@ -38,10 +38,10 @@ index f87ddaeb1ee..30cba7f5ea2 100644
  
  int
 diff --git a/docs/grub.texi b/docs/grub.texi
-index 0a53c28ee88..6f5efaace32 100644
+index f957535dbea..755de88d7d8 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -5781,6 +5781,9 @@ The GRUB can be locked down when booted on a secure boot environment, for exampl
+@@ -5985,6 +5985,9 @@ The GRUB can be locked down when booted on a secure boot environment, for exampl
  if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will
  be restricted and some operations/commands cannot be executed.
  
diff --git a/SOURCES/0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch b/SOURCES/0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch
similarity index 100%
rename from SOURCES/0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch
rename to SOURCES/0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch
diff --git a/SOURCES/0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch b/SOURCES/0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch
similarity index 100%
rename from SOURCES/0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch
rename to SOURCES/0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch
diff --git a/SOURCES/0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch b/SOURCES/0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
similarity index 94%
rename from SOURCES/0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
rename to SOURCES/0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
index f1b2859d37a1fe1846b96a1bf73ec07040978f73..603796cf527a5e9ec2e6c69f9a3609cd95c7542a 100644
--- a/SOURCES/0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
+++ b/SOURCES/0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
@@ -22,7 +22,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  2 files changed, 13 insertions(+), 7 deletions(-)
 
 diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c
-index 9f02f22019a..a2912989b5c 100644
+index 5a1499aa0e3..1215f2a62ef 100644
 --- a/grub-core/commands/acpi.c
 +++ b/grub-core/commands/acpi.c
 @@ -27,6 +27,7 @@
@@ -55,10 +55,10 @@ index 9f02f22019a..a2912989b5c 100644
  
  GRUB_MOD_FINI(acpi)
 diff --git a/docs/grub.texi b/docs/grub.texi
-index 6f5efaace32..a724d0712ed 100644
+index 755de88d7d8..01acf672b80 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -4033,6 +4033,11 @@ Normally, this command will replace the Root System Description Pointer
+@@ -4038,6 +4038,11 @@ Normally, this command will replace the Root System Description Pointer
  (RSDP) in the Extended BIOS Data Area to point to the new tables. If the
  @option{--no-ebda} option is used, the new tables will be known only to
  GRUB, but may be used by GRUB's EFI emulation.
diff --git a/SOURCES/0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch b/SOURCES/0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
similarity index 96%
rename from SOURCES/0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
rename to SOURCES/0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
index ee1fddcd917d4c909c116ec0e72957539e64ca6c..2781cd9fa8a04ca01ccf70f86165a8031fd2f485 100644
--- a/SOURCES/0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
+++ b/SOURCES/0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
@@ -50,10 +50,10 @@ index 57b4e9a72a9..7ebf32e1e5e 100644
  }
  
 diff --git a/docs/grub.texi b/docs/grub.texi
-index a724d0712ed..a9b02190404 100644
+index 01acf672b80..f1675b6140c 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -4098,6 +4098,10 @@ this page is to be filtered.  This syntax makes it easy to represent patterns
+@@ -4103,6 +4103,10 @@ this page is to be filtered.  This syntax makes it easy to represent patterns
  that are often result of memory damage, due to physical distribution of memory
  cells.
  
diff --git a/SOURCES/0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch b/SOURCES/0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
similarity index 94%
rename from SOURCES/0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
rename to SOURCES/0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
index 301910c97cea3ac2e7b709c6e7f0c32429eeabbf..ae197cb5bbfc101f37bcf84b1ac75579b7a740b8 100644
--- a/SOURCES/0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
+++ b/SOURCES/0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
@@ -27,7 +27,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  4 files changed, 16 insertions(+), 14 deletions(-)
 
 diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c
-index 132cadbc764..3da4c26df7a 100644
+index d41d521a4ae..5c7725f8bd8 100644
 --- a/grub-core/commands/efi/loadbios.c
 +++ b/grub-core/commands/efi/loadbios.c
 @@ -205,14 +205,14 @@ static grub_command_t cmd_fakebios, cmd_loadbios;
@@ -53,10 +53,10 @@ index 132cadbc764..3da4c26df7a 100644
  
  GRUB_MOD_FINI(loadbios)
 diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c
-index ea29d7a724a..ff2911baa67 100644
+index 1e944a2b671..653f2e07692 100644
 --- a/grub-core/loader/arm/linux.c
 +++ b/grub-core/loader/arm/linux.c
-@@ -489,9 +489,9 @@ GRUB_MOD_INIT (linux)
+@@ -493,9 +493,9 @@ GRUB_MOD_INIT (linux)
  				     0, N_("Load Linux."));
    cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
  				      0, N_("Load initrd."));
@@ -70,7 +70,7 @@ index ea29d7a724a..ff2911baa67 100644
    current_fdt = (const void *) grub_arm_firmware_get_boot_data ();
    machine_type = grub_arm_firmware_get_machine_type ();
 diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
-index a9dbcfdfeaf..c0ea050dc8b 100644
+index e3ee3ad79d6..64c560f5610 100644
 --- a/grub-core/loader/efi/fdt.c
 +++ b/grub-core/loader/efi/fdt.c
 @@ -167,8 +167,8 @@ static grub_command_t cmd_devicetree;
@@ -85,10 +85,10 @@ index a9dbcfdfeaf..c0ea050dc8b 100644
  
  GRUB_MOD_FINI (fdt)
 diff --git a/docs/grub.texi b/docs/grub.texi
-index a9b02190404..71943b15dd1 100644
+index f1675b6140c..c55452307dc 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -4276,13 +4276,15 @@ hour, minute, and second unchanged.
+@@ -4281,13 +4281,15 @@ hour, minute, and second unchanged.
  
  
  @node devicetree
diff --git a/SOURCES/0325-commands-setpci-Restrict-setpci-command-when-locked-.patch b/SOURCES/0380-commands-setpci-Restrict-setpci-command-when-locked-.patch
similarity index 100%
rename from SOURCES/0325-commands-setpci-Restrict-setpci-command-when-locked-.patch
rename to SOURCES/0380-commands-setpci-Restrict-setpci-command-when-locked-.patch
diff --git a/SOURCES/0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch b/SOURCES/0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch
similarity index 100%
rename from SOURCES/0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch
rename to SOURCES/0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch
diff --git a/SOURCES/0327-gdb-Restrict-GDB-access-when-locked-down.patch b/SOURCES/0382-gdb-Restrict-GDB-access-when-locked-down.patch
similarity index 100%
rename from SOURCES/0327-gdb-Restrict-GDB-access-when-locked-down.patch
rename to SOURCES/0382-gdb-Restrict-GDB-access-when-locked-down.patch
diff --git a/SOURCES/0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch b/SOURCES/0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch
similarity index 96%
rename from SOURCES/0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch
rename to SOURCES/0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch
index 8ccc433897bbf8623ba18029d1c0fc45e8702657..fe39c3381d78fd0c5a3186f1550acf8f9758e3c2 100644
--- a/SOURCES/0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch
+++ b/SOURCES/0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch
@@ -14,10 +14,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 17 insertions(+), 14 deletions(-)
 
 diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
-index 2bf02489bad..0c4b33250fb 100644
+index 5944dc5eafc..b33a384321c 100644
 --- a/grub-core/loader/xnu.c
 +++ b/grub-core/loader/xnu.c
-@@ -1480,20 +1480,23 @@ GRUB_MOD_INIT(xnu)
+@@ -1489,20 +1489,23 @@ GRUB_MOD_INIT(xnu)
  				      N_("Load XNU image."));
    cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64,
  					0, N_("Load 64-bit XNU image."));
diff --git a/SOURCES/0329-docs-Document-the-cutmem-command.patch b/SOURCES/0384-docs-Document-the-cutmem-command.patch
similarity index 91%
rename from SOURCES/0329-docs-Document-the-cutmem-command.patch
rename to SOURCES/0384-docs-Document-the-cutmem-command.patch
index d199a34b120bdc3e080dc4f37d65ab5379b9f8b2..fd37e8f26813f34b705d1ae05843bef39b015b6e 100644
--- a/SOURCES/0329-docs-Document-the-cutmem-command.patch
+++ b/SOURCES/0384-docs-Document-the-cutmem-command.patch
@@ -14,10 +14,10 @@ Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
  1 file changed, 21 insertions(+)
 
 diff --git a/docs/grub.texi b/docs/grub.texi
-index 71943b15dd1..067aa294162 100644
+index c55452307dc..314bbeb8471 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -3941,6 +3941,7 @@ you forget a command, you can run the command @command{help}
+@@ -3942,6 +3942,7 @@ you forget a command, you can run the command @command{help}
  * cpuid::                       Check for CPU features
  * crc::                         Compute or check CRC32 checksums
  * cryptomount::                 Mount a crypto device
@@ -25,7 +25,7 @@ index 71943b15dd1..067aa294162 100644
  * date::                        Display or set current date and time
  * devicetree::                  Load a device tree blob
  * distrust::                    Remove a pubkey from trusted keys
-@@ -4098,6 +4099,8 @@ this page is to be filtered.  This syntax makes it easy to represent patterns
+@@ -4103,6 +4104,8 @@ this page is to be filtered.  This syntax makes it easy to represent patterns
  that are often result of memory damage, due to physical distribution of memory
  cells.
  
@@ -34,7 +34,7 @@ index 71943b15dd1..067aa294162 100644
  Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}).
        This prevents removing EFI memory regions to potentially subvert the
        security mechanisms provided by the UEFI secure boot.
-@@ -4261,6 +4264,24 @@ GRUB suports devices encrypted using LUKS and geli. Note that necessary modules
+@@ -4266,6 +4269,24 @@ GRUB suports devices encrypted using LUKS and geli. Note that necessary modules
  be used.
  @end deffn
  
diff --git a/SOURCES/0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch b/SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch
similarity index 87%
rename from SOURCES/0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch
rename to SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch
index b96552b28950ebe25f377a0ea363d389082c73ce..b482bba778350b3a9d53ea739654b16e71a1d6ac 100644
--- a/SOURCES/0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch
+++ b/SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch
@@ -25,12 +25,12 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  3 files changed, 19 insertions(+), 5 deletions(-)
 
 diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
-index b25ca4b9f17..4660a020bda 100644
+index 6d66b7c453a..2bd3ac76f2d 100644
 --- a/grub-core/commands/minicmd.c
 +++ b/grub-core/commands/minicmd.c
-@@ -137,8 +137,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
-   if (! mod)
-     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module");
+@@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
+   if (grub_dl_is_persistent (mod))
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module");
  
 -  if (grub_dl_unref (mod) <= 0)
 -    grub_dl_unload (mod);
@@ -43,7 +43,7 @@ index b25ca4b9f17..4660a020bda 100644
    return 0;
  }
 diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index 91105bc4677..333c1329eab 100644
+index d7a7c8f97b0..520126beab7 100644
 --- a/grub-core/kern/dl.c
 +++ b/grub-core/kern/dl.c
 @@ -621,6 +621,15 @@ grub_dl_unref (grub_dl_t mod)
@@ -63,10 +63,10 @@ index 91105bc4677..333c1329eab 100644
  grub_dl_flush_cache (grub_dl_t mod)
  {
 diff --git a/include/grub/dl.h b/include/grub/dl.h
-index 7b5bfb07ce6..a58fbc767c0 100644
+index 877821dcb04..6a3e251b455 100644
 --- a/include/grub/dl.h
 +++ b/include/grub/dl.h
-@@ -204,9 +204,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
+@@ -205,9 +205,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
  grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
  grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
  int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
diff --git a/SOURCES/0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch b/SOURCES/0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch
similarity index 100%
rename from SOURCES/0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch
rename to SOURCES/0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch
diff --git a/SOURCES/0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch b/SOURCES/0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch
similarity index 100%
rename from SOURCES/0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch
rename to SOURCES/0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch
diff --git a/SOURCES/0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch b/SOURCES/0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
similarity index 97%
rename from SOURCES/0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
rename to SOURCES/0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
index b70fd476842d06b5250690d950e21153d8e9158d..0f50d98d6c248f3779ce6ddbc0ae994b790a2549 100644
--- a/SOURCES/0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
+++ b/SOURCES/0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
@@ -15,7 +15,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 7 insertions(+), 2 deletions(-)
 
 diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index 0e72bbb9b39..50d0609038c 100644
+index 1fd104aeaf2..a27c53eee1c 100644
 --- a/grub-core/net/net.c
 +++ b/grub-core/net/net.c
 @@ -89,8 +89,13 @@ grub_net_link_layer_add_address (struct grub_net_card *card,
diff --git a/SOURCES/0334-net-tftp-Fix-dangling-memory-pointer.patch b/SOURCES/0389-net-tftp-Fix-dangling-memory-pointer.patch
similarity index 100%
rename from SOURCES/0334-net-tftp-Fix-dangling-memory-pointer.patch
rename to SOURCES/0389-net-tftp-Fix-dangling-memory-pointer.patch
diff --git a/SOURCES/0335-kern-parser-Fix-resource-leak-if-argc-0.patch b/SOURCES/0390-kern-parser-Fix-resource-leak-if-argc-0.patch
similarity index 100%
rename from SOURCES/0335-kern-parser-Fix-resource-leak-if-argc-0.patch
rename to SOURCES/0390-kern-parser-Fix-resource-leak-if-argc-0.patch
diff --git a/SOURCES/0336-kern-efi-Fix-memory-leak-on-failure.patch b/SOURCES/0391-kern-efi-Fix-memory-leak-on-failure.patch
similarity index 100%
rename from SOURCES/0336-kern-efi-Fix-memory-leak-on-failure.patch
rename to SOURCES/0391-kern-efi-Fix-memory-leak-on-failure.patch
diff --git a/SOURCES/0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch b/SOURCES/0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch
similarity index 100%
rename from SOURCES/0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch
rename to SOURCES/0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch
diff --git a/SOURCES/0338-gnulib-regexec-Resolve-unused-variable.patch b/SOURCES/0393-gnulib-regexec-Resolve-unused-variable.patch
similarity index 100%
rename from SOURCES/0338-gnulib-regexec-Resolve-unused-variable.patch
rename to SOURCES/0393-gnulib-regexec-Resolve-unused-variable.patch
diff --git a/SOURCES/0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch b/SOURCES/0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch
similarity index 100%
rename from SOURCES/0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch
rename to SOURCES/0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch
diff --git a/SOURCES/0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch b/SOURCES/0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch
similarity index 100%
rename from SOURCES/0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch
rename to SOURCES/0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch
diff --git a/SOURCES/0341-gnulib-regexec-Fix-possible-null-dereference.patch b/SOURCES/0396-gnulib-regexec-Fix-possible-null-dereference.patch
similarity index 100%
rename from SOURCES/0341-gnulib-regexec-Fix-possible-null-dereference.patch
rename to SOURCES/0396-gnulib-regexec-Fix-possible-null-dereference.patch
diff --git a/SOURCES/0342-gnulib-regcomp-Fix-uninitialized-re_token.patch b/SOURCES/0397-gnulib-regcomp-Fix-uninitialized-re_token.patch
similarity index 100%
rename from SOURCES/0342-gnulib-regcomp-Fix-uninitialized-re_token.patch
rename to SOURCES/0397-gnulib-regcomp-Fix-uninitialized-re_token.patch
diff --git a/SOURCES/0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch b/SOURCES/0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
similarity index 96%
rename from SOURCES/0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
rename to SOURCES/0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
index 71d1979f82757b1b664eea4657dc767858677f0a..d7affbd763997af88c31516ef438718d0adce04b 100644
--- a/SOURCES/0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
+++ b/SOURCES/0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
@@ -15,7 +15,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 4 deletions(-)
 
 diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c
-index 7559c6c9cab..dcb58746da1 100644
+index 84edf6dd2dc..6bf14daf474 100644
 --- a/grub-core/io/lzopio.c
 +++ b/grub-core/io/lzopio.c
 @@ -125,8 +125,6 @@ read_block_header (struct grub_lzopio *lzopio)
diff --git a/SOURCES/0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch b/SOURCES/0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch
similarity index 100%
rename from SOURCES/0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch
rename to SOURCES/0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch
diff --git a/SOURCES/0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch b/SOURCES/0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch
similarity index 100%
rename from SOURCES/0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch
rename to SOURCES/0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch
diff --git a/SOURCES/0346-disk-ldm-If-failed-then-free-vg-variable-too.patch b/SOURCES/0401-disk-ldm-If-failed-then-free-vg-variable-too.patch
similarity index 100%
rename from SOURCES/0346-disk-ldm-If-failed-then-free-vg-variable-too.patch
rename to SOURCES/0401-disk-ldm-If-failed-then-free-vg-variable-too.patch
diff --git a/SOURCES/0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch b/SOURCES/0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch
similarity index 100%
rename from SOURCES/0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch
rename to SOURCES/0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch
diff --git a/SOURCES/0348-disk-cryptodisk-Fix-potential-integer-overflow.patch b/SOURCES/0403-disk-cryptodisk-Fix-potential-integer-overflow.patch
similarity index 100%
rename from SOURCES/0348-disk-cryptodisk-Fix-potential-integer-overflow.patch
rename to SOURCES/0403-disk-cryptodisk-Fix-potential-integer-overflow.patch
diff --git a/SOURCES/0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch b/SOURCES/0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch
similarity index 100%
rename from SOURCES/0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch
rename to SOURCES/0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch
diff --git a/SOURCES/0350-zfs-Fix-possible-negative-shift-operation.patch b/SOURCES/0405-zfs-Fix-possible-negative-shift-operation.patch
similarity index 100%
rename from SOURCES/0350-zfs-Fix-possible-negative-shift-operation.patch
rename to SOURCES/0405-zfs-Fix-possible-negative-shift-operation.patch
diff --git a/SOURCES/0351-zfs-Fix-resource-leaks-while-constructing-path.patch b/SOURCES/0406-zfs-Fix-resource-leaks-while-constructing-path.patch
similarity index 100%
rename from SOURCES/0351-zfs-Fix-resource-leaks-while-constructing-path.patch
rename to SOURCES/0406-zfs-Fix-resource-leaks-while-constructing-path.patch
diff --git a/SOURCES/0352-zfs-Fix-possible-integer-overflows.patch b/SOURCES/0407-zfs-Fix-possible-integer-overflows.patch
similarity index 100%
rename from SOURCES/0352-zfs-Fix-possible-integer-overflows.patch
rename to SOURCES/0407-zfs-Fix-possible-integer-overflows.patch
diff --git a/SOURCES/0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch b/SOURCES/0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch
similarity index 100%
rename from SOURCES/0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch
rename to SOURCES/0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch
diff --git a/SOURCES/0354-affs-Fix-memory-leaks.patch b/SOURCES/0409-affs-Fix-memory-leaks.patch
similarity index 100%
rename from SOURCES/0354-affs-Fix-memory-leaks.patch
rename to SOURCES/0409-affs-Fix-memory-leaks.patch
diff --git a/SOURCES/0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch b/SOURCES/0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch
similarity index 100%
rename from SOURCES/0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch
rename to SOURCES/0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch
diff --git a/SOURCES/0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch b/SOURCES/0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch
similarity index 100%
rename from SOURCES/0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch
rename to SOURCES/0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch
diff --git a/SOURCES/0357-syslinux-Fix-memory-leak-while-parsing.patch b/SOURCES/0412-syslinux-Fix-memory-leak-while-parsing.patch
similarity index 96%
rename from SOURCES/0357-syslinux-Fix-memory-leak-while-parsing.patch
rename to SOURCES/0412-syslinux-Fix-memory-leak-while-parsing.patch
index 80ed160b2a837152e66ada0169a958cfe016f52b..f85cc51efd5739c3c7f30e085e8dadf857e30e7e 100644
--- a/SOURCES/0357-syslinux-Fix-memory-leak-while-parsing.patch
+++ b/SOURCES/0412-syslinux-Fix-memory-leak-while-parsing.patch
@@ -15,7 +15,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 5 insertions(+), 1 deletion(-)
 
 diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c
-index 21ca040ada7..2eb59ff8ac4 100644
+index 83e7bdb9161..f477feff1c3 100644
 --- a/grub-core/lib/syslinux_parse.c
 +++ b/grub-core/lib/syslinux_parse.c
 @@ -737,7 +737,10 @@ syslinux_parse_real (struct syslinux_menu *menu)
diff --git a/SOURCES/0358-normal-completion-Fix-leaking-of-memory-when-process.patch b/SOURCES/0413-normal-completion-Fix-leaking-of-memory-when-process.patch
similarity index 100%
rename from SOURCES/0358-normal-completion-Fix-leaking-of-memory-when-process.patch
rename to SOURCES/0413-normal-completion-Fix-leaking-of-memory-when-process.patch
diff --git a/SOURCES/0359-commands-hashsum-Fix-a-memory-leak.patch b/SOURCES/0414-commands-hashsum-Fix-a-memory-leak.patch
similarity index 86%
rename from SOURCES/0359-commands-hashsum-Fix-a-memory-leak.patch
rename to SOURCES/0414-commands-hashsum-Fix-a-memory-leak.patch
index 5fe9eb602488904d6bd0aa52615a0ac00e81edb2..35088828725977684dd23e3ffb898537c3c3df7d 100644
--- a/SOURCES/0359-commands-hashsum-Fix-a-memory-leak.patch
+++ b/SOURCES/0414-commands-hashsum-Fix-a-memory-leak.patch
@@ -16,7 +16,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 12 insertions(+), 3 deletions(-)
 
 diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c
-index d18687351a5..282922bba1e 100644
+index 456ba908b6f..b8a22b0c8bb 100644
 --- a/grub-core/commands/hashsum.c
 +++ b/grub-core/commands/hashsum.c
 @@ -128,11 +128,17 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
@@ -44,10 +44,10 @@ index d18687351a5..282922bba1e 100644
  	  filename = grub_xasprintf ("%s/%s", prefix, p);
  	  if (!filename)
 -	    return grub_errno;
-+            {
-+              grub_free (buf);
-+              return grub_errno;
-+            }
- 	  if (!uncompress)
- 	    grub_file_filter_disable_compression ();
- 	  file = grub_file_open (filename);
++	    {
++	      grub_free (buf);
++	      return grub_errno;
++	    }
+ 	  file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH
+ 				 | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
+ 				    : GRUB_FILE_TYPE_NONE));
diff --git a/SOURCES/0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch b/SOURCES/0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch
similarity index 100%
rename from SOURCES/0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch
rename to SOURCES/0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch
diff --git a/SOURCES/0361-video-fb-fbfill-Fix-potential-integer-overflow.patch b/SOURCES/0416-video-fb-fbfill-Fix-potential-integer-overflow.patch
similarity index 100%
rename from SOURCES/0361-video-fb-fbfill-Fix-potential-integer-overflow.patch
rename to SOURCES/0416-video-fb-fbfill-Fix-potential-integer-overflow.patch
diff --git a/SOURCES/0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch b/SOURCES/0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch
similarity index 100%
rename from SOURCES/0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch
rename to SOURCES/0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch
diff --git a/SOURCES/0363-video-fb-video_fb-Fix-possible-integer-overflow.patch b/SOURCES/0418-video-fb-video_fb-Fix-possible-integer-overflow.patch
similarity index 100%
rename from SOURCES/0363-video-fb-video_fb-Fix-possible-integer-overflow.patch
rename to SOURCES/0418-video-fb-video_fb-Fix-possible-integer-overflow.patch
diff --git a/SOURCES/0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch b/SOURCES/0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
similarity index 97%
rename from SOURCES/0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
rename to SOURCES/0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
index e59c09cb06955c9a0c583ec181cb69e85fb1df75..f9a514a36845f0af0ac8efbac7a585fd46a996b3 100644
--- a/SOURCES/0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
+++ b/SOURCES/0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
@@ -17,7 +17,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 6 insertions(+)
 
 diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index 21b0d9ded67..a4a8269e237 100644
+index 31359a4c9c8..0b6ce3cee64 100644
 --- a/grub-core/video/readers/jpeg.c
 +++ b/grub-core/video/readers/jpeg.c
 @@ -253,6 +253,12 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
diff --git a/SOURCES/0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch b/SOURCES/0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch
similarity index 100%
rename from SOURCES/0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch
rename to SOURCES/0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch
diff --git a/SOURCES/0366-loader-bsd-Check-for-NULL-arg-up-front.patch b/SOURCES/0421-loader-bsd-Check-for-NULL-arg-up-front.patch
similarity index 90%
rename from SOURCES/0366-loader-bsd-Check-for-NULL-arg-up-front.patch
rename to SOURCES/0421-loader-bsd-Check-for-NULL-arg-up-front.patch
index bb1585f943838fe6762629395815942634219177..f4c63b367c8c05698d5bfa8965ff3da85e2ef5c7 100644
--- a/SOURCES/0366-loader-bsd-Check-for-NULL-arg-up-front.patch
+++ b/SOURCES/0421-loader-bsd-Check-for-NULL-arg-up-front.patch
@@ -21,10 +21,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
-index 0f317632a3b..35a06e66d38 100644
+index 45a71509956..b5ab848ee44 100644
 --- a/grub-core/loader/i386/bsd.c
 +++ b/grub-core/loader/i386/bsd.c
-@@ -1600,7 +1600,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
+@@ -1606,7 +1606,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
    kernel_type = KERNEL_TYPE_OPENBSD;
    bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags);
  
@@ -33,7 +33,7 @@ index 0f317632a3b..35a06e66d38 100644
      {
        const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg;
        unsigned type, unit, part;
-@@ -1617,7 +1617,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
+@@ -1623,7 +1623,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
  			   "unknown disk type name");
  
        unit = grub_strtoul (arg, (char **) &arg, 10);
diff --git a/SOURCES/0367-loader-xnu-Fix-memory-leak.patch b/SOURCES/0422-loader-xnu-Fix-memory-leak.patch
similarity index 91%
rename from SOURCES/0367-loader-xnu-Fix-memory-leak.patch
rename to SOURCES/0422-loader-xnu-Fix-memory-leak.patch
index 7d43b7b026c5a622711ef7c470ce61516b138887..76d9711a001a0a285ba02d76a38c56992951fd5d 100644
--- a/SOURCES/0367-loader-xnu-Fix-memory-leak.patch
+++ b/SOURCES/0422-loader-xnu-Fix-memory-leak.patch
@@ -19,10 +19,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
-index 0c4b33250fb..2adeac8a549 100644
+index b33a384321c..16bfa7cec72 100644
 --- a/grub-core/loader/xnu.c
 +++ b/grub-core/loader/xnu.c
-@@ -1383,9 +1383,9 @@ grub_xnu_fill_devicetree (void)
+@@ -1392,9 +1392,9 @@ grub_xnu_fill_devicetree (void)
      name[len] = 0;
  
      curvalue = grub_xnu_create_value (curkey, name);
diff --git a/SOURCES/0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch b/SOURCES/0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
similarity index 92%
rename from SOURCES/0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
rename to SOURCES/0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
index 5faa317be86bcfe7f15f54251e55329444d87001..d4c945c1cea10b4201963f2014a1964e1d1f0894 100644
--- a/SOURCES/0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
+++ b/SOURCES/0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
@@ -15,10 +15,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 20 insertions(+), 4 deletions(-)
 
 diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
-index 2adeac8a549..a0aaa290ef7 100644
+index 16bfa7cec72..af885a648c6 100644
 --- a/grub-core/loader/xnu.c
 +++ b/grub-core/loader/xnu.c
-@@ -227,26 +227,33 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
+@@ -228,26 +228,33 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
    if (! memorymap)
      return grub_errno;
  
@@ -56,7 +56,7 @@ index 2adeac8a549..a0aaa290ef7 100644
  
    /* Put real data in the dummy. */
    extdesc->addr = *target;
-@@ -255,6 +262,15 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
+@@ -256,6 +263,15 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
    /* Write the tree to heap. */
    grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/");
    return GRUB_ERR_NONE;
diff --git a/SOURCES/0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch b/SOURCES/0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
similarity index 75%
rename from SOURCES/0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
rename to SOURCES/0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
index 46770227fcedd8a885656c6fcc240411b2349e9e..ba24db22ef9c0c15d5050d11ae103a1f38f7fe5c 100644
--- a/SOURCES/0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
+++ b/SOURCES/0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
@@ -12,10 +12,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 4 insertions(+), 4 deletions(-)
 
 diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
-index a0aaa290ef7..5e0c8c84797 100644
+index af885a648c6..49641b8bbc2 100644
 --- a/grub-core/loader/xnu.c
 +++ b/grub-core/loader/xnu.c
-@@ -662,6 +662,9 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
+@@ -671,6 +671,9 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
    char *name, *nameend;
    int namelen;
  
@@ -25,15 +25,15 @@ index a0aaa290ef7..5e0c8c84797 100644
    name = get_name_ptr (infoplistname);
    nameend = grub_strchr (name, '/');
  
-@@ -693,10 +696,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
+@@ -702,10 +705,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
    else
      macho = 0;
  
 -  if (infoplistname)
--    infoplist = grub_file_open (infoplistname);
+-    infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
 -  else
 -    infoplist = 0;
-+  infoplist = grub_file_open (infoplistname);
++  infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
    grub_errno = GRUB_ERR_NONE;
    if (infoplist)
      {
diff --git a/SOURCES/0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch b/SOURCES/0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch
similarity index 100%
rename from SOURCES/0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch
rename to SOURCES/0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch
diff --git a/SOURCES/0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch b/SOURCES/0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch
similarity index 100%
rename from SOURCES/0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch
rename to SOURCES/0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch
diff --git a/SOURCES/0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch b/SOURCES/0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch
similarity index 100%
rename from SOURCES/0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch
rename to SOURCES/0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch
diff --git a/SOURCES/0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch b/SOURCES/0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch
similarity index 96%
rename from SOURCES/0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch
rename to SOURCES/0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch
index 349ca39ab8e6473f053cd0309751db7f46ceda35..b916cb173ca05a73fc814fcfe446b14d1989da8a 100644
--- a/SOURCES/0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch
+++ b/SOURCES/0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch
@@ -16,7 +16,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c
-index c25161cc4f2..ed646201035 100644
+index 2cdb2acc552..d4dcffd3168 100644
 --- a/grub-core/commands/ls.c
 +++ b/grub-core/commands/ls.c
 @@ -196,7 +196,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
diff --git a/SOURCES/0374-script-execute-Avoid-crash-when-using-outside-a-func.patch b/SOURCES/0429-script-execute-Avoid-crash-when-using-outside-a-func.patch
similarity index 100%
rename from SOURCES/0374-script-execute-Avoid-crash-when-using-outside-a-func.patch
rename to SOURCES/0429-script-execute-Avoid-crash-when-using-outside-a-func.patch
diff --git a/SOURCES/0375-lib-arg-Block-repeated-short-options-that-require-an.patch b/SOURCES/0430-lib-arg-Block-repeated-short-options-that-require-an.patch
similarity index 100%
rename from SOURCES/0375-lib-arg-Block-repeated-short-options-that-require-an.patch
rename to SOURCES/0430-lib-arg-Block-repeated-short-options-that-require-an.patch
diff --git a/SOURCES/0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch b/SOURCES/0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch
similarity index 100%
rename from SOURCES/0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch
rename to SOURCES/0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch
diff --git a/SOURCES/0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch b/SOURCES/0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch
similarity index 100%
rename from SOURCES/0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch
rename to SOURCES/0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch
diff --git a/SOURCES/0378-kern-misc-Always-set-end-in-grub_strtoull.patch b/SOURCES/0433-kern-misc-Always-set-end-in-grub_strtoull.patch
similarity index 86%
rename from SOURCES/0378-kern-misc-Always-set-end-in-grub_strtoull.patch
rename to SOURCES/0433-kern-misc-Always-set-end-in-grub_strtoull.patch
index b3e77aba01968eb2f67545d8f55f49974f54f3d9..8bcb7150004bd92a2ab3965f29bd9d788bc359d5 100644
--- a/SOURCES/0378-kern-misc-Always-set-end-in-grub_strtoull.patch
+++ b/SOURCES/0433-kern-misc-Always-set-end-in-grub_strtoull.patch
@@ -16,10 +16,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 8 insertions(+)
 
 diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index c034f49f97c..62b4068e810 100644
+index 97378c48b22..475f3e0ef05 100644
 --- a/grub-core/kern/misc.c
 +++ b/grub-core/kern/misc.c
-@@ -452,6 +452,10 @@ grub_strtoull (const char *str, const char ** const end, int base)
+@@ -485,6 +485,10 @@ grub_strtoull (const char *str, const char ** const end, int base)
  	{
  	  grub_error (GRUB_ERR_OUT_OF_RANGE,
  		      N_("overflow is detected"));
@@ -30,7 +30,7 @@ index c034f49f97c..62b4068e810 100644
  	  return ~0ULL;
  	}
  
-@@ -463,6 +467,10 @@ grub_strtoull (const char *str, const char ** const end, int base)
+@@ -496,6 +500,10 @@ grub_strtoull (const char *str, const char ** const end, int base)
      {
        grub_error (GRUB_ERR_BAD_NUMBER,
  		  N_("unrecognized number"));
diff --git a/SOURCES/0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch b/SOURCES/0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
similarity index 98%
rename from SOURCES/0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
rename to SOURCES/0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
index 93dd5d450d2ce27b232f9c8ababb07906eb58078..23e9f3e94d5b4568ba0539ef5c4011e23c76db6c 100644
--- a/SOURCES/0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
+++ b/SOURCES/0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
@@ -21,7 +21,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 8 insertions(+)
 
 diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index a4a8269e237..856573996ac 100644
+index 0b6ce3cee64..23f919aa070 100644
 --- a/grub-core/video/readers/jpeg.c
 +++ b/grub-core/video/readers/jpeg.c
 @@ -333,7 +333,11 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
diff --git a/SOURCES/0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch b/SOURCES/0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
similarity index 97%
rename from SOURCES/0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
rename to SOURCES/0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
index cc6f84c38c33932811e0a7df16dc16f23a653b21..9cd6519991d7f89c4a08aa7c3bf7721970df6d66 100644
--- a/SOURCES/0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
+++ b/SOURCES/0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
@@ -24,7 +24,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 8 insertions(+)
 
 diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index 856573996ac..28c1d62515e 100644
+index 23f919aa070..e5148120f69 100644
 --- a/grub-core/video/readers/jpeg.c
 +++ b/grub-core/video/readers/jpeg.c
 @@ -526,6 +526,14 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
diff --git a/SOURCES/0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch b/SOURCES/0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
similarity index 97%
rename from SOURCES/0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
rename to SOURCES/0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
index cdb6fe916dae84fb6d1a53e1ff3b1b55e8267d45..8fc6b131c081d28c2811c5b799e805c529a9df61 100644
--- a/SOURCES/0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
+++ b/SOURCES/0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
@@ -20,7 +20,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 4 insertions(+)
 
 diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index 28c1d62515e..c48cbd41b48 100644
+index e5148120f69..e31602f766a 100644
 --- a/grub-core/video/readers/jpeg.c
 +++ b/grub-core/video/readers/jpeg.c
 @@ -646,6 +646,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
diff --git a/SOURCES/0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch b/SOURCES/0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch
similarity index 100%
rename from SOURCES/0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch
rename to SOURCES/0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch
diff --git a/SOURCES/0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch b/SOURCES/0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch
similarity index 100%
rename from SOURCES/0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch
rename to SOURCES/0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch
diff --git a/SOURCES/0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch b/SOURCES/0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch
similarity index 100%
rename from SOURCES/0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch
rename to SOURCES/0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch
diff --git a/SOURCES/0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch b/SOURCES/0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch
similarity index 100%
rename from SOURCES/0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch
rename to SOURCES/0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch
diff --git a/SOURCES/0386-fs-hfs-Disable-under-lockdown.patch b/SOURCES/0441-fs-hfs-Disable-under-lockdown.patch
similarity index 100%
rename from SOURCES/0386-fs-hfs-Disable-under-lockdown.patch
rename to SOURCES/0441-fs-hfs-Disable-under-lockdown.patch
diff --git a/SOURCES/0387-fs-sfs-Fix-over-read-of-root-object-name.patch b/SOURCES/0442-fs-sfs-Fix-over-read-of-root-object-name.patch
similarity index 100%
rename from SOURCES/0387-fs-sfs-Fix-over-read-of-root-object-name.patch
rename to SOURCES/0442-fs-sfs-Fix-over-read-of-root-object-name.patch
diff --git a/SOURCES/0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch b/SOURCES/0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch
similarity index 100%
rename from SOURCES/0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch
rename to SOURCES/0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch
diff --git a/SOURCES/0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch b/SOURCES/0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch
similarity index 100%
rename from SOURCES/0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch
rename to SOURCES/0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch
diff --git a/SOURCES/0390-fs-jfs-Catch-infinite-recursion.patch b/SOURCES/0445-fs-jfs-Catch-infinite-recursion.patch
similarity index 100%
rename from SOURCES/0390-fs-jfs-Catch-infinite-recursion.patch
rename to SOURCES/0445-fs-jfs-Catch-infinite-recursion.patch
diff --git a/SOURCES/0391-fs-nilfs2-Reject-too-large-keys.patch b/SOURCES/0446-fs-nilfs2-Reject-too-large-keys.patch
similarity index 100%
rename from SOURCES/0391-fs-nilfs2-Reject-too-large-keys.patch
rename to SOURCES/0446-fs-nilfs2-Reject-too-large-keys.patch
diff --git a/SOURCES/0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch b/SOURCES/0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch
similarity index 100%
rename from SOURCES/0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch
rename to SOURCES/0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch
diff --git a/SOURCES/0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch b/SOURCES/0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch
similarity index 100%
rename from SOURCES/0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch
rename to SOURCES/0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch
diff --git a/SOURCES/0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch b/SOURCES/0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
similarity index 97%
rename from SOURCES/0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
rename to SOURCES/0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
index 43e798daf8dc638187b10882af6d1ca21709730b..d50a18289586899dcabb4e3d6116dd6162ab0c71 100644
--- a/SOURCES/0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
+++ b/SOURCES/0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
@@ -17,7 +17,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 20 insertions(+)
 
 diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
-index 7024cda84ea..b9a93c471b7 100644
+index 2ecf076dd5e..6e9b9c9361a 100644
 --- a/grub-core/io/gzio.c
 +++ b/grub-core/io/gzio.c
 @@ -669,6 +669,13 @@ inflate_codes_in_window (grub_gzio_t gzio)
diff --git a/SOURCES/0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch b/SOURCES/0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
similarity index 97%
rename from SOURCES/0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
rename to SOURCES/0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
index 71cfb66bb985a0c29180df6c69e5c94fedf4a53a..9e33dee709203cd725c224c5c4ed1721b3471986 100644
--- a/SOURCES/0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
+++ b/SOURCES/0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
@@ -18,7 +18,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 9 insertions(+), 3 deletions(-)
 
 diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
-index b9a93c471b7..389fd345488 100644
+index 6e9b9c9361a..97b34f88574 100644
 --- a/grub-core/io/gzio.c
 +++ b/grub-core/io/gzio.c
 @@ -953,7 +953,7 @@ init_dynamic_block (grub_gzio_t gzio)
diff --git a/SOURCES/0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch b/SOURCES/0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
similarity index 97%
rename from SOURCES/0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
rename to SOURCES/0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
index 4f523d8da735a36cf167d4810640d61839b9368f..1d1c372c133052b5b3d9cf6aa1ce5769a2600f6c 100644
--- a/SOURCES/0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
+++ b/SOURCES/0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
@@ -20,7 +20,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 9 insertions(+), 1 deletion(-)
 
 diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
-index 389fd345488..fa7d9990b84 100644
+index 97b34f88574..f85dbae237d 100644
 --- a/grub-core/io/gzio.c
 +++ b/grub-core/io/gzio.c
 @@ -507,6 +507,7 @@ huft_build (unsigned *b,	/* code lengths in bits (all assumed <= BMAX) */
diff --git a/SOURCES/0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch b/SOURCES/0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
similarity index 97%
rename from SOURCES/0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
rename to SOURCES/0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
index a2a2efcc113adca7a29c4b36992a30e09d483f2a..c75f528e286b01731054f3a1028037e77d4ccda8 100644
--- a/SOURCES/0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
+++ b/SOURCES/0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
@@ -17,7 +17,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 2 insertions(+)
 
 diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
-index fa7d9990b84..81d658818be 100644
+index f85dbae237d..e9f332fbcd9 100644
 --- a/grub-core/io/gzio.c
 +++ b/grub-core/io/gzio.c
 @@ -1010,6 +1010,7 @@ init_dynamic_block (grub_gzio_t gzio)
diff --git a/SOURCES/0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch b/SOURCES/0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch
similarity index 100%
rename from SOURCES/0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch
rename to SOURCES/0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch
diff --git a/SOURCES/0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch b/SOURCES/0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch
similarity index 100%
rename from SOURCES/0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch
rename to SOURCES/0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch
diff --git a/SOURCES/0400-disk-lvm-Bail-on-missing-PV-list.patch b/SOURCES/0455-disk-lvm-Bail-on-missing-PV-list.patch
similarity index 100%
rename from SOURCES/0400-disk-lvm-Bail-on-missing-PV-list.patch
rename to SOURCES/0455-disk-lvm-Bail-on-missing-PV-list.patch
diff --git a/SOURCES/0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch b/SOURCES/0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch
similarity index 100%
rename from SOURCES/0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch
rename to SOURCES/0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch
diff --git a/SOURCES/0402-disk-lvm-Do-not-overread-metadata.patch b/SOURCES/0457-disk-lvm-Do-not-overread-metadata.patch
similarity index 100%
rename from SOURCES/0402-disk-lvm-Do-not-overread-metadata.patch
rename to SOURCES/0457-disk-lvm-Do-not-overread-metadata.patch
diff --git a/SOURCES/0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch b/SOURCES/0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch
similarity index 100%
rename from SOURCES/0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch
rename to SOURCES/0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch
diff --git a/SOURCES/0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch b/SOURCES/0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch
similarity index 100%
rename from SOURCES/0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch
rename to SOURCES/0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch
diff --git a/SOURCES/0405-kern-parser-Fix-a-memory-leak.patch b/SOURCES/0460-kern-parser-Fix-a-memory-leak.patch
similarity index 100%
rename from SOURCES/0405-kern-parser-Fix-a-memory-leak.patch
rename to SOURCES/0460-kern-parser-Fix-a-memory-leak.patch
diff --git a/SOURCES/0406-kern-parser-Introduce-process_char-helper.patch b/SOURCES/0461-kern-parser-Introduce-process_char-helper.patch
similarity index 100%
rename from SOURCES/0406-kern-parser-Introduce-process_char-helper.patch
rename to SOURCES/0461-kern-parser-Introduce-process_char-helper.patch
diff --git a/SOURCES/0407-kern-parser-Introduce-terminate_arg-helper.patch b/SOURCES/0462-kern-parser-Introduce-terminate_arg-helper.patch
similarity index 100%
rename from SOURCES/0407-kern-parser-Introduce-terminate_arg-helper.patch
rename to SOURCES/0462-kern-parser-Introduce-terminate_arg-helper.patch
diff --git a/SOURCES/0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch b/SOURCES/0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch
similarity index 100%
rename from SOURCES/0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch
rename to SOURCES/0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch
diff --git a/SOURCES/0409-kern-buffer-Add-variable-sized-heap-buffer.patch b/SOURCES/0464-kern-buffer-Add-variable-sized-heap-buffer.patch
similarity index 99%
rename from SOURCES/0409-kern-buffer-Add-variable-sized-heap-buffer.patch
rename to SOURCES/0464-kern-buffer-Add-variable-sized-heap-buffer.patch
index c1aaa002801060e57aa3d0c52c13923b5e5ace57..0c468768e344e5f8dc2b7309940154199c5b44ab 100644
--- a/SOURCES/0409-kern-buffer-Add-variable-sized-heap-buffer.patch
+++ b/SOURCES/0464-kern-buffer-Add-variable-sized-heap-buffer.patch
@@ -18,7 +18,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  create mode 100644 include/grub/buffer.h
 
 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 0eb7f312b29..6c25cf3e26a 100644
+index 02fbecd4b81..612df2e9c40 100644
 --- a/grub-core/Makefile.core.def
 +++ b/grub-core/Makefile.core.def
 @@ -112,6 +112,7 @@ kernel = {
diff --git a/SOURCES/0410-kern-parser-Fix-a-stack-buffer-overflow.patch b/SOURCES/0465-kern-parser-Fix-a-stack-buffer-overflow.patch
similarity index 100%
rename from SOURCES/0410-kern-parser-Fix-a-stack-buffer-overflow.patch
rename to SOURCES/0465-kern-parser-Fix-a-stack-buffer-overflow.patch
diff --git a/SOURCES/0411-kern-efi-Add-initial-stack-protector-implementation.patch b/SOURCES/0466-kern-efi-Add-initial-stack-protector-implementation.patch
similarity index 99%
rename from SOURCES/0411-kern-efi-Add-initial-stack-protector-implementation.patch
rename to SOURCES/0466-kern-efi-Add-initial-stack-protector-implementation.patch
index 0032577adc140dafeb19a9922fb6865a2a0fbd66..8da130b94a3f39ce499cdd7b5349697953d94acb 100644
--- a/SOURCES/0411-kern-efi-Add-initial-stack-protector-implementation.patch
+++ b/SOURCES/0466-kern-efi-Add-initial-stack-protector-implementation.patch
@@ -21,7 +21,7 @@ Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
  create mode 100644 include/grub/stack_protector.h
 
 diff --git a/configure.ac b/configure.ac
-index 9323c125469..f335874cb9d 100644
+index 0059b938a3a..f59a7b86c51 100644
 --- a/configure.ac
 +++ b/configure.ac
 @@ -1330,12 +1330,41 @@ fi]
@@ -71,7 +71,7 @@ index 9323c125469..f335874cb9d 100644
  fi
  
  CFLAGS="$TARGET_CFLAGS"
-@@ -2229,5 +2258,10 @@ echo "Without liblzma (no support for XZ-compressed mips images) ($liblzma_excus
+@@ -2247,5 +2276,10 @@ echo "Without liblzma (no support for XZ-compressed mips images) ($liblzma_excus
  else
  echo "With liblzma from $LIBLZMA (support for XZ-compressed mips images)"
  fi
diff --git a/SOURCES/0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch b/SOURCES/0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
similarity index 90%
rename from SOURCES/0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
rename to SOURCES/0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
index fc300549f4c7b8223a7151b17ed505c9ba3f4e7c..6447426abac943b8ad04c79cf5fa8fb837ff1b4a 100644
--- a/SOURCES/0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
+++ b/SOURCES/0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
@@ -14,10 +14,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 17 deletions(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index e22d82afa61..7dbd504ec5b 100644
+index 2529de4bb78..64f4f139832 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
-@@ -1257,7 +1257,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1292,7 +1292,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	    o->code_size = grub_host_to_target32 (layout.exec_size);
  	    o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size
  					     - header_size);
@@ -25,7 +25,7 @@ index e22d82afa61..7dbd504ec5b 100644
  	    o->entry_addr = grub_cpu_to_le32 (layout.start_address);
  	    o->code_base = grub_cpu_to_le32 (header_size);
  
-@@ -1295,7 +1294,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1330,7 +1329,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	    o->code_size = grub_host_to_target32 (layout.exec_size);
  	    o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size
  					     - header_size);
@@ -33,7 +33,7 @@ index e22d82afa61..7dbd504ec5b 100644
  	    o->entry_addr = grub_cpu_to_le32 (layout.start_address);
  	    o->code_base = grub_cpu_to_le32 (header_size);
  	    o->image_base = 0;
-@@ -1340,21 +1338,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1375,21 +1373,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	  = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
  			      | GRUB_PE32_SCN_MEM_READ
  			      | GRUB_PE32_SCN_MEM_WRITE);
diff --git a/SOURCES/0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch b/SOURCES/0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
similarity index 93%
rename from SOURCES/0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
rename to SOURCES/0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
index 81350693557996cb3deb1cf2b52331c7b9771ec9..0043fd06dcb2385f445f93c94ad8d9c88c0e8895 100644
--- a/SOURCES/0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
+++ b/SOURCES/0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
@@ -16,10 +16,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 22 insertions(+), 22 deletions(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index 7dbd504ec5b..131f3ec75e2 100644
+index 64f4f139832..601521d34cf 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
-@@ -1255,10 +1255,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1290,10 +1290,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	       + sizeof (struct grub_pe32_coff_header));
  	    o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC);
  	    o->code_size = grub_host_to_target32 (layout.exec_size);
@@ -33,7 +33,7 @@ index 7dbd504ec5b..131f3ec75e2 100644
  
  	    o->data_base = grub_host_to_target32 (header_size + layout.exec_size);
  
-@@ -1292,10 +1292,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1327,10 +1327,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	       + sizeof (struct grub_pe32_coff_header));
  	    o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC);
  	    o->code_size = grub_host_to_target32 (layout.exec_size);
@@ -47,7 +47,7 @@ index 7dbd504ec5b..131f3ec75e2 100644
  	    o->image_base = 0;
  	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
  	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
-@@ -1319,10 +1319,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1354,10 +1354,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	/* The sections.  */
  	text_section = sections;
  	strcpy (text_section->name, ".text");
@@ -62,7 +62,7 @@ index 7dbd504ec5b..131f3ec75e2 100644
  	text_section->characteristics = grub_cpu_to_le32_compile_time (
  						  GRUB_PE32_SCN_CNT_CODE
  						| GRUB_PE32_SCN_MEM_EXECUTE
-@@ -1330,10 +1330,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1365,10 +1365,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  
  	data_section = text_section + 1;
  	strcpy (data_section->name, ".data");
@@ -77,7 +77,7 @@ index 7dbd504ec5b..131f3ec75e2 100644
  	data_section->characteristics
  	  = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
  			      | GRUB_PE32_SCN_MEM_READ
-@@ -1341,10 +1341,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1376,10 +1376,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
      
  	mods_section = data_section + 1;
  	strcpy (mods_section->name, "mods");
@@ -92,7 +92,7 @@ index 7dbd504ec5b..131f3ec75e2 100644
  	mods_section->characteristics
  	  = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
  			      | GRUB_PE32_SCN_MEM_READ
-@@ -1352,10 +1352,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1387,10 +1387,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  
  	reloc_section = mods_section + 1;
  	strcpy (reloc_section->name, ".reloc");
diff --git a/SOURCES/0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch b/SOURCES/0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
similarity index 93%
rename from SOURCES/0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
rename to SOURCES/0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
index 92f987573472037f4d7e48689a18b4d45b9cdd84..cef0a353a810b1d321652eb83cbfb9621b165461 100644
--- a/SOURCES/0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
+++ b/SOURCES/0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
@@ -15,10 +15,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 4 insertions(+), 4 deletions(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index 131f3ec75e2..25ea4ea9711 100644
+index 601521d34cf..d2876cdb5fb 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
-@@ -1304,10 +1304,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1339,10 +1339,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
  
  	    /* Do these really matter? */
diff --git a/SOURCES/0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch b/SOURCES/0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
similarity index 97%
rename from SOURCES/0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
rename to SOURCES/0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
index 78e18fbe45eafcca40473ed20e64fbaeb07726ef..e8e286add74cfad2c1fc613bf7e9b05f09733b5a 100644
--- a/SOURCES/0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
+++ b/SOURCES/0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
@@ -18,7 +18,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 51 insertions(+), 60 deletions(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index 25ea4ea9711..f7bf69efec2 100644
+index d2876cdb5fb..ff5462c98c1 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
 @@ -771,6 +771,21 @@ grub_install_get_image_targets_string (void)
@@ -43,7 +43,7 @@ index 25ea4ea9711..f7bf69efec2 100644
  void
  grub_install_generate_image (const char *dir, const char *prefix,
  			     FILE *out, const char *outname, char *mods[],
-@@ -1205,6 +1220,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1240,6 +1255,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;
  	int header_size;
  	int reloc_addr;
@@ -52,7 +52,7 @@ index 25ea4ea9711..f7bf69efec2 100644
  
  	if (image_target->voidp_sizeof == 4)
  	  header_size = EFI32_HEADER_SIZE;
-@@ -1246,76 +1263,50 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1281,76 +1298,50 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	/* The PE Optional header.  */
  	if (image_target->voidp_sizeof == 4)
  	  {
diff --git a/SOURCES/0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch b/SOURCES/0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
similarity index 91%
rename from SOURCES/0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
rename to SOURCES/0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
index c07359892774ed26e86a6473239b33de458a5d4f..95a3c7d99213648c141d384ed6bcd9bce62ebc1c 100644
--- a/SOURCES/0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
+++ b/SOURCES/0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
@@ -14,10 +14,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 8 insertions(+), 8 deletions(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index f7bf69efec2..18a92c68d15 100644
+index ff5462c98c1..e73a5864b22 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
-@@ -1285,16 +1285,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1320,16 +1320,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	    sections = o64 + 1;
  	  }
  
@@ -36,7 +36,7 @@ index f7bf69efec2..18a92c68d15 100644
  	PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
  
  	/* Do these really matter? */
-@@ -1304,10 +1300,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1339,10 +1335,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000);
  
  	PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
@@ -49,7 +49,7 @@ index f7bf69efec2..18a92c68d15 100644
  	text_section = sections;
  	strcpy (text_section->name, ".text");
  	text_section->virtual_size = grub_host_to_target32 (layout.exec_size);
-@@ -1319,6 +1315,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1354,6 +1350,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
  						| GRUB_PE32_SCN_MEM_EXECUTE
  						| GRUB_PE32_SCN_MEM_READ);
  
@@ -58,7 +58,7 @@ index f7bf69efec2..18a92c68d15 100644
  	data_section = text_section + 1;
  	strcpy (data_section->name, ".data");
  	data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size);
-@@ -1341,6 +1339,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1376,6 +1374,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
  			      | GRUB_PE32_SCN_MEM_READ
  			      | GRUB_PE32_SCN_MEM_WRITE);
  
diff --git a/SOURCES/0417-util-mkimage-Improve-data_size-value-calculation.patch b/SOURCES/0472-util-mkimage-Improve-data_size-value-calculation.patch
similarity index 91%
rename from SOURCES/0417-util-mkimage-Improve-data_size-value-calculation.patch
rename to SOURCES/0472-util-mkimage-Improve-data_size-value-calculation.patch
index f20e244f68c4daf67e1e40a9fad51003950ef668..31428ef57132e80a79224d9e8b43a737571fe2cf 100644
--- a/SOURCES/0417-util-mkimage-Improve-data_size-value-calculation.patch
+++ b/SOURCES/0472-util-mkimage-Improve-data_size-value-calculation.patch
@@ -21,10 +21,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 5 insertions(+), 1 deletion(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index 18a92c68d15..ed2d59d995f 100644
+index e73a5864b22..f22b398d973 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
-@@ -1213,6 +1213,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1248,6 +1248,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	void *pe_img;
  	grub_uint8_t *header;
  	void *sections;
@@ -32,7 +32,7 @@ index 18a92c68d15..ed2d59d995f 100644
  	size_t pe_size;
  	struct grub_pe32_coff_header *c;
  	struct grub_pe32_section_table *text_section, *data_section;
-@@ -1315,7 +1316,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1350,7 +1351,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  						| GRUB_PE32_SCN_MEM_EXECUTE
  						| GRUB_PE32_SCN_MEM_READ);
  
diff --git a/SOURCES/0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch b/SOURCES/0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
similarity index 96%
rename from SOURCES/0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
rename to SOURCES/0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
index b65f8c809b3fe1e7e834a0369193f5876ff31b9d..41d3f2fb91ecfa8fd3ee63834747d636dff803ec 100644
--- a/SOURCES/0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
+++ b/SOURCES/0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
@@ -14,7 +14,7 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 76 insertions(+), 65 deletions(-)
 
 diff --git a/util/mkimage.c b/util/mkimage.c
-index ed2d59d995f..e8e579304aa 100644
+index f22b398d973..0f5ae2a76f2 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
 @@ -771,6 +771,38 @@ grub_install_get_image_targets_string (void)
@@ -56,7 +56,7 @@ index ed2d59d995f..e8e579304aa 100644
  /*
   * tmp_ is just here so the compiler knows we'll never derefernce a NULL.
   * It should get fully optimized away.
-@@ -1210,17 +1242,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1245,17 +1277,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
        break;
      case IMAGE_EFI:
        {
@@ -78,7 +78,7 @@ index ed2d59d995f..e8e579304aa 100644
  	struct grub_pe32_optional_header *o32 = NULL;
  	struct grub_pe64_optional_header *o64 = NULL;
  
-@@ -1229,17 +1257,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1264,17 +1292,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	else
  	  header_size = EFI64_HEADER_SIZE;
  
@@ -101,7 +101,7 @@ index ed2d59d995f..e8e579304aa 100644
  
  	/* The magic.  */
  	memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE);
-@@ -1272,18 +1295,17 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1307,18 +1330,17 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	    o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC);
  	    o32->data_base = grub_host_to_target32 (header_size + layout.exec_size);
  
@@ -122,7 +122,7 @@ index ed2d59d995f..e8e579304aa 100644
  	  }
  
  	PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size);
-@@ -1303,58 +1325,47 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1338,58 +1360,47 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
  
  	/* The sections.  */
diff --git a/SOURCES/0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch b/SOURCES/0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
similarity index 75%
rename from SOURCES/0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
rename to SOURCES/0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
index f359681fc9bf5e771ca0230198d44407132ffba2..7044e573052bc6023d9ede8c37bc6047f4dafd01 100644
--- a/SOURCES/0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
+++ b/SOURCES/0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
@@ -12,49 +12,48 @@ Signed-off-by: Peter Jones <pjones@redhat.com>
 Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
 Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
 ---
- util/grub-install-common.c  |  3 ++-
+ util/grub-install-common.c  |  2 +-
  util/grub-mkimage.c         | 15 ++++++++++++++-
  util/mkimage.c              | 43 ++++++++++++++++++++++++++++++++++++-------
  include/grub/util/install.h |  3 ++-
  include/grub/util/mkimage.h |  1 +
- docs/grub.texi              | 21 +++++++++++++++++++++
- 6 files changed, 76 insertions(+), 10 deletions(-)
+ docs/grub.texi              | 19 +++++++++++++++++++
+ 6 files changed, 73 insertions(+), 10 deletions(-)
 
 diff --git a/util/grub-install-common.c b/util/grub-install-common.c
-index cf993c059ad..909db42e7d6 100644
+index fa6b65347ea..fde4ca7fc8c 100644
 --- a/util/grub-install-common.c
 +++ b/util/grub-install-common.c
-@@ -506,7 +506,8 @@ 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, compression, dtb, NULL);
-+
+@@ -537,7 +537,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+ 			       pubkeys, npubkeys,
+ 			       x509keys, nx509keys,
+ 			       config_path, tgt,
+-			       note, appsig_size, compression, dtb);
++			       note, appsig_size, compression, dtb, NULL);
    while (dc--)
      grub_install_pop_module ();
  }
 diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
-index 98d24cc06ea..bce7f7a5f02 100644
+index 394d2dc5fc9..17a86261ffc 100644
 --- a/util/grub-mkimage.c
 +++ b/util/grub-mkimage.c
-@@ -81,6 +81,7 @@ static struct argp_option options[] = {
+@@ -82,6 +82,7 @@ static struct argp_option options[] = {
    {"output",  'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
    {"format",  'O', N_("FORMAT"), 0, 0, 0},
    {"compression",  'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0},
 +  {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 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 }
- };
-@@ -123,6 +124,7 @@ struct arguments
-   size_t npubkeys;
+@@ -127,6 +128,7 @@ struct arguments
+   size_t nx509keys;
    char *font;
    char *config;
 +  char *sbat;
    int note;
+   size_t appsig_size;
    const struct grub_install_image_target_desc *image_target;
-   grub_compression_t comp;
-@@ -224,6 +226,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
+@@ -244,6 +246,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
        arguments->prefix = xstrdup (arg);
        break;
  
@@ -68,17 +67,17 @@ index 98d24cc06ea..bce7f7a5f02 100644
      case 'v':
        verbosity++;
        break;
-@@ -309,7 +318,8 @@ main (int argc, char *argv[])
- 			       arguments.memdisk, arguments.pubkeys,
- 			       arguments.npubkeys, arguments.config,
+@@ -331,7 +340,8 @@ main (int argc, char *argv[])
+ 			       arguments.nx509keys, arguments.config,
  			       arguments.image_target, arguments.note,
+ 			       arguments.appsig_size,
 -			       arguments.comp, arguments.dtb);
 +			       arguments.comp, arguments.dtb,
-+                               arguments.sbat);
++			       arguments.sbat);
  
    grub_util_file_sync  (fp);
    fclose (fp);
-@@ -324,5 +334,8 @@ main (int argc, char *argv[])
+@@ -346,5 +356,8 @@ main (int argc, char *argv[])
    if (arguments.output)
      free (arguments.output);
  
@@ -88,16 +87,16 @@ index 98d24cc06ea..bce7f7a5f02 100644
    return 0;
  }
 diff --git a/util/mkimage.c b/util/mkimage.c
-index e8e579304aa..8c7d9164396 100644
+index 0f5ae2a76f2..16418e245d3 100644
 --- a/util/mkimage.c
 +++ b/util/mkimage.c
-@@ -824,12 +824,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
- 			     char *memdisk_path, char **pubkey_paths,
- 			     size_t npubkeys, char *config_path,
+@@ -826,12 +826,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     char **x509key_paths, size_t nx509keys,
+ 			     char *config_path,
  			     const struct grub_install_image_target_desc *image_target,
--			     int note, grub_compression_t comp, const char *dtb_path)
-+			     int note, grub_compression_t comp, const char *dtb_path,
-+                             const char *sbat_path)
+-			     int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path)
++			     int note, size_t appsig_size, grub_compression_t comp,
++			     const char *dtb_path, const char *sbat_path)
  {
    char *kernel_img, *core_img;
    size_t total_module_size, core_size;
@@ -107,7 +106,7 @@ index e8e579304aa..8c7d9164396 100644
    char *kernel_path;
    size_t offset;
    struct grub_util_path_list *path_list, *p;
-@@ -880,6 +881,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -895,6 +896,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
        total_module_size += dtb_size + sizeof (struct grub_module_header);
      }
  
@@ -117,7 +116,7 @@ index e8e579304aa..8c7d9164396 100644
    if (config_path)
      {
        config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1);
-@@ -1242,8 +1246,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1277,8 +1281,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
        break;
      case IMAGE_EFI:
        {
@@ -128,7 +127,7 @@ index e8e579304aa..8c7d9164396 100644
  	size_t scn_size;
  	grub_uint32_t vma, raw_data;
  	size_t pe_size, header_size;
-@@ -1258,8 +1263,15 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1293,8 +1298,15 @@ grub_install_generate_image (const char *dir, const char *prefix,
  	  header_size = EFI64_HEADER_SIZE;
  
  	vma = raw_data = header_size;
@@ -145,7 +144,7 @@ index e8e579304aa..8c7d9164396 100644
  	header = pe_img = xcalloc (1, pe_size);
  
  	memcpy (pe_img + raw_data, core_img, core_size);
-@@ -1274,7 +1286,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1309,7 +1321,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
  					      + GRUB_PE32_SIGNATURE_SIZE);
  	c->machine = grub_host_to_target16 (image_target->pe_target);
  
@@ -157,7 +156,7 @@ index e8e579304aa..8c7d9164396 100644
  	c->time = grub_host_to_target32 (STABLE_EMBEDDING_TIMESTAMP);
  	c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE
  						    | GRUB_PE32_LINE_NUMS_STRIPPED
-@@ -1336,7 +1351,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1371,7 +1386,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
  				   GRUB_PE32_SCN_MEM_READ);
  
  	scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT);
@@ -167,7 +166,7 @@ index e8e579304aa..8c7d9164396 100644
  							       ALIGN_UP (total_module_size,
  									 GRUB_PE32_FILE_ALIGNMENT));
  
-@@ -1347,7 +1363,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1382,7 +1398,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
  				   GRUB_PE32_SCN_MEM_READ |
  				   GRUB_PE32_SCN_MEM_WRITE);
  
@@ -176,7 +175,7 @@ index e8e579304aa..8c7d9164396 100644
  	section = init_pe_section (image_target, section, "mods",
  				   &vma, scn_size, image_target->section_align,
  				   &raw_data, scn_size,
-@@ -1355,6 +1371,19 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -1390,6 +1406,19 @@ grub_install_generate_image (const char *dir, const char *prefix,
  				   GRUB_PE32_SCN_MEM_READ |
  				   GRUB_PE32_SCN_MEM_WRITE);
  
@@ -197,13 +196,13 @@ index e8e579304aa..8c7d9164396 100644
  	PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma);
  	PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size);
 diff --git a/include/grub/util/install.h b/include/grub/util/install.h
-index 0dba8b67f93..a08f0b5325f 100644
+index 95059285bd4..dad17561c4f 100644
 --- a/include/grub/util/install.h
 +++ b/include/grub/util/install.h
-@@ -180,7 +180,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
+@@ -187,7 +187,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
  			     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);
 +			     grub_compression_t comp, const char *dtb_file,
 +			     const char *sbat_path);
@@ -211,7 +210,7 @@ index 0dba8b67f93..a08f0b5325f 100644
  const struct grub_install_image_target_desc *
  grub_install_get_image_target (const char *arg);
 diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
-index b3a5ca132bc..151c178e6ee 100644
+index cef7fffa7ae..f48d544c28a 100644
 --- a/include/grub/util/mkimage.h
 +++ b/include/grub/util/mkimage.h
 @@ -24,6 +24,7 @@ struct grub_mkimage_layout
@@ -223,22 +222,21 @@ index b3a5ca132bc..151c178e6ee 100644
    void *reloc_section;
    size_t reloc_size;
 diff --git a/docs/grub.texi b/docs/grub.texi
-index 067aa294162..fc7b56b8f47 100644
+index 314bbeb8471..52e6e5763b8 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -5642,6 +5642,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
+@@ -5719,6 +5719,7 @@ environment variables and commands are listed in the same order.
+ * 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
 +* Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
  * Lockdown::                           Lockdown when booting on a secure setup
- 
  @end menu
-@@ -5806,6 +5807,26 @@ 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.
  
-+
+@@ -6010,6 +6011,24 @@ As with UEFI secure boot, it is necessary to build in the required modules,
+ or sign them separately.
+ 
+ 
 +@node Secure Boot Advanced Targeting
 +@section Embedded information for generation number based revocation
 +
@@ -256,7 +254,6 @@ index 067aa294162..fc7b56b8f47 100644
 +@example
 +grub-mkimage -O x86_64-efi -o grubx64.efi -p '(tftp)/grub' --sbat sbat.csv efinet tftp
 +@end example
-+
 +
  @node Lockdown
  @section Lockdown when booting on a secure setup
diff --git a/SOURCES/0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch b/SOURCES/0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch
similarity index 88%
rename from SOURCES/0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch
rename to SOURCES/0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch
index 879ce5948a9fe1768f5ee21d9dec46232751b17c..7ff44dd10ec3f4064b250db6020f586c3114e471 100644
--- a/SOURCES/0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch
+++ b/SOURCES/0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch
@@ -16,10 +16,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 9 insertions(+), 2 deletions(-)
 
 diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index 62b4068e810..ca851c29d51 100644
+index 475f3e0ef05..ebfcc95f01d 100644
 --- a/grub-core/kern/misc.c
 +++ b/grub-core/kern/misc.c
-@@ -678,8 +678,7 @@ grub_lltoa (char *str, int c, unsigned long long n)
+@@ -711,8 +711,7 @@ grub_lltoa (char *str, int c, unsigned long long n)
  }
  
  static void
@@ -29,7 +29,7 @@ index 62b4068e810..ca851c29d51 100644
  {
    const char *fmt;
    char c;
-@@ -837,6 +836,14 @@ parse_printf_args (const char *fmt0, struct printf_args *args,
+@@ -870,6 +869,14 @@ parse_printf_args (const char *fmt0, struct printf_args *args,
  	  break;
  	}
      }
diff --git a/SOURCES/0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch b/SOURCES/0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch
similarity index 90%
rename from SOURCES/0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch
rename to SOURCES/0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch
index f301df2c8749bbcb59fcd68a2363b8a77c25932c..8e6e474760653a4f6600cdb832f6f1185be2581b 100644
--- a/SOURCES/0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch
+++ b/SOURCES/0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch
@@ -20,10 +20,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  1 file changed, 11 insertions(+), 2 deletions(-)
 
 diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index ca851c29d51..9e2a237b118 100644
+index ebfcc95f01d..07456faa2a7 100644
 --- a/grub-core/kern/misc.c
 +++ b/grub-core/kern/misc.c
-@@ -34,7 +34,8 @@ union printf_arg
+@@ -37,7 +37,8 @@ union printf_arg
    enum
      {
        INT, LONG, LONGLONG,
@@ -33,7 +33,7 @@ index ca851c29d51..9e2a237b118 100644
      } type;
    long long ll;
  };
-@@ -824,12 +825,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
+@@ -857,12 +858,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
  	  args->ptr[curn].type = INT + longfmt;
  	  break;
  	case 'p':
@@ -49,7 +49,7 @@ index ca851c29d51..9e2a237b118 100644
  	case 'C':
  	case 'c':
  	  args->ptr[curn].type = INT;
-@@ -864,6 +867,12 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in)
+@@ -897,6 +900,12 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in)
        case UNSIGNED_LONGLONG:
  	args->ptr[n].ll = va_arg (args_in, long long);
  	break;
diff --git a/SOURCES/0422-kern-misc-Add-function-to-check-printf-format-agains.patch b/SOURCES/0477-kern-misc-Add-function-to-check-printf-format-agains.patch
similarity index 92%
rename from SOURCES/0422-kern-misc-Add-function-to-check-printf-format-agains.patch
rename to SOURCES/0477-kern-misc-Add-function-to-check-printf-format-agains.patch
index 377c9f4422fd989dec995e8b8855b36ac463cce9..0dacf6304d60b0ddc1e2c46af3ebe047847e201d 100644
--- a/SOURCES/0422-kern-misc-Add-function-to-check-printf-format-agains.patch
+++ b/SOURCES/0477-kern-misc-Add-function-to-check-printf-format-agains.patch
@@ -49,10 +49,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  2 files changed, 94 insertions(+), 4 deletions(-)
 
 diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index 9e2a237b118..f56b5d2034e 100644
+index 07456faa2a7..859d71659a2 100644
 --- a/grub-core/kern/misc.c
 +++ b/grub-core/kern/misc.c
-@@ -678,8 +678,26 @@ grub_lltoa (char *str, int c, unsigned long long n)
+@@ -711,8 +711,26 @@ grub_lltoa (char *str, int c, unsigned long long n)
    return p;
  }
  
@@ -81,7 +81,7 @@ index 9e2a237b118..f56b5d2034e 100644
  {
    const char *fmt;
    char c;
-@@ -706,7 +724,12 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
+@@ -739,7 +757,12 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
  	fmt++;
  
        if (*fmt == '$')
@@ -95,7 +95,7 @@ index 9e2a237b118..f56b5d2034e 100644
  
        if (*fmt =='-')
  	fmt++;
-@@ -738,9 +761,19 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
+@@ -771,9 +794,19 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
  	case 's':
  	  args->count++;
  	  break;
@@ -115,7 +115,7 @@ index 9e2a237b118..f56b5d2034e 100644
    if (args->count <= ARRAY_SIZE (args->prealloc))
      args->ptr = args->prealloc;
    else
-@@ -748,6 +781,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
+@@ -781,6 +814,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
        args->ptr = grub_calloc (args->count, sizeof (args->ptr[0]));
        if (!args->ptr)
  	{
@@ -125,7 +125,7 @@ index 9e2a237b118..f56b5d2034e 100644
  	  grub_errno = GRUB_ERR_NONE;
  	  args->ptr = args->prealloc;
  	  args->count = ARRAY_SIZE (args->prealloc);
-@@ -839,6 +875,8 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
+@@ -872,6 +908,8 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args)
  	  break;
  	}
      }
@@ -134,7 +134,7 @@ index 9e2a237b118..f56b5d2034e 100644
  }
  
  static void
-@@ -846,7 +884,7 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in)
+@@ -879,7 +917,7 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in)
  {
    grub_size_t n;
  
@@ -143,7 +143,7 @@ index 9e2a237b118..f56b5d2034e 100644
  
    for (n = 0; n < args->count; n++)
      switch (args->ptr[n].type)
-@@ -1154,6 +1192,42 @@ grub_xasprintf (const char *fmt, ...)
+@@ -1187,6 +1225,42 @@ grub_xasprintf (const char *fmt, ...)
    return ret;
  }
  
@@ -187,10 +187,10 @@ index 9e2a237b118..f56b5d2034e 100644
  static inline void __attribute__ ((noreturn))
  grub_abort (void)
 diff --git a/include/grub/misc.h b/include/grub/misc.h
-index 1258ec6bbf3..b1cbb4a51bc 100644
+index 6ca03c4d692..6be6a88f652 100644
 --- a/include/grub/misc.h
 +++ b/include/grub/misc.h
-@@ -487,6 +487,22 @@ grub_error_load (const struct grub_error_saved *save)
+@@ -488,6 +488,22 @@ grub_error_load (const struct grub_error_saved *save)
    grub_errno = save->grub_errno;
  }
  
diff --git a/SOURCES/0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch b/SOURCES/0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch
similarity index 100%
rename from SOURCES/0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch
rename to SOURCES/0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch
diff --git a/SOURCES/0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch b/SOURCES/0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch
similarity index 100%
rename from SOURCES/0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch
rename to SOURCES/0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch
diff --git a/SOURCES/0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch b/SOURCES/0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch
similarity index 100%
rename from SOURCES/0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch
rename to SOURCES/0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch
diff --git a/SOURCES/centos-ca-secureboot.der b/SOURCES/centos-ca-secureboot.der
deleted file mode 100644
index 44a2563dee3f8eeecd5026306be46d2a8d89970d..0000000000000000000000000000000000000000
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 e8216b1db725cd132b515a277368fc89a9d8fa3d..0000000000000000000000000000000000000000
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 ab8213c1769acb23cafb4e8a9dc5162b6e6186cd..0000000000000000000000000000000000000000
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 42bdfcfbcda649796099fdc87bbe9dc58e2348d5..0000000000000000000000000000000000000000
Binary files a/SOURCES/centossecurebootca2.der and /dev/null differ
diff --git a/SOURCES/grub.macros b/SOURCES/grub.macros
index 6279c55ef7f0fb9bbc234997b6a6fff86236b0e7..98ad11adbfc24f17f0e63a275a002d55e9b5d43a 100644
--- a/SOURCES/grub.macros
+++ b/SOURCES/grub.macros
@@ -112,7 +112,7 @@
 %ifarch aarch64 %{arm}
 %global platform_modules " "
 %else
-%global platform_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug "
+%global platform_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug keylayouts at_keyboard "
 %endif
 
 %ifarch aarch64 %{arm}
@@ -344,6 +344,8 @@ PYTHON=python3 ./autogen.sh					\
 	--with-grubdir=%{name}					\\\
 	--program-transform-name=s,grub,%{name},		\\\
 	--disable-grub-mount					\\\
+	--with-debug-timestamps					\\\
+	--enable-boot-time					\\\
 	--disable-werror || ( cat config.log ; exit 1 )		\
 git add .							\
 git commit -m "After efi configure"				\
@@ -367,11 +369,11 @@ done								\
 %ifarch x86_64 aarch64 %{arm}
 %define mkimage()						\
 %{4}./grub-mkimage -O %{1} -o %{2}.orig				\\\
-       -p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES}      \\\
-       --sbat %{4}./sbat.csv                                   \
+	-p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES}	\\\
+	--sbat %{4}./sbat.csv					\
 %{4}./grub-mkimage -O %{1} -o %{3}.orig				\\\
-       -p /EFI/BOOT -d grub-core ${GRUB_MODULES}               \\\
-       --sbat %{4}./sbat.csv                                   \
+	-p /EFI/BOOT -d grub-core ${GRUB_MODULES}		\\\
+	--sbat %{4}./sbat.csv					\
 %{expand:%%{pesign -s -i %%{2}.orig -o %%{2}.one -a %%{5} -c %%{6} -n %%{7}}}	\
 %{expand:%%{pesign -s -i %%{3}.orig -o %%{3}.one -a %%{5} -c %%{6} -n %%{7}}}	\
 %{expand:%%{pesign -s -i %%{2}.one -o %%{2} -a %%{8} -c %%{9} -n %%{10}}}	\
@@ -388,11 +390,13 @@ done								\
 
 %define do_efi_build_images()					\
 GRUB_MODULES="	all_video boot blscfg btrfs			\\\
-		cat configfile					\\\
+		cat configfile cryptodisk			\\\
 		echo efi_netfs efifwsetup efinet ext2		\\\
-		fat font gfxmenu gfxterm gzio			\\\
+		fat font gcry_rijndael gcry_rsa gcry_serpent	\\\
+		gcry_sha256 gcry_twofish gcry_whirlpool		\\\
+		gfxmenu gfxterm gzio				\\\
 		halt hfsplus http increment iso9660 jpeg	\\\
-		loadenv loopback linux lvm lsefi lsefimmap	\\\
+		loadenv loopback linux lvm lsefi lsefimmap luks	\\\
 		mdraid09 mdraid1x minicmd net			\\\
 		normal part_apple part_msdos part_gpt		\\\
 		password_pbkdf2 png reboot			\\\
@@ -436,6 +440,8 @@ cd grub-%{1}-%{tarversion}					\
 	--with-grubdir=%{name}					\\\
 	--program-transform-name=s,grub,%{name},		\\\
 	--disable-grub-mount					\\\
+	--with-debug-timestamps					\\\
+	--enable-boot-time					\\\
 	--disable-werror || ( cat config.log ; exit 1 )		\
 git add .							\
 git commit -m "After legacy configure"				\
@@ -558,7 +564,7 @@ touch ${RPM_BUILD_ROOT}/boot/%{name}/grub.cfg			\
 %dir %attr(0700,root,root)%{efi_esp_dir}/fonts			\
 %dir %attr(0700,root,root)/boot/loader/entries			\
 %ghost %config(noreplace) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg	\
-%config(noreplace) /boot/grub2/grubenv					\
+%config(noreplace) %verify(not size mode md5 mtime) /boot/grub2/grubenv	\
 %ghost %config(noreplace) %attr(0700,root,root)%{efi_esp_dir}/grubenv	\
 %{expand:%if 0%{?without_efi_modules}				\
 %exclude %{_libdir}/grub/%{6}					\
diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches
index 578dfee32722a7a5c9ea6db34676f0ab1ff77fa4..cc743e384d518da0f25da3e8cb9bfb268e48dea6 100644
--- a/SOURCES/grub.patches
+++ b/SOURCES/grub.patches
@@ -315,111 +315,166 @@ Patch0314: 0314-linux-Fix-integer-overflows-in-initrd-size-handling.patch
 Patch0315: 0315-blscfg-Always-look-for-BLS-snippets-in-the-root-devi.patch
 Patch0316: 0316-blscfg-Don-t-hardcode-an-env-var-as-fallback-for-the.patch
 Patch0317: 0317-tftp-roll-over-block-counter-to-prevent-timeouts-wit.patch
-Patch0318: 0318-kern-Add-lockdown-support.patch
-Patch0319: 0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
-Patch0320: 0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch
-Patch0321: 0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch
-Patch0322: 0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
-Patch0323: 0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
-Patch0324: 0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
-Patch0325: 0325-commands-setpci-Restrict-setpci-command-when-locked-.patch
-Patch0326: 0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch
-Patch0327: 0327-gdb-Restrict-GDB-access-when-locked-down.patch
-Patch0328: 0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch
-Patch0329: 0329-docs-Document-the-cutmem-command.patch
-Patch0330: 0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch
-Patch0331: 0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch
-Patch0332: 0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch
-Patch0333: 0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
-Patch0334: 0334-net-tftp-Fix-dangling-memory-pointer.patch
-Patch0335: 0335-kern-parser-Fix-resource-leak-if-argc-0.patch
-Patch0336: 0336-kern-efi-Fix-memory-leak-on-failure.patch
-Patch0337: 0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch
-Patch0338: 0338-gnulib-regexec-Resolve-unused-variable.patch
-Patch0339: 0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch
-Patch0340: 0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch
-Patch0341: 0341-gnulib-regexec-Fix-possible-null-dereference.patch
-Patch0342: 0342-gnulib-regcomp-Fix-uninitialized-re_token.patch
-Patch0343: 0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
-Patch0344: 0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch
-Patch0345: 0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch
-Patch0346: 0346-disk-ldm-If-failed-then-free-vg-variable-too.patch
-Patch0347: 0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch
-Patch0348: 0348-disk-cryptodisk-Fix-potential-integer-overflow.patch
-Patch0349: 0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch
-Patch0350: 0350-zfs-Fix-possible-negative-shift-operation.patch
-Patch0351: 0351-zfs-Fix-resource-leaks-while-constructing-path.patch
-Patch0352: 0352-zfs-Fix-possible-integer-overflows.patch
-Patch0353: 0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch
-Patch0354: 0354-affs-Fix-memory-leaks.patch
-Patch0355: 0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch
-Patch0356: 0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch
-Patch0357: 0357-syslinux-Fix-memory-leak-while-parsing.patch
-Patch0358: 0358-normal-completion-Fix-leaking-of-memory-when-process.patch
-Patch0359: 0359-commands-hashsum-Fix-a-memory-leak.patch
-Patch0360: 0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch
-Patch0361: 0361-video-fb-fbfill-Fix-potential-integer-overflow.patch
-Patch0362: 0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch
-Patch0363: 0363-video-fb-video_fb-Fix-possible-integer-overflow.patch
-Patch0364: 0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
-Patch0365: 0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch
-Patch0366: 0366-loader-bsd-Check-for-NULL-arg-up-front.patch
-Patch0367: 0367-loader-xnu-Fix-memory-leak.patch
-Patch0368: 0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
-Patch0369: 0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
-Patch0370: 0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch
-Patch0371: 0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch
-Patch0372: 0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch
-Patch0373: 0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch
-Patch0374: 0374-script-execute-Avoid-crash-when-using-outside-a-func.patch
-Patch0375: 0375-lib-arg-Block-repeated-short-options-that-require-an.patch
-Patch0376: 0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch
-Patch0377: 0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch
-Patch0378: 0378-kern-misc-Always-set-end-in-grub_strtoull.patch
-Patch0379: 0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
-Patch0380: 0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
-Patch0381: 0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
-Patch0382: 0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch
-Patch0383: 0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch
-Patch0384: 0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch
-Patch0385: 0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch
-Patch0386: 0386-fs-hfs-Disable-under-lockdown.patch
-Patch0387: 0387-fs-sfs-Fix-over-read-of-root-object-name.patch
-Patch0388: 0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch
-Patch0389: 0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch
-Patch0390: 0390-fs-jfs-Catch-infinite-recursion.patch
-Patch0391: 0391-fs-nilfs2-Reject-too-large-keys.patch
-Patch0392: 0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch
-Patch0393: 0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch
-Patch0394: 0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
-Patch0395: 0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
-Patch0396: 0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
-Patch0397: 0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
-Patch0398: 0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch
-Patch0399: 0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch
-Patch0400: 0400-disk-lvm-Bail-on-missing-PV-list.patch
-Patch0401: 0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch
-Patch0402: 0402-disk-lvm-Do-not-overread-metadata.patch
-Patch0403: 0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch
-Patch0404: 0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch
-Patch0405: 0405-kern-parser-Fix-a-memory-leak.patch
-Patch0406: 0406-kern-parser-Introduce-process_char-helper.patch
-Patch0407: 0407-kern-parser-Introduce-terminate_arg-helper.patch
-Patch0408: 0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch
-Patch0409: 0409-kern-buffer-Add-variable-sized-heap-buffer.patch
-Patch0410: 0410-kern-parser-Fix-a-stack-buffer-overflow.patch
-Patch0411: 0411-kern-efi-Add-initial-stack-protector-implementation.patch
-Patch0412: 0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
-Patch0413: 0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
-Patch0414: 0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
-Patch0415: 0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
-Patch0416: 0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
-Patch0417: 0417-util-mkimage-Improve-data_size-value-calculation.patch
-Patch0418: 0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
-Patch0419: 0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
-Patch0420: 0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch
-Patch0421: 0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch
-Patch0422: 0422-kern-misc-Add-function-to-check-printf-format-agains.patch
-Patch0423: 0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch
-Patch0424: 0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch
-Patch0425: 0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch
+Patch0318: 0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
+Patch0319: 0319-grub-install-disable-support-for-EFI-platforms.patch
+Patch0320: 0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch
+Patch0321: 0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
+Patch0322: 0322-Introduce-function-grub_debug_is_enabled-void-return.patch
+Patch0323: 0323-Don-t-clear-screen-when-debugging-is-enabled.patch
+Patch0324: 0324-grub_file_-instrumentation-new-file-debug-tag.patch
+Patch0325: 0325-ieee1275-Avoiding-many-unecessary-open-close.patch
+Patch0326: 0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
+Patch0327: 0327-ieee1275-powerpc-enables-device-mapper-discovery.patch
+Patch0328: 0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
+Patch0329: 0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch
+Patch0330: 0330-verifiers-File-type-for-fine-grained-signature-verif.patch
+Patch0331: 0331-verifiers-Framework-core.patch
+Patch0332: 0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch
+Patch0333: 0333-verifiers-Add-possibility-to-defer-verification-to-o.patch
+Patch0334: 0334-verifiers-Rename-verify-module-to-pgp-module.patch
+Patch0335: 0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch
+Patch0336: 0336-include-grub-file.h-Add-device-tree-file-type.patch
+Patch0337: 0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch
+Patch0338: 0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch
+Patch0339: 0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch
+Patch0340: 0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch
+Patch0341: 0341-verifiers-Xen-fallout-cleanup.patch
+Patch0342: 0342-verifiers-ARM-Xen-fallout-cleanup.patch
+Patch0343: 0343-verifiers-IA-64-fallout-cleanup.patch
+Patch0344: 0344-verifiers-PowerPC-fallout-cleanup.patch
+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-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
+Patch0373: 0373-kern-Add-lockdown-support.patch
+Patch0374: 0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch
+Patch0375: 0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch
+Patch0376: 0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch
+Patch0377: 0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch
+Patch0378: 0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch
+Patch0379: 0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch
+Patch0380: 0380-commands-setpci-Restrict-setpci-command-when-locked-.patch
+Patch0381: 0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch
+Patch0382: 0382-gdb-Restrict-GDB-access-when-locked-down.patch
+Patch0383: 0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch
+Patch0384: 0384-docs-Document-the-cutmem-command.patch
+Patch0385: 0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch
+Patch0386: 0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch
+Patch0387: 0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch
+Patch0388: 0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch
+Patch0389: 0389-net-tftp-Fix-dangling-memory-pointer.patch
+Patch0390: 0390-kern-parser-Fix-resource-leak-if-argc-0.patch
+Patch0391: 0391-kern-efi-Fix-memory-leak-on-failure.patch
+Patch0392: 0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch
+Patch0393: 0393-gnulib-regexec-Resolve-unused-variable.patch
+Patch0394: 0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch
+Patch0395: 0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch
+Patch0396: 0396-gnulib-regexec-Fix-possible-null-dereference.patch
+Patch0397: 0397-gnulib-regcomp-Fix-uninitialized-re_token.patch
+Patch0398: 0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch
+Patch0399: 0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch
+Patch0400: 0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch
+Patch0401: 0401-disk-ldm-If-failed-then-free-vg-variable-too.patch
+Patch0402: 0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch
+Patch0403: 0403-disk-cryptodisk-Fix-potential-integer-overflow.patch
+Patch0404: 0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch
+Patch0405: 0405-zfs-Fix-possible-negative-shift-operation.patch
+Patch0406: 0406-zfs-Fix-resource-leaks-while-constructing-path.patch
+Patch0407: 0407-zfs-Fix-possible-integer-overflows.patch
+Patch0408: 0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch
+Patch0409: 0409-affs-Fix-memory-leaks.patch
+Patch0410: 0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch
+Patch0411: 0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch
+Patch0412: 0412-syslinux-Fix-memory-leak-while-parsing.patch
+Patch0413: 0413-normal-completion-Fix-leaking-of-memory-when-process.patch
+Patch0414: 0414-commands-hashsum-Fix-a-memory-leak.patch
+Patch0415: 0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch
+Patch0416: 0416-video-fb-fbfill-Fix-potential-integer-overflow.patch
+Patch0417: 0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch
+Patch0418: 0418-video-fb-video_fb-Fix-possible-integer-overflow.patch
+Patch0419: 0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch
+Patch0420: 0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch
+Patch0421: 0421-loader-bsd-Check-for-NULL-arg-up-front.patch
+Patch0422: 0422-loader-xnu-Fix-memory-leak.patch
+Patch0423: 0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch
+Patch0424: 0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch
+Patch0425: 0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch
+Patch0426: 0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch
+Patch0427: 0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch
+Patch0428: 0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch
+Patch0429: 0429-script-execute-Avoid-crash-when-using-outside-a-func.patch
+Patch0430: 0430-lib-arg-Block-repeated-short-options-that-require-an.patch
+Patch0431: 0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch
+Patch0432: 0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch
+Patch0433: 0433-kern-misc-Always-set-end-in-grub_strtoull.patch
+Patch0434: 0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch
+Patch0435: 0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch
+Patch0436: 0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch
+Patch0437: 0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch
+Patch0438: 0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch
+Patch0439: 0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch
+Patch0440: 0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch
+Patch0441: 0441-fs-hfs-Disable-under-lockdown.patch
+Patch0442: 0442-fs-sfs-Fix-over-read-of-root-object-name.patch
+Patch0443: 0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch
+Patch0444: 0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch
+Patch0445: 0445-fs-jfs-Catch-infinite-recursion.patch
+Patch0446: 0446-fs-nilfs2-Reject-too-large-keys.patch
+Patch0447: 0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch
+Patch0448: 0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch
+Patch0449: 0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch
+Patch0450: 0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch
+Patch0451: 0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch
+Patch0452: 0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch
+Patch0453: 0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch
+Patch0454: 0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch
+Patch0455: 0455-disk-lvm-Bail-on-missing-PV-list.patch
+Patch0456: 0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch
+Patch0457: 0457-disk-lvm-Do-not-overread-metadata.patch
+Patch0458: 0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch
+Patch0459: 0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch
+Patch0460: 0460-kern-parser-Fix-a-memory-leak.patch
+Patch0461: 0461-kern-parser-Introduce-process_char-helper.patch
+Patch0462: 0462-kern-parser-Introduce-terminate_arg-helper.patch
+Patch0463: 0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch
+Patch0464: 0464-kern-buffer-Add-variable-sized-heap-buffer.patch
+Patch0465: 0465-kern-parser-Fix-a-stack-buffer-overflow.patch
+Patch0466: 0466-kern-efi-Add-initial-stack-protector-implementation.patch
+Patch0467: 0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch
+Patch0468: 0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch
+Patch0469: 0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch
+Patch0470: 0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch
+Patch0471: 0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch
+Patch0472: 0472-util-mkimage-Improve-data_size-value-calculation.patch
+Patch0473: 0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch
+Patch0474: 0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch
+Patch0475: 0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch
+Patch0476: 0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch
+Patch0477: 0477-kern-misc-Add-function-to-check-printf-format-agains.patch
+Patch0478: 0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch
+Patch0479: 0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch
+Patch0480: 0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch
diff --git a/SOURCES/redhatsecureboot301.cer b/SOURCES/redhatsecureboot301.cer
new file mode 100644
index 0000000000000000000000000000000000000000..4ff8b79e6736e566dbf39603e0887a53345aa4e4
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 0000000000000000000000000000000000000000..be0b5e211ccf8ad7ba74c88841c921cfdbad5a70
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 0000000000000000000000000000000000000000..b2354007b9668258683b99a68fa5bdd3067c31b1
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 0000000000000000000000000000000000000000..dfb0284954861282d1a0ce16c8c5cdc71c27659f
Binary files /dev/null and b/SOURCES/redhatsecurebootca5.cer differ
diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec
index d1e1aa61f4733edc00a758f7663d5b53e1f5b3ad..86208d27d995887d39cd44bcf4eb26a78853b025 100644
--- a/SPECS/grub2.spec
+++ b/SPECS/grub2.spec
@@ -7,7 +7,7 @@
 Name:		grub2
 Epoch:		1
 Version:	2.02
-Release:	90%{?dist}.1
+Release:	99%{?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
 Source17:	sbat.csv.in
 
 %include %{SOURCE1}
@@ -55,11 +55,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}
@@ -173,10 +169,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}}
@@ -358,7 +354,7 @@ fi
 %dir %attr(0700,root,root) %{efi_esp_dir}
 %exclude %{efi_esp_dir}/*
 %license COPYING
-%ghost %config(noreplace) /boot/grub2/grubenv
+%ghost %config(noreplace) %verify(not size mode md5 mtime) /boot/grub2/grubenv
 %doc INSTALL
 %doc NEWS
 %doc README
@@ -507,7 +503,17 @@ fi
 %endif
 
 %changelog
-* Thu Feb 25 2021 Javier Martinez Canillas <javierm@redhat.com> - 2.02-90.el8_3.1
+* Thu Feb 25 2021 Javier Martinez Canillas <javierm@redhat.com> - 2.02-99
+- Fix bug of grub2-install not checking for the SBAT option
+  Resolves: CVE-2020-14372
+  Resolves: CVE-2020-25632
+  Resolves: CVE-2020-25647
+  Resolves: CVE-2020-27749
+  Resolves: CVE-2020-27779
+  Resolves: CVE-2021-20225
+  Resolves: CVE-2021-20233
+
+* Thu Feb 25 2021 Javier Martinez Canillas <javierm@redhat.com> - 2.02-98
 - Fix another batch of CVEs
   Resolves: CVE-2020-14372
   Resolves: CVE-2020-25632
@@ -517,6 +523,50 @@ fi
   Resolves: CVE-2021-20225
   Resolves: CVE-2021-20233
 
+* 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
+
+* Wed Jan 20 2021 Renaud Métrich <rmetrich@redhat.com> - 2.02-94
+- Add 'at_keyboard_fallback_set' var to force the set manually
+- Related: rhbz#1897587
+
+* Mon Dec 14 2020 Javier Martinez Canillas <javierm@redhat.com> - 2.02-93
+- add keylayouts and at_keyboard modules to UEFI Grub2 (rmetrich)
+  Related: rhbz#1897587
+- at_keyboard: use set 1 when keyboard is in Translate mode (rmetrich)
+  Resolves: rhbz#1897587
+- add GRUB enhanced debugging features (rmetrich)
+  Resolves: rhbz#1776249
+- ieee1275: Avoiding many unecessary open/close (diegodo)
+  Resolves: rhbz#1862632
+- ieee1275: device mapper and fibre channel discovery support (diegodo)
+  Resolves: rhbz#1873724
+
+* Mon Nov 23 2020 Jan Hlavac <jhlavac@redhat.com> - 2.02-92
+- grub2-install: disable support for EFI platforms
+  Resolves: rhbz#1737444
+- Include a few more modules to EFI build needed for LUKS support (javierm)
+  Related: rhbz#1873725
+
+* Mon Nov 16 2020 Javier Martinez Canillas <javierm@redhat.com> - 2.02-91
+- Fix tps-rpmtest failing due /boot/grub2/grubenv attributes mismatch
+  Resolves: rhbz#1813959
+- Include in EFI build the modules needed for LUKS support
+  Resolves: rhbz#1873725
+- Fix keyboards that report IBM PC AT scan codes
+  Resolves: rhbz#1897587
+
 * Mon Aug 31 2020 Javier Martinez Canillas <javierm@redhat.com> - 2.02-90
 - Roll over TFTP block counter to prevent timeouts with data packets
   Resolves: rhbz#1871034