summaryrefslogblamecommitdiffstats
path: root/satellit_installer/static_files/lighttpd/opt/openslx/slx-cert
blob: e25e3d7dffe090bef9eb416394bffce1f879885c (plain) (tree)























































































                                                                         
               

                                        
                               
                   



                                                              
                                                    
                                                                                                       


                        
                                             














                                                                                                                
                                                                                                












                                                                                                                        


                                                                                                    

                                               






                                                                                
                                 



                                                                                                     






                                         
                               
                   
                                                                   

















                                                                                               
                                       



















                                                                                     












                                                                 
                                                                                                  
                                                                                            

                                                                                                         
                                    














                                                                                                              
                                                   






                                                  
#!/bin/bash

# OpenSLX SSL Certificate management

if ! mkdir "/run/openslx-cert-manager"; then
	echo "Already in progress."
	exit 1
fi
trap 'rm -rf -- /run/openslx-cert-manager' EXIT

declare -rg BASE="/etc/ssl/openslx"
declare -rg PRIV="$BASE/private"
declare -rg CERT="$BASE/cert"
declare -rg LIGHT="$BASE/lighttpd"

mkdir -p "$BASE" "$PRIV" "$CERT"

chown -R root:root "$BASE" || exit 1
chmod u+rwx,go+rx-w "$BASE" "$CERT" || exit 1
chmod u+rwx,go-rwx "$PRIV" || exit 1
# Before doing anything, make sure we have a CA with enough validity left
# File name format for ca is:
# ${PRIV}/ca-FFFFFFFFFF-TTTTTTTTTT.key
# ${CERT}/ca-TTTTTTTTTT.crt
# Where TT is the unix timestamp of "validTo" of that cert
# And FF is the unix timestamp of when we should starting using a CA to
# sign our certificates. This is for a grace period between CA certs.
# We deliver a new CA certificate immediately when it was generated, but
# only start signing server certificates with it after a grace period of
# 180 days. Any client that rebooted within those 180 days will not run
# into any certificate issues, but if you wanted to cover that case too
# you could make it so the client re-downloads trusted CA-certs every
# couple days.

declare -rg NOW="$( date +%s )"
# PROD
declare -rg ca_days="$(( 10 * 365 ))" # 10y
declare -rg ca_min_remain_s="$(( 400 * 86400 ))" # bit more than 1y
declare -rg ca_new_expire_ts="$(( ca_days * 86400 + NOW ))"
declare -rg srv_days=365 # 1y
declare -rg srv_min_remain_s="$(( 180 * 86400 ))" # half a year
declare -rg srv_new_ts="$(( srv_days * 86400 + NOW ))"
# TEST
#declare -rg ca_days=1825 # 5y
#declare -rg ca_min_remain_s="$(( 1260 ))" # bit more than 1y
#declare -rg ca_new_expire_ts="$(( 1320 + NOW ))"
#declare -rg srv_days=365 # 1y
#declare -rg srv_min_remain_s="$(( 1200 ))" # half a year
#declare -rg srv_new_ts="$(( 1230 + NOW ))"


get_ts () {
	ts="${1%.*}"
	ts="${ts##*/ca-}"
	ts="${ts##*/srv-}"
	from="${ts%-*}"
	if [ "$from" = "$ts" ]; then
		from=
	else
		ts="${ts#*-}"
	fi
}

create_conf () {
	ca_dir="$( mktemp -d /tmp/bwlp-XXXXXXXX )"
	[ -z "$ca_dir" ] && exit 1
	mkdir "$ca_dir"/{certs,crl,newcerts,private}
	touch "$ca_dir"/index.txt
	ca_config="$ca_dir/openssl.cnf"
	cp -f "/etc/ssl/openssl.cnf" "$ca_config"
	cat >> "$ca_config" <<-MYCA
		[ CA_openslx ]
		dir		= $ca_dir
		certs		= \$dir/certs
		crl_dir		= \$dir/crl
		database	= \$dir/index.txt
		new_certs_dir	= \$dir/newcerts
		serial		= \$dir/serial
		crl		= \$dir/crl.pem
		x509_extensions	= usr_cert
		name_opt 	= ca_default
		cert_opt 	= ca_default
		default_md	= default
		preserve	= no
		policy		= policy_match
	MYCA
}

latest_ca_file=
ca_last=
for i in "${PRIV}"/ca-??????????.key; do
	[ -s "$i" ] || continue
	get_ts "$i"
	if ! [ -s "${CERT}/ca-${ts}.crt" ] \
		|| ! [ -s "${CERT}/intermediate-${ts}.crt" ] \
		|| ! [ -s "${PRIV}/intermediate.key" ] \
		|| (( ts < NOW )); then
		# Missing cert, or expired -> delete
		rm -f -- "${CERT}/ca-${ts}.crt" "${PRIV}/ca-${ts}.key" "${CERT}/intermediate-${ts}.crt"
		continue
	fi
	ca_last="$ts"
	latest_ca_file="${CERT}/ca-${ts}.crt"
done

mknew=
if [ -z "$ca_last" ] || (( NOW + ca_min_remain_s > ca_last )); then
	# Make new CA
	echo "Creating new CA..."
	openssl req -new -newkey rsa:4096 -x509 -days "$ca_days" -extensions v3_ca \
		-nodes -subj "/C=DE/ST=PewPew/L=HeyHey/O=bwLehrpool/CN=ca-${NOW}.bwlehrpool" \
		-keyout "${PRIV}/ca-${ca_new_expire_ts}.key" -out "${CERT}/ca-${ca_new_expire_ts}.crt" || exit 2
	mknew=1
	#
	# Create new intermediate, sign with all CAs
	csr="$( mktemp /tmp/bwlp-XXXXXXX.csr )"
	# Create request, CA:TRUE
	echo "Generate intermediate key+CSR..."
	[ -s "${PRIV}/intermediate.key" ] || openssl genrsa -out "${PRIV}/intermediate.key" 4096
	openssl req -new -key "${PRIV}/intermediate.key" \
		-nodes -subj "/C=DE/ST=PewPew/L=HeyHey/O=bwLehrpool/CN=intermediate.bwlehrpool" \
		-out "$csr" || exit 2
	create_conf
	# Sign request, CA:TRUE
	echo "Sign new intermediate key with CA..."
	openssl ca -config "$ca_config" -extensions v3_ca -create_serial \
		-policy policy_anything -days "$ca_days" \
		-cert "${CERT}/ca-${ca_new_expire_ts}.crt" -keyfile "${PRIV}/ca-${ca_new_expire_ts}.key" \
		-notext -name CA_openslx -batch -out "${CERT}/intermediate-${ca_new_expire_ts}.crt" -in "$csr" || exit 2
	rm -rf -- "$ca_dir" "$csr"
fi


if [ -n "$mknew" ] || ! [ -s "/opt/openslx/configs/modules/self-signed-ca.tar" ] \
		|| [ "/opt/openslx/configs/modules/self-signed-ca.tar" -ot "$latest_ca_file" ]; then
	# Rebuild config module for clients
	echo "Updating client config module..."
	(
		tmpdir="$( mktemp -d '/tmp/bwlp-XXXXXXX' )"
		cp -a "${CERT}/"ca-*.crt "$tmpdir/"
		cd "$tmpdir/" || exit 6
		openssl rehash .
		tar -c -k -f "/opt/openslx/configs/modules/self-signed-ca.tar" \
			--transform 's#^[./][./]*#/opt/openslx/ssl/#' .
		cd /tmp || exit 7
		rm -rf -- "$tmpdir"
		sudo -u www-data -n php /srv/openslx/www/slx-admin/api.php sysconfig --action rebuild
		echo "."
	)
fi

# Now check the server certificate

declare -a srv_list
srv_list=()
for i in "${PRIV}"/srv-??????????.key; do
	[ -s "$i" ] || continue
	get_ts "$i"
	if (( ts < NOW )) || ! [ -s "${CERT}/srv-${ts}.crt" ]; then
		rm -f -- "$i" "${CERT}/srv-${ts}.crt"
		continue
	fi
	srv_list+=( "$ts" )
done

if [ -n "$mknew" ] || [ "${#srv_list[@]}" = 0 ] \
		|| [ "$(( NOW + srv_min_remain_s ))" -gt "${srv_list[-1]}" ]; then
	# Request ServerCert
	csr="$( mktemp /tmp/bwlp-XXXXXXX.csr )"
	echo "Generating new Server Certificate. Key+CSR..."
	rm -f -- "${CERT}"/srv-*.crt "${PRIV}/srv.key.tmp" "${PRIV}"/srv-*.key
	openssl req -new -nodes -keyout "${PRIV}/srv.key.tmp" -out "$csr" \
		-subj "/C=DE/ST=PewPew/L=HeyHey/O=bwLehrpool/CN=satellite.bwlehrpool" || exit 4
	echo "Signing Server Certificate with intermediate..."
	declare -a in_list
	in_list=()
	for i in "${CERT}"/intermediate-??????????.crt; do
		[ -s "$i" ] || continue
		get_ts "$i"
		if (( ts < NOW )); then
			echo "Expired intermediate $i"
			rm -f -- "$i"
			continue
		fi
		echo "Have intermediate $i"
		in_list+=( "$i" )
	done
	if [ "${#in_list[@]}" = 0 ]; then
		echo "ERROR: Have no intermediate certificate"
		exit 11
	fi
	for in_cert in "${in_list[@]}"; do
		get_ts "$in_cert"
		(( ts < 30 * 86400 + NOW )) && continue # Expiring in a month, ignore
		break # Need only one really
	done
	echo "Signing with $in_cert"
	create_conf
	# Need extfile for SAN, chromium doesn't honor CN anymore
	cat > "${csr}.cnf" <<-END
	basicConstraints = CA:FALSE
	nsCertType = server
	nsComment = "OpenSSL Generated Server Certificate"
	subjectKeyIdentifier = hash
	authorityKeyIdentifier = keyid,issuer:always
	keyUsage = critical, digitalSignature, keyEncipherment
	extendedKeyUsage = serverAuth
	subjectAltName = @alt_names
	[alt_names]
	DNS.1 = satellite.bwlehrpool
	END
	openssl ca -config "$ca_config" -create_serial -policy policy_anything -days "$srv_days" \
		-cert "$in_cert" -keyfile "${PRIV}/intermediate.key" -extfile "${csr}.cnf" \
		-notext -name CA_openslx -batch -out "${CERT}/srv-${srv_new_ts}.crt" -in "$csr" || exit 4
	rm -rf -- "$ca_dir"
	rm -f -- "$csr" "${csr}.cnf"
	mv "${PRIV}/srv.key.tmp" "${PRIV}/srv-${srv_new_ts}.key" || exit 5
	srv_list+=( "$srv_new_ts" )

	# Combine and prepare for lighttpd

	mkdir -p "$LIGHT" || exit 10

	# Combine cert and key, as required by lighttpd
	echo "Writing out lighttpd PEMs..."
	cat "${CERT}/srv-${srv_new_ts}.crt" "${PRIV}/srv-${srv_new_ts}.key" > "${LIGHT}/server.pem" || exit 10
	chmod 0600 "${LIGHT}/server.pem"

	# Create ca-chain
	cat "${in_list[@]}" > "${LIGHT}/ca-chain.pem"

	if [ "$1" = "--restart" ] || [ -t 0 ]; then
		echo "Restarting lighttpd..."
		systemctl restart lighttpd.service
	fi
fi

echo "Done."
exit 0