2023-07-10 15:43:08 +00:00
|
|
|
---
|
|
|
|
title: Hardening GRUB
|
|
|
|
x-toc-enable: true
|
|
|
|
...
|
|
|
|
|
|
|
|
This article only applies to those people who use the GRUB bootloader as
|
|
|
|
their default payload (options besides GRUB are also available in
|
2023-10-26 00:10:41 +00:00
|
|
|
Canoeboot). Whenever this article refers to GRUB, or configuration files
|
2023-07-10 15:43:08 +00:00
|
|
|
used in GRUB, it is referring exclusively to those files hosted in CBFS
|
2023-10-26 00:10:41 +00:00
|
|
|
(coreboot file system) in the Canoeboot ROM image. In this configuration,
|
2023-07-10 15:43:08 +00:00
|
|
|
GRUB is running on *bare metal* as a coreboot payload (instead of relying on
|
|
|
|
BIOS or UEFI services, like it does on *most* x86 based configurations).
|
|
|
|
|
|
|
|
This guide deals with various ways in which you can harden your GRUB
|
|
|
|
configuration, for security purposes. These steps are optional, but *strongly*
|
2023-10-26 00:10:41 +00:00
|
|
|
recommended by the Canoeboot project.
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
GRUB provides *many* advanced security features, which most people don't
|
2023-10-26 00:10:41 +00:00
|
|
|
know about but are fully documented on the Canoeboot website. Read on!
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
This article doesn't cover how to dump your ROM, or flash a new one. Please
|
2023-10-26 00:10:41 +00:00
|
|
|
read other sections in the Canoeboot documentation if you don't know how to do
|
2023-07-10 15:43:08 +00:00
|
|
|
that. As such, this is an *expert only* guide. There is a great possibility for
|
|
|
|
bricking your system if you follow this guide incorrectly, or otherwise don't
|
|
|
|
know what you're doing.
|
|
|
|
|
|
|
|
GRUB secure boot with GPG
|
|
|
|
=========================
|
|
|
|
|
|
|
|
GRUB contains code, based on [GPG](https://gnupg.org/), that can verify
|
|
|
|
PGP signatures on *any* type of file, on any storage medium supported by
|
|
|
|
GRUB (it supports basically everything, including CBFS which is short
|
|
|
|
for coreboot file system and it is what we will focus on in this article).
|
2023-10-26 00:10:41 +00:00
|
|
|
We will be using this functionality to verify the signature of a Linux kernel,
|
|
|
|
at boot time. In conjunction with reproducible builds (both Canoeboot and your
|
extreme cleanup / grandiose gesture
make canoeboot a truly GNU FSDG compliant coreboot distro,
by removing all overly positive reference to Libreboot;
what remains is technical in nature, so as to provide
historical context since Canoeboot is a fork of Libreboot.
I've stated before that I wish to take a more neutral tone
toward the FSF, in contrast to the *coldboot war* of 2023
when GNU Boot started.
Canoeboot was heavily linking to Libreboot, even going so far
as to call itself "inferior" and tell the reader to use
Libreboot.
From now on, Canoeboot will be maintained as though I actually
believed in FSF propoganda. I don't, but its users do. Treat
them with respect. My reason for providing Canoeboot is
precisely that I wish for such people to have a high quality
coreboot distro, much unlike the inferior *GNU Boot* project;
inferior because to this day, it's still based on very old
Libreboot, with not much changed (of any real substance)
relative to the Libreboot 20220710 release on which it forked.
In general, I've also found a lot of stragglers from when
Canoeboot started, where paragraphs referred to Libreboot that
should have actually referred to Canoeboot, or paragraphs
with Libreboot-specific information that does not make sense
in the Canoeboot project e.g. references to vendor scripts.
The resulting canoeboot.org will now look no different to any
typical reader than a typical FSF-aligned project.
There is a next stage to this, which will become apparent to
everyone if I have my way.
Signed-off-by: Leah Rowe <info@minifree.org>
2024-05-10 02:12:44 +00:00
|
|
|
GNU+Linux kernel), this can greatly improve system security.
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
For your reference: a reproducible build is one where, given a precise (and
|
|
|
|
well documented) development setup, the exact same binary can be produced each
|
|
|
|
time the source code is compiled when that *very same development setup* is
|
|
|
|
replicated by another person. In other words, the file checksum (e.g.
|
|
|
|
SHA512 hash) will be exactly the same at all times. In practise, this means
|
|
|
|
that metadata such as time stamps are not included in the binary, or if they
|
|
|
|
are, they are constant (in many scenarios, it's based on the date of a Git
|
|
|
|
commit ID that the build is based on, if the software is built from a Git
|
|
|
|
repository). More information about reproducible builds can be found here:
|
|
|
|
|
|
|
|
<https://reproducible-builds.org/>
|
|
|
|
|
2023-10-26 00:10:41 +00:00
|
|
|
Reproducibility is a key goal of the Canoeboot project, though it has not yet
|
2023-07-10 15:43:08 +00:00
|
|
|
achieved that goal. However, it is an important part of any secure system. We
|
2023-10-26 00:10:41 +00:00
|
|
|
suggest that, when securing your Canoeboot system as instructed by this guide,
|
2023-07-17 15:45:56 +00:00
|
|
|
you should also use a reproducible GNU+Linux distribution (because checking GPG
|
|
|
|
signatures on a non-reproducible binary, such as a GNU+Linux kernel, is meaningless
|
2023-07-10 15:43:08 +00:00
|
|
|
if that binary can be compromised as a result of literally not being able to
|
|
|
|
verify that the source code *actually* corresponds to the provided binary,
|
|
|
|
which is exactly what reproducible builds allow). If *someone else* compiles an
|
|
|
|
executable for you, and that executable is non-reproducible, you have no way to
|
|
|
|
verify that the source code they provided *actually* corresponds to the binary
|
|
|
|
they gave you. Based on these facts, we can observe that checking GPG
|
|
|
|
signatures will improve your *operational* security, but only in specific
|
|
|
|
circumstances under *controlled conditions*.
|
|
|
|
|
2023-10-26 00:10:41 +00:00
|
|
|
This tutorial assumes you have a Canoeboot image (ROM) that you wish to modify,
|
2023-07-10 15:43:08 +00:00
|
|
|
which from now on we will refer to simply as *`my.rom`*. It should go without
|
|
|
|
saying that this ROM uses the GRUB bootloader as payload. This page shows
|
|
|
|
how to modify grubtest.cfg, which means that signing and password protection
|
|
|
|
will work after switching to it in the main boot menu and bricking due to
|
|
|
|
incorrect configuration will be impossible. After you are satisfied with the
|
|
|
|
new setup, you should transfer the new settings to grub.cfg to make your
|
|
|
|
machine truly secure.
|
|
|
|
|
2023-10-26 00:10:41 +00:00
|
|
|
First, extract the old grubtest.cfg and remove it from the Canoeboot
|
2023-07-10 15:43:08 +00:00
|
|
|
image:
|
|
|
|
|
|
|
|
cbfstool my.rom extract -n grubtest.cfg -f my.grubtest.cfg
|
|
|
|
cbfstool my.rom remove -n grubtest.cfg
|
|
|
|
|
2023-10-26 00:10:41 +00:00
|
|
|
You can build `cbfstool` in the Canoeboot build system. Run this command:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-23 00:28:08 +00:00
|
|
|
./mk -d coreboot TREENAME
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
This, in turn, assumes that you have installed the build dependencies for
|
2023-10-26 00:10:41 +00:00
|
|
|
Canoeboot. On Ubuntu 20.04 and other apt-get distros, you can do this:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-23 00:28:08 +00:00
|
|
|
./mk dependencies ubuntu2004
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
The `cbfstool` executables will be under each coreboot directory, under
|
|
|
|
each `coreboot/boardname/` directory for each board. Just pick one, presumably
|
2023-10-26 00:10:41 +00:00
|
|
|
from the coreboot directory for your board. Canoeboot creates multiple coreboot
|
2023-07-10 15:43:08 +00:00
|
|
|
archives for different board revisions, on different boards.
|
|
|
|
|
|
|
|
References:
|
|
|
|
|
|
|
|
* [GRUB manual](https://www.gnu.org/software/grub/manual/html_node/Security.html#Security)
|
|
|
|
* [GRUB info pages](http://git.savannah.gnu.org/cgit/grub.git/tree/docs/grub.texi)
|
|
|
|
* [SATA connected storage considered dangerous.](../../faq.md#hddssd-firmware)
|
|
|
|
* [Coreboot GRUB security howto](https://www.coreboot.org/GRUB2#Security)
|
|
|
|
|
|
|
|
GRUB Password
|
|
|
|
=============
|
|
|
|
|
|
|
|
The security of this setup depends on a good GRUB password as GPG signature
|
|
|
|
checking can be disabled through the interactive console:
|
|
|
|
|
|
|
|
set check_signatures=no
|
|
|
|
|
|
|
|
This is useful because it allows you to occasionally boot unsigned live CD/USB
|
|
|
|
media and such. You might consider supplying signatures on a USB stick, but the
|
|
|
|
signature checking code currently looks for `/path/to/filename.sig` when
|
|
|
|
verifying `/path/to/filename` and, as such, it will be impossible to supply
|
|
|
|
signatures in any other location (unless the software is modified accordingly).
|
|
|
|
|
|
|
|
It's worth noting that this is not your LUKS password but, rather, a password
|
|
|
|
that you must enter in order to use *restricted* functionality (such as the
|
|
|
|
GRUB terminal for executing commands). This behaviour protects your system
|
2023-07-17 15:45:56 +00:00
|
|
|
from an attacker simply booting a live USB key (e.g. live GNU+Linux
|
2023-07-10 15:43:08 +00:00
|
|
|
distribution) for the purpose of flashing modified boot firmware, which from
|
|
|
|
your perspective is *compromised* boot firmware. *This should be different than
|
|
|
|
your LUKS passphrase and user password.*
|
|
|
|
|
|
|
|
GRUB supports storing salted, hashed passwords in the configuration file.
|
|
|
|
This is a far more secure configuration, because an attacker cannot simply read
|
|
|
|
your password as *plain text* inside said file.
|
|
|
|
|
|
|
|
Use of the *diceware method* is *strongly* recommended, for generating secure
|
|
|
|
passphrases (as opposed to passwords). The diceware method involves rolling
|
|
|
|
dice to generate random numbers, which are then used as an index to pick a
|
|
|
|
random word from a large dictionary of words. You can use any language (e.g.
|
|
|
|
English, German). Look it up on a search engine. Diceware method is a way to
|
|
|
|
generate secure passphrases that are very hard (almost impossible, with enough
|
|
|
|
words) to crack, while being easy enough to remember. On the other hand, most
|
|
|
|
kinds of secure passwords are hard to remember and easier to crack. Diceware
|
|
|
|
passphrases are harder to crack because of far higher entropy (there are many
|
|
|
|
words available to use, but only about 50 commonly used symbols in
|
|
|
|
pass*words*). This high level of entropy is precisely what makes such pass
|
|
|
|
phrases secure, even if an attacker knows exactly which dictionary you used!
|
|
|
|
|
|
|
|
The GRUB password can be stored in one of two ways:
|
|
|
|
|
|
|
|
* plaintext
|
|
|
|
* protected with [PBKDF2](https://en.wikipedia.org/wiki/Pbkdf2)
|
|
|
|
|
|
|
|
We will *obviously* use the latter method. Generating the PBKDF2 derived key is
|
|
|
|
done using the `grub-mkpasswd-pbkdf2` utility. You can get it by
|
|
|
|
installing GRUB version 2. Generate a key by giving it a password:
|
|
|
|
|
|
|
|
NOTE: This utility is included under the `grub/` directory, when you build
|
2023-10-26 00:10:41 +00:00
|
|
|
GRUB using the Canoeboot build system. Run the following commands (assuming
|
2023-07-10 15:43:08 +00:00
|
|
|
you have the correct build dependencies installed) to build GRUB, from the
|
2023-10-26 00:10:41 +00:00
|
|
|
Canoeboot Git repository:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-23 00:28:08 +00:00
|
|
|
./mk -b grub default
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-23 00:28:08 +00:00
|
|
|
The following executable will then be available under `src/grub/default/`:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
grub-mkpasswd-pbkdf2
|
|
|
|
|
|
|
|
Its output will be a string of the following form:
|
|
|
|
|
|
|
|
grub.pbkdf2.sha512.10000.HEXDIGITS.MOREHEXDIGITS
|
|
|
|
|
|
|
|
Now open my.grubtest.cfg and put the following before the menu entries
|
|
|
|
(prefered above the functions and after other directives). Of course use
|
|
|
|
the pbdkf string that you had generated yourself:
|
|
|
|
|
|
|
|
set superusers="root"
|
|
|
|
password_pbkdf2 root grub.pbkdf2.sha512.10000.711F186347156BC105CD83A2ED7AF1EB971AA2B1EB2640172F34B0DEFFC97E654AF48E5F0C3B7622502B76458DA494270CC0EA6504411D676E6752FD1651E749.8DD11178EB8D1F633308FD8FCC64D0B243F949B9B99CCEADE2ECA11657A757D22025986B0FA116F1D5191E0A22677674C994EDBFADE62240E9D161688266A711
|
|
|
|
|
|
|
|
Obviously, replace it with the correct hash that you actually obtained for the
|
|
|
|
password you entered. In other words, *do not use the hash that you see above!*
|
|
|
|
|
|
|
|
With this configuration in place, you must now enter the passphrase *every
|
|
|
|
single time you boot your computer*. This completely restricts an attacker in
|
|
|
|
such a way that they cannot simply boot an arbitrary operating system on your
|
|
|
|
computer. NOTE: An attacker could still open your system and re-flash new
|
|
|
|
firmware externally. You should implement some detection mechanism, such as
|
|
|
|
epoxy applied in a *random pattern* on every screw; this slows down the attack
|
|
|
|
and means that you will know someone tampered with it because they cannot
|
2023-10-26 00:10:41 +00:00
|
|
|
easily re-produce the exact same glob of epoxy in the same pattern (when you
|
2023-07-10 15:43:08 +00:00
|
|
|
apply it, swirl it around a bit for a few minutes while it cures. The purpose
|
|
|
|
is not to prevent disassembly, but to slow it down and make it detectable when
|
|
|
|
it has occured).
|
|
|
|
|
|
|
|
Another good thing to do, if we chose to load signed on-disk GRUB
|
|
|
|
configurations, is to remove (or comment out) `unset superusers` in
|
|
|
|
function try\_user\_config:
|
|
|
|
|
|
|
|
```
|
|
|
|
function try_user_config {
|
|
|
|
set root="${1}"
|
|
|
|
for dir in boot grub grub2 boot/grub boot/grub2; do
|
2023-10-26 00:10:41 +00:00
|
|
|
for name in '' autoboot_ canoeboot_ coreboot_; do
|
2023-07-10 15:43:08 +00:00
|
|
|
if [ -f /"${dir}"/"${name}"grub.cfg ]; then
|
|
|
|
#unset superusers
|
|
|
|
configfile /"${dir}"/"${name}"grub.cfg
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
done
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The `unset superusers` command disables password authentication, which will
|
|
|
|
allow the attacker to boot an arbitrary operating system, regardless of
|
2023-10-26 00:10:41 +00:00
|
|
|
signature checking. The default Canoeboot configuration is tweaked for *easy of
|
2023-07-10 15:43:08 +00:00
|
|
|
use* by end users, and it is *not* done with security in mind (though security
|
2023-10-26 00:10:41 +00:00
|
|
|
is preferred). Thus, Canoeboot is less restrictive by default. What you are
|
2023-07-10 15:43:08 +00:00
|
|
|
doing, per this article, is making your system *more secure* but at the expense
|
|
|
|
of user-friendliness.
|
|
|
|
|
|
|
|
That just about covers it, where password setup is concerned!
|
|
|
|
|
2024-05-27 23:46:50 +00:00
|
|
|
SeaBIOS first?
|
|
|
|
==============
|
|
|
|
|
|
|
|
In releases after Canoeboot 20240510, SeaBIOS is the primary payload on
|
|
|
|
all images, but GRUB is available in the boot menu. Select a ROM image
|
|
|
|
with `grubfirst` at the end, and do this to the ROM image:
|
|
|
|
|
|
|
|
cbfstool canoeboot.rom add-int -i 0 -n etc/show-boot-menu
|
|
|
|
|
|
|
|
This disables the SeaBIOS menu, so that it only loads GRUB. The `grubfirst`
|
|
|
|
image had this done to it by lbmk (Canoeboot build system) during build:
|
|
|
|
|
|
|
|
cbfstool canoeboot.rom add -f config/grub/bootorder -n bootorder -t raw
|
|
|
|
|
|
|
|
This `bootorder` file has the following contents:
|
|
|
|
|
|
|
|
```
|
|
|
|
/rom@img/grub2
|
|
|
|
```
|
|
|
|
|
|
|
|
You can add it yourself if your image doesn't have it. With this, SeaBIOS
|
|
|
|
only loads GRUB first.
|
|
|
|
|
|
|
|
NOTE: Before disabling the boot menu, make sure GRUB works. Access it using
|
|
|
|
the `bootorder` file and/or press ESC in the SeaBIOS menu. Then disable the
|
|
|
|
SeaBIOS menu.
|
|
|
|
|
2023-07-10 15:43:08 +00:00
|
|
|
GPG keys
|
|
|
|
========
|
|
|
|
|
|
|
|
First, generate a GPG keypair to use for signing. Option RSA (sign only)
|
|
|
|
is ok.
|
|
|
|
|
|
|
|
WARNING: GRUB does not read ASCII armored keys. When attempting to
|
|
|
|
trust ... a key filename it will print `error: bad signature` on the screen.
|
|
|
|
|
|
|
|
```
|
|
|
|
mkdir --mode 0700 keys
|
|
|
|
gpg --homedir keys --gen-key
|
|
|
|
gpg --homedir keys --export-secret-keys --armor > boot.secret.key # backup
|
|
|
|
gpg --homedir keys --export > boot.key
|
|
|
|
```
|
|
|
|
|
|
|
|
Now that we have a key, we can sign some files with it. We must sign:
|
|
|
|
|
|
|
|
- a kernel
|
|
|
|
- (if we have one) an initramfs
|
|
|
|
- (if we wish to transfer control to it) an on-disk `grub.cfg`
|
|
|
|
- `grubtest.cfg` (so that you can go back to `grubtest.cfg` after signature
|
|
|
|
checking is enforced. You can always get back to `grub.cfg` by pressing ESC,
|
|
|
|
but, afterwards, `grubtest.cfg` is not signed and it will not load.
|
|
|
|
|
|
|
|
Suppose that we have a pair of `my.kernel` and `my.initramfs` and an
|
2023-10-26 00:10:41 +00:00
|
|
|
on-disk `canoeboot_grub.cfg`. We will sign them by running the following
|
2023-07-10 15:43:08 +00:00
|
|
|
commands:
|
|
|
|
|
|
|
|
```
|
|
|
|
gpg --homedir keys --detach-sign my.initramfs
|
|
|
|
gpg --homedir keys --detach-sign my.kernel
|
2023-10-26 00:10:41 +00:00
|
|
|
gpg --homedir keys --detach-sign canoeboot_grub.cfg
|
2023-07-10 15:43:08 +00:00
|
|
|
gpg --homedir keys --detach-sign my.grubtest.cfg
|
|
|
|
```
|
|
|
|
|
|
|
|
Of course, some further modifications to my.grubtest.cfg will be required. We
|
|
|
|
need to *trust* the key and enable signature enforcement (put this before menu
|
|
|
|
entries):
|
|
|
|
|
|
|
|
```
|
|
|
|
trust (cbfsdisk)/boot.key
|
|
|
|
set check_signatures=enforce
|
|
|
|
```
|
|
|
|
|
2023-10-26 00:10:41 +00:00
|
|
|
What remains now is to include the modifications into the Canoeboot image
|
2023-07-10 15:43:08 +00:00
|
|
|
(ROM):
|
|
|
|
|
|
|
|
```
|
|
|
|
cbfstool my.rom add -n boot.key -f boot.key -t raw
|
|
|
|
cbfstool my.rom add -n grubtest.cfg -f my.grubtest.cfg -t raw
|
|
|
|
cbfstool my.rom add -n grubtest.cfg.sig -f my.grubtest.cfg.sig -t raw
|
|
|
|
```
|
|
|
|
|
|
|
|
Now, flash it. If it works, copy it over to `grub.cfg` in CBFS.
|