279 lines
7.0 KiB
Bash
279 lines
7.0 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# ksigner - Secure Boot kernel signing utility
|
|
# Version: @VERSION@
|
|
|
|
# Source configuration
|
|
CONFIG_FILE="/etc/ksigner/ksigner.conf"
|
|
if [[ -f "$CONFIG_FILE" ]]; then
|
|
source "$CONFIG_FILE"
|
|
fi
|
|
|
|
# Key lifetime in days (default: 100 years)
|
|
KEY_LIFETIME_DAYS=$((365 * 100))
|
|
|
|
# Directory paths for keys
|
|
KEY_PUB_DIR="/etc/pki/sbsign/certs/"
|
|
KEY_PRIV_DIR="/etc/pki/sbsign/private/"
|
|
|
|
# Key filenames
|
|
KEY_PUB="MOK.pem"
|
|
KEY_PRIV="MOK.priv"
|
|
KEY_DER="MOK.der"
|
|
|
|
REQUIRED_BINARIES=(
|
|
"openssl"
|
|
"mokutil"
|
|
"sbsign"
|
|
"sha512hmac"
|
|
)
|
|
|
|
panic() {
|
|
echo "ERROR: $1" >&2
|
|
exit 1
|
|
}
|
|
|
|
log() {
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
|
|
}
|
|
|
|
usage() {
|
|
echo "Usage: $0 {setup|sign|sign-all|version|status} [vmlinuz_kernel_filepath]"
|
|
echo " setup - Create and install signing keys"
|
|
echo " sign - Sign a kernel file (optional: vmlinuz_kernel_filepath)"
|
|
echo " sign-all - Sign all available kernels"
|
|
echo " version - Show version information"
|
|
echo " status - Show signing key status"
|
|
exit 1
|
|
}
|
|
|
|
version() {
|
|
echo "ksigner version @VERSION@"
|
|
echo "Copyright (C) @YEAR@"
|
|
echo "This is free software; see the source for copying conditions."
|
|
}
|
|
|
|
status() {
|
|
echo "Kernel Signer Status:"
|
|
echo "====================="
|
|
echo "Public key file: $KEY_PUB_DIR$KEY_PUB"
|
|
if [[ -f "$KEY_PUB_DIR$KEY_PUB" ]]; then
|
|
echo " Status: Found"
|
|
echo " Details:"
|
|
openssl x509 -in "$KEY_PUB_DIR$KEY_PUB" -noout -subject -dates 2>/dev/null || echo " Error reading certificate"
|
|
else
|
|
echo " Status: Not found"
|
|
fi
|
|
|
|
echo "Private key file: $KEY_PRIV_DIR$KEY_PRIV"
|
|
[[ -f "$KEY_PRIV_DIR$KEY_PRIV" ]] && echo " Status: Found" || echo " Status: Not found"
|
|
|
|
echo "DER key file: $KEY_PUB_DIR$KEY_DER"
|
|
[[ -f "$KEY_PUB_DIR$KEY_DER" ]] && echo " Status: Found" || echo " Status: Not found"
|
|
|
|
echo "MOK keys enrolled:"
|
|
mokutil --list-enrolled 2>/dev/null | grep -A 3 -B 1 "Kernel Signing" || echo " No custom MOK keys found"
|
|
|
|
echo "Configuration file: $CONFIG_FILE"
|
|
[[ -f "$CONFIG_FILE" ]] && echo " Status: Found" || echo " Status: Using defaults"
|
|
}
|
|
|
|
req_check() {
|
|
local missing_binaries=()
|
|
for binary in "${REQUIRED_BINARIES[@]}"; do
|
|
if ! command -v "$binary" >/dev/null 2>&1; then
|
|
missing_binaries+=("$binary")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#missing_binaries[@]} -gt 0 ]]; then
|
|
echo "Missing required binaries: ${missing_binaries[*]}" >&2
|
|
echo "Please install the following packages:" >&2
|
|
for binary in "${missing_binaries[@]}"; do
|
|
case "$binary" in
|
|
"openssl") echo " - openssl" >&2 ;;
|
|
"mokutil") echo " - mokutil" >&2 ;;
|
|
"sbsign") echo " - sbsigntools" >&2 ;;
|
|
"sha512hmac") echo " - hmaccalc" >&2 ;;
|
|
esac
|
|
done
|
|
exit 1
|
|
fi
|
|
log "All required binaries are present"
|
|
}
|
|
|
|
version_greater() {
|
|
local ver1="$1"
|
|
local ver2="$2"
|
|
[ "$ver1" = "$(printf '%s\n%s' "$ver1" "$ver2" | sort -V | tail -n1)" ]
|
|
}
|
|
|
|
find_all_kernels() {
|
|
local all_files=()
|
|
for file in /boot/vmlinuz-*; do
|
|
[ -f "$file" ] || continue
|
|
if [[ "$file" == *"rescue"* ]]; then
|
|
continue
|
|
fi
|
|
all_files+=("$file")
|
|
done
|
|
echo "${all_files[@]}"
|
|
}
|
|
|
|
find_latest_kernel() {
|
|
local latest_file=""
|
|
local latest_version=""
|
|
for file in /boot/vmlinuz-*; do
|
|
[ -f "$file" ] || continue
|
|
if [[ "$file" == *"rescue"* ]]; then
|
|
continue
|
|
fi
|
|
local kver="${file#*vmlinuz-}"
|
|
kver="${kver%%-*}"
|
|
if [ -z "$latest_version" ] || version_greater "$kver" "$latest_version"; then
|
|
latest_version="$kver"
|
|
latest_file="$file"
|
|
fi
|
|
done
|
|
echo "$latest_file"
|
|
}
|
|
|
|
setup_signing_keys() {
|
|
# Step 1: Create the signing keys
|
|
log "[Step 1] Creating signing keys..."
|
|
openssl req -new -x509 -newkey rsa:4096 \
|
|
-keyout $KEY_PRIV \
|
|
-outform DER -out $KEY_DER \
|
|
-nodes -days $KEY_LIFETIME_DAYS -subj "/CN=Kernel Signing/" ||
|
|
panic "[Step 1] Failed to create signing keys"
|
|
|
|
# Step 2: Convert the keys to PEM format
|
|
log "[Step 2] Converting keys to PEM format..."
|
|
openssl x509 -inform der -in $KEY_DER -out $KEY_PUB ||
|
|
panic "[Step 2] Failed to convert keys to PEM format"
|
|
|
|
# Step 3: Create the directory for the keys
|
|
log "[Step 3] Creating the directory for the keys..."
|
|
mkdir -p $KEY_PUB_DIR $KEY_PRIV_DIR ||
|
|
panic "[Step 3] Failed to create the directory for the keys"
|
|
|
|
# Step 4: Copy the keys to the directory
|
|
log "[Step 4] Copying the keys to the directory..."
|
|
mv -f $KEY_DER $KEY_PUB $KEY_PUB_DIR ||
|
|
panic "[Step 4a] Failed to copy the keys to the directory"
|
|
mv -f $KEY_PRIV $KEY_PRIV_DIR ||
|
|
panic "[Step 4b] Failed to copy the keys to the directory"
|
|
|
|
# Step 5: Set the permissions for the keys
|
|
log "[Step 5] Setting the permissions for the keys..."
|
|
chmod -R 600 $KEY_PRIV_DIR ||
|
|
panic "[Step 5] Failed to set the permissions for the keys"
|
|
|
|
# Step 6: Import the keys to the MOK
|
|
log "[Step 6] Importing the keys to the MOK..."
|
|
mokutil --import $KEY_PUB_DIR$KEY_DER ||
|
|
panic "[Step 6] Failed to import the keys to the MOK"
|
|
|
|
echo
|
|
log "Signing keys have been created and installed"
|
|
echo
|
|
echo "Please reboot your computer and enroll the keys with MOK"
|
|
echo
|
|
echo "Enroll MOK -> Continue -> Yes -> Enter password -> OK"
|
|
echo
|
|
}
|
|
|
|
sign_kernel() {
|
|
local kern_version="$1"
|
|
local kern_file="$2"
|
|
|
|
# Step 1: Sign the kernel
|
|
log "[Step 1] Signing '$kern_version'..."
|
|
/usr/bin/sbsign \
|
|
--key "$KEY_PRIV_DIR$KEY_PRIV" \
|
|
--cert "$KEY_PUB_DIR$KEY_PUB" \
|
|
"$kern_file" \
|
|
--output "$kern_file.signed" ||
|
|
panic "[Step 1] Failed to sign '$kern_version'"
|
|
|
|
# Step 2: Verify the kernel was signed
|
|
log "[Step 2] Verifying '$kern_file' was signed"
|
|
[ -f "$kern_file.signed" ] ||
|
|
panic "'$kern_file.signed' was not found"
|
|
|
|
# Step 3: Move the signed kernel
|
|
log "[Step 3] Moving '$kern_file.signed' to '$kern_file'"
|
|
mv -f "$kern_file.signed" "$kern_file" ||
|
|
panic "Failed to move '$kern_file.signed'"
|
|
|
|
# Step 4: Make the kernel executable
|
|
log "[Step 4] Setting permissions for '$kern_file'"
|
|
chmod +x "$kern_file" ||
|
|
panic "Failed to make '$kern_file' executable"
|
|
|
|
# Step 5: Create the HMAC
|
|
log "[Step 5] Creating HMAC for '$kern_file'"
|
|
sha512hmac "$kern_file" >"${kern_file/vmlinuz/.vmlinuz}.hmac" ||
|
|
panic "Failed to create HMAC for '$kern_file'"
|
|
|
|
echo
|
|
log "Signed '$kern_version' successfully"
|
|
echo
|
|
}
|
|
|
|
file_checks() {
|
|
local kfile="$1"
|
|
[ -e "$kfile" ] ||
|
|
panic "Kernel file '$kfile' was not found"
|
|
[ -e "$KEY_PUB_DIR$KEY_PUB" ] ||
|
|
panic "'$KEY_PUB_DIR$KEY_PUB' was not found, please run 'setup' first"
|
|
[ -e "$KEY_PRIV_DIR$KEY_PRIV" ] ||
|
|
panic "'$KEY_PRIV_DIR$KEY_PRIV' was not found, please run 'setup' first"
|
|
}
|
|
|
|
main() {
|
|
case "$1" in
|
|
"setup")
|
|
req_check
|
|
setup_signing_keys
|
|
;;
|
|
"sign")
|
|
req_check
|
|
shift
|
|
[ -n "$1" ] &&
|
|
kfile="$1" ||
|
|
kfile="$(find_latest_kernel)"
|
|
kver="${kfile#*vmlinuz-}"
|
|
kver="${kver%%-*}"
|
|
file_checks "$kfile"
|
|
sign_kernel "$kver" "$kfile"
|
|
;;
|
|
"sign-all")
|
|
req_check
|
|
all_kernels_str=$(find_all_kernels)
|
|
read -ra all_kernels <<<"$all_kernels_str"
|
|
for kfile in "${all_kernels[@]}"; do
|
|
[ -n "$kfile" ] || continue
|
|
kver="${kfile#*vmlinuz-}"
|
|
kver="${kver%%-*}"
|
|
file_checks "$kfile"
|
|
sign_kernel "$kver" "$kfile"
|
|
done
|
|
;;
|
|
"version")
|
|
version
|
|
;;
|
|
"status")
|
|
status
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Ensure running as root
|
|
[[ $EUID -eq 0 ]] || exec sudo "$0" "$@"
|
|
|
|
main "$@"
|