Re: [PATCH v2 0/7] Add LoadFile2 and riscv Linux loader

2021-06-30 Thread Ard Biesheuvel
On Tue, 29 Jun 2021 at 21:13, Atish Patra  wrote:
>
> On Mon, Jun 28, 2021 at 2:24 PM Heinrich Schuchardt  
> wrote:
> >
> >
> > +cc Ard Biesheuvel 
> >
> > Ard, please see question for you below.
> >
> > On 6/27/21 11:01 PM, Heinrich Schuchardt wrote:
> > > On 6/26/21 8:07 PM, Andreas Schwab wrote:
> > >> On Jun 03 2021, Nikita Ermakov wrote:
> > >>
> > >>> This series contains patches to add support for LoadFile2 protocol to
> > >>> load
> > >>> initrd on EFI systems. Also it contains patches to load Linux kernel
> > >>> with EFI
> > >>> stub on riscv platforms and unites arm and riscv codes together into
> > >>> common
> > >>> loader code for EFI systems.
> > >>
> > >> That doesn't work with a CD image.  When I try to run
> > >> http://download.opensuse.org/ports/riscv/tumbleweed/iso/openSUSE-Tumbleweed-NET-riscv64-Media.iso
> > >>
> > >> with qemu, the initrd fails to load.
> > >
> > > Please, indicate how you built u-boot.bin.
> > >
> > >>
> > >> $ qemu-system-riscv64 -M virt -nographic -serial mon:stdio -smp 4 -m
> > >> 8g -kernel u-boot.bin -drive
> > >> format=raw,if=virtio,media=cdrom,file=openSUSE-Tumbleweed-NET-riscv64-Media.iso
> > >>
> > >
> > > This command results in an error
> > >
> > > qemu-system-riscv64: warning:
> > > No -bios option specified. Not loading a firmware.
> > >
> > > Please, provide a repo with the GRUB code you have been compiling.
> > >
> > >>
> > >> OpenSBI v0.9
> > >> _  _
> > >>/ __ \  / |  _ \_   _|
> > >>   | |  | |_ __   ___ _ __ | (___ | |_) || |
> > >>   | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
> > >>   | |__| | |_) |  __/ | | |) | |_) || |_
> > >>\/| .__/ \___|_| |_|_/|/_|
> > >>  | |
> > >>  |_|
> > >>
> > >> Platform Name : riscv-virtio,qemu
> > >> Platform Features : timer,mfdeleg
> > >> Platform HART Count   : 4
> > >> Firmware Base : 0x8000
> > >> Firmware Size : 124 KB
> > >> Runtime SBI Version   : 0.2
> > >>
> > >> Domain0 Name  : root
> > >> Domain0 Boot HART : 1
> > >> Domain0 HARTs : 0*,1*,2*,3*
> > >> Domain0 Region00  : 0x8000-0x8001 ()
> > >> Domain0 Region01  : 0x-0x (R,W,X)
> > >> Domain0 Next Address  : 0x8020
> > >> Domain0 Next Arg1 : 0xbf00
> > >> Domain0 Next Mode : S-mode
> > >> Domain0 SysReset  : yes
> > >>
> > >> Boot HART ID  : 1
> > >> Boot HART Domain  : root
> > >> Boot HART ISA : rv64imafdcsu
> > >> Boot HART Features: scounteren,mcounteren,time
> > >> Boot HART PMP Count   : 16
> > >> Boot HART PMP Granularity : 4
> > >> Boot HART PMP Address Bits: 54
> > >> Boot HART MHPM Count  : 0
> > >> Boot HART MHPM Count  : 0
> > >> Boot HART MIDELEG : 0x0222
> > >> Boot HART MEDELEG : 0xb109
> > >>
> > >>
> > >> U-Boot 2021.04 (Jun 09 2021 - 00:00:00 +)
> > >>
> > >> CPU:   rv64imafdcsu
> > >> Model: riscv-virtio,qemu
> > >> DRAM:  8 GiB
> > >> In:uart@1000
> > >> Out:   uart@1000
> > >> Err:   uart@1000
> > >> Net:   No ethernet found.
> > >> Hit any key to stop autoboot:  0
> > >>
> > >> Device 0: 1af4 VirtIO Block Device
> > >>  Type: Hard Disk
> > >>  Capacity: 225.7 MB = 0.2 GB (462376 x 512)
> > >> ... is now current device
> > >> ** Invalid partition 3 **
> > >> ** Invalid partition 4 **
> > >> ** Invalid partition 2 **
> > >> Scanning virtio 0:1...
> > >> ** Unable to read file / **
> > >> Failed to load '/'
> > >> libfdt fdt_check_header(): FDT_ERR_BADMAGIC
> > >> Scanning disk virtio-blk#8...
> > >> Found 2 disks
> > >> No EFI system partition
> > >> BootOrder not defined
> > >> EFI boot manager: Cannot load any image
> > >> Found EFI removable media binary efi/boot/bootriscv64.efi
> > >
> > > When I press 'e' in GRUB I see:
> > >
> > > setparams 'Installation'
> > > set gfxpayload=keep
> > > echo 'Loading kernel ...'
> > > linux /boot/riscv64/linux splash=silent
> > >echo 'Loading
> > > initial ramdisk ...' initrd
> > > /boot/riscv64/initrd
> > >
> > > With debug=all I get as output:
> > >
> > > kern/verifiers.c:88: file: /boot/riscv64/initrd type: 131076
> > > loader/efi/linux.c:368: LoadFile2 initrd loading protocol installed
> > >
> > > With a bit of debugging enabled in U-Boot:
> > >
> > >EFI: Call: image_obj->entry(image_handle, &systab)
> > >  EFI: Entry efi_open_protocol(ff751310,
> > > EFI_LOADED_IMAGE_PROTOCOL_GUID, ff73a6e0, ff750050,
> > > , 0x1)
> > >  EFI: Exit: efi_open_protocol: 0
> > > EFI stub: Booting Linux Kernel...
> > >  EFI: Entry efi_locate_handle_ext(2,
> > > EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, 

[PATCH v2 00/22] appended signature secure boot support

2021-06-30 Thread Daniel Axtens
This patch set contains v2 of the consolidated version of the patch
sets sent for secure boot using appended signatures on powerpc,
rebased on top of git HEAD.

The series consists of 4 main parts:

 0) Patches 1-3: powerpc-ieee1275 memory enablement.

These patches have already been posted to the mailing list and are
unchanged. I have included them here as well to make this one
monolithic series of everything needed for full support for appended
signatures on powerpc-ieee1275.


 1) Patches 4-6: signing grub.elf with an appended signature

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

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

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

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

This has attracted some controversy in the past, with suggestions that
we could avoid the ELF note by placing the signature at the end of
core.elf if the image was loaded from a filesystem or network, and by
placing it at the end of the PReP partition if it is loaded from
there. This is not currently supported by either proprietary or open
source firmware, but the current solution does not preclude this
solution being added in the future.

There was also a suggestion of allowing grub-{install,mkimage} to call
out to openssl directly to sign itself. I'm not opposed to doing this,
but as I expect signing to mostly be something done by distros rather
than the average grub-install user, I'm interested to hear any
thoughts on whether that's actually going to be useful.


 2) Patches 7 - 21: Teach grub to verify appended signatures

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

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

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

This section is composed of the following patches:
 
 - patch 7 is a small fix to allow persistent modules to work on the
   emu target.

 - patches 8 and 9 are small refactorings.

 - patch 10 prepares posix_wrap for importing libtasn1

 - patches 11 through 15 import libtasn1 and add tests. I've taken a
   different approach from gcrypt. We import gcrypt via a script that
   transforms the code into something that works for grub. Rather than
   taking that approach, we import libtasn1 through first just copying
   a subset of the code in (patch 11), then disabling parts we don't
   need for grub (patch 12), making changes for grub compatibility
   (patch 13) and then compiling it into a module (patch 14) and
   testing it (patch 15).

   This means that should we want to upgrade our version of libtasn1,
   we should be able to copy the new files in (repeat the process in
   patch 11) and then just cherry-pick/reapply patches 12 and 13 to
   repeat the process of disabling unused code and making grub
   compatiblity fixes. Hopefully that makes sense!

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

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

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

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

 - patch 20 adds tests, and patch 21 adds documentation.

This chunk is where all the v2 changes are. They're documented in the
patches themselves, but the big feature changes are: support for
Extended Key Usage, thanks to Javier Martinez; and support for
verifying a file with multiple signatures in the pkcs7 message. If any
trusted key ca

[PATCH v2 01/22] ieee1275: drop HEAP_MAX_ADDR, HEAP_MIN_SIZE

2021-06-30 Thread Daniel Axtens
HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except
on ieee1275 on x86, where it is 64MB.

There is a comment which purports to explain it:

/* If possible, we will avoid claiming heap above this address, because it
   seems to cause relocation problems with OSes that link at 4 MiB */

This doesn't make a lot of sense when the constants are well above 4MB
already. It was not always this way. Prior to
commit 7b5d0fe4440c ("Increase heap limit") in 2010, HEAP_MAX_SIZE and
HEAP_MAX_ADDR were indeed 4MB. However, when the constants were increased
the comment was left unchanged.

It's been over a decade. It doesn't seem like we have problems with
claims over 4MB on powerpc or x86 ieee1275. (sparc does things completely
differently and never used the constant.)

Drop the constant and the check.

The only use of HEAP_MIN_SIZE was to potentially override the
HEAP_MAX_ADDR check. It is now unused. Remove it.

Signed-off-by: Daniel Axtens 
---
 grub-core/kern/ieee1275/init.c | 17 -
 1 file changed, 17 deletions(-)

diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index d483e35eed2b..c5d091689f29 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -45,9 +45,6 @@
 #include 
 #endif
 
-/* The minimal heap size we can live with. */
-#define HEAP_MIN_SIZE  (unsigned long) (2 * 1024 * 1024)
-
 /* The maximum heap size we're going to claim */
 #ifdef __i386__
 #define HEAP_MAX_SIZE  (unsigned long) (64 * 1024 * 1024)
@@ -55,14 +52,6 @@
 #define HEAP_MAX_SIZE  (unsigned long) (32 * 1024 * 1024)
 #endif
 
-/* If possible, we will avoid claiming heap above this address, because it
-   seems to cause relocation problems with OSes that link at 4 MiB */
-#ifdef __i386__
-#define HEAP_MAX_ADDR  (unsigned long) (64 * 1024 * 1024)
-#else
-#define HEAP_MAX_ADDR  (unsigned long) (32 * 1024 * 1024)
-#endif
-
 extern char _start[];
 extern char _end[];
 
@@ -183,12 +172,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, 
grub_memory_type_t type,
   if (*total + len > HEAP_MAX_SIZE)
 len = HEAP_MAX_SIZE - *total;
 
-  /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */
-  if ((addr < HEAP_MAX_ADDR) &&/* if it's too 
late, don't bother */
-  (addr + len > HEAP_MAX_ADDR) &&  /* if it wasn't 
available anyway, don't bother */
-  (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE))   /* only limit 
ourselves when we can afford to */
- len = HEAP_MAX_ADDR - addr;
-
   /* In theory, firmware should already prevent this from happening by not
  listing our own image in /memory/available.  The check below is intended
  as a safeguard in case that doesn't happen.  However, it doesn't protect
-- 
2.30.2


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


[PATCH v2 02/22] ieee1275: claim more memory

2021-06-30 Thread Daniel Axtens
On powerpc-ieee1275, we are running out of memory trying to verify
anything. This is because:

 - we have to load an entire file into memory to verify it. This is
   extremely difficult to change with appended signatures.
 - We only have 32MB of heap.
 - Distro kernels are now often around 30MB.

So we want to claim more memory from OpenFirmware for our heap.

There are some complications:

 - The grub mm code isn't the only thing that will make claims on
   memory from OpenFirmware:

* PFW/SLOF will have claimed some for their own use.

* The ieee1275 loader will try to find other bits of memory that we
  haven't claimed to place the kernel and initrd when we go to boot.

* Once we load Linux, it will also try to claim memory. It claims
  memory without any reference to /memory/available, it just starts
  at min(top of RMO, 768MB) and works down. So we need to avoid this
  area. See arch/powerpc/kernel/prom_init.c as of v5.11.

 - The smallest amount of memory a ppc64 KVM guest can have is 256MB.
   It doesn't work with distro kernels but can work with custom kernels.
   We should maintain support for that. (ppc32 can boot with even less,
   and we shouldn't break that either.)

 - Even if a VM has more memory, the memory OpenFirmware makes available
   as Real Memory Area can be restricted. A freshly created LPAR on a
   PowerVM machine is likely to have only 256MB available to OpenFirmware
   even if it has many gigabytes of memory allocated.

EFI systems will attempt to allocate 1/4th of the available memory,
clamped to between 1M and 1600M. That seems like a good sort of
approach, we just need to figure out if 1/4 is the right fraction
for us.

We don't know in advance how big the kernel and initrd are going to be,
which makes figuring out how much memory we can take a bit tricky.

To figure out how much memory we should leave unused, I looked at:

 - an Ubuntu 20.04.1 ppc64le pseries KVM guest:
vmlinux: ~30MB
initrd:  ~50MB

 - a RHEL8.2 ppc64le pseries KVM guest:
vmlinux: ~30MB
initrd:  ~30MB

Ubuntu VMs struggle to boot with just 256MB under SLOF.
RHEL likewise has a higher minimum supported memory figure.
So lets first consider a distro kernel and 512MB of addressible memory.
(This is the default case for anything booting under PFW.) Say we lose
131MB to PFW (based on some tests). This leaves us 381MB. 1/4 of 381MB
is ~95MB. That should be enough to verify a 30MB vmlinux and should
leave plenty of space to load Linux and the initrd.

If we consider 256MB of RMA under PFW, we have just 125MB remaining. 1/4
of that is a smidge under 32MB, which gives us very poor odds of verifying
a distro-sized kernel. However, if we need 80MB just to put the kernel
and initrd in memory, we can't claim any more than 45MB anyway. So 1/4
will do. We'll come back to this later.

grub is always built as a 32-bit binary, even if it's loading a ppc64
kernel. So we can't address memory beyond 4GB. This gives a natural cap
of 1GB for powerpc-ieee1275.

Also apply this 1/4 approach to i386-ieee1275, but keep the 32MB cap.

make check still works for both i386 and powerpc and I've booted
powerpc grub with this change under SLOF and PFW.

Signed-off-by: Daniel Axtens 
---
 docs/grub-dev.texi |  6 ++-
 grub-core/kern/ieee1275/init.c | 81 +++---
 2 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 6c629a23e2dc..c11f1ac46de2 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -1047,7 +1047,9 @@ space is limited to 4GiB. GRUB allocates pages from EFI 
for its heap, at most
 1.6 GiB.
 
 On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275.
-It allocates at most 32MiB for its heap.
+
+On i386-ieee1275, GRUB allocates at most 32MiB for its heap. On
+powerpc-ieee1275, GRUB allocates up to 1GiB.
 
 On sparc64-ieee1275 stack is 256KiB and heap is 2MiB.
 
@@ -1075,7 +1077,7 @@ In short:
 @item i386-qemu   @tab 60 KiB  @tab < 4 GiB
 @item *-efi   @tab ?   @tab < 1.6 GiB
 @item i386-ieee1275   @tab ?   @tab < 32 MiB
-@item powerpc-ieee1275@tab ?   @tab < 32 MiB
+@item powerpc-ieee1275@tab ?   @tab < 1 GiB
 @item sparc64-ieee1275@tab 256KiB  @tab 2 MiB
 @item arm-uboot   @tab 256KiB  @tab 2 MiB
 @item mips(el)-qemu_mips  @tab 2MiB@tab 253 MiB
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index c5d091689f29..4162b5949df4 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -45,11 +45,12 @@
 #include 
 #endif
 
-/* The maximum heap size we're going to claim */
+/* The maximum heap size we're going to claim. Not used by sparc.
+   We allocate 1/4 of the available memory under 4G, up to this limit. */
 #ifdef __i386__
 #define HEAP_MAX_SIZE  (unsigned long) (64 * 1024 * 1024)
-#else
-#define HEAP_MAX_SIZE  

[PATCH v2 09/22] crypto: move storage for grub_crypto_pk_* to crypto.c

2021-06-30 Thread Daniel Axtens
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 
---
 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 2408db4994f6..355a43844acc 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 ca334d5a40e0..c578128a59db 100644
--- a/grub-core/lib/crypto.c
+++ b/grub-core/lib/crypto.c
@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
   }
 }
 
+struct gcry_pk_spec *grub_crypto_pk_dsa;
+struct gcry_pk_spec *grub_crypto_pk_ecdsa;
+struct gcry_pk_spec *grub_crypto_pk_rsa;
+
 void
 grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
  grub_size_t inlen)
-- 
2.30.2


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


[PATCH v2 03/22] ieee1275: request memory with ibm, client-architecture-support

2021-06-30 Thread Daniel Axtens
On PowerVM, the first time we boot a Linux partition, we may only get
256MB of real memory area, even if the partition has more memory.

This isn't really enough. Fortunately, the Power Architecture Platform
Reference (PAPR) defines a method we can call to ask for more memory.
This is part of the broad and powerful ibm,client-architecture-support
(CAS) method.

CAS can do an enormous amount of things on a PAPR platform: as well as
asking for memory, you can set the supported processor level, the interrupt
controller, hash vs radix mmu, and so on. We want to touch as little of
this as possible because we don't want to step on the toes of the future OS.

If:

 - we are running under what we think is PowerVM (compatible property of /
   begins with "IBM"), and

 - the full amount of RMA is less than 512MB (as determined by the reg
   property of /memory)

then call CAS as follows: (refer to the Linux on Power Architecture
Reference, LoPAR, which is public, at B.5.2.3):

 - Use the "any" PVR value and supply 2 option vectors.

 - Set option vector 1 (PowerPC Server Processor Architecture Level)
   to "ignore".

 - Set option vector 2 with default or Linux-like options, including a
   min-rma-size of 512MB.

This will cause a CAS reboot and the partition will restart with 512MB
of RMA. Grub will notice the 512MB and not call CAS again.

(A partition can be configured with only 256MB of memory, which would
mean this request couldn't be satisfied, but PFW refuses to load with
only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB,
but we will never call CAS under qemu/SLOF because /compatible won't
begin with "IBM".)

One of the first things Linux does while still running under OpenFirmware
is to call CAS with a much fuller set of options (including asking for
512MB of memory). This includes a much more restrictive set of PVR values
and processor support levels, and this will induce another reboot. On this
reboot grub will again notice the higher RMA, and not call CAS. We will get
to Linux, Linux will call CAS but because the values are now set for Linux
this will not induce another CAS reboot and we will finally boot.

On all subsequent boots, everything will be configured with 512MB of RMA
and all the settings Linux likes, so there will be no further CAS reboots.

(phyp is super sticky with the RMA size - it persists even on cold boots.
So if you've ever booted Linux in a partition, you'll probably never have
grub call CAS. It'll only ever fire the first time a partition loads grub,
or if you deliberately lower the amount of memory your partition has below
512MB.)

Signed-off-by: Daniel Axtens 
---
 grub-core/kern/ieee1275/cmain.c  |   3 +
 grub-core/kern/ieee1275/init.c   | 144 ++-
 include/grub/ieee1275/ieee1275.h |   6 ++
 3 files changed, 151 insertions(+), 2 deletions(-)

diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c
index 20cbbd761ec3..cc98811f4f99 100644
--- a/grub-core/kern/ieee1275/cmain.c
+++ b/grub-core/kern/ieee1275/cmain.c
@@ -124,6 +124,9 @@ grub_ieee1275_find_options (void)
  break;
}
}
+
+  if (grub_strncmp (tmp, "IBM,", 4) == 0)
+   grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY);
 }
 
   if (is_smartfirmware)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 4162b5949df4..4586bec939b2 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -240,6 +240,135 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, 
grub_memory_type_t type,
   return 0;
 }
 
+/* How much memory does OF believe it has? (regardless of whether
+   it's accessible or not) */
+static grub_err_t
+grub_ieee1275_total_mem (grub_uint64_t *total)
+{
+  grub_ieee1275_phandle_t root;
+  grub_ieee1275_phandle_t memory;
+  grub_uint32_t reg[4];
+  grub_ssize_t reg_size;
+  grub_uint32_t address_cells = 1;
+  grub_uint32_t size_cells = 1;
+  grub_uint64_t size;
+
+  /* If we fail to get to the end, report 0. */
+  *total = 0;
+
+  /* Determine the format of each entry in `reg'.  */
+  grub_ieee1275_finddevice ("/", &root);
+  grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
+ sizeof address_cells, 0);
+  grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
+ sizeof size_cells, 0);
+
+  if (size_cells > address_cells)
+address_cells = size_cells;
+
+  /* Load `/memory/reg'.  */
+  if (grub_ieee1275_finddevice ("/memory", &memory))
+return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+  "couldn't find /memory node");
+  if (grub_ieee1275_get_integer_property (memory, "reg", reg,
+ sizeof reg, ®_size))
+return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+  "couldn't examine /memory/reg property");
+  if (reg_size < 0 || (grub_size_t) reg_size 

[PATCH v2 07/22] dl: provide a fake grub_dl_set_persistent for the emu target

2021-06-30 Thread Daniel Axtens
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 
---
 include/grub/dl.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/include/grub/dl.h b/include/grub/dl.h
index b3753c9ca262..5decbe2f2fb9 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)
-- 
2.30.2


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


[PATCH v2 04/22] Add suport for signing grub with an appended signature

2021-06-30 Thread Daniel Axtens
From: Rashmica Gupta 

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 
Signed-off-by: Rashmica Gupta 

---

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).
---
 include/grub/util/install.h |  8 ++--
 include/grub/util/mkimage.h |  4 ++--
 util/grub-install-common.c  | 15 +++---
 util/grub-mkimage.c | 11 +++
 util/grub-mkimagexx.c   | 39 -
 util/mkimage.c  | 13 +++--
 6 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 7df3191f47ef..cf4531e02b66 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -67,6 +67,9 @@
   N_("SBAT metadata"), 0 },
\
   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \
   N_("disable shim_lock verifier"), 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 }
 
@@ -128,7 +131,8 @@ enum grub_install_options {
   GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
   GRUB_INSTALL_OPTIONS_DTB,
   GRUB_INSTALL_OPTIONS_SBAT,
-  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK
+  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
+  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
 };
 
 extern char *grub_install_source_directory;
@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char 
*prefix,
 size_t npubkeys,
 char *config_path,
 const struct grub_install_image_target_desc 
*image_target,
-int note,
+int note, size_t appsig_size,
 grub_compression_t comp, const char *dtb_file,
 const char *sbat_path, const int 
disable_shim_lock);
 
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
index 3819a67441c8..6f1da89b9b65 100644
--- a/include/grub/util/mkimage.h
+++ b/include/grub/util/mkimage.h
@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
   const struct grub_install_image_target_desc 
*image_target);
 void
 grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc 
*image_target,
-int note, char **core_img, size_t *core_size,
+int note, size_t appsig_size, char **core_img, 
size_t *core_size,
 Elf32_Addr target_addr,
 struct grub_mkimage_layout *layout);
 void
 grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc 
*image_target,
-int note, char **core_img, size_t *core_size,
+int note, size_t appsig_size, char **core_img, 
size_t *core_size,
 Elf64_Addr target_addr,
 struct grub_mkimage_layout *layout);
 
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 4e212e690c52..1216a203c292 100644
--- a/util/grub-install-common.c
+++ b/util/grub-ins

[PATCH v2 12/22] libtasn1: disable code not needed in grub

2021-06-30 Thread Daniel Axtens
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 
---
 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 245ea64cf0aa..52def5983685 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 
 #include "element.h"
-#include "minmax.h"
 #include 
 
 #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 ff04eb778cba..42f9a92b5d44 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 997eb2725dca..539008d8e949 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 cee74daf7959..42785e8622b7 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 8189c56a4c93..fcfde01a3930 100644
--- a/grub-core/lib/libtasn1/lib/structure.c
+++ b/grub-core/lib/libtasn1/lib/structure.c
@@ -76,7 +76,7 @@ _asn

[PATCH v2 05/22] docs/grub: Document signing grub under UEFI

2021-06-30 Thread Daniel Axtens
Before adding information about how grub is signed with an appended
signature scheme, it's worth adding some information about how it
can currently be signed for UEFI.

Signed-off-by: Daniel Axtens 
---
 docs/grub.texi | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index f8b4b3b21a7f..2ffc3b417312 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5795,6 +5795,7 @@ environment variables and commands are listed in the same 
order.
 * Secure Boot Advanced Targeting::   Embedded information for generation 
number based revocation
 * Measured Boot::Measuring boot components
 * Lockdown:: Lockdown when booting on a secure setup
+* Signing GRUB itself::  Ensuring the integrity of the GRUB core 
image
 @end menu
 
 @node Authentication and authorisation
@@ -5873,7 +5874,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}
@@ -6035,6 +6036,25 @@ be restricted and some operations/commands cannot be 
executed.
 The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
 Otherwise it does not exit.
 
+@node Signing GRUB itself
+@section Signing GRUB itself
+
+To ensure a complete secure-boot chain, there must be a way for the code that
+loads GRUB to verify the integrity of the core image.
+
+This is ultimately platform-specific and individual platforms can define their
+own mechanisms. However, there are general-purpose mechanisms that can be used
+with GRUB.
+
+@section Signing GRUB for UEFI secure boot
+
+On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
+with a tool such as @command{pesign} or @command{sbsign}. Refer to the
+suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
+image works under UEFI secure boot and can maintain the secure-boot chain. It
+will also be necessary to enrol the public key used into a relevant firmware
+key database.
+
 @node Platform limitations
 @chapter Platform limitations
 
-- 
2.30.2


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


[PATCH v2 08/22] pgp: factor out rsa_pad

2021-06-30 Thread Daniel Axtens
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 
---
 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 8022e1c0a794..915287d44c13 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2469,6 +2469,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 5daa1e9d00c7..2408db4994f6 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -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 ..dbacd563d014
--- /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 .
+ */
+
+#include 
+#include 
+
+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 ..5c338c84a158
--- /dev/null
+++ b/include/grub/pkcs1_v15.h
@@ -0,0 +1,27 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GR

[PATCH v2 06/22] docs/grub: Document signing grub with an appended signature

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

Signed-off-by: Daniel Axtens 
---
 docs/grub.texi | 42 ++
 1 file changed, 42 insertions(+)

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


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


[PATCH v2 10/22] posix_wrap: tweaks in preparation for libtasn1

2021-06-30 Thread Daniel Axtens
 - 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 
---
 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 7217138ffd6b..591dbf3289d8 100644
--- a/grub-core/lib/posix_wrap/limits.h
+++ b/grub-core/lib/posix_wrap/limits.h
@@ -37,5 +37,6 @@
 #define LONG_MAX GRUB_LONG_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 7a8d385e973a..4634db09f294 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 854eb0122efa..f63412c8da06 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
-- 
2.30.2


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


[PATCH v2 20/22] appended signatures: verification tests

2021-06-30 Thread Daniel Axtens
These tests are run through all_functional_test and test a range
of commands and behaviours.

Signed-off-by: Daniel Axtens 

---

v2 changes:

  - add a test for EKU
  - add tests for files signed with multiple signers
  - add a test of padded PKCS#7 messages
  - use macros to reduce duplication for exposing certificate files
 to the test via procfs
  - more useful comments
---
 grub-core/Makefile.core.def   |   6 +
 grub-core/tests/appended_signature_test.c | 273 ++
 grub-core/tests/appended_signatures.h | 975 ++
 grub-core/tests/lib/functional_test.c |   1 +
 4 files changed, 1255 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 beeedd8ca356..4aa4cf263d94 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2131,6 +2131,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 ..5365185cb5cc
--- /dev/null
+++ b/grub-core/tests/appended_signature_test.c
@@ -0,0 +1,273 @@
+/*
+ *  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 .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "appended_signatures.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define PROC_FILE(identifier, file_name) \
+static char * \
+get_ ## identifier (grub_size_t *sz) \
+{ \
+  char *ret; \
+  \
+  *sz = identifier ## _len; \
+  ret = grub_malloc (*sz); \
+  if (ret) \
+grub_memcpy (ret, identifier, *sz); \
+  return ret; \
+} \
+\
+static struct grub_procfs_entry identifier ## _entry = \
+{ \
+  .name = file_name, \
+  .get_contents = get_ ## identifier \
+};
+
+#define DEFINE_TEST_CASE(case_name) PROC_FILE(case_name, #case_name)
+
+#define DO_TEST(case_name, is_valid) \
+{ \
+  grub_procfs_register (#case_name, &case_name ## _entry); \
+  do_verify ("(proc)/" #case_name, is_valid); \
+  grub_procfs_unregister (&case_name ## _entry); \
+}
+
+
+DEFINE_TEST_CASE (hi_signed);
+DEFINE_TEST_CASE (hi_signed_sha256);
+DEFINE_TEST_CASE (hj_signed);
+DEFINE_TEST_CASE (short_msg);
+DEFINE_TEST_CASE (unsigned_msg);
+DEFINE_TEST_CASE (hi_signed_2nd);
+DEFINE_TEST_CASE (hi_double);
+DEFINE_TEST_CASE (hi_double_extended);
+
+PROC_FILE (certificate_der, "certificate.der")
+PROC_FILE (certificate2_der, "certificate2.der")
+PROC_FILE (certificate_printable_der, "certificate_printable.der")
+PROC_FILE (certificate_eku_der, "certificate_eku.der")
+
+static void
+do_verify (const char *f, int is_valid)
+{
+  grub_command_t cmd;
+  char *args[] = { (char *) f, NULL };
+  grub_err_t err;
+
+  cmd = grub_command_find ("verify_appended");
+  if (!cmd)
+{
+  grub_test_assert (0, "can't find command `%s'", "verify_appended");
+  return;
+}
+  err = (cmd->func) (cmd, 1, args);
+  if (is_valid)
+{
+  grub_test_assert (err == GRUB_ERR_NONE,
+   "verification of %s failed: %d: %s", f, grub_errno,
+   grub_errmsg);
+}
+  else
+{
+  grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE,
+   "verification of %s unexpectedly succeeded", f);
+}
+  grub_errno = GRUB_ERR_NONE;
+
+}
+
+static void
+appended_signature_test (void)
+{
+  grub_command_t cmd_trust, cmd_distrust;
+  char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
+  char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
+  char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der",
+  NULL };
+  char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL };
+  char *distrust_args[] = { (char *) "1", NULL };
+  char *distrust2_args[] = { (char *) "2", NULL };
+  grub_err_t err;
+
+  grub_procfs_register ("certificate.der", &certificate_der_entry);
+  grub_procfs_register ("certificate2.der", &certificate2_der_entry);
+  grub_pr

[PATCH v2 16/22] grub-install: support embedding x509 certificates

2021-06-30 Thread Daniel Axtens
From: Alastair D'Silva 

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 
Signed-off-by: Daniel Axtens 
---
 grub-core/commands/pgp.c|  2 +-
 include/grub/kernel.h   |  3 ++-
 include/grub/util/install.h |  7 +--
 util/grub-install-common.c  | 22 +++-
 util/grub-mkimage.c | 15 --
 util/mkimage.c  | 41 ++---
 6 files changed, 80 insertions(+), 10 deletions(-)

diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
index 355a43844acc..b81ac0ae46ce 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
 grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
 
 /* Not an ELF module, skip.  */
-if (header->type != OBJ_TYPE_PUBKEY)
+if (header->type != OBJ_TYPE_GPG_PUBKEY)
   continue;
 
 pseudo_file.fs = &pseudo_fs;
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index abbca5ea3359..d3aafc8848d2 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,
   OBJ_TYPE_DISABLE_SHIM_LOCK
 };
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index cf4531e02b66..51f3b13ac130 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -67,6 +67,8 @@
   N_("SBAT metadata"), 0 },
\
   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \
   N_("disable shim_lock verifier"), 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}, \
@@ -188,8 +190,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/util/grub-install-common.c b/util/grub-install-common.c
index 1216a203c292..7bfa9752a031 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -460,6 +460,8 @@ static char **pubkeys;
 static size_t npubkeys;
 static char *sbat;
 static int disable_shim_lock;
+static char **x509keys;
+static size_t nx509keys;
 static grub_compression_t compression;
 static size_t appsig_size;
 
@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg)
 case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK:
   disable_shim_lock = 1;
   return 1;
+case 'x':
+  x509keys = xrealloc (x509keys,
+ sizeof (x509keys[0])
+ * (nx509keys + 1));
+  x509keys[nx509keys++] = xstrdup (arg);
+  return 1;
 
 case GRUB_INSTALL_OPTIONS_VERBOSITY:
   verbosity++;
@@ -627,6 +635,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);
@@ -655,6 +666,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++ = '\'';
@@ -683,7 +702,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,
+  pubkeys, npubkeys, x509keys, nx509keys,
+  

[PATCH v2 13/22] libtasn1: changes for grub compatibility

2021-06-30 Thread Daniel Axtens
Do a few things to make libtasn1 compile as part of grub:

 - redefine _asn1_strcat. grub removed strcat so replace it with the
   appropriate calls to memcpy and strlen. Use this internally where
   strcat was used.

 - 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 

---

v2: Clean up strcat handling, thanks Stefan Berger.
---
 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/int.h|  4 ++--
 grub-core/lib/libtasn1/lib/parser_aux.c |  7 ---
 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 42f9a92b5d44..3406e1832746 100644
--- a/grub-core/lib/libtasn1/lib/decoding.c
+++ b/grub-core/lib/libtasn1/lib/decoding.c
@@ -32,7 +32,8 @@
 #include 
 #include 
 #include 
-#include 
+
+#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);
+ _asn1_strcat (name, ".");
+ _asn1_strcat (name, p2->name);
 
  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);
+ _asn1_strcat (name, ".");
+ _asn1_strcat (name, p2->name);
 
  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 539008d8e949..ed761ff56bd9 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 
 #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 e91a3a151c0d..a092c9a5a24b 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);
+  _asn1_strcat (dest, src);
 }
   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/int.h b/grub-core/lib/libtasn1/lib/int.h
index ea1625786c1b..4a568efee9c1 100644
--- a/grub-core/lib/libtasn1/lib/int.h
+++ b/grub-core/lib/libtasn1/lib/int.h
@@ -35,7 +35,7 @@
 #include 
 #endif
 
-#include 
+#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/grub-core/lib/libtasn1/lib/parser_aux.c 
b/grub-core/lib/libtasn1/lib/parser_aux.c
index d5dbbf8765da..89c9be69dc2a 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"
-

[PATCH v2 17/22] appended signatures: import GNUTLS's ASN.1 description files

2021-06-30 Thread Daniel Axtens
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 
---
 .../commands/appendedsig/gnutls_asn1_tab.c| 121 +
 .../commands/appendedsig/pkix_asn1_tab.c  | 484 ++
 2 files changed, 605 insertions(+)
 create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
 create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c

diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c 
b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
new file mode 100644
index ..ddd1314e63b6
--- /dev/null
+++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
@@ -0,0 +1,121 @@
+#include 
+#include 
+
+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 },
+  {

[PATCH v2 14/22] libtasn1: compile into asn1 module

2021-06-30 Thread Daniel Axtens
Create a wrapper file that specifies the module license.
Set up the makefile so it is built.

Signed-off-by: Daniel Axtens 
---
 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 915287d44c13..6fbae150c687 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2535,3 +2535,18 @@ module = {
   common = commands/i386/wrmsr.c;
   enable = x86;
 };
+
+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 ..622ba942e33f
--- /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 .
+ */
+
+#include 
+
+/*
+ * 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+");
-- 
2.30.2


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


[PATCH v2 18/22] appended signatures: parse PKCS#7 signedData and X.509 certificates

2021-06-30 Thread Daniel Axtens
This code allows us to parse:

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

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

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

Signed-off-by: Javier Martinez Canillas  # EKU support
Signed-off-by: Daniel Axtens 

---

v2 changes:

 - Handle the Extended Key Usage extension
 - Fix 2 leaks in x509 cert parsing
 - Improve x509 parser function name
 - Constify the data parameter in parser signatures
 - Support multiple signers in a pkcs7 message. Accept any passing sig.
 - Allow padding after a pkcs7 message in an appended signature, required
to support my model for signers separated in time.
 - Fix a test that used GRUB_ERR_NONE rather than ASN1_SUCCESS. They're
both 0 so no harm was done, but better to be correct.
 - Various code and comment cleanups.

Thanks to Nayna Jain and Stefan Berger for their reviews.

revert

Signed-off-by: Daniel Axtens 
---
 grub-core/commands/appendedsig/appendedsig.h |  118 ++
 grub-core/commands/appendedsig/asn1util.c|  103 ++
 grub-core/commands/appendedsig/pkcs7.c   |  509 +
 grub-core/commands/appendedsig/x509.c| 1079 ++
 4 files changed, 1809 insertions(+)
 create mode 100644 grub-core/commands/appendedsig/appendedsig.h
 create mode 100644 grub-core/commands/appendedsig/asn1util.c
 create mode 100644 grub-core/commands/appendedsig/pkcs7.c
 create mode 100644 grub-core/commands/appendedsig/x509.c

diff --git a/grub-core/commands/appendedsig/appendedsig.h 
b/grub-core/commands/appendedsig/appendedsig.h
new file mode 100644
index ..327d68ddb1b7
--- /dev/null
+++ b/grub-core/commands/appendedsig/appendedsig.h
@@ -0,0 +1,118 @@
+/*
+ *  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 .
+ */
+
+#include 
+#include 
+
+extern asn1_node _gnutls_gnutls_asn;
+extern asn1_node _gnutls_pkix_asn;
+
+#define MAX_OID_LEN 32
+
+/*
+ * One or more x509 certificates.
+ *
+ * We do limited parsing: extracting only the serial, CN and RSA public key.
+ */
+struct x509_certificate
+{
+  struct x509_certificate *next;
+
+  grub_uint8_t *serial;
+  grub_size_t serial_len;
+
+  char *subject;
+  grub_size_t subject_len;
+
+  /* We only support RSA public keys. This encodes [modulus, publicExponent] */
+  gcry_mpi_t mpis[2];
+};
+
+/*
+ * A PKCS#7 signedData signerInfo.
+ */
+struct pkcs7_signerInfo
+{
+  const gcry_md_spec_t *hash;
+  gcry_mpi_t sig_mpi;
+};
+
+/*
+ * A PKCS#7 signedData message.
+ *
+ * We make no attempt to match intelligently, so we don't save any info about
+ * the signer.
+ */
+struct pkcs7_signedData
+{
+  int signerInfo_count;
+  struct pkcs7_signerInfo *signerInfos;
+};
+
+
+/* Do libtasn1 init */
+int asn1_init (void);
+
+/*
+ * Import a DER-encoded certificate at 'data', of size 'size'.
+ *
+ * Place the results into 'results', which must be already allocated.
+ */
+grub_err_t
+parse_x509_certificate (const void *data, grub_size_t size,
+   struct x509_certificate *results);
+
+/*
+ * Release all the storage associated with the x509 certificate.
+ * If the caller dynamically allocated the certificate, it must free it.
+ * The caller is also responsible for maintenance of the linked list.
+ */
+void certificate_release (struct x509_certificate *cert);
+
+/*
+ * Parse a PKCS#7 message, which must be a signedData message.
+ *
+ * The message must be in 'sigbuf' and of size 'data_size'. The result is
+ * placed in 'msg', which must already be allocated.
+ */
+grub_err_t
+parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size,
+   struct pkcs7_signedData *msg);
+
+/*
+ * Release all the storage associated with the PKCS#7 message.
+ * If the caller dynami

[PATCH v2 22/22] ieee1275: enter lockdown based on /ibm,secure-boot

2021-06-30 Thread Daniel Axtens
If the 'ibm,secure-boot' property of the root node is 2 or greater,
enter lockdown.

Signed-off-by: Daniel Axtens 
---
 docs/grub.texi |  4 ++--
 grub-core/Makefile.core.def|  1 +
 grub-core/kern/ieee1275/init.c | 27 +++
 include/grub/lockdown.h|  3 ++-
 4 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 02fcda11e3bd..b13316cdb491 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6189,8 +6189,8 @@ Measured boot is currently only supported on EFI 
platforms.
 @section Lockdown when booting on a secure setup
 
 The GRUB can be locked down when booted on a secure boot environment, for 
example
-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB 
will
-be restricted and some operations/commands cannot be executed.
+if UEFI or Power secure boot is enabled. On a locked down configuration, the
+GRUB will be restricted and some operations/commands cannot be executed.
 
 The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
 Otherwise it does not exit.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 4aa4cf263d94..775a031f1843 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -317,6 +317,7 @@ kernel = {
   powerpc_ieee1275 = kern/powerpc/cache.S;
   powerpc_ieee1275 = kern/powerpc/dl.c;
   powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
+  powerpc_ieee1275 = kern/lockdown.c;
 
   sparc64_ieee1275 = kern/sparc64/cache.S;
   sparc64_ieee1275 = kern/sparc64/dl.c;
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 4586bec939b2..5faf4e736074 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -44,6 +44,7 @@
 #ifdef __sparc__
 #include 
 #endif
+#include 
 
 /* The maximum heap size we're going to claim. Not used by sparc.
We allocate 1/4 of the available memory under 4G, up to this limit. */
@@ -442,6 +443,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_lockdown ();
+}
+
 grub_addr_t grub_modbase;
 
 void
@@ -467,6 +492,8 @@ grub_machine_init (void)
 #else
   grub_install_get_time_ms (grub_rtc_get_time_ms);
 #endif
+
+  grub_get_ieee1275_secure_boot ();
 }
 
 void
diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
index 40531fa823bf..ebfee4bf06e7 100644
--- a/include/grub/lockdown.h
+++ b/include/grub/lockdown.h
@@ -24,7 +24,8 @@
 #define GRUB_LOCKDOWN_DISABLED   0
 #define GRUB_LOCKDOWN_ENABLED1
 
-#ifdef GRUB_MACHINE_EFI
+#if defined(GRUB_MACHINE_EFI) || \
+(defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
 extern void
 EXPORT_FUNC (grub_lockdown) (void);
 extern int
-- 
2.30.2


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


[PATCH v2 19/22] appended signatures: support verifying appended signatures

2021-06-30 Thread Daniel Axtens
Building on the parsers and the ability to embed x509 certificates, as
well as the existing gcrypt functionality, add a module for verifying
appended signatures.

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

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

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

Signed-off-by: Daniel Axtens 

---

v2 changes:

 - Improve x509 parser function name
 - Constify data parameters in function signatures
 - Support multiple signers
 - Use an enum rather than 0, 1 and 2 for various signature
enforcement states.
 - Spin out a file reading function that was duplicated.
 - Fix some code style and clarity issues.

Thanks to Nayna Jain and Stefan Berger for their reviews.

Revert "fixups so that you can build pkcs7 without posixly"

This reverts commit 676a19fa8a7f9cca7a58ce2180110f609185b2bd.
---
 grub-core/Makefile.core.def  |  14 +
 grub-core/commands/appendedsig/appendedsig.c | 669 +++
 include/grub/file.h  |   2 +
 3 files changed, 685 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 d63f216111ca..beeedd8ca356 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -946,6 +946,20 @@ module = {
   cppflags = '-I$(srcdir)/lib/posix_wrap';
 };
 
+module = {
+  name = appendedsig;
+  common = commands/appendedsig/appendedsig.c;
+  common = commands/appendedsig/x509.c;
+  common = commands/appendedsig/pkcs7.c;
+  common = commands/appendedsig/asn1util.c;
+  common = commands/appendedsig/gnutls_asn1_tab.c;
+  common = commands/appendedsig/pkix_asn1_tab.c;
+
+  // posix wrapper required for gcry to get sys/types.h
+  cflags = '$(CFLAGS_POSIX)';
+  cppflags = '-I$(srcdir)/lib/posix_wrap';
+};
+
 module = {
   name = hdparm;
   common = commands/hdparm.c;
diff --git a/grub-core/commands/appendedsig/appendedsig.c 
b/grub-core/commands/appendedsig/appendedsig.c
new file mode 100644
index ..e63ad1ac645a
--- /dev/null
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -0,0 +1,669 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020-2021  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 .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 s

[PATCH v2 21/22] appended signatures: documentation

2021-06-30 Thread Daniel Axtens
This explains how appended signatures can be used to form part of
a secure boot chain, and documents the commands and variables
introduced.

Signed-off-by: Daniel Axtens 

---

v2: fix a grammar issue, thanks Stefan Berger.
---
 docs/grub.texi | 193 -
 1 file changed, 176 insertions(+), 17 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index bed565371460..02fcda11e3bd 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3209,6 +3209,7 @@ These variables have special meaning to GRUB.
 
 @menu
 * biosnum::
+* check_appended_signatures::
 * check_signatures::
 * chosen::
 * cmdpath::
@@ -3268,11 +3269,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
@@ -3989,6 +3997,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
@@ -4005,6 +4014,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
@@ -4042,8 +4052,10 @@ 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
 @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
@@ -4371,9 +4383,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
 
@@ -4631,6 +4662,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
 
@@ -4650,7 +4696,7 @@ The output is in GPG's v4 key fingerprint format (i