initial commit
This commit is contained in:
commit
25dddb2c8b
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Build artifacts
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.rpm
|
||||||
|
*.src.rpm
|
||||||
|
*.tar.gz
|
||||||
|
ksigner.spec
|
||||||
|
src/ksigner
|
||||||
|
docs/ksigner.8
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# RPM build artifacts
|
||||||
|
noarch/
|
||||||
|
x86_64/
|
||||||
|
SOURCES/
|
||||||
|
SPECS/
|
||||||
|
BUILD/
|
||||||
|
BUILDROOT/
|
||||||
|
RPMS/
|
||||||
|
SRPMS/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 KSigner Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
59
Makefile
Normal file
59
Makefile
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
NAME = ksigner
|
||||||
|
VERSION = $(shell cat VERSION)
|
||||||
|
RELEASE = $(shell cat RELEASE)
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = build
|
||||||
|
SOURCES = src/ksigner src/ksigner.conf src/ksigner-update-hook docs/ksigner.8 README.md LICENSE
|
||||||
|
CLEANFILES = $(BUILDDIR) $(NAME).spec src/$(NAME) docs/$(NAME).8 noarch *.tar.gz *.rpm *.src.rpm
|
||||||
|
|
||||||
|
.PHONY: all clean dist rpm srpm install
|
||||||
|
|
||||||
|
all: dist
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(CLEANFILES)
|
||||||
|
|
||||||
|
$(BUILDDIR):
|
||||||
|
mkdir -p $(BUILDDIR)
|
||||||
|
|
||||||
|
%.spec: %.spec.in VERSION RELEASE
|
||||||
|
sed -e 's/@VERSION@/$(VERSION)/g' \
|
||||||
|
-e 's/@RELEASE@/$(RELEASE)/g' \
|
||||||
|
$< > $@
|
||||||
|
|
||||||
|
src/%: src/%.in VERSION RELEASE
|
||||||
|
sed -e 's/@VERSION@/$(VERSION)/g' \
|
||||||
|
$< > $@
|
||||||
|
|
||||||
|
docs/%: docs/%.in VERSION RELEASE
|
||||||
|
sed -e 's/@VERSION@/$(VERSION)/g' \
|
||||||
|
$< > $@
|
||||||
|
|
||||||
|
dist: $(BUILDDIR) $(NAME).spec src/$(NAME) docs/$(NAME).8
|
||||||
|
mkdir -p $(BUILDDIR)/$(NAME)-$(VERSION)
|
||||||
|
cp -r $(SOURCES) $(NAME).spec $(BUILDDIR)/$(NAME)-$(VERSION)/
|
||||||
|
cd $(BUILDDIR) && tar -czf $(NAME)-$(VERSION).tar.gz $(NAME)-$(VERSION)/
|
||||||
|
cp $(BUILDDIR)/$(NAME)-$(VERSION).tar.gz $(SOURCEDIR)
|
||||||
|
|
||||||
|
srpm: dist
|
||||||
|
rpmbuild --define "_topdir $(PWD)/$(BUILDDIR)" \
|
||||||
|
--define "_sourcedir $(PWD)" \
|
||||||
|
--define "_srcrpmdir $(PWD)" \
|
||||||
|
-bs $(NAME).spec
|
||||||
|
|
||||||
|
rpm: dist
|
||||||
|
rpmbuild --define "_topdir $(PWD)/$(BUILDDIR)" \
|
||||||
|
--define "_sourcedir $(PWD)" \
|
||||||
|
--define "_rpmdir $(PWD)" \
|
||||||
|
--define "_buildrootdir $(PWD)/$(BUILDDIR)" \
|
||||||
|
-ba $(NAME).spec
|
||||||
|
|
||||||
|
install:
|
||||||
|
install -d $(DESTDIR)/usr/bin
|
||||||
|
install -d $(DESTDIR)/etc/ksigner
|
||||||
|
install -d $(DESTDIR)/etc/kernel/postinst.d
|
||||||
|
install -d $(DESTDIR)/usr/share/man/man8
|
||||||
|
install -m 755 src/ksigner $(DESTDIR)/usr/bin/
|
||||||
|
install -m 644 src/ksigner.conf $(DESTDIR)/etc/ksigner/
|
||||||
|
install -m 755 src/ksigner-update-hook $(DESTDIR)/etc/kernel/postinst.d/zz-ksigner
|
||||||
|
install -m 644 docs/ksigner.8 $(DESTDIR)/usr/share/man/man8/
|
171
README.md
Normal file
171
README.md
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
```bash
|
||||||
|
# Enable/disable automatic signing on kernel updates# Kernel Signer
|
||||||
|
|
||||||
|
A secure boot kernel signing utility for Red Hat based systems (RHEL, CentOS, Fedora, Rocky Linux, AlmaLinux, etc.).
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This package provides a comprehensive solution for signing Linux kernels with custom keys for Secure Boot environments. It includes:
|
||||||
|
|
||||||
|
- Automatic key generation and MOK enrollment
|
||||||
|
- Support for signing individual or all kernels
|
||||||
|
- Configurable through `/etc/ksigner/ksigner.conf`
|
||||||
|
- Comprehensive logging and status reporting
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Building the RPM
|
||||||
|
|
||||||
|
1. Install build dependencies:
|
||||||
|
```bash
|
||||||
|
# RHEL/CentOS/Rocky/Alma
|
||||||
|
sudo dnf install rpm-build rpmdevtools
|
||||||
|
|
||||||
|
# Create build environment
|
||||||
|
rpmdev-setuptree
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build the package:
|
||||||
|
```bash
|
||||||
|
# Create source tarball
|
||||||
|
make dist
|
||||||
|
|
||||||
|
# Build RPM
|
||||||
|
make rpm
|
||||||
|
|
||||||
|
# Or build source RPM
|
||||||
|
make srpm
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install the package:
|
||||||
|
```bash
|
||||||
|
sudo rpm -ivh ksigner*.rpm
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
The following packages will be automatically installed as dependencies:
|
||||||
|
- `openssl` - Key generation and certificate operations
|
||||||
|
- `mokutil` - Machine Owner Key management
|
||||||
|
- `sbsigntools` - Kernel signing utilities
|
||||||
|
- `hmaccalc` - HMAC generation for signed kernels
|
||||||
|
- `sudo` - Privilege escalation
|
||||||
|
- `bash` (>= 4.0) - Shell scripting features
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. **Install the package** (as shown above)
|
||||||
|
|
||||||
|
2. **Set up signing keys**:
|
||||||
|
```bash
|
||||||
|
sudo ksigner setup
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Reboot and enroll MOK keys**:
|
||||||
|
- Reboot your system
|
||||||
|
- In the MOK management interface: Enroll MOK → Continue → Yes → Enter password → OK
|
||||||
|
|
||||||
|
4. **Sign kernels**:
|
||||||
|
```bash
|
||||||
|
# Sign latest kernel
|
||||||
|
sudo ksigner sign
|
||||||
|
|
||||||
|
# Sign all kernels
|
||||||
|
sudo ksigner sign-all
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
sudo ksigner status
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Edit `/etc/ksigner/ksigner.conf` to customize behavior:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable/disable automatic signing on kernel updates
|
||||||
|
SIGN_ON_UPDATE=true
|
||||||
|
|
||||||
|
# Type of automatic signing (sign, sign-lts, sign-all, sign-all-lts)
|
||||||
|
AUTO_SIGN_TYPE="sign-lts"
|
||||||
|
|
||||||
|
# Define which kernel versions are considered LTS
|
||||||
|
LTS_VERSIONS=(
|
||||||
|
"6.12"
|
||||||
|
"6.6"
|
||||||
|
"6.1"
|
||||||
|
"5.15"
|
||||||
|
"5.10"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
- `ksigner setup` - Create and install signing keys
|
||||||
|
- `ksigner sign [kernel_file]` - Sign a kernel (latest if no file specified)
|
||||||
|
- `ksigner sign-lts [kernel_file]` - Sign an LTS kernel
|
||||||
|
- `ksigner sign-all` - Sign all available kernels
|
||||||
|
- `ksigner sign-all-lts` - Sign all LTS kernels
|
||||||
|
- `ksigner status` - Show signing key status
|
||||||
|
- `ksigner version` - Show version information
|
||||||
|
|
||||||
|
## Automatic Kernel Signing
|
||||||
|
|
||||||
|
When `SIGN_ON_UPDATE=true` in the configuration, kernels are automatically signed when installed via package manager. The hook script `/etc/kernel/postinst.d/zz-ksigner` handles this process.
|
||||||
|
|
||||||
|
Logs are written to `/var/log/ksigner.log`.
|
||||||
|
|
||||||
|
## File Locations
|
||||||
|
|
||||||
|
- **Configuration**: `/etc/ksigner/ksigner.conf`
|
||||||
|
- **Public Key**: `/etc/pki/sbsign/certs/MOK.pem`
|
||||||
|
- **Private Key**: `/etc/pki/sbsign/private/MOK.priv`
|
||||||
|
- **DER Key**: `/etc/pki/sbsign/certs/MOK.der`
|
||||||
|
- **Log File**: `/var/log/ksigner.log`
|
||||||
|
- **Update Hook**: `/etc/kernel/postinst.d/zz-ksigner`
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- Private keys are stored with restrictive permissions (600)
|
||||||
|
- MOK enrollment requires manual confirmation to prevent unauthorized access
|
||||||
|
- All operations require root privileges
|
||||||
|
- HMAC files are generated for integrity verification
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
```bash
|
||||||
|
sudo ksigner status
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
```bash
|
||||||
|
sudo tail -f /var/log/ksigner.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify MOK Enrollment
|
||||||
|
```bash
|
||||||
|
sudo mokutil --list-enrolled
|
||||||
|
```
|
||||||
|
|
||||||
|
### Re-enroll Keys
|
||||||
|
If keys become corrupted or lost:
|
||||||
|
```bash
|
||||||
|
sudo ksigner setup
|
||||||
|
# Then reboot and re-enroll MOK
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This software is released under the MIT License. See LICENSE file for details.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please submit pull requests or issues through the project repository.
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For support, please:
|
||||||
|
1. Check the man page: `man ksigner`
|
||||||
|
2. Review logs in `/var/log/ksigner.log`
|
||||||
|
3. Use the status command: `sudo ksigner status`
|
||||||
|
4. File issues in the project repository
|
147
docs/ksigner.8.in
Normal file
147
docs/ksigner.8.in
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
.TH KSIGNER 8 "September 2025" "ksigner @VERSION@" "System Administration"
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
ksigner \- Secure Boot kernel signing utility
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B ksigner
|
||||||
|
.RI { setup | sign | sign-all | version | status }
|
||||||
|
.RI [ vmlinuz_kernel_filepath ]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B ksigner
|
||||||
|
is a utility for signing Linux kernels with custom keys for Secure Boot environments.
|
||||||
|
It supports signing individual kernels or all available kernels.
|
||||||
|
|
||||||
|
.SH COMMANDS
|
||||||
|
.TP
|
||||||
|
.B setup
|
||||||
|
Create and install signing keys. This must be run before any signing operations.
|
||||||
|
The command generates RSA-4096 keys, converts them to appropriate formats,
|
||||||
|
installs them in the system directories, and imports them to the Machine Owner Key (MOK) database.
|
||||||
|
After running this command, you must reboot and enroll the keys through the MOK management interface.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B sign
|
||||||
|
Sign a single kernel file. If no kernel filepath is provided, signs the latest available kernel.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B sign-all
|
||||||
|
Sign all available kernels in /boot that match the pattern vmlinuz-*.
|
||||||
|
Excludes rescue kernels.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B version
|
||||||
|
Display version information.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B status
|
||||||
|
Show the current status of signing keys and MOK enrollment.
|
||||||
|
|
||||||
|
.SH FILES
|
||||||
|
.TP
|
||||||
|
.I /etc/ksigner/ksigner.conf
|
||||||
|
Main configuration file. Contains key paths, automatic signing settings, and LTS version definitions.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.I /etc/pki/sbsign/certs/MOK.pem
|
||||||
|
Public signing key in PEM format.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.I /etc/pki/sbsign/private/MOK.priv
|
||||||
|
Private signing key.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.I /etc/pki/sbsign/certs/MOK.der
|
||||||
|
Public signing key in DER format for MOK import.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.I /etc/kernel/postinst.d/zz-ksigner
|
||||||
|
Kernel update hook script for automatic signing.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.I /var/log/ksigner.log
|
||||||
|
Log file for automatic signing operations.
|
||||||
|
|
||||||
|
.SH CONFIGURATION
|
||||||
|
The behavior of ksigner can be customized through the configuration file
|
||||||
|
.IR /etc/ksigner/ksigner.conf .
|
||||||
|
Key configuration options include:
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B KEY_LIFETIME_DAYS
|
||||||
|
Number of days the signing keys should remain valid (default: 36500, approximately 100 years).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B SIGN_ON_UPDATE
|
||||||
|
Enable or disable automatic signing when kernels are updated (default: true).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B AUTO_SIGN_TYPE
|
||||||
|
Type of automatic signing to perform on kernel updates.
|
||||||
|
Valid options are: sign, sign-all (default: sign).
|
||||||
|
|
||||||
|
.SH AUTOMATIC KERNEL SIGNING
|
||||||
|
When SIGN_ON_UPDATE is enabled in the configuration, new kernels are automatically signed
|
||||||
|
when they are installed through the package manager. The kernel update hook script
|
||||||
|
.I /etc/kernel/postinst.d/zz-ksigner
|
||||||
|
is executed during kernel package installation and performs the configured signing operation.
|
||||||
|
|
||||||
|
.SH EXAMPLES
|
||||||
|
.TP
|
||||||
|
Set up signing keys for the first time:
|
||||||
|
.B ksigner setup
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Sign the latest kernel:
|
||||||
|
.B ksigner sign
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Sign a specific kernel:
|
||||||
|
.B ksigner sign /boot/vmlinuz-6.1.0-13-amd64
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Sign all kernels:
|
||||||
|
.B ksigner sign-all
|
||||||
|
|
||||||
|
.TP
|
||||||
|
Check the status of signing keys:
|
||||||
|
.B ksigner status
|
||||||
|
|
||||||
|
.SH REQUIREMENTS
|
||||||
|
The following packages must be installed for ksigner to function:
|
||||||
|
.IP \(bu 4
|
||||||
|
openssl - for key generation and certificate operations
|
||||||
|
.IP \(bu 4
|
||||||
|
mokutil - for Machine Owner Key management
|
||||||
|
.IP \(bu 4
|
||||||
|
sbsigntools - for signing kernels (provides sbsign command)
|
||||||
|
.IP \(bu 4
|
||||||
|
hmaccalc - for generating kernel HMAC files
|
||||||
|
.IP \(bu 4
|
||||||
|
sudo - for privilege escalation
|
||||||
|
.IP \(bu 4
|
||||||
|
bash (version 4.0 or later) - for shell scripting features
|
||||||
|
|
||||||
|
.SH SECURITY CONSIDERATIONS
|
||||||
|
.IP \(bu 4
|
||||||
|
Private keys are stored with restrictive permissions (600) in /etc/pki/sbsign/private/
|
||||||
|
.IP \(bu 4
|
||||||
|
The setup process requires manual MOK enrollment to prevent unauthorized key installation
|
||||||
|
.IP \(bu 4
|
||||||
|
All operations require root privileges
|
||||||
|
.IP \(bu 4
|
||||||
|
HMAC files are generated for signed kernels to maintain integrity
|
||||||
|
|
||||||
|
.SH EXIT STATUS
|
||||||
|
.B ksigner
|
||||||
|
exits with status 0 on success, and non-zero on error.
|
||||||
|
|
||||||
|
.SH BUGS
|
||||||
|
Report bugs to your distribution's bug tracking system or the project repository.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR mokutil (8),
|
||||||
|
.BR sbsign (1),
|
||||||
|
.BR openssl (1),
|
||||||
|
.BR systemctl (1)
|
70
ksigner.spec.in
Normal file
70
ksigner.spec.in
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
Name: ksigner
|
||||||
|
Version: @VERSION@
|
||||||
|
Release: @RELEASE@%{?dist}
|
||||||
|
Summary: Secure Boot kernel signing utility
|
||||||
|
|
||||||
|
License: MIT
|
||||||
|
URL: https://git.radon.win/radon/ksigner
|
||||||
|
Source0: %{name}-%{version}.tar.gz
|
||||||
|
|
||||||
|
BuildArch: noarch
|
||||||
|
|
||||||
|
Requires: openssl
|
||||||
|
Requires: mokutil
|
||||||
|
Requires: sbsigntools
|
||||||
|
Requires: hmaccalc
|
||||||
|
Requires: sudo
|
||||||
|
Requires: bash >= 4.0
|
||||||
|
|
||||||
|
%description
|
||||||
|
A utility for signing Linux kernels with custom keys for Secure Boot.
|
||||||
|
Supports signing individual kernels or all kernels.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q
|
||||||
|
|
||||||
|
%build
|
||||||
|
# Nothing to build - shell script
|
||||||
|
|
||||||
|
%install
|
||||||
|
# Create directories
|
||||||
|
install -d %{buildroot}%{_bindir}
|
||||||
|
install -d %{buildroot}%{_sysconfdir}/ksigner
|
||||||
|
install -d %{buildroot}%{_unitdir}
|
||||||
|
install -d %{buildroot}%{_sysconfdir}/kernel/postinst.d
|
||||||
|
install -d %{buildroot}%{_mandir}/man8
|
||||||
|
|
||||||
|
# Install main script
|
||||||
|
install -m 755 ksigner %{buildroot}%{_bindir}/ksigner
|
||||||
|
|
||||||
|
# Install configuration file
|
||||||
|
install -m 644 ksigner.conf %{buildroot}%{_sysconfdir}/ksigner/ksigner.conf
|
||||||
|
|
||||||
|
# Install kernel update hook
|
||||||
|
install -m 755 ksigner-update-hook %{buildroot}%{_sysconfdir}/kernel/postinst.d/zz-ksigner
|
||||||
|
|
||||||
|
# Install man page
|
||||||
|
install -m 644 ksigner.8 %{buildroot}%{_mandir}/man8/ksigner.8
|
||||||
|
|
||||||
|
%post
|
||||||
|
echo "==========================================="
|
||||||
|
echo "Kernel Signer has been installed."
|
||||||
|
echo "To set up kernel signing:"
|
||||||
|
echo " 1. Run: sudo ksigner setup"
|
||||||
|
echo " 2. Reboot your system"
|
||||||
|
echo " 3. In MOK Manager: Enroll MOK → Continue → Yes → Enter password"
|
||||||
|
echo "==========================================="
|
||||||
|
|
||||||
|
%files
|
||||||
|
%license LICENSE
|
||||||
|
%doc README.md
|
||||||
|
%{_bindir}/ksigner
|
||||||
|
%config(noreplace) %{_sysconfdir}/ksigner/ksigner.conf
|
||||||
|
%{_sysconfdir}/kernel/postinst.d/zz-ksigner
|
||||||
|
%{_mandir}/man8/ksigner.8*
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Tue Sep 23 2025 RadioactivePb <radioactivepb@gmail.com> - @VERSION@-@RELEASE@
|
||||||
|
- Initial RPM release
|
||||||
|
- Added automatic kernel signing on updates
|
||||||
|
- Added configuration file support
|
67
src/ksigner-update-hook
Normal file
67
src/ksigner-update-hook
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Kernel update hook for automatic signing
|
||||||
|
# This script is called when new kernels are installed
|
||||||
|
|
||||||
|
CONFIG_FILE="/etc/ksigner/ksigner.conf"
|
||||||
|
KERNEL_SIGNER="/usr/bin/ksigner"
|
||||||
|
LOG_FILE="/var/log/ksigner.log"
|
||||||
|
|
||||||
|
# Source configuration
|
||||||
|
if [[ -f "$CONFIG_FILE" ]]; then
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
SIGN_ON_UPDATE=${SIGN_ON_UPDATE:-true}
|
||||||
|
AUTO_SIGN_TYPE=${AUTO_SIGN_TYPE:-sign}
|
||||||
|
LOG_FILE=${LOG_FILE:-/var/log/ksigner.log}
|
||||||
|
|
||||||
|
log_message() {
|
||||||
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - ksigner-update-hook: $1" >>"$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Exit if automatic signing is disabled
|
||||||
|
if [[ "$SIGN_ON_UPDATE" != "true" ]]; then
|
||||||
|
log_message "Automatic signing disabled, skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if ksigner exists and keys are set up
|
||||||
|
if [[ ! -x "$KERNEL_SIGNER" ]]; then
|
||||||
|
log_message "ksigner not found at $KERNEL_SIGNER"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "/etc/pki/sbsign/certs/MOK.pem" ]]; then
|
||||||
|
log_message "Signing keys not found, run 'ksigner setup' first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the kernel version from the environment or find the latest
|
||||||
|
if [[ -n "$KERNEL_VERSION" ]]; then
|
||||||
|
KERNEL_FILE="/boot/vmlinuz-$KERNEL_VERSION"
|
||||||
|
if [[ -f "$KERNEL_FILE" ]]; then
|
||||||
|
log_message "Signing newly installed kernel: $KERNEL_VERSION"
|
||||||
|
if "$KERNEL_SIGNER" sign "$KERNEL_FILE" >>"$LOG_FILE" 2>&1; then
|
||||||
|
log_message "Successfully signed kernel $KERNEL_VERSION"
|
||||||
|
else
|
||||||
|
log_message "Failed to sign kernel $KERNEL_VERSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_message "Kernel file not found: $KERNEL_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Fallback to configured auto-sign type
|
||||||
|
log_message "Running automatic signing: $AUTO_SIGN_TYPE"
|
||||||
|
if "$KERNEL_SIGNER" "$AUTO_SIGN_TYPE" >>"$LOG_FILE" 2>&1; then
|
||||||
|
log_message "Successfully completed $AUTO_SIGN_TYPE"
|
||||||
|
else
|
||||||
|
log_message "Failed to complete $AUTO_SIGN_TYPE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
25
src/ksigner.conf
Normal file
25
src/ksigner.conf
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Configuration file for ksigner
|
||||||
|
# This file is sourced by the ksigner script
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
# Automatic signing on kernel updates
|
||||||
|
# Set to true to enable automatic signing when kernels are updated
|
||||||
|
SIGN_ON_UPDATE=true
|
||||||
|
|
||||||
|
# Type of automatic signing to perform
|
||||||
|
# Options: sign, sign-all
|
||||||
|
AUTO_SIGN_TYPE="sign"
|
||||||
|
|
||||||
|
# Log file for automatic signing operations
|
||||||
|
LOG_FILE="/var/log/ksigner.log"
|
276
src/ksigner.in
Normal file
276
src/ksigner.in
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#!/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
|
||||||
|
|
||||||
|
# Default configuration values (can be overridden in config file)
|
||||||
|
KEY_LIFETIME_DAYS=${KEY_LIFETIME_DAYS:-$((365 * 100))}
|
||||||
|
KEY_PUB_DIR=${KEY_PUB_DIR:-/etc/pki/sbsign/certs/}
|
||||||
|
KEY_PUB=${KEY_PUB:-MOK.pem}
|
||||||
|
KEY_PRIV_DIR=${KEY_PRIV_DIR:-/etc/pki/sbsign/private/}
|
||||||
|
KEY_PRIV=${KEY_PRIV:-MOK.priv}
|
||||||
|
KEY_DER=${KEY_DER:-MOK.der}
|
||||||
|
SIGN_ON_UPDATE=${SIGN_ON_UPDATE:-true}
|
||||||
|
AUTO_SIGN_TYPE=${AUTO_SIGN_TYPE:-sign}
|
||||||
|
|
||||||
|
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) 2025"
|
||||||
|
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 "$@"
|
Loading…
x
Reference in New Issue
Block a user