1
0
Fork 0
No description
This repository has been archived on 2026-04-23. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
Find a file
Ellie Gummere b51a4def3e update script
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 "$@"
2026-04-06 16:35:20 -04:00
README.md Add README 2026-03-19 21:51:37 -04:00
sign-latest-kernel.sh update script 2026-04-06 16:35:20 -04:00

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:

  • openssl
  • sbsigntools
  • 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 .unsigned backups unless --keep-backup is used