From: Andreas Steffen Date: Fri, 1 Sep 2023 10:33:09 +0000 (+0200) Subject: cert-enroll: certificate checking and enrollment X-Git-Tag: 5.9.12dr1~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbfc12b3300571b43fa07604e8c550778021b4d5;p=thirdparty%2Fstrongswan.git cert-enroll: certificate checking and enrollment The cert-enroll script handles the initial enrollment of an X.509 host certificate with a PKI server via the EST or SCEP protocols. Run as a systemd timer or via a crontab entry the script daily checks the expiration date of the host certificate. When a given deadline is reached, the host certificate is automatically renewed via EST or SCEP re-enrollment based on the possession of the old private key and the matching certificate. --- diff --git a/configure.ac b/configure.ac index 7fa80fbd98..8184d31ac8 100644 --- a/configure.ac +++ b/configure.ac @@ -307,6 +307,7 @@ ARG_ENABL_SET([svc], [enable charon Windows service.]) ARG_ENABL_SET([systemd], [enable systemd specific IKE daemon charon-systemd.]) ARG_DISBL_SET([swanctl], [disable swanctl configuration and control tool.]) ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.]) +ARG_ENABL_SET([cert-enroll], [enable automatic certificate enrollment via EST or SCEP.]) # optional features ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.]) ARG_ENABL_SET([dbghelp-backtraces],[use dbghlp.dll on Windows to create and print backtraces for memory leaks and segfaults.]) @@ -325,6 +326,7 @@ ARG_ENABL_SET([perl-cpan-install],[enable installation of provided CPAN module.] ARG_ENABL_SET([selinux], [enable SELinux support for labeled IPsec.]) ARG_ENABL_SET([tss-trousers], [enable the use of the TrouSerS Trusted Software Stack]) ARG_ENABL_SET([tss-tss2], [enable the use of the TSS 2.0 Trusted Software Stack]) +ARG_ENABL_SET([cert-enroll-timer],[enable installation of cert-enroll as a systemd timer.]) # compile options ARG_ENABL_SET([asan], [enable build with AddressSanitizer (ASan).]) @@ -516,6 +518,10 @@ if test x$stroke = xtrue; then counters=true fi +if test x$cert_enroll = xtrue; then + pki=true +fi + if test x$kdf = xfalse; then if test x$aesni = xtrue -o x$cmac = xtrue -o x$xcbc = xtrue; then AC_MSG_WARN(m4_normalize([ @@ -1030,14 +1036,16 @@ if test x$xml = xtrue; then AC_SUBST(xml_LIBS) fi -if test x$systemd = xtrue; then +if test x$systemd = xtrue -o x$cert_enroll_timer = xtrue; then AC_MSG_CHECKING([for systemd system unit directory]) if test -n "$systemdsystemunitdir" -a "x$systemdsystemunitdir" != xno; then AC_MSG_RESULT([$systemdsystemunitdir]) else AC_MSG_ERROR([not found (try --with-systemdsystemunitdir)]) fi +fi +if test x$systemd = xtrue; then PKG_CHECK_MODULES(systemd, [libsystemd >= 209], [AC_SUBST(systemd_CFLAGS) AC_SUBST(systemd_LIBS)], @@ -1893,6 +1901,8 @@ AM_CONDITIONAL(USE_SWANCTL, test x$swanctl = xtrue) AM_CONDITIONAL(USE_SVC, test x$svc = xtrue) AM_CONDITIONAL(USE_SYSTEMD, test x$systemd = xtrue) AM_CONDITIONAL(USE_LEGACY_SYSTEMD, test -n "$systemdsystemunitdir" -a "x$systemdsystemunitdir" != xno) +AM_CONDITIONAL(USE_CERT_ENROLL, test x$cert_enroll = xtrue) +AM_CONDITIONAL(USE_CERT_ENROLL_TIMER, test x$cert_enroll_timer = xtrue) AM_CONDITIONAL(USE_RUBY_GEMS, test x$ruby_gems = xtrue) AM_CONDITIONAL(USE_PYTHON_EGGS, test x$python_eggs = xtrue) AM_CONDITIONAL(USE_PERL_CPAN, test x$perl_cpan = xtrue) @@ -2167,6 +2177,7 @@ AC_CONFIG_FILES([ src/sw-collector/Makefile src/sec-updater/Makefile src/swanctl/Makefile + src/cert-enroll/Makefile src/xfrmi/Makefile scripts/Makefile testing/Makefile @@ -2206,6 +2217,7 @@ AC_CONFIG_FILES([ src/pt-tls-client/pt-tls-client.1 src/sw-collector/sw-collector.8 src/sec-updater/sec-updater.8 + src/cert-enroll/cert-enroll.8 ]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 2e3af366d0..8abcbcf672 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -142,3 +142,7 @@ endif if USE_LIBTPMTSS SUBDIRS += tpm_extendpcr endif + +if USE_CERT_ENROLL + SUBDIRS += cert-enroll +endif diff --git a/src/cert-enroll/.gitignore b/src/cert-enroll/.gitignore new file mode 100644 index 0000000000..5833c73e29 --- /dev/null +++ b/src/cert-enroll/.gitignore @@ -0,0 +1,5 @@ +cert-enroll +cert-enroll.8 +cert-enroll.service +cert-install-swanctl +cert-install-ipsec diff --git a/src/cert-enroll/Makefile.am b/src/cert-enroll/Makefile.am new file mode 100644 index 0000000000..0ea9e9d2c1 --- /dev/null +++ b/src/cert-enroll/Makefile.am @@ -0,0 +1,51 @@ +REPLACE_TARGETS = \ + cert-enroll \ + cert-install-swanctl \ + cert-install-ipsec \ + cert-enroll.service + +$(REPLACE_TARGETS) : Makefile + $(AM_V_GEN) \ + sed \ + -e "s:@SYSCONFDIR@:$(sysconfdir):" \ + -e "s:@SBINDIR@:$(sbindir):" \ + -e "s:@BINDIR@:$(bindir):" \ + -e "s:@IPSEC_SCRIPT@:$(ipsec_script):" \ + $(srcdir)/$@.in > $@ + +sbin_SCRIPTS = cert-enroll + +cert-enroll : cert-enroll.in + +cert_enrolldir = $(sysconfdir)/cert-enroll.d +cert_enroll_DATA = cert-enroll.conf + +install-data-local: + test -e "$(DESTDIR)$(cert_enrolldir)/cert-install.d" || \ + $(INSTALL) -d "$(DESTDIR)$(cert_enrolldir)/cert-install.d" || true + +cert_install_availabledir = $(sysconfdir)/cert-enroll.d/cert-install-available +cert_install_available_DATA = \ + cert-install-sssd \ + cert-install-dirsrv \ + cert-install-lighttpd \ + cert-install-openxpki \ + cert-install-gitea \ + cert-install-ipsec \ + cert-install-swanctl + +cert-install-swanctl : cert-install-swanctl.in + +cert-install-ipsec : cert-install-ipsec.in + +man8_MANS = cert-enroll.8 + +CLEANFILES = cert-enroll cert-install-swanctl cert-install-ipsec + +if USE_CERT_ENROLL_TIMER +systemdsystemunit_DATA = cert-enroll.service cert-enroll.timer + +cert-enroll.service : cert-enroll.service.in + +CLEANFILES += cert-enroll.service +endif diff --git a/src/cert-enroll/cert-enroll.8.in b/src/cert-enroll/cert-enroll.8.in new file mode 100644 index 0000000000..7824d90736 --- /dev/null +++ b/src/cert-enroll/cert-enroll.8.in @@ -0,0 +1,86 @@ +.TH CERT-ENROLL 8 "2023-09-01" "@PACKAGE_VERSION@" "strongSwan" +. +.SH "NAME" +. +cert-enroll \- Requests X.509 certificates from a PKI via EST or SCEP protocols +. +.SH "SYNOPSIS" +. +.SY "cert-enroll" +.OP \-c "file +.OP \-i "directory" +.YS +. +.SY "cert-enroll" +.B \-h +.YS +. +.SH "DESCRIPTION" +. +.B cert-enroll +uses the strongSwan +.BR pki +command to request an initial X.509 certificate from a PKI server using either +the EST (Enrollment over Secure Transport) or the SCEP (Simple Certificate +Enrollment Protocol) certificate enrollment protocol. After having received the +host certificate, its expiration date can be monitored periodically and a new +certificate will be automatically requested when a predefined deadline of +remaining validity days is reached. The availability of new CA certificates is +also monitored periodically. The generated RSA or EDCSA private key, the +downloaded X.509 certificate and the current set of CA certificates can then be +installed in specific places on the host via a selection of installation scripts. +. +.SH "OPTIONS" +. +.TP +.B "\-h" +Prints usage information and a short summary of the available commands. +.TP +.BI "\-c " file +Path to the optional local configuration file that can be used to overwrite +parameters in the default configuration file +@sysconfdir@/cert-enroll.d/cert-enroll.conf. +Defaults to @sysconfdir@/cert-enroll.d/cert-enroll.conf.local. +.TP +.BI "\-i " directory +Path to the installation script directory. Defaults to +@sysconfdir@/cert-enroll.d/cert-install.d. This directory will contain dynamic +links to selected installation scripts available in the +@sysconfdir@/cert-enroll.d/cert-install-available directory. +. +.SH "CONFIGURATION" +. +The configuration parameters for the +.BR cert-enroll +script are defined in +.BR cert-enroll.conf. +and selected parameters can be overwritten with the local configuration file +.BR cert-enroll.conf.local. +. +.SH FILES +. +.nf +.na +@sysconfdir@/cert-enroll/cert-enroll.conf default configuration file +.ad +.fi +.nf +.na +@sysconfdir@/cert-enroll/cert-enroll.conf.local optional local configuration file +.ad +.fi +.nf +.na +@sysconfdir@/cert-enroll/cert-install.d default installation script directory +.ad +.fi +.nf +.na +@sysconfdir@/cert-enroll/cert-install-available selection of available installation scripts +.ad +.fi +.nf +.na +/root/certificates/ default certificate directory +.ad +.fi diff --git a/src/cert-enroll/cert-enroll.conf b/src/cert-enroll/cert-enroll.conf new file mode 100644 index 0000000000..d690465005 --- /dev/null +++ b/src/cert-enroll/cert-enroll.conf @@ -0,0 +1,73 @@ +#!/bin/bash +# Global configuration file for the strongSwan cert-enroll script +# +# This default configuration file should not be edited as the changes +# might get overwritten by software updates. If you just want to adapt +# a few parameters, do this in a 'cert-enroll.conf.local' file which +# will overload the corresponding default values. + +# Minimum number of days when a new certificate will be requested +: ${MIN_DAYS=42} + +# Interval in days for checking CA certificate changes +: ${CA_CHECK_INTERVAL=7} + +# Directory where the certificates and keys will be stored +: ${CERTDIR=/root/certificates} + +# Key and certificate names +: ${HOSTKEY=key.pem} +: ${HOSTCERT=cert.pem} +: ${CERTREQ=req.pem} +: ${CAOUT=cacert} +: ${ROOTCA=$CAOUT.pem} +: ${OLDROOTCA=$CAOUT-old.pem} +: ${SUBCA=$CAOUT-1.pem} +: ${OLDSUBCA=$CAOUT-1-old.pem} +: ${RAOUT=racert} +: ${RACERT=$RAOUT.pem} + +# TLS root CA certificate required by EST +# (might also be a Let's Encrypt or other third party root CA certificate) +: ${TLSROOTCA=$CERTDIR/$ROOTCA} + +# Private key type (either "ECDSA", "RSA", "ED25519" or "ED448") +: ${KEYTYPE=ECDSA} + +# RSA private key size in bits +: ${RSA_SIZE=3072} + +# ECDSA private key size in bits +: ${ECDSA_SIZE=256} + +# Fully Qualified Domain Name and Distinguished Name +: ${FQDN=`hostname`} +: ${DN="C=CH, O=Example Company, CN=$FQDN"} + +# Subject Alternative Name (SAN) +: ${SAN=--san $FQDN} + +# Optional additional Subject Alternative Names (fill in and uncomment) +: ${ADD_SANS=()} +# ADD_SANS+=(--san ) + +# Certificate profile (one of "client", "server", "dual" or "ocsp") +: ${PROFILE=dual} + +# Enrollment protocol (either "EST" or "SCEP") +: ${PROTOCOL=EST} + +# Protocol for fetching CA certificates (either "EST" or "SCEP") +: ${CA_PROTOCOL=$PROTOCOL} + +# URL of the EST enrollment server +: ${EST_URL=https://pki.example.com} + +# URL of the SCEP enrollment server +: ${SCEP_URL=http://pki.example.com/scep} + +# Maximum poll time in seconds for EST enrollment process +: ${EST_MAX_POLL_TIME=28800} + +# Maximum poll time in seconds for SCEP enrollment process +: ${SCEP_MAX_POLL_TIME=28800} diff --git a/src/cert-enroll/cert-enroll.in b/src/cert-enroll/cert-enroll.in new file mode 100644 index 0000000000..ad21c79a26 --- /dev/null +++ b/src/cert-enroll/cert-enroll.in @@ -0,0 +1,412 @@ +#!/bin/bash +# Enroll or re-enroll X.509 certificates via EST or SCEP protocols using +# the strongSwan pki tool. Install the certificates via the install scripts +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set default configuration and installation scripts +# +CONFIG_DIR="@SYSCONFDIR@/cert-enroll.d" +CONFIG_SCRIPT="$CONFIG_DIR/cert-enroll.conf" +CONFIG_SCRIPT_LOCAL="$CONFIG_DIR/cert-enroll.conf.local" +INSTALL_SCRIPT_DIR="$CONFIG_DIR/cert-install.d" + +############################################################################## +# Parse optional arguments +# +function help() +{ + echo "Usage:" + echo "cert-enroll [-c filename] [-i directory]" + echo "Options:" + echo " -h print usage information" + echo " -c local configuration file, defaults to $CONFIG_SCRIPT_LOCAL" + echo " -i installation script directory, defaults to $INSTALL_SCRIPT_DIR" +} + +while getopts "c:i:h" opt +do + case "$opt" in + c) + CONFIG_SCRIPT_LOCAL=${OPTARG} + ;; + i) + INSTALL_SCRIPT_DIR=${OPTARG} + ;; + h) + help; exit 0 + ;; + esac +done + +############################################################################## +# Set optional local configuration parameters, overwriting default parameters +# +if [ -f $CONFIG_SCRIPT_LOCAL ] +then + . $CONFIG_SCRIPT_LOCAL +fi + +############################################################################## +# Set default configuration parameters +# +if [ -f $CONFIG_SCRIPT ] +then + . $CONFIG_SCRIPT +elif [ -f $CONFIG_SCRIPT_LOCAL ] +then + echo "Warning: default configuration file '$CONFIG_SCRIPT' not found," \ + "depending on local configuration '$CONFIG_SCRIPT_LOCAL' only" +else + echo "Error: neither '$CONFIG_SCRIPT' nor '$CONFIG_SCRIPT_LOCAL'" \ + "configuration files found" + exit 1 +fi + +# Path to the strongSwan pki command +PKI="@BINDIR@/pki" + +############################################################################## +# Define some local functions +# +function gen_private_key() +{ + status=0 + $PKI --gen --type $key_type --size $size --outform pem > "$1" || status=$? + if [ $status -ne 0 -o ! -s $1 ] + then + echo "Error: generation of $size bit $KEYTYPE private key failed" + exit 1 + fi + chmod 600 $1 + echo " generated $size bit $KEYTYPE private key '$1'" +} + +function gen_cert_request() +{ + status=0 + $PKI --req --in "$1/$HOSTKEY" --type $in_type --dn "$DN" \ + $SAN "${ADD_SANS[@]}" \ + --profile $PROFILE --outform pem > "$1/$CERTREQ" || status=$? + + if [ $status -ne 0 -o ! -s $1 ] + then + echo "Error: generation of PKCS#10 certificate request failed" + exit 1 + fi + chmod 600 $1 + echo " generated PKCS#10 certificate request" +} + +function get_ca_certs() +{ + cd $1 + status=0 + if [ $CA_PROTOCOL == "EST" ] + then + $PKI --estca --url $EST_URL --cacert $TLSROOTCA --caout $CAOUT \ + --outform pem --force || status=$? + if [ $status -ne 0 -o ! -s $ROOTCA -o ! -s $SUBCA ] + then + echo "Error: download of CA certificates via EST failed" + exit 1 + fi + echo " downloaded CA certificates via EST" + else + $PKI --scepca --url $SCEP_URL --caout $CAOUT --raout $RAOUT \ + --outform pem --force || status=$? + if [ $status -ne 0 -o ! -s $ROOTCA -o ! -s $SUBCA -o ! -s $RACERT ] + then + echo "Error: download of CA or RA certificates via SCEP failed" + exit 1 + fi + echo " downloaded CA and RA certificates via SCEP" + fi + cd $CERTDIR +} + +function check_ca_certs() +{ + get_ca_certs "$CERTDIR/new" + + ROOTCA_CHANGED=0 + cmp -s $ROOTCA new/$ROOTCA || ROOTCA_CHANGED=$? + if [ $ROOTCA_CHANGED -ne 0 ] + then + echo "Warning: '$ROOTCA' has changed" + mv $ROOTCA old + mv new/$ROOTCA . + fi + + SUBCA_CHANGED=0 + cmp -s $SUBCA new/$SUBCA || SUBCA_CHANGE=$? + if [ $SUBCA_CHANGED -ne 0 ] + then + echo "Warning: '$SUBCA' has changed" + mv $SUBCA old + mv new/$SUBCA . + fi + + if [ $CA_PROTOCOL == "SCEP" ] + then + mv new/$RACERT . + fi + + if [ $ROOTCA_CHANGED -eq 0 -a $SUBCA_CHANGED -eq 0 ] + then + echo "Ok: '$ROOTCA' and '$SUBCA' are unchanged" + rm new/$ROOTCA new/$SUBCA + return 0 + else + return 1 + fi +} + +function install_certs() +{ + for script in $INSTALL_SCRIPT_DIR/* + do + status=0 + echo " executing '$script'" + KEYTYPE="$KEYTYPE" CERTDIR="$CERTDIR" HOSTKEY="$HOSTKEY" \ + HOSTCERT="$HOSTCERT" ROOTCA="$ROOTCA" SUBCA="$SUBCA" \ + OLDROOTCA="$OLDROOTCA" OLDSUBCA="$OLDSUBCA" \ + /bin/bash $script || status=$? + if [ $status -ne 0 ] + then + echo "Error: executing '$script' failed" + fi + done +} + +############################################################################## +# SCEP certificate enrollment protocol requires RSA +# +if [ $PROTOCOL == "SCEP" -a $KEYTYPE != "RSA" ] +then + echo "Warning: the SCEP protocol does not support $KEYTYPE keys," \ + "switched to RSA key" + KEYTYPE="RSA" +fi + +############################################################################## +# Select key size +# +case $KEYTYPE in + + + RSA) + key_type="rsa" + in_type="rsa" + size=$RSA_SIZE + ;; + + ECDSA) + key_type="ecdsa" + in_type="ecdsa" + size=$ECDSA_SIZE + ;; + + ED25519) + key_type="ed25519" + in_type="priv" + size="256" + ;; + + ED448) + key_type="ed448" + in_type="priv" + size="456" + ;; + + *) + echo "Error: $KEYTYPE key type unknown" + exit 1 + ;; + +esac + +############################################################################## +# Create and change into certificates directory +# +mkdir -p $CERTDIR/new $CERTDIR/old +cd $CERTDIR +echo " changed into the '$CERTDIR' directory" + +############################################################################# +# Fetch the CA certificates with the selected enrollment protocol if possible +# +if [ $CA_PROTOCOL == "EST" -a ! -s $TLSROOTCA ] +then + echo " no TLS root CA certificate for EST available," \ + "revert to SCEP CA protocol" + CA_PROTOCOL="SCEP" +fi + +############################################################################## +# Check if non-empty certficate already exists +# +if [ -s $HOSTCERT ] +then +############################################################################## +# Determine the remaining validity of the certificate in days +# + DAYS=$($PKI --print --in $HOSTCERT | awk '/not after/ { + if (($7 == "ok") && ($11 == "days)")) { + print $10 + } else { + printf("0") + } + }' -) + + if [ $DAYS -ge $MIN_DAYS ] + then + echo "Ok: validity of '$HOSTCERT' is $DAYS days," \ + "more than the minimum of $MIN_DAYS days" + if [ $(expr $DAYS % $CA_CHECK_INTERVAL) -eq 0 ] + then + check_ca_certs && exit 0 + # update CA certificates if any of them changed + install_certs + fi + exit 0 + fi + echo "Warning: validity of '$HOSTCERT' is only $DAYS days," \ + "less than the minimum of $MIN_DAYS days" + +############################################################################## +# Check if non-empty private key already exists +# + if [ -s "new/$HOSTKEY" ] + then + echo "Warning: 'new/$HOSTKEY' already exists," \ + "resuming $PROTOCOL re-enrollment" + else +############################################################################## +# Generate new private key +# + gen_private_key "new/$HOSTKEY" + fi +############################################################################## +# Get and check CA and RA certificates via SCEP or EST +# + check_ca_certs + +############################################################################## +# Re-enroll certificate via SCEP or EST +# + status=0 + if [ $PROTOCOL == "SCEP" ] + then + $PKI --scep --url $SCEP_URL --in new/$HOSTKEY --key $HOSTKEY \ + --cert $HOSTCERT --dn "$DN" $SAN "${ADD_SANS[@]}" \ + --cacert-sig $SUBCA --cacert-enc $RACERT --cacert $ROOTCA \ + --maxpolltime $SCEP_MAX_POLL_TIME --profile $PROFILE \ + --outform pem > new/$HOSTCERT || status=$? + else + gen_cert_request "$CERTDIR/new" + $PKI --est --url $EST_URL --in new/$CERTREQ --cacert $ROOTCA \ + --cacert $SUBCA --cacert $TLSROOTCA --key $HOSTKEY \ + --cert $HOSTCERT --maxpolltime $EST_MAX_POLL_TIME \ + --outform pem > new/$HOSTCERT || status=$? + fi + + if [ $status -ne 0 -o ! -s $HOSTCERT ] + then + echo "Error: re-enrollment via $PROTOCOL failed" + exit 1 + fi + echo "Ok: successfully re-enrolled '$HOSTCERT' via $PROTOCOL" + +############################################################################## +# Replace old key and certificate +# + mv $HOSTKEY $HOSTCERT old + mv new/$HOSTKEY new/$HOSTCERT . + if [ $PROTOCOL == "EST" ] + then + mv $CERTREQ old + mv new/$CERTREQ . + fi + echo " replaced old '$HOSTKEY' and '$HOSTCERT'" + +############################################################################## +# Install keys and certificates +# + install_certs + exit 0 +else +############################################################################## +# No certificate exists yet +# + echo " '$HOSTCERT' doesn't exist yet" + +############################################################################## +# Check if non-empty private key already exists +# + if [ -s "$HOSTKEY" ] + then + echo "Warning: '$HOSTKEY' already exists, resuming $PROTOCOL enrollment" + else +############################################################################## +# Generate private key +# + gen_private_key "$HOSTKEY" + fi +############################################################################## +# Get CA and RA certificates via SCEP +# + get_ca_certs "$CERTDIR" + +############################################################################## +# Enroll certificate via SCEP or EST +# + status=0 + if [ $PROTOCOL == "SCEP" ] + then + $PKI --scep --url $SCEP_URL --in $HOSTKEY --dn "$DN" $SAN "${ADD_SANS[@]}" \ + --cacert-sig $SUBCA --cacert-enc $RACERT --cacert $ROOTCA \ + --profile $PROFILE --maxpolltime $SCEP_MAX_POLL_TIME \ + --outform pem > $HOSTCERT || status=$? + else + gen_cert_request "$CERTDIR" + $PKI --est --url $EST_URL --in $CERTREQ \ + --cacert $ROOTCA --cacert $SUBCA --cacert $TLSROOTCA \ + --maxpolltime $EST_MAX_POLL_TIME \ + --outform pem > $HOSTCERT || status=$? + fi + + if [ $status -ne 0 -o ! -s $HOSTCERT ] + then + echo "Error: enrollment via $PROTOCOL failed" + exit 1 + fi + echo "Ok: successfully enrolled '$HOSTCERT' via $PROTOCOL" + +############################################################################## +# Install keys and certificates +# + install_certs + exit 0 +fi diff --git a/src/cert-enroll/cert-enroll.service.in b/src/cert-enroll/cert-enroll.service.in new file mode 100644 index 0000000000..eda3c7bfe7 --- /dev/null +++ b/src/cert-enroll/cert-enroll.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=X.509 certificate checking (re-enrollment if necessary) +Documentation=man:cert-enroll(8) + +[Service] +Type=oneshot +User=root +ExecStart=@SBINDIR@/cert-enroll +SuccessExitStatus=1 diff --git a/src/cert-enroll/cert-enroll.timer b/src/cert-enroll/cert-enroll.timer new file mode 100644 index 0000000000..10bf658c95 --- /dev/null +++ b/src/cert-enroll/cert-enroll.timer @@ -0,0 +1,12 @@ +[Unit] +Description=daily check of the remaining X.509 certificate lifetime +Documentation=man:cert-enroll(8) + +[Timer] +# The cert-enroll script should be run once a day. +OnCalendar=*-*-* 02:00:00 +RandomizedDelaySec=7200 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/src/cert-enroll/cert-install-dirsrv b/src/cert-enroll/cert-install-dirsrv new file mode 100644 index 0000000000..da196f7565 --- /dev/null +++ b/src/cert-enroll/cert-install-dirsrv @@ -0,0 +1,103 @@ +#!/bin/bash +# Install the private key, the server certificate and the CA certificates in +# the NSS key (key4.db) and certificate (cert9.db) databases used by the 389 +# directory server to identify itself via TLS. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set some local paths +# + +# Path to the NSS directory +NSS_DIR="/etc/dirsrv/slapd-localhost" + +# Path to openssl command +OPENSSL=/usr/bin/openssl + +# Path to certutil command +CERTUTIL=/usr/bin/certutil + +# Path to pk12util command +PK12UTIL=/usr/bin/pk12util + +# Path to dsctl command +DSCTL=/usr/sbin/dsctl + +############################################################################## +# Go to the NSS directory, create a new build subdirectory and change into it +# +rm -r -f $NSS_DIR/build && mkdir $NSS_DIR/build && cd $NSS_DIR/build + +############################################################################## +# Generate a new random password into passwd.txt and also store it in pin.txt +# +$OPENSSL rand -base64 48 > passwd.txt + +echo "Internal (Software) Token:$(cat passwd.txt)" > pin.txt + +chmod 600 passwd.txt pin.txt + +############################################################################## +# Pack the private key and host certificate into a PKCS#12 container +# +$OPENSSL pkcs12 -export -name "Server-Cert" -passout file:passwd.txt \ + -in $CERTDIR/$HOSTCERT -inkey $CERTDIR/$HOSTKEY \ + -out Server-Cert.p12 + +############################################################################## +# Create a new password-protected NSS store and import the PKCS#12 file +# +$CERTUTIL -d . -N -f passwd.txt +$PK12UTIL -d . -i Server-Cert.p12 -w passwd.txt -k passwd.txt + +############################################################################## +# Install the CA certificates +# +$CERTUTIL -d . -A -t "CT,," -n "Root CA" -i $CERTDIR/$ROOTCA \ + -f passwd.txt +$CERTUTIL -d . -A -t "CT,," -n "Sub CA" -i $CERTDIR/$SUBCA \ + -f passwd.txt +if [ -s $CERTDIR/old/$ROOTCA ] +then + $CERTUTIL -d . -A -t "CT,," -n "Old Root CA" -i $CERTDIR/old/$ROOTCA \ + -f passwd.txt +fi +if [ -s $CERTDIR/old/$SUBCA ] +then + $CERTUTIL -d . -A -t "CT,," -n "Old Sub CA" -i $CERTDIR/old/$SUBCA \ + -f passwd.txt +fi + +############################################################################## +# Move the generated credentials to the correct place and delete the build dir +# +mv key4.db cert9.db passwd.txt pin.txt .. + +rm -r $NSS_DIR/build + +############################################################################## +# Restart the 389 directory server +# +$DSCTL localhost restart +exit 0 diff --git a/src/cert-enroll/cert-install-gitea b/src/cert-enroll/cert-install-gitea new file mode 100644 index 0000000000..3ecfbb5d68 --- /dev/null +++ b/src/cert-enroll/cert-install-gitea @@ -0,0 +1,49 @@ +#!/bin/bash +# Install the generated key and certificate as TLS credentials for the Gitea +# web server. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set local paths +# + +# Path to the Gitea credentials +GITEA="/var/lib/gitea/custom" + +############################################################################## +# Change into the certificates directory +# +cd $CERTDIR + +############################################################################## +# Install the private key and certificate +# +cp $HOSTKEY $HOSTCERT $GITEA/ + +############################################################################## +# Restart the gitea systemd service +# +/usr/bin/systemctl restart gitea.service +exit 0 + diff --git a/src/cert-enroll/cert-install-ipsec.in b/src/cert-enroll/cert-install-ipsec.in new file mode 100644 index 0000000000..1eea8def0a --- /dev/null +++ b/src/cert-enroll/cert-install-ipsec.in @@ -0,0 +1,65 @@ +#!/bin/bash +# Install the generated key as well as host an CA certificates on a host running +# strongSwan via the legacy ipsec command line tool. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set some local paths +# + +# Path to the strongSwan ipsec command +IPSEC="@SBINDIR@/@IPSEC_SCRIPT@" + +# Path to the strongSwan ipsec.d directory +IPSECDIR="@SYSCONFDIR@/ipsec.d" + +############################################################################## +# Change into the certificates directory +# +cd $CERTDIR + +############################################################################## +# Install the private key +# +cp $HOSTKEY $IPSECDIR/private + +############################################################################## +# Install the certificate +# +cp $HOSTCERT $IPSECDIR/certs + +############################################################################## +# Install the CA certificates +# +cp $ROOTCA $SUBCA $IPSECDIR/cacerts + +############################################################################## +# Reload the strongSwan charon daemon if it is running +# +if [ -e /var/run/charon.pid ] +then + $IPSEC rereadall + $IPSEC reload +fi +exit 0 diff --git a/src/cert-enroll/cert-install-lighttpd b/src/cert-enroll/cert-install-lighttpd new file mode 100644 index 0000000000..3e799afb2d --- /dev/null +++ b/src/cert-enroll/cert-install-lighttpd @@ -0,0 +1,48 @@ +#!/bin/bash +# Install the generated key and certificate as TLS credentials for a web server +# based based on the lighttpd daemon. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Change into the certificates directory +# +cd $CERTDIR + +############################################################################## +# Install the web server's TLS key and certificate in single file +# +cat $HOSTKEY $HOSTCERT > /etc/lighttpd/https-cert.pem + +############################################################################## +# Restart the lighttpd daemon +# +systemctl list-unit-files lighttpd.service | \ + grep -q "lighttpd.service enabled" && status=$? || status=$? +if [ $status -eq 0 ] +then + /usr/bin/systemctl restart lighttpd.service +else + /etc/init.d/lighttpd restart +fi +exit 0 diff --git a/src/cert-enroll/cert-install-openxpki b/src/cert-enroll/cert-install-openxpki new file mode 100644 index 0000000000..a47444005c --- /dev/null +++ b/src/cert-enroll/cert-install-openxpki @@ -0,0 +1,66 @@ +#!/bin/bash +# Install the generated key and host certificate as well as the CA certificates +# as TLS credentials for the Apache2-based OpenXPKI web server. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set local paths +# + +# Path to the OpenXPKI TLS credentials +OPENXPKI_TLS="/etc/openxpki/tls" + +############################################################################## +# Change into the certificates directory +# +cd $CERTDIR + +############################################################################## +# Install the private key and certificate +# +cp $HOSTKEY $OPENXPKI_TLS/private/openxpki.pem +cp $HOSTCERT $OPENXPKI_TLS/endentity/openxpki.crt + +############################################################################## +# Install and rehash the CA certificates +# +cp $ROOTCA $SUBCA $OPENXPKI_TLS/chain +if [ -s old/$ROOTCA ] +then + cp old/$ROOTCA $OPENXPKI_TLS/chain/$OLDROOTCA +fi +if [ -s old/$SUBCA ] +then + cp old/$SUBCA $OPENXPKI_TLS/chain/$OLDSUBCA +fi + +rm $OPENXPKI_TLS/*.0 + +/usr/bin/openssl rehash $OPENXPKI_TLS + +############################################################################## +# Restart the apache2 systemd service +# +/usr/bin/systemctl restart apache2.service +exit 0 diff --git a/src/cert-enroll/cert-install-sssd b/src/cert-enroll/cert-install-sssd new file mode 100644 index 0000000000..2bfb5ea219 --- /dev/null +++ b/src/cert-enroll/cert-install-sssd @@ -0,0 +1,65 @@ +#!/bin/bash +# Install the present and past CA certificates in the ldap_tls_cacertdir +# directory defined by sssd.conf, folllowed by the execution of the +# openssl_rehash command in that directory so that the SSSD daemon can verify +# the LDAP server certificate. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set some local paths +# + +# Path to the SSSD configuration file +SSSD_CONF="/etc/sssd/sssd.conf" + +# Extract or set path to the LDAP TLS CA cert directory +LDAP_TLS_CACERTDIR=$(awk '/ldap_tls_cacertdir/ {print $3}' $SSSD_CONF) + +############################################################################## +# Change into the certificate directory +# +cd $CERTDIR + +############################################################################## +# Install and rehash the CA certificates +# +cp $ROOTCA $SUBCA $LDAP_TLS_CACERTDIR +if [ -s old/$ROOTCA ] +then + cp old/$ROOTCA $LDAP_TLS_CACERTDIR/$OLDROOTCA +fi +if [ -s old/$SUBCA ] +then + cp old/$SUBCA $LDAP_TLS_CACERTDIR/$OLDSUBCA +fi + +rm $LDAP_TLS_CACERTDIR/*.0 + +/usr/bin/openssl rehash $LDAP_TLS_CACERTDIR + +############################################################################## +# Restart the SSSD systemd service +# +/usr/bin/systemctl restart sssd.service +exit 0 diff --git a/src/cert-enroll/cert-install-swanctl.in b/src/cert-enroll/cert-install-swanctl.in new file mode 100644 index 0000000000..2b2781d525 --- /dev/null +++ b/src/cert-enroll/cert-install-swanctl.in @@ -0,0 +1,81 @@ +#!/bin/bash +# Install the generated key and certificates on the host running strongSwan +# as a systemd service and managed via the swanctl command line tool. +# +# Copyright (C) 2023 Andreas Steffen +# +# 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. +# +set -e + +############################################################################## +# Set some local paths +# + +# Path to the strongSwan swanctl command +SWANCTL="@SBINDIR@/swanctl" + +# Path to the strongSwan swanctl directory +SWANCTLDIR="@SYSCONFDIR@/swanctl" + +############################################################################## +# Change to the certificate directory +# +cd $CERTDIR + +############################################################################## +# Install the private key +# +if [ $KEYTYPE == "RSA" ] +then + cp $HOSTKEY ${SWANCTLDIR}/rsa +elif [ $KEYTYPE == "ECDSA" ] +then + cp $HOSTKEY ${SWANCTLDIR}/ecdsa +else + cp $HOSTKEY ${SWANCTLDIR}/private +fi + +############################################################################## +# Install the certificate +# +cp $HOSTCERT ${SWANCTLDIR}/x509 + +############################################################################## +# Install the CA certificates +# +cp $ROOTCA $SUBCA ${SWANCTLDIR}/x509ca +if [ -s old/$ROOTCA ] +then + cp old/$ROOTCA ${SWANCTLDIR}/x509ca/$OLDROOTCA +fi +if [ -s old/$SUBCA ] +then + cp old/$SUBCA ${SWANCTLDIR}/x509ca/$OLDSUBCA +fi + +############################################################################## +# Reload the strongswan systemd service if it is running +# +if /usr/bin/systemctl -q is-active strongswan.service +then + $SWANCTL --load-creds --noprompt + $SWANCTL --load-conns +fi +exit 0