Add Secure Boot Support (#12692)
- Why I did it Add Secure Boot support to SONiC OS. Secure Boot (SB) is a verification mechanism for ensuring that code launched by a computer's UEFI firmware is trusted. It is designed to protect a system against malicious code being loaded and executed early in the boot process before the operating system has been loaded. - How I did it Added a signing process to sign the following components: shim, grub, Linux kernel, and kernel modules when doing the build, and when feature is enabled in build time according to the HLD explanations (the feature is disabled by default). - How to verify it There are self-verifications of each boot component when building the image, in addition, there is an existing end-to-end test in sonic-mgmt repo that checks that the boot succeeds when loading a secure system (details below). How to build a sonic image with secure boot feature: (more description in HLD) Required to use the following build flags from rules/config: SECURE_UPGRADE_MODE="dev" SECURE_UPGRADE_DEV_SIGNING_KEY="/path/to/private/key.pem" SECURE_UPGRADE_DEV_SIGNING_CERT="/path/to/cert/key.pem" After setting those flags should build the sonic-buildimage. Before installing the image, should prepared the setup (switch device) with the follow: check that the device support UEFI stored pub keys in UEFI DB enabled Secure Boot flag in UEFI How to run a test that verify the Secure Boot flow: The existing test "test_upgrade_path" under "sonic-mgmt/tests/upgrade_path/test_upgrade_path", is enough to validate proper boot You need to specify the following arguments: Base_image_list your_secure_image Taget_image_list your_second_secure_image Upgrade_type cold And run the test, basically the test will install the base image given in the parameter and then upgrade to target image by doing cold reboot and validates all the services are up and working correctly
This commit is contained in:
parent
1cd67444e4
commit
8098bc4bf5
@ -309,6 +309,21 @@ ifdef SONIC_BUILD_QUIETER
|
||||
DOCKER_RUN += -e "SONIC_BUILD_QUIETER=$(SONIC_BUILD_QUIETER)"
|
||||
endif
|
||||
|
||||
# Mount the Signing key and Certificate in the slave container
|
||||
ifneq ($(SECURE_UPGRADE_DEV_SIGNING_KEY),)
|
||||
DOCKER_RUN += -v $(SECURE_UPGRADE_DEV_SIGNING_KEY):$(SECURE_UPGRADE_DEV_SIGNING_KEY):ro
|
||||
endif
|
||||
ifneq ($(SECURE_UPGRADE_DEV_SIGNING_CERT),)
|
||||
DOCKER_RUN += -v $(SECURE_UPGRADE_DEV_SIGNING_CERT):$(SECURE_UPGRADE_DEV_SIGNING_CERT):ro
|
||||
endif
|
||||
# Mount the Signing prod tool in the slave container
|
||||
$(info "SECURE_UPGRADE_PROD_SIGNING_TOOL": "$(SECURE_UPGRADE_PROD_SIGNING_TOOL)")
|
||||
ifneq ($(SECURE_UPGRADE_PROD_SIGNING_TOOL),)
|
||||
SECURE_UPGRADE_PROD_SIGNING_TOOL_DST = /sonic/scripts/$(shell basename -- $(SECURE_UPGRADE_PROD_SIGNING_TOOL))
|
||||
DOCKER_RUN += -v $(SECURE_UPGRADE_PROD_SIGNING_TOOL):$(SECURE_UPGRADE_PROD_SIGNING_TOOL_DST):ro
|
||||
SECURE_UPGRADE_PROD_SIGNING_TOOL := $(SECURE_UPGRADE_PROD_SIGNING_TOOL_DST)
|
||||
endif
|
||||
|
||||
ifneq ($(SONIC_DPKG_CACHE_SOURCE),)
|
||||
DOCKER_RUN += -v "$(SONIC_DPKG_CACHE_SOURCE):/dpkg_cache:rw"
|
||||
endif
|
||||
@ -525,6 +540,10 @@ SONIC_BUILD_INSTRUCTION := $(MAKE) \
|
||||
BUILD_LOG_TIMESTAMP=$(BUILD_LOG_TIMESTAMP) \
|
||||
SONIC_ENABLE_IMAGE_SIGNATURE=$(ENABLE_IMAGE_SIGNATURE) \
|
||||
SONIC_ENABLE_SECUREBOOT_SIGNATURE=$(SONIC_ENABLE_SECUREBOOT_SIGNATURE) \
|
||||
SECURE_UPGRADE_MODE=$(SECURE_UPGRADE_MODE) \
|
||||
SECURE_UPGRADE_DEV_SIGNING_KEY=$(SECURE_UPGRADE_DEV_SIGNING_KEY) \
|
||||
SECURE_UPGRADE_DEV_SIGNING_CERT=$(SECURE_UPGRADE_DEV_SIGNING_CERT) \
|
||||
SECURE_UPGRADE_PROD_SIGNING_TOOL=$(SECURE_UPGRADE_PROD_SIGNING_TOOL) \
|
||||
SONIC_DEFAULT_CONTAINER_REGISTRY=$(DEFAULT_CONTAINER_REGISTRY) \
|
||||
ENABLE_HOST_SERVICE_ON_START=$(ENABLE_HOST_SERVICE_ON_START) \
|
||||
SLAVE_DIR=$(SLAVE_DIR) \
|
||||
|
@ -167,7 +167,8 @@ if [[ $CONFIGURED_ARCH == amd64 ]]; then
|
||||
fi
|
||||
|
||||
## Sign the Linux kernel
|
||||
if [ "$SONIC_ENABLE_SECUREBOOT_SIGNATURE" = "y" ]; then
|
||||
# note: when flag SONIC_ENABLE_SECUREBOOT_SIGNATURE is enabled the Secure Upgrade flags should be disabled (no_sign) to avoid conflict between the features.
|
||||
if [ "$SONIC_ENABLE_SECUREBOOT_SIGNATURE" = "y" ] && [ "$SECURE_UPGRADE_MODE" != 'dev' ] && [ "$SECURE_UPGRADE_MODE" != "prod" ]; then
|
||||
if [ ! -f $SIGNING_KEY ]; then
|
||||
echo "Error: SONiC linux kernel signing key missing"
|
||||
exit 1
|
||||
@ -631,6 +632,62 @@ then
|
||||
|
||||
fi
|
||||
|
||||
# #################
|
||||
# secure boot
|
||||
# #################
|
||||
if [[ $SECURE_UPGRADE_MODE == 'dev' || $SECURE_UPGRADE_MODE == "prod" && $SONIC_ENABLE_SECUREBOOT_SIGNATURE != 'y' ]]; then
|
||||
# note: SONIC_ENABLE_SECUREBOOT_SIGNATURE is a feature that signing just kernel,
|
||||
# SECURE_UPGRADE_MODE is signing all the boot component including kernel.
|
||||
# its required to do not enable both features together to avoid conflicts.
|
||||
echo "Secure Boot support build stage: Starting .."
|
||||
|
||||
# debian secure boot dependecies
|
||||
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install \
|
||||
shim-unsigned \
|
||||
grub-efi
|
||||
|
||||
if [ ! -f $SECURE_UPGRADE_DEV_SIGNING_CERT ]; then
|
||||
echo "Error: SONiC SECURE_UPGRADE_DEV_SIGNING_CERT=$SECURE_UPGRADE_DEV_SIGNING_CERT key missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $SECURE_UPGRADE_MODE == 'dev' ]]; then
|
||||
# development signing & verification
|
||||
|
||||
if [ ! -f $SECURE_UPGRADE_DEV_SIGNING_KEY ]; then
|
||||
echo "Error: SONiC SECURE_UPGRADE_DEV_SIGNING_KEY=$SECURE_UPGRADE_DEV_SIGNING_KEY key missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo ./scripts/signing_secure_boot_dev.sh -a $CONFIGURED_ARCH \
|
||||
-r $FILESYSTEM_ROOT \
|
||||
-l $LINUX_KERNEL_VERSION \
|
||||
-c $SECURE_UPGRADE_DEV_SIGNING_CERT \
|
||||
-p $SECURE_UPGRADE_DEV_SIGNING_KEY
|
||||
elif [[ $SECURE_UPGRADE_MODE == "prod" ]]; then
|
||||
# Here Vendor signing should be implemented
|
||||
OUTPUT_SEC_BOOT_DIR=$FILESYSTEM_ROOT/boot
|
||||
|
||||
if [ ! -f $SECURE_UPGRADE_PROD_SIGNING_TOOL ]; then
|
||||
echo "Error: SONiC SECURE_UPGRADE_PROD_SIGNING_TOOL=$SECURE_UPGRADE_PROD_SIGNING_TOOL script missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo $SECURE_UPGRADE_PROD_SIGNING_TOOL $CONFIGURED_ARCH $FILESYSTEM_ROOT $LINUX_KERNEL_VERSION $OUTPUT_SEC_BOOT_DIR
|
||||
|
||||
# verifying all EFI files and kernel modules in $OUTPUT_SEC_BOOT_DIR
|
||||
sudo ./scripts/secure_boot_signature_verification.sh -e $OUTPUT_SEC_BOOT_DIR \
|
||||
-c $SECURE_UPGRADE_DEV_SIGNING_CERT \
|
||||
-k $FILESYSTEM_ROOT
|
||||
|
||||
# verifying vmlinuz file.
|
||||
sudo ./scripts/secure_boot_signature_verification.sh -e $FILESYSTEM_ROOT/boot/vmlinuz-${LINUX_KERNEL_VERSION}-${CONFIGURED_ARCH} \
|
||||
-c $SECURE_UPGRADE_DEV_SIGNING_CERT \
|
||||
-k $FILESYSTEM_ROOT
|
||||
fi
|
||||
echo "Secure Boot support build stage: END."
|
||||
fi
|
||||
|
||||
## Update initramfs
|
||||
sudo chroot $FILESYSTEM_ROOT update-initramfs -u
|
||||
## Convert initrd image to u-boot format
|
||||
|
@ -78,6 +78,10 @@ fi
|
||||
# Update apt's snapshot of its repos
|
||||
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get update
|
||||
|
||||
# Install efitools to support secure upgrade
|
||||
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install efitools
|
||||
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install mokutil
|
||||
|
||||
# Apply environtment configuration files
|
||||
sudo cp $IMAGE_CONFIGS/environment/environment $FILESYSTEM_ROOT/etc/
|
||||
sudo cp $IMAGE_CONFIGS/environment/motd $FILESYSTEM_ROOT/etc/
|
||||
|
@ -359,6 +359,71 @@ demo_install_uefi_grub()
|
||||
|
||||
}
|
||||
|
||||
# Install UEFI BIOS SHIM for DEMO OS
|
||||
demo_install_uefi_shim()
|
||||
{
|
||||
echo "demo_install_uefi_shim(): Installing Secure Boot components"
|
||||
|
||||
local demo_mnt="$1"
|
||||
local blk_dev="$2"
|
||||
|
||||
# make sure /boot/efi is mounted
|
||||
if ! mount | grep -q "/boot/efi"; then
|
||||
mount /boot/efi || {
|
||||
echo "Error: Unable to mount /boot/efi"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Look for the EFI system partition UUID on the same block device as
|
||||
# the ONIE-BOOT partition.
|
||||
local uefi_part=0
|
||||
for p in $(seq 8) ; do
|
||||
if sgdisk -i $p $blk_dev | grep -q C12A7328-F81F-11D2-BA4B-00A0C93EC93B ; then
|
||||
uefi_part=$p
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
[ $uefi_part -eq 0 ] && {
|
||||
echo "ERROR: Unable to determine UEFI system partition"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "creating demo_volume_label=$demo_volume_label in dir: /boot/efi/EFI/ ."
|
||||
mkdir -p /boot/efi/EFI/$demo_volume_label
|
||||
|
||||
if [ ! -f $demo_mnt/$image_dir/boot/mmx64.efi ]; then
|
||||
echo "ERROR: $demo_mnt/$image_dir/boot/mmx64.efi file does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f $demo_mnt/$image_dir/boot/shimx64.efi ]; then
|
||||
echo "ERROR: $demo_mnt/$image_dir/boot/shimx64.efi file does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f $demo_mnt/$image_dir/boot/grubx64.efi ]; then
|
||||
echo "ERROR: $demo_mnt/$image_dir/boot/grubx64.efi file does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "copying signed shim, mm, grub, grub.cfg from $demo_mnt/$image_dir/boot/ to /boot/efi/EFI/$demo_volume_label directory"
|
||||
cp $demo_mnt/$image_dir/boot/mmx64.efi /boot/efi/EFI/$demo_volume_label/mmx64.efi
|
||||
cp $demo_mnt/$image_dir/boot/shimx64.efi /boot/efi/EFI/$demo_volume_label/shimx64.efi
|
||||
cp $demo_mnt/$image_dir/boot/grubx64.efi /boot/efi/EFI/$demo_volume_label/grubx64.efi
|
||||
|
||||
# Configure EFI NVRAM Boot variables. --create also sets the
|
||||
# new boot number as active.
|
||||
efibootmgr --quiet --create \
|
||||
--label "$demo_volume_label" \
|
||||
--disk $blk_dev --part $uefi_part \
|
||||
--loader "/EFI/$demo_volume_label/shimx64.efi" || {
|
||||
echo "ERROR: efibootmgr failed to create new boot variable on: $blk_dev"
|
||||
exit 1
|
||||
}
|
||||
echo "demo_install_uefi_shim(): Secure Boot components installed successfully"
|
||||
}
|
||||
|
||||
bootloader_menu_config()
|
||||
{
|
||||
@ -370,7 +435,15 @@ bootloader_menu_config()
|
||||
mv $onie_initrd_tmp/tmp/onie-support*.tar.bz2 $demo_mnt/$image_dir/
|
||||
|
||||
if [ "$firmware" = "uefi" ] ; then
|
||||
demo_install_uefi_grub "$demo_mnt" "$blk_dev"
|
||||
secure_boot_state=$(mokutil --sb-state)
|
||||
echo secure_boot_state=$secure_boot_state
|
||||
if [ "$secure_boot_state" = "SecureBoot enabled" ]; then
|
||||
echo "UEFI Secure Boot is enabled"
|
||||
demo_install_uefi_shim "$demo_mnt" "$blk_dev"
|
||||
else
|
||||
echo "UEFI Secure Boot is disabled"
|
||||
demo_install_uefi_grub "$demo_mnt" "$blk_dev"
|
||||
fi
|
||||
else
|
||||
demo_install_grub "$demo_mnt" "$blk_dev"
|
||||
fi
|
||||
@ -469,9 +542,34 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make a first grub config file that located in default debian path:/boot/efi/EFI/debian/
|
||||
# this first grub.cfg will call the complete grub.cfg created below with sonic configuration
|
||||
tmp_config=$(mktemp)
|
||||
cat <<EOF > $tmp_config
|
||||
search --no-floppy --label --set=root $demo_volume_label
|
||||
set prefix=(\$root)'/grub'
|
||||
configfile \$prefix/grub.cfg
|
||||
EOF
|
||||
|
||||
# Copy first grub.cfg as entrypoint to default debian path where grubx64.efi expected it.
|
||||
mkdir -p /boot/efi/EFI/debian/
|
||||
echo "cp $tmp_config /boot/efi/EFI/debian/grub.cfg"
|
||||
cp $tmp_config /boot/efi/EFI/debian/grub.cfg
|
||||
|
||||
# Add extra linux command line
|
||||
echo "EXTRA_CMDLINE_LINUX=$extra_cmdline_linux"
|
||||
GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX $extra_cmdline_linux"
|
||||
GRUB_CFG_LINUX_CMD=""
|
||||
GRUB_CFG_INITRD_CMD=""
|
||||
if [ "$firmware" = "uefi" ] ; then
|
||||
# grub.cfg when BIOS is UEFI and support Secure Boot
|
||||
GRUB_CFG_LINUX_CMD="linuxefi"
|
||||
GRUB_CFG_INITRD_CMD="initrdefi"
|
||||
else
|
||||
# grub.cfg when BIOS is Legacy
|
||||
GRUB_CFG_LINUX_CMD="linux"
|
||||
GRUB_CFG_INITRD_CMD="initrd"
|
||||
fi
|
||||
|
||||
cat <<EOF >> $grub_cfg
|
||||
menuentry '$demo_grub_entry' {
|
||||
@ -481,13 +579,13 @@ menuentry '$demo_grub_entry' {
|
||||
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
|
||||
insmod part_msdos
|
||||
insmod ext2
|
||||
linux /$image_dir/boot/vmlinuz-5.10.0-18-2-amd64 root=$grub_cfg_root rw $GRUB_CMDLINE_LINUX \
|
||||
$GRUB_CFG_LINUX_CMD /$image_dir/boot/vmlinuz-5.10.0-18-2-amd64 root=$grub_cfg_root rw $GRUB_CMDLINE_LINUX \
|
||||
net.ifnames=0 biosdevname=0 \
|
||||
loop=$image_dir/$FILESYSTEM_SQUASHFS loopfstype=squashfs \
|
||||
systemd.unified_cgroup_hierarchy=0 \
|
||||
apparmor=1 security=apparmor varlog_size=$VAR_LOG_SIZE usbcore.autosuspend=-1 $ONIE_PLATFORM_EXTRA_CMDLINE_LINUX
|
||||
echo 'Loading $demo_volume_label $demo_type initial ramdisk ...'
|
||||
initrd /$image_dir/boot/initrd.img-5.10.0-18-2-amd64
|
||||
$GRUB_CFG_INITRD_CMD /$image_dir/boot/initrd.img-5.10.0-18-2-amd64
|
||||
}
|
||||
EOF
|
||||
|
||||
@ -510,6 +608,17 @@ EOF
|
||||
cp $grub_cfg $onie_initrd_tmp/$demo_mnt/grub/grub.cfg
|
||||
fi
|
||||
|
||||
if [ "$secure_boot_state" = "SecureBoot enabled" ]; then
|
||||
# Secure Boot grub.cfg support
|
||||
# Saving grub_cfg in the same place where is grubx64.efi,
|
||||
# this grub_cfg file will be called by first grub.cfg file from: /boot/efi/EFI/debian/grub.cfg
|
||||
if [ -f $NVOS_BOOT_DIR/grub.cfg ]; then
|
||||
rm $NVOS_BOOT_DIR/grub.cfg
|
||||
fi
|
||||
|
||||
cp $grub_cfg $NVOS_BOOT_DIR/grub.cfg
|
||||
fi
|
||||
|
||||
cd /
|
||||
|
||||
echo "Installed SONiC base image $demo_volume_label successfully"
|
||||
|
@ -220,6 +220,15 @@ SONIC_ENABLE_IMAGE_SIGNATURE ?= n
|
||||
# The absolute path should be provided.
|
||||
SONIC_ENABLE_SECUREBOOT_SIGNATURE ?= n
|
||||
|
||||
# Full Secure Boot feature flags.
|
||||
# SECURE_UPGRADE_DEV_SIGNING_KEY - path to development signing key, used for image signing during build
|
||||
# SECURE_UPGRADE_DEV_SIGNING_CERT - path to development signing certificate, used for image signing during build
|
||||
# SECURE_UPGRADE_MODE - enum value for secure upgrade mode, valid options are "dev", "prod" and "no_sign"
|
||||
# SECURE_UPGRADE_PROD_SIGNING_TOOL - path to a vendor signing tool for production flow.
|
||||
SECURE_UPGRADE_DEV_SIGNING_KEY = /sonic/your/private/key/path/private_key.pem
|
||||
SECURE_UPGRADE_DEV_SIGNING_CERT = /sonic/your/certificate/path/cert.pem
|
||||
SECURE_UPGRADE_MODE = "no_sign"
|
||||
SECURE_UPGRADE_PROD_SIGNING_TOOL ?=
|
||||
# PACKAGE_URL_PREFIX - the package url prefix
|
||||
PACKAGE_URL_PREFIX ?= https://packages.trafficmanager.net/public/packages
|
||||
|
||||
|
@ -4,11 +4,10 @@ DEP_FILES := rules/linux-kernel.mk rules/linux-kernel.dep
|
||||
SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files))
|
||||
|
||||
DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) \
|
||||
$(KERNEL_PROCURE_METHOD) $(KERNEL_CACHE_PATH)
|
||||
$(KERNEL_PROCURE_METHOD) $(KERNEL_CACHE_PATH) $(SECURE_UPGRADE_MODE) $(SECURE_UPGRADE_DEV_SIGNING_CERT)
|
||||
|
||||
$(LINUX_HEADERS_COMMON)_CACHE_MODE := GIT_CONTENT_SHA
|
||||
$(LINUX_HEADERS_COMMON)_DEP_FLAGS := $(DEP_FLAGS)
|
||||
$(LINUX_HEADERS_COMMON)_DEP_FILES := $(DEP_FILES)
|
||||
$(LINUX_HEADERS_COMMON)_SMDEP_FILES := $(SMDEP_FILES)
|
||||
$(LINUX_HEADERS_COMMON)_SMDEP_PATHS := $(SPATH)
|
||||
|
||||
|
63
scripts/efi-sign.sh
Executable file
63
scripts/efi-sign.sh
Executable file
@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
#
|
||||
# Sign efi file with secret key and certificate
|
||||
# - shim
|
||||
# - grub
|
||||
# - vmlinuz
|
||||
#
|
||||
print_usage() {
|
||||
cat <<EOF
|
||||
|
||||
$0: Usage
|
||||
$0 -p <PRIVATE_KEY_PEM> -c <CERT_PEM> -e <EFI_FILE> -s <EFI_FILE_SIGNED>
|
||||
Usage example: efi-sign.sh -p priv-key.pem -c pub-key.pem -e shimx64.efi -s shimx64-signed.efi
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
while getopts 'p:c:e:s:hv' flag; do
|
||||
case "${flag}" in
|
||||
p) PRIVATE_KEY_PEM="${OPTARG}" ;;
|
||||
c) CERT_PEM="${OPTARG}" ;;
|
||||
e) EFI_FILE="${OPTARG}" ;;
|
||||
s) EFI_FILE_SIGNED="${OPTARG}" ;;
|
||||
v) VERBOSE='true' ;;
|
||||
h) print_usage
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ $OPTIND -eq 1 ]; then echo "no options were pass"; print_usage; exit 1 ;fi
|
||||
|
||||
[ -f "$PRIVATE_KEY_PEM" ] || {
|
||||
echo "Error: PRIVATE_KEY_PEM file does not exist: $PRIVATE_KEY_PEM"
|
||||
print_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -f "$CERT_PEM" ] || {
|
||||
echo "Error: CERT_PEM file does not exist: $CERT_PEM"
|
||||
print_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -f "$EFI_FILE" ] || {
|
||||
echo "Error: File for signing does not exist: $EFI_FILE"
|
||||
print_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -z ${EFI_FILE_SIGNED} ]; then
|
||||
echo "ERROR: no arg named <EFI_FILE_SIGNED> supplied"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$0 signing $EFI_FILE with ${PRIVATE_KEY_PEM}, ${CERT_PEM} to create $EFI_FILE_SIGNED"
|
||||
sbsign --key ${PRIVATE_KEY_PEM} --cert ${CERT_PEM} \
|
||||
--output ${EFI_FILE_SIGNED} ${EFI_FILE} || {
|
||||
echo "EFI sign error"
|
||||
exit 1
|
||||
}
|
96
scripts/secure_boot_signature_verification.sh
Executable file
96
scripts/secure_boot_signature_verification.sh
Executable file
@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# This Script is verifying the efi file signature by using sbverify.
|
||||
# In addition, is verifying that kernel modules a directory contained a signature.
|
||||
# Note: Kernel Module verification is not checking that the signature is correct, but its checking that the Kernel Modules have one.
|
||||
|
||||
EFI_FILE=''
|
||||
KERNEL_MODULES_DIR=''
|
||||
CERT_PEM=''
|
||||
VERBOSE='false'
|
||||
|
||||
print_usage() {
|
||||
cat <<EOF
|
||||
|
||||
$0: Usage
|
||||
$0 -e <EFI_FILE/EFI_DIR> -c <CERT_PEM> -k <KERNEL_MODULES_DIR>
|
||||
Run Example: secure_boot_signature_verification.sh -e shimx64.efi -c pub-key.pem -k fsroot-mellanox
|
||||
Run Example: secure_boot_signature_verification.sh -e /boot/efi_dir -c pub-key.pem -k fsroot-mellanox
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
verify_efi(){
|
||||
cert_pem=$1
|
||||
efi_file=$2
|
||||
echo "sbverify --cert $cert_pem $efi_file"
|
||||
sbverify --cert $cert_pem $efi_file || {
|
||||
echo "sbverify error with $efi_file"
|
||||
exit 1
|
||||
}
|
||||
echo "$efi_file signed OK."
|
||||
}
|
||||
|
||||
while getopts 'e:k:c:hv' flag; do
|
||||
case "${flag}" in
|
||||
e) EFI_FILE="${OPTARG}" ;;
|
||||
k) KERNEL_MODULES_DIR="${OPTARG}" ;;
|
||||
c) CERT_PEM="${OPTARG}" ;;
|
||||
v) VERBOSE='true' ;;
|
||||
h) print_usage
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ $OPTIND -eq 1 ]; then echo "no options were pass"; print_usage; exit 1 ;fi
|
||||
|
||||
if [ -d "$EFI_FILE" ];then
|
||||
[ -f "$CERT_PEM" ] || {
|
||||
echo "Error: option '-c' incorrect, file: certificate=$CERT_PEM does not exist"
|
||||
print_usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
# find all efi files.
|
||||
efi_file_list=$(sudo find ${EFI_FILE} -name "*.efi")
|
||||
for efi_file in $efi_file_list
|
||||
do
|
||||
echo "verifying efi_file named: ${efi_file} .."
|
||||
verify_efi $CERT_PEM ${efi_file}
|
||||
done
|
||||
echo "$0: All EFI files SIGNED OK."
|
||||
fi
|
||||
|
||||
if [ -f "$EFI_FILE" ]; then
|
||||
[ -f "$CERT_PEM" ] || {
|
||||
echo "Error: option '-c' incorrect, file: certificate=$CERT_PEM does not exist"
|
||||
print_usage
|
||||
exit 1
|
||||
}
|
||||
verify_efi $CERT_PEM $EFI_FILE
|
||||
fi
|
||||
|
||||
if [ -d "$KERNEL_MODULES_DIR" ]; then
|
||||
# Condition checking that all the kernel modules in the KERNEL_MODULES_DIR contain a signature.
|
||||
|
||||
# find all the kernel modules.
|
||||
modules_list=$(sudo find ${KERNEL_MODULES_DIR} -name "*.ko")
|
||||
|
||||
# Do sign for each found module
|
||||
kernel_modules_cnt=0
|
||||
for mod in $modules_list
|
||||
do
|
||||
# check Kernel module is signed.
|
||||
if ! grep -q "~Module signature appended~" "${mod}"; then
|
||||
echo "Error: Kernel module=${mod} have no signature appened."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $VERBOSE = 'true' ]; then
|
||||
echo "kernel module named=${mod} have signature appended."
|
||||
fi
|
||||
|
||||
kernel_modules_cnt=$((kernel_modules_cnt+1))
|
||||
done
|
||||
echo "Num of kernel modules signed: kernel_modules_cnt=$kernel_modules_cnt"
|
||||
echo "$0: All Kernel Modules SIGNED OK."
|
||||
fi
|
||||
|
123
scripts/signing_kernel_modules.sh
Executable file
123
scripts/signing_kernel_modules.sh
Executable file
@ -0,0 +1,123 @@
|
||||
#!/bin/bash
|
||||
# This script is signing kernel modules by using sign-file tool
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
$0: # Display Help
|
||||
$0 -l <LINUX_KERNEL_VERSION> -c <PEM_CERT> -p <PEM_PRIVATE_KEY> -s <LOCAL_SIGN_FILE> -e <LOCAL_EXTRACT_CERT> -k <KERNEL_MODULES_DIR>
|
||||
Sign kernel modules in <KERNEL_MODULES_DIR> using private & public keys.
|
||||
|
||||
Parameters description:
|
||||
LINUX_KERNEL_VERSION
|
||||
PEM_CERT public key (pem format)
|
||||
PEM_PRIVATE_KEY private key (pem format)
|
||||
LOCAL_SIGN_FILE path of the sign-file tool for signing Kernel Modules, if the value is empty it will used the sign-file installed in /usr/lib/linux-kbuild-<version>/scripts
|
||||
LOCAL_EXTRACT_CERT path of the extract-cert tool for Extract X.509 certificate, if the value is empty it will used the extract-cert installed in /usr/lib/linux-kbuild-<version>/scripts
|
||||
KERNEL_MODULES_DIR root directory of all the kernel modules to be sign by the script, if the value empty it will use the call script location as root.
|
||||
|
||||
Runs examples:
|
||||
1. ./scripts/signing_kernel_modules.sh -l 5.10.0-8-2 -c cert.pem -p priv-key.pem
|
||||
2. ./scripts/signing_kernel_modules.sh -l 5.10.0-8-2 -c cert.pem -p priv-key.pem -k fsroot-mellanox -e /usr/lib/linux-kbuild-5.10/scripts/extract-cert -s /usr/lib/linux-kbuild-5.10/scripts/sign-file
|
||||
EOF
|
||||
}
|
||||
|
||||
while getopts 'l:c:p:k:s:e:hv' flag; do
|
||||
case "${flag}" in
|
||||
l) LINUX_KERNEL_VERSION="${OPTARG}" ;;
|
||||
c) PEM_CERT="${OPTARG}" ;;
|
||||
p) PEM_PRIVATE_KEY="${OPTARG}" ;;
|
||||
k) KERNEL_MODULES_DIR="${OPTARG}" ;;
|
||||
s) LOCAL_SIGN_FILE="${OPTARG}" ;;
|
||||
e) LOCAL_EXTRACT_CERT="${OPTARG}" ;;
|
||||
v) VERBOSE='true' ;;
|
||||
h) usage
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ $OPTIND -eq 1 ]; then echo "no options were pass"; usage; exit 1 ;fi
|
||||
|
||||
if [ -z ${LINUX_KERNEL_VERSION} ]; then
|
||||
echo "ERROR: LINUX_KERNEL_VERSION arg1 is empty"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f ${PEM_CERT} ]; then
|
||||
echo "ERROR: arg2 PEM_CERT=${PEM_CERT} file does not exist"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f ${PEM_PRIVATE_KEY} ]; then
|
||||
echo "ERROR: arg3 PEM_PRIVATE_KEY=${PEM_PRIVATE_KEY} file does not exist"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kbuild_ver_major="$(cut -d '.' -f 1 <<< "$LINUX_KERNEL_VERSION")"."$(cut -d '.' -f 2 <<< "$LINUX_KERNEL_VERSION")"
|
||||
if [ -z ${LOCAL_SIGN_FILE} ]; then
|
||||
LOCAL_SIGN_FILE="/usr/lib/linux-kbuild-${kbuild_ver_major}/scripts/sign-file"
|
||||
fi
|
||||
|
||||
if [ ! -f ${LOCAL_SIGN_FILE} ]; then
|
||||
echo "ERROR: LOCAL_SIGN_FILE=${LOCAL_SIGN_FILE} file does not exist"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z ${LOCAL_EXTRACT_CERT} ]; then
|
||||
LOCAL_EXTRACT_CERT="/usr/lib/linux-kbuild-${kbuild_ver_major}/scripts/extract-cert"
|
||||
fi
|
||||
|
||||
if [ ! -f ${LOCAL_EXTRACT_CERT} ]; then
|
||||
echo "ERROR: LOCAL_EXTRACT_CERT=${LOCAL_EXTRACT_CERT} file does not exist"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$KERNEL_MODULES_DIR" ]; then
|
||||
# If the user do not provide a KERNEL_MODULES_DIR, the script is going to search in the script call path for Kernel modules.
|
||||
KERNEL_MODULES_DIR="./"
|
||||
echo "KERNEL_MODULES_DIR set to default path: $KERNEL_MODULES_DIR"
|
||||
fi
|
||||
|
||||
# find all the kernel modules.
|
||||
modules_list=$(find ${KERNEL_MODULES_DIR} -name "*.ko")
|
||||
|
||||
dev_certs_tmp_folder="/tmp/dev_kmod_sign"
|
||||
|
||||
# clean env
|
||||
if [ -d ${dev_certs_tmp_folder} ]; then
|
||||
rm -r ${dev_certs_tmp_folder}
|
||||
fi
|
||||
|
||||
mkdir -p ${dev_certs_tmp_folder}
|
||||
local_sign_key="${dev_certs_tmp_folder}/$(basename $PEM_PRIVATE_KEY)"
|
||||
local_sign_cert="${dev_certs_tmp_folder}/$(basename $PEM_CERT)"
|
||||
|
||||
# Combine cert for module signing
|
||||
echo "keys concat: cat ${PEM_PRIVATE_KEY} ${PEM_CERT} > ${local_sign_key}"
|
||||
cat ${PEM_PRIVATE_KEY} ${PEM_CERT} > ${local_sign_key}
|
||||
|
||||
# Extract x509 cert in corect format
|
||||
echo "create x509 cert: ${LOCAL_EXTRACT_CERT} ${local_sign_key} ${local_sign_cert}"
|
||||
${LOCAL_EXTRACT_CERT} ${local_sign_key} ${local_sign_cert}
|
||||
|
||||
# Do sign for each found module
|
||||
kernel_modules_cnt=0
|
||||
for mod in $modules_list
|
||||
do
|
||||
echo "signing module named: ${mod} .."
|
||||
echo "${LOCAL_SIGN_FILE} sha512 ${local_sign_key} ${local_sign_cert} ${mod}"
|
||||
kernel_modules_cnt=$((kernel_modules_cnt+1))
|
||||
${LOCAL_SIGN_FILE} sha512 ${local_sign_key} ${local_sign_cert} ${mod}
|
||||
|
||||
# check Kernel module is signed.
|
||||
if ! grep -q "~Module signature appended~" "${mod}"; then
|
||||
echo "Error: Kernel module=${mod} have no signature appened."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Num of kernel modules signed: kernel_modules_cnt=$kernel_modules_cnt"
|
||||
echo "$0: All Kernel Modules SIGNED OK."
|
121
scripts/signing_secure_boot_dev.sh
Executable file
121
scripts/signing_secure_boot_dev.sh
Executable file
@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
# This script is signing boot components: shim, mmx, grub, kernel and kernel modules in development env.
|
||||
|
||||
## Enable debug output for script & exit code when failing occurs
|
||||
set -x -e
|
||||
|
||||
print_usage() {
|
||||
cat <<EOF
|
||||
|
||||
$0: Usage
|
||||
$0 -r <FS_ROOT> -l <LINUX_KERNEL_VERSION> -c <PEM_CERT> -p <PEM_PRIV_KEY>
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
clean_file() {
|
||||
if [ -f $1 ]; then
|
||||
echo "clean old file named: $1"
|
||||
echo "rm -f $1"
|
||||
rm -f $1
|
||||
fi
|
||||
}
|
||||
|
||||
while getopts 'a:r:l:c:p:hv' flag; do
|
||||
case "${flag}" in
|
||||
a) CONFIGURED_ARCH="${OPTARG}" ;;
|
||||
r) FS_ROOT="${OPTARG}" ;;
|
||||
l) LINUX_KERNEL_VERSION="${OPTARG}" ;;
|
||||
c) PEM_CERT="${OPTARG}" ;;
|
||||
p) PEM_PRIV_KEY="${OPTARG}" ;;
|
||||
v) VERBOSE='true' ;;
|
||||
h) print_usage
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ $OPTIND -eq 1 ]; then echo "no options were pass"; print_usage; exit 1 ;fi
|
||||
|
||||
echo "$0 signing & verifying EFI files and Kernel Modules start ..."
|
||||
|
||||
if [ -z ${CONFIGURED_ARCH} ]; then
|
||||
echo "ERROR: CONFIGURED_ARCH=${CONFIGURED_ARCH} is empty"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z ${FS_ROOT} ]; then
|
||||
echo "ERROR: FS_ROOT=${FS_ROOT} is empty"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z ${LINUX_KERNEL_VERSION} ]; then
|
||||
echo "ERROR: LINUX_KERNEL_VERSION=${LINUX_KERNEL_VERSION} is empty"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${PEM_CERT}" ]; then
|
||||
echo "ERROR: PEM_CERT=${PEM_CERT} file does not exist"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${PEM_PRIV_KEY}" ]; then
|
||||
echo "ERROR: PEM_PRIV_KEY=${PEM_PRIV_KEY} file does not exist"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# efi-sign.sh is used to sign: shim, mmx, grub, and kernel (vmlinuz)
|
||||
EFI_SIGNING=scripts/efi-sign.sh
|
||||
|
||||
# ######################################
|
||||
# Signing EFI files: mm, shim, grub
|
||||
# #####################################
|
||||
efi_file_list=$(sudo find ${KERNEL_MODULES_DIR} -name "*.efi")
|
||||
|
||||
for efi in $efi_file_list
|
||||
do
|
||||
# grep filename from full path
|
||||
efi_filename=$(echo $efi | grep -o '[^/]*$')
|
||||
|
||||
if echo $efi_filename | grep -e "shim" -e "grub" -e "mm"; then
|
||||
|
||||
clean_file ${efi}-signed
|
||||
|
||||
echo "signing efi file - full path: ${efi} filename: ${efi_filename}"
|
||||
echo "sudo ${EFI_SIGNING} -p $PEM_PRIV_KEY -c $PEM_CERT -e ${efi} -s ${efi}-signed"
|
||||
${EFI_SIGNING} -p $PEM_PRIV_KEY -c $PEM_CERT -e ${efi} -s ${efi}-signed
|
||||
|
||||
# cp shim & mmx signed files to boot directory in the fs.
|
||||
cp ${efi}-signed $FS_ROOT/boot/${efi_filename}
|
||||
|
||||
# verifying signature of mm & shim efi files.
|
||||
./scripts/secure_boot_signature_verification.sh -c $PEM_CERT -e $FS_ROOT/boot/${efi_filename}
|
||||
fi
|
||||
done
|
||||
|
||||
######################
|
||||
## vmlinuz signing
|
||||
######################
|
||||
|
||||
CURR_VMLINUZ=$FS_ROOT/boot/vmlinuz-${LINUX_KERNEL_VERSION}-${CONFIGURED_ARCH}
|
||||
|
||||
# clean old files
|
||||
clean_file ${CURR_VMLINUZ}-signed
|
||||
|
||||
echo "signing ${CURR_VMLINUZ} .."
|
||||
${EFI_SIGNING} -p $PEM_PRIV_KEY -c $PEM_CERT -e ${CURR_VMLINUZ} -s ${CURR_VMLINUZ}-signed
|
||||
|
||||
# rename signed vmlinuz with the name vmlinuz without signed suffix
|
||||
mv ${CURR_VMLINUZ}-signed ${CURR_VMLINUZ}
|
||||
|
||||
./scripts/secure_boot_signature_verification.sh -c $PEM_CERT -e ${CURR_VMLINUZ}
|
||||
|
||||
#########################
|
||||
# Kernel Modules signing
|
||||
#########################
|
||||
./scripts/signing_kernel_modules.sh -l $LINUX_KERNEL_VERSION -c ${PEM_CERT} -p ${PEM_PRIV_KEY} -k ${FS_ROOT}
|
||||
|
||||
echo "$0 signing & verifying EFI files and Kernel Modules DONE"
|
12
slave.mk
12
slave.mk
@ -377,6 +377,10 @@ $(info "SONIC_USE_DOCKER_BUILDKIT" : "$(SONIC_USE_DOCKER_BUILDKIT)")
|
||||
$(info "USERNAME" : "$(USERNAME)")
|
||||
$(info "PASSWORD" : "$(PASSWORD)")
|
||||
$(info "CHANGE_DEFAULT_PASSWORD" : "$(CHANGE_DEFAULT_PASSWORD)")
|
||||
$(info "SECURE_UPGRADE_MODE" : "$(SECURE_UPGRADE_MODE)")
|
||||
$(info "SECURE_UPGRADE_DEV_SIGNING_KEY" : "$(SECURE_UPGRADE_DEV_SIGNING_KEY)")
|
||||
$(info "SECURE_UPGRADE_DEV_SIGNING_CERT" : "$(SECURE_UPGRADE_DEV_SIGNING_CERT)")
|
||||
$(info "SECURE_UPGRADE_PROD_SIGNING_TOOL": "$(SECURE_UPGRADE_PROD_SIGNING_TOOL)")
|
||||
$(info "ENABLE_DHCP_GRAPH_SERVICE" : "$(ENABLE_DHCP_GRAPH_SERVICE)")
|
||||
$(info "SHUTDOWN_BGP_ON_START" : "$(SHUTDOWN_BGP_ON_START)")
|
||||
$(info "ENABLE_PFCWD_ON_START" : "$(ENABLE_PFCWD_ON_START)")
|
||||
@ -1258,6 +1262,10 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \
|
||||
export enable_ztp="$(ENABLE_ZTP)"
|
||||
export include_teamd="$(INCLUDE_TEAMD)"
|
||||
export include_router_advertiser="$(INCLUDE_ROUTER_ADVERTISER)"
|
||||
export sonic_su_dev_signing_key="$(SECURE_UPGRADE_DEV_SIGNING_KEY)"
|
||||
export sonic_su_dev_signing_cert="$(SECURE_UPGRADE_DEV_SIGNING_CERT)"
|
||||
export sonic_su_mode="$(SECURE_UPGRADE_MODE)"
|
||||
export sonic_su_prod_signing_tool="$(SECURE_UPGRADE_PROD_SIGNING_TOOL)"
|
||||
export include_system_telemetry="$(INCLUDE_SYSTEM_TELEMETRY)"
|
||||
export include_restapi="$(INCLUDE_RESTAPI)"
|
||||
export include_nat="$(INCLUDE_NAT)"
|
||||
@ -1458,6 +1466,10 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \
|
||||
TARGET_MACHINE=$(dep_machine) \
|
||||
IMAGE_TYPE=$($*_IMAGE_TYPE) \
|
||||
SONIC_ENABLE_IMAGE_SIGNATURE="$(SONIC_ENABLE_IMAGE_SIGNATURE)" \
|
||||
SECURE_UPGRADE_MODE="$(SECURE_UPGRADE_MODE)" \
|
||||
SECURE_UPGRADE_DEV_SIGNING_KEY="$(SECURE_UPGRADE_DEV_SIGNING_KEY)" \
|
||||
SECURE_UPGRADE_DEV_SIGNING_CERT="$(SECURE_UPGRADE_DEV_SIGNING_CERT)" \
|
||||
SECURE_UPGRADE_PROD_SIGNING_TOOL="$(SECURE_UPGRADE_PROD_SIGNING_TOOL)" \
|
||||
SIGNING_KEY="$(SIGNING_KEY)" \
|
||||
SIGNING_CERT="$(SIGNING_CERT)" \
|
||||
CA_CERT="$(CA_CERT)" \
|
||||
|
Loading…
Reference in New Issue
Block a user