-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ShimUtils: Rename ShimToCert as ShimUtils; add new tools:
- shim-make.tool - sbat-info.tool - unsign-efi-sig-list.tool and update shim-to-cert.tool
- Loading branch information
1 parent
2b718a2
commit d1c6a01
Showing
8 changed files
with
704 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
## OpenCore + OpenLinuxBoot + Secure Boot | ||
|
||
If you want to use OpenCore + OpenLinuxBoot + Secure Boot it is possible to self-sign | ||
everything, including any new Linux kernels after updates. This is possible since most | ||
standard distros leave at least the previous kernel bootable (and OpenLinuxBoot exposes | ||
this, via the Auxiliary menu), so you can boot into the old kernel, then own-sign the | ||
new kernel. | ||
|
||
More convenient may be to trust the signing keys of the specific distros which you | ||
want to boot, which are bundled into the `shimx64.efi` file installed with each distro. | ||
You can extract these with `shim-to-cert.tool` distributed with OpenCore, then install | ||
them in your system Secure Boot `db` variable. Best practice would be to install the deny | ||
list (`vendor.dbx`) from `shimx64.efi`, if any, into your system `dbx` variable, as well. | ||
(Otherwise you are ignoring any recovations which the vendor has made.) | ||
|
||
Recently, Shim has added SBAT support, as a more efficient way to revoke unsafe | ||
binaries. Unfortunately, the SBAT enforcement code is part of Shim, it is not | ||
something you can extract and add to your system Secure Boot database. | ||
|
||
To work round this, the new recommended way to boot OpenCore + OpenLinuxBoot + | ||
Secure Boot is to make an own-build of Shim. The vendor certificates | ||
and revocation lists extracted from the distro `shimx64.efi` files are combined | ||
and signed by you, into your own build of Shim; in this approach, these vendor | ||
certificates should NOT also be included in the system Secure Boot database, | ||
and should be removed if you added them previously. Including them in both places | ||
will still boot under Secure Boot, but will effectively disable SBAT revocation. (If you are | ||
own-signing everything, including Linux kernels after updates, this will still | ||
work as before and the below is not needed. Equally, if you are not using | ||
Secure Boot the below is not needed.) | ||
|
||
The advantages of using an own-build of Shim are: | ||
- No need to sign every kernel after updates (same as previous method) | ||
- Linux SBAT integration (new) | ||
- Linux MOK integration (new) | ||
- No need to include the Windows intermediate CA - you are trusting whichever distro | ||
keys you choose to include in your own Shim, directly (new) | ||
|
||
Disadvantages are: | ||
- Need to update when distro keys or distro recovation lists within Shim are updated | ||
(same as previous method) | ||
- Need to udpate when Shim SBAT level is updated (new) | ||
|
||
### Method | ||
`Utilities/ShimUtils` includes a script `shim-make.tool` which will download the | ||
current Shim source and build it for you, on macOS (using Ubuntu multipass) or on | ||
Linux (Ubuntu and Fedora supported, others may work). | ||
|
||
- Extract `vendor.db` and `vendor.dbx` files from the `shimx64.efi` file of each distro | ||
which you want to load (using `shim-to-cert.tool`) | ||
- Concatentate these (e.g. `cat fedora/vendor.db ubuntu/vendor.db > combined/vendor.db` | ||
and `cat fedora/vendor.dbx ubuntu/vendor.dbx > combined/vendor.dbx`) | ||
- Do not concatenate `.der` files directly, it will not work | ||
- If you have a single distro with a single `.der` file, you can use `VENDOR_CERT_FILE` | ||
instead of `VENDOR_DB_FILE` in the `make` options below; otherwise, you will need to use | ||
`cert-to-efi-sig-list` from `efitools` to convert the `.der` file to a sig list - this | ||
is done automatically by `shim-to-cert.tool` when `efitools` are available (in | ||
Linux; or from within Ubuntu multipass on macOS, e.g. `multipass shell oc-shim`) | ||
- Build a version of Shim which includes these concatenated signature lists (and | ||
launches OpenCore.efi directly): | ||
- `./shim-make.tool setup` | ||
- `./shim-make.tool clean` (only needed if remaking after the initial make) | ||
- `./shim-make.tool make VENDOR_DB_FILE=combined/vendor.db VENDOR_DBX_FILE=combined/vendor.dbx` | ||
- Copy the relevant files (`shimx64.efi` and `mmx64.efi` as well as `BOOTX64.CSV`) to your mounted ESP volume, e.g.: | ||
- `./shim-make.tool install /Volumes/EFI` (macOS) | ||
- `sudo ./shim-make.tool install /boot/efi` (Linux) | ||
- Sign the newly built `shimx64.efi` and `mmx64.efi` with your own ISK (see e.g. | ||
https://habr.com/en/articles/273497/ - Google translate is your friend) | ||
- If you do not copy and sign `mmx64.efi` as well as `shimx64.efi`, your system will hang if any MOK operations are attempted | ||
- `BOOTX64.CSV` is not required and is for information only | ||
|
||
As before you need to sign `OpenCore.efi` and any drivers it loads with your ISK. | ||
You now also need to add an empty SBAT section to `OpenCore.efi` before signing it. | ||
|
||
> An empty SBAT section means: 'I'm not part of the system which allocates SBAT names | ||
and signs them into boot files, and I don't want this boot file to be revoked by any | ||
future SBAT revocations'. Of course, you can still revoke your own-signed boot files | ||
by rotating your own signing keys. | ||
|
||
As noted [here](https://github.com/fwupd/fwupd/issues/2910) and | ||
[here](https://github.com/rhboot/shim/issues/376), | ||
the [documented](https://github.com/rhboot/shim/blob/main/SBAT.md) method for adding an | ||
SBAT section to an already-linked `.efi` file does not work correctly (GNU `objcopy` | ||
corrupts the executable). This | ||
[third party python script](https://github.com/rhboot/shim/issues/376#issuecomment-1628004034) | ||
does work. A suitable command is: | ||
|
||
`pe-add-sections.py -s .sbat <(echo -n) -z .sbat -i OpenCore.efi -o OpenCore_empty_sbat.efi` | ||
|
||
This file then needs to be signed and copied back into place, e.g.: | ||
|
||
`sbsign --key {path-to}/ISK.key --cert {path-to}/ISK.pem OpenCore_empty_sbat.efi --output OpenCore.efi` | ||
|
||
Finally, in order for OpenCore integration with Shim to work correctly | ||
`UEFI/Quirks/ShimRetainProtocol` must be enabled in `config.plist`, and | ||
`LauncherPath` should be set to `\EFI\OC\shimx64.efi`. | ||
|
||
> Using Ubuntu multipass, it is now possible to operate entirely within macOS for signing, | ||
key generation, etc. Note that the `~/shim_root` directory is already shared between | ||
macOS and the `oc-shim` multipass VM (under its macOS path, e.g. `/Users/username/shim_root`), | ||
and other macOS folders and volumes can be mounted if you wish, e.g. | ||
`multipass mount /Volumes/EFI oc-shim:/Volumes/EFI`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
#!/bin/bash | ||
|
||
# sbat-info.tool - Dump some useful information about own-build or standard shimx64.efi. | ||
# | ||
# Copyright (c) 2023, Michael Beaton. All rights reserved.<BR> | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
# | ||
|
||
LIGHT_GREEN='\033[1;32m' | ||
YELLOW='\033[1;33m' | ||
RED='\033[0;31m' | ||
NC='\033[0m' # No Color | ||
|
||
# Note: binutils can be placed last on path in macOS, to provide objcopy but avoid overwriting native tools. | ||
command -v objcopy >/dev/null 2>&1 || { echo >&2 "objcopy not found - please install binutils package."; exit 1; } | ||
|
||
usage () { | ||
echo "Usage: $(basename "$0") <efifile>" | ||
echo " Display SBAT information, if present, for any .efi executable." | ||
echo " If the file is a version of Shim, also dislay Shim version info and SBAT enforcement level." | ||
} | ||
|
||
has_section () { | ||
objdump -h "$1" | sed -nr 's/^ *[0-9]+ ([^ ]+).*/\1/p' | grep "$2" 1>/dev/null | ||
} | ||
|
||
if [ -z "$1" ]; then | ||
usage | ||
exit 1 | ||
fi | ||
|
||
# https://unix.stackexchange.com/a/84980/340732 | ||
op_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'shim_info') || exit 1 | ||
|
||
# objcopy and objdump do not like writing to stdout when part of a pipe, so just write to temp files | ||
# Note: these get created as empty files even if the section does not exist | ||
objcopy -O binary -j ".sbat" "$1" "${op_dir}/sbat" || { rm -rf "${op_dir}"; exit 1; } | ||
objcopy -O binary -j ".sbatlevel" "$1" "${op_dir}/sbatlevel" || { rm -rf "${op_dir}"; exit 1; } | ||
objcopy -O binary -j ".data.ident" "$1" "${op_dir}/data.ident" || { rm -rf "${op_dir}"; exit 1; } | ||
|
||
if ! has_section "$1" ".data.ident" ; then | ||
IS_SHIM=0 | ||
echo -e "${YELLOW}Shim version info not present (probably not Shim)${NC}" | ||
else | ||
# Treat this section's presence as enough for the warning colours below | ||
IS_SHIM=1 | ||
FILE_HEADER="$(head -n 1 "${op_dir}/data.ident")" | ||
SHIM_HEADER="UEFI SHIM" | ||
if [ ! "$FILE_HEADER" = "$SHIM_HEADER" ] ; then | ||
echo -e "${RED}!!!Version header found '${FILE_HEADER}' expected '${SHIM_HEADER}'${NC}" | ||
else | ||
echo -e "${YELLOW}Found ${SHIM_HEADER} version header${NC}" | ||
fi | ||
|
||
# shellcheck disable=SC2016 | ||
VERSION="$(grep -a 'Version' "${op_dir}/data.ident" | sed -n 's/^\$Version: *\([^[:space:]]*\) *\$$/\1/p')" | ||
if [ "$VERSION" = "" ] ; then | ||
echo -e "${RED}Expected version number not present${NC}" | ||
else | ||
echo -e "Version: ${LIGHT_GREEN}${VERSION}${NC} (${VERSION}+, if own build)" | ||
fi | ||
|
||
# shellcheck disable=SC2016 | ||
COMMIT="$(grep -a 'Commit' "${op_dir}/data.ident" | sed -n 's/^\$Commit: *\([^[:space:]]*\) *\$$/\1/p')" | ||
if [ "$COMMIT" = "" ] ; then | ||
echo -e "${RED}Expected commit id not present${NC}" | ||
else | ||
echo "Commit: ${COMMIT}" | ||
fi | ||
fi | ||
|
||
echo | ||
echo -e "${YELLOW}SBAT (when tested by other files or by self):${NC}" | ||
|
||
if ! has_section "$1" ".sbat" ; then | ||
echo | ||
echo -e "${RED}No .sbat section${NC}" | ||
else | ||
echo | ||
echo -n -e "$LIGHT_GREEN" | ||
cat "${op_dir}/sbat" | ||
echo -n -e "$NC" | ||
if ! cat "${op_dir}/sbat" | grep -E "[a-z]|[A-Z]" 1>/dev/null ; then | ||
# Red for shim; yellow for other file | ||
if [ "$IS_SHIM" -eq 1 ] ; then | ||
echo -n -e "$RED" | ||
else | ||
echo -n -e "$LIGHT_GREEN" | ||
fi | ||
echo -e "Present but empty .sbat section" | ||
fi | ||
fi | ||
|
||
echo | ||
echo -e "${YELLOW}SBAT Level (when testing other files):${NC}" | ||
|
||
if ! has_section "$1" ".sbatlevel" ; then | ||
echo | ||
# Yellow for shim (not present in earlier shims with .sbat, ~15.6); green for other file | ||
if [ "$IS_SHIM" -eq 1 ] ; then | ||
echo -n -e "$YELLOW" | ||
else | ||
echo -n -e "$LIGHT_GREEN" | ||
fi | ||
echo -n "No .sbatlevel section" | ||
echo -e "$NC" | ||
else | ||
sbat_level_version=$(dd if="${op_dir}/sbatlevel" ibs=1 skip=0 count=4 2>/dev/null | od -t u4 -An | xargs) || { rm -rf "${op_dir}"; exit 1; } | ||
sbat_level_previous=$(dd if="${op_dir}/sbatlevel" ibs=1 skip=4 count=4 2>/dev/null | od -t u4 -An | xargs) || { rm -rf "${op_dir}"; exit 1; } | ||
sbat_level_latest=$(dd if="${op_dir}/sbatlevel" ibs=1 skip=8 count=4 2>/dev/null | od -t u4 -An | xargs) || { rm -rf "${op_dir}"; exit 1; } | ||
|
||
if [ "$sbat_level_version" -ne 0 ] ; then | ||
echo -e "${RED}!!! Unexpected .sbatlevel version $sbat_level_version != 0 !!!${NC}" | ||
fi | ||
|
||
echo | ||
echo -e "${YELLOW}Previous (more permissive boot, default):${NC}" | ||
echo -n -e "$LIGHT_GREEN" | ||
dd if="${op_dir}/sbatlevel" ibs=1 skip="$(($sbat_level_previous + 4))" count="$(($sbat_level_latest - $sbat_level_previous))" 2>/dev/null | ||
echo -e "$NC" | ||
|
||
echo -e "${YELLOW}Latest (stricter boot, optional):${NC}" | ||
echo -n -e "$LIGHT_GREEN" | ||
dd if="${op_dir}/sbatlevel" ibs=1 skip="$(($sbat_level_latest + 4))" 2>/dev/null | ||
echo -e "$NC" | ||
fi | ||
|
||
rm -rf "${op_dir}" | ||
|
||
exit 0 |
Oops, something went wrong.