No description
- Shell 100%
set -euo pipefail
SCRIPT_NAME="$(basename "$0")"
KEY_DIR="${KEY_DIR:-/root/.kernel-signing-keys}"
KEY_NAME="${KEY_NAME:-kernel}"
ESP_DIR="${ESP_DIR:-/boot/efi/EFI/fedora}"
KERNEL_GLOB="${KERNEL_GLOB:-/boot/vmlinuz-*}"
FORCE_REGENERATE_KEYS=0
FORCE_RESIGN=0
COPY_CERT=1
KEEP_BACKUP=0
usage() {
cat <<EOF
Usage: sudo $SCRIPT_NAME [options]
Signs all installed kernel images with a local Secure Boot key.
Options:
--key-dir PATH Directory containing signing key material.
--key-name NAME Base filename for key, cert, and DER files.
--esp-dir PATH Destination directory for the DER certificate.
--kernel-glob GLOB Glob used to find candidate kernel images.
--regen-keys Regenerate the signing key and certificate.
--force Re-sign the kernel even if it already has a signature.
--no-copy-cert Skip copying the DER certificate to the EFI partition.
--keep-backup Keep a .unsigned backup next to each kernel before signing.
-h, --help Show this help text.
Environment overrides:
KEY_DIR, KEY_NAME, ESP_DIR, KERNEL_GLOB
EOF
}
log() {
printf '[*] %s\n' "$*"
}
fail() {
printf '[!] %s\n' "$*" >&2
exit 1
}
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
fail "Run this script with sudo or as root."
fi
}
require_tool() {
local tool="$1"
local install_hint="$2"
if ! command -v "$tool" >/dev/null 2>&1; then
fail "Missing required tool: $tool. Install it with: $install_hint"
fi
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--key-dir)
KEY_DIR="$2"
shift 2
;;
--key-name)
KEY_NAME="$2"
shift 2
;;
--esp-dir)
ESP_DIR="$2"
shift 2
;;
--kernel-glob)
KERNEL_GLOB="$2"
shift 2
;;
--regen-keys)
FORCE_REGENERATE_KEYS=1
shift
;;
--force)
FORCE_RESIGN=1
shift
;;
--no-copy-cert)
COPY_CERT=0
shift
;;
--keep-backup)
KEEP_BACKUP=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
fail "Unknown argument: $1"
;;
esac
done
}
key_path() {
printf '%s/%s.%s' "$KEY_DIR" "$KEY_NAME" "$1"
}
ensure_keys() {
local key_file cert_file der_file
key_file="$(key_path key)"
cert_file="$(key_path crt)"
der_file="$(key_path der)"
mkdir -p "$KEY_DIR"
chmod 700 "$KEY_DIR"
if [[ "$FORCE_REGENERATE_KEYS" -eq 1 ]]; then
rm -f "$key_file" "$cert_file" "$der_file"
fi
if [[ ! -f "$key_file" || ! -f "$cert_file" ]]; then
log "Generating signing keypair in $KEY_DIR"
openssl req -new -x509 -newkey rsa:2048 \
-keyout "$key_file" \
-out "$cert_file" \
-days 36500 -nodes \
-subj "/CN=CachyOS Kernel Signing Key"
chmod 600 "$key_file"
chmod 644 "$cert_file"
else
log "Reusing existing signing keypair from $KEY_DIR"
fi
openssl x509 -outform DER -in "$cert_file" -out "$der_file"
chmod 644 "$der_file"
if [[ "$COPY_CERT" -eq 1 ]]; then
[[ -d "$ESP_DIR" ]] || fail "EFI destination does not exist: $ESP_DIR"
install -m 644 "$der_file" "$ESP_DIR/$(basename "$der_file")"
log "Certificate copied to $ESP_DIR/$(basename "$der_file")"
fi
}
find_kernels() {
local kernels=()
local kernel
shopt -s nullglob
for kernel in $KERNEL_GLOB; do
[[ -f "$kernel" ]] || continue
[[ "$kernel" == *.backup ]] && continue
[[ "$kernel" == *rescue* ]] && continue
kernels+=("$kernel")
done
shopt -u nullglob
[[ "${#kernels[@]}" -gt 0 ]] || fail "No kernels matched: $KERNEL_GLOB"
printf '%s\n' "${kernels[@]}" | sort -V
}
kernel_is_signed_with_local_cert() {
local kernel="$1"
local cert_file
cert_file="$(key_path crt)"
sbverify --cert "$cert_file" "$kernel" >/dev/null 2>&1
}
sign_kernel() {
local kernel="$1"
local key_file cert_file backup_file tmp_output kernel_mode
key_file="$(key_path key)"
cert_file="$(key_path crt)"
backup_file="${kernel}.unsigned"
tmp_output="$(mktemp "${kernel##*/}.XXXXXX")"
kernel_mode="$(stat -c '%a' "$kernel")"
if [[ "$FORCE_RESIGN" -eq 0 ]] && kernel_is_signed_with_local_cert "$kernel"; then
log "Kernel already has a local signature: $kernel"
return 0
fi
if [[ "$KEEP_BACKUP" -eq 1 && ! -f "$backup_file" ]]; then
cp -a "$kernel" "$backup_file"
log "Saved unsigned backup to $backup_file"
fi
log "Signing kernel: $kernel"
sbsign --key "$key_file" --cert "$cert_file" --output "$tmp_output" "$kernel"
install -m "$kernel_mode" "$tmp_output" "$kernel"
rm -f "$tmp_output"
sbverify --cert "$cert_file" "$kernel" >/dev/null
log "Local signature verification succeeded"
}
main() {
parse_args "$@"
require_root
require_tool openssl "dnf install -y openssl"
require_tool sbsign "dnf install -y sbsigntools"
require_tool sbverify "dnf install -y sbsigntools"
ensure_keys
local kernels=()
local kernel
mapfile -t kernels < <(find_kernels)
log "Found ${#kernels[@]} kernel(s) to process"
for kernel in "${kernels[@]}"; do
sign_kernel "$kernel"
done
cat <<EOF
Finished.
Key directory: $KEY_DIR
Processed kernels: ${#kernels[@]}
Certificate for enrollment: $(key_path der)
EFI copy: $ESP_DIR/$(basename "$(key_path der)")
EOF
}
main "$@"
|
||
|---|---|---|
| README.md | ||
| sign-latest-kernel.sh | ||
sign-cachy-kernels
Signs all installed non-rescue kernels with a local Secure Boot key.
I needed this because I keep Secure Boot enabled to play Valorant on Windows, while still wanting to boot CachyOS kernels on the same machine. CachyOS kernels are not signed, so this script signs them with my local key so they can boot after I enroll that cert.
Requirements:
opensslsbsigntools- root
Usage:
sudo ./sign-latest-kernel.sh
Notes:
- Generates or reuses a keypair in
/root/.kernel-signing-keys - Copies the public DER cert to
/boot/efi/EFI/fedora/kernel.der - Skips kernels already signed with the local cert
- Does not keep
.unsignedbackups unless--keep-backupis used