190 lines
6.8 KiB
Bash
190 lines
6.8 KiB
Bash
#!/bin/sh
|
|
#
|
|
###############################################################################
|
|
#
|
|
# edh-keygen.sh
|
|
#
|
|
# Diffie-Hellman Key Generation and Service Management Script
|
|
#
|
|
# This script generates Diffie-Hellman parameter files for various key sizes,
|
|
# manages their permissions and can synchronize keys to custom locations
|
|
# with specified ownership and permissions. It supports service restarts
|
|
# for both root and non-root systemd users and is designed for integration
|
|
# with automated cron jobs.
|
|
#
|
|
# Configuration is read from a .conf or .local file, supporting per-service
|
|
# customization including:
|
|
# - Service name and owner
|
|
# - DH key size
|
|
# - Sync path for DH key
|
|
# - User.group for destination
|
|
# - File permissions for the key
|
|
#
|
|
# Authors: Ivo Noack aka Insonic <me@jabber.ivonoack.de>
|
|
# Stephan Düsterhaupt <me@jabber.stephanduesterhaupt.de>
|
|
#
|
|
# Copyright (c) 2016-2025 CB-601 - the open tec Elevator <mail@opensource-technology.de>
|
|
# License: MIT
|
|
#
|
|
# Project Home: https://dev.town-square.de/cb601/edh-keygen
|
|
#
|
|
###############################################################################
|
|
|
|
# MIT License
|
|
#
|
|
# Copyright (c) 2025 CB-601 - the open tec Elevator <mail@opensource-technology.de>
|
|
#
|
|
# 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.
|
|
|
|
|
|
# Default values (in case not set in config)
|
|
tls_tmp_path='/etc/pki/tls/tmp'
|
|
tls_private_path='/etc/pki/tls/private/'
|
|
|
|
# Determine config file: prefer edh-keygen.local, else use edh-keygen.conf
|
|
script_dir=$(dirname "$0")
|
|
if [ -f "$script_dir/edh-keygen.local" ]; then
|
|
my_service_conf="$script_dir/edh-keygen.local"
|
|
else
|
|
my_service_conf="$script_dir/edh-keygen.conf"
|
|
fi
|
|
|
|
# Check config file
|
|
if [ ! -f "$my_service_conf" ]; then
|
|
echo "Service config file $my_service_conf not found!" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Read global settings from config file
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
case "$line" in
|
|
''|\#*) continue ;; # Skip empty lines and comments
|
|
tls_tmp_path=*) tls_tmp_path="${line#tls_tmp_path=}" ;;
|
|
tls_private_path=*) tls_private_path="${line#tls_private_path=}" ;;
|
|
key_sizes=*) key_sizes="${line#key_sizes=}" ;;
|
|
*) break ;; # Stop at first non-global line (service lines start here)
|
|
esac
|
|
done < "$my_service_conf"
|
|
|
|
# Create path for 'tmp' in '/etc/pki/tls'
|
|
if [ ! -d "$tls_tmp_path" ]; then
|
|
mkdir -p "$tls_tmp_path"
|
|
fi
|
|
|
|
umask 022
|
|
|
|
# If key_sizes is set in the config, use it; otherwise, extract from service lines or set a default
|
|
if [ -z "$key_sizes" ]; then
|
|
key_sizes=$(awk -F: 'NF >= 3 && $3 ~ /^[0-9]+$/ { print $3 }' "$my_service_conf" | sort -nu)
|
|
[ -z "$key_sizes" ] && key_sizes="2048 4096"
|
|
fi
|
|
|
|
# Generate DH params
|
|
for bits in $key_sizes; do
|
|
echo "Generating DH parameters for $bits bits..."
|
|
openssl dhparam -out "$tls_tmp_path/dh_${bits}.pem" "$bits"
|
|
done
|
|
|
|
# Set permissions
|
|
find "$tls_tmp_path" -type f -name "*.pem" -exec chmod 644 {} \;
|
|
|
|
# Sync certs from temporary to private folder
|
|
rsync -a "$tls_tmp_path/"*.pem "$tls_private_path"
|
|
|
|
# Delete the temporary files
|
|
rm -rf "$tls_tmp_path"
|
|
|
|
# Read and process service list
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
# Skip empty lines, comments and global settings (lines with '=')
|
|
case "$line" in
|
|
''|\#*|*=*) continue ;;
|
|
esac
|
|
|
|
# Extract service, owner and sync parameters
|
|
service=$(printf "%s" "$line" | awk -F: '{print $1}')
|
|
owner=$(printf "%s" "$line" | awk -F: '{print $2}')
|
|
key_size=$(printf "%s" "$line" | awk -F: '{print $3}')
|
|
sync_path=$(printf "%s" "$line" | awk -F: '{print $4}')
|
|
user_group=$(printf "%s" "$line" | awk -F: '{print $5}')
|
|
permissions=$(printf "%s" "$line" | awk -F: '{print $6}')
|
|
|
|
echo "$service.service (owner: $owner)..."
|
|
|
|
# Check service status (must run as root)
|
|
if [ "$owner" = "root" ]; then
|
|
mySubState=$(systemctl show -p SubState --value "$service.service" 2>/dev/null)
|
|
else
|
|
uid=$(id -u "$owner" 2>/dev/null)
|
|
if [ -n "$uid" ]; then
|
|
mySubState=$(sudo -u "$owner" XDG_RUNTIME_DIR="/run/user/$uid" /usr/bin/systemctl --user show -p SubState --value "$service.service" 2>/dev/null)
|
|
else
|
|
echo "User $owner not found! Skipping $service." 1>&2
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
if [ "$mySubState" = "running" ]; then
|
|
echo "$service.service is running, restarting as $owner..."
|
|
if [ "$owner" = "root" ]; then
|
|
/usr/bin/systemctl restart "$service.service"
|
|
else
|
|
sudo -u "$owner" XDG_RUNTIME_DIR="/run/user/$uid" /usr/bin/systemctl --user restart "$service"
|
|
fi
|
|
echo "$service.service restarted."
|
|
fi
|
|
|
|
# Handle DH key sync if parameters exist
|
|
if [ -n "$key_size" ] && [ -n "$sync_path" ] && [ -n "$user_group" ] && [ -n "$permissions" ]; then
|
|
if ! echo "$user_group" | grep -q "."; then
|
|
echo "Error: user_group must be 'user.group' for $service. Skipping sync." 1>&2
|
|
continue
|
|
fi
|
|
|
|
dh_file="$tls_private_path/dh_${key_size}.pem"
|
|
if [ ! -f "$dh_file" ]; then
|
|
echo "DH key $dh_file not found. Skipping sync for $service." 1>&2
|
|
continue
|
|
fi
|
|
|
|
# Create directory if missing
|
|
if [ ! -d "$sync_path" ]; then
|
|
mkdir -p "$sync_path" || {
|
|
echo "Failed to create $sync_path for $service." 1>&2
|
|
continue
|
|
}
|
|
chown "$user_group" "$sync_path"
|
|
chmod 750 "$sync_path"
|
|
echo "Created directory $sync_path for $service."
|
|
fi
|
|
|
|
# Copy DH key and set permissions
|
|
cp "$dh_file" "$sync_path/" || {
|
|
echo "Failed to copy DH key to $sync_path for $service." 1>&2
|
|
continue
|
|
}
|
|
chown "$user_group" "$sync_path/dh_${key_size}.pem"
|
|
chmod "$permissions" "$sync_path/dh_${key_size}.pem"
|
|
echo "Synced DH key (${key_size}-bit) to $sync_path for $service."
|
|
fi
|
|
done < "$my_service_conf"
|
|
|
|
|
|
exit 0
|