#!/bin/bash

set -e

srv_file_pref=host
pbx_file_pref=pbx
certs_folder="/etc/apache2/certs"
conf_folder="/root/.mt_certs"

myname=$(basename "$0")
usage() {
	[ "$#" -gt 0 ] && echo >&2 "$@"
	echo >&2 "Usage: $myname {action} [arguments]"
	echo >&2 "  Actions:"
	echo >&2 "      gen <FQDN> <Country> <Locality> <Organization> <Organization Unit> <E-mail> # generate wildcard certificate request (CSR)"
	echo >&2 "         FQDN             -  Fully Qualified Domain Name ('CN' and 'subjectAltName')"
	echo >&2 "                             The CSR will be prepared for this FQDN and also"
	echo >&2 "                             for the corresponding wildcard."
	echo >&2 "                             For example: if FQDN=pbx.example.com then the CSR 'subjectAltName' will contain"
	echo >&2 "                             pbx.example.com and *.pbx.example.com"
	echo >&2 "         Country           - two letter code country name ('C'). For example: US"
	echo >&2 "         State             - The state/region where your organization is located ('ST'). For example: California or \"\" to omit"
	echo >&2 "         Locality Name     - your city or town ('L'). For example: \"My City\""
	echo >&2 "         Organization      - organization name ('O'). For example: \"My Company\""
	echo >&2 "         Organization Unit - organization unit name ('OU'). For example: \"Technical Support\""
	echo >&2 "         E-mail            - email address ('emailAddress')"
	echo >&2 ""
	echo >&2 "      renew                - generate a CSR file for certificate renewal"
	echo >&2 "      view    <CSR file name>  - view content of a CSR file"
	echo >&2 "      print   <CSR file name>  - print encoded CSR file content"
	echo >&2 "      install-full <private_key> <certificate file> [<full path folder>]  - install the private key and the certificate. Default folder: /etc/apache2/certs"
	echo >&2 "      install-cert <certificate file> [<full path folder>]  - install the certificate only. Default folder: /etc/apache2/certs"
	exit 1
}

gen() {
	fqdn=$1
	Country=$2
	State=$3
	Locality=$4
	Organization=$5
	OrgUnit=$6
	Email=$7
	
	mkdir -p "$conf_folder"
	set +e
	rm ${conf_folder}/*{csr,key}
	set -e
	
	echo "**** Generating the server key (${conf_folder}/${srv_file_pref}_key.key) and CSR (${conf_folder}/${srv_file_pref}.csr) ****"

	# Save the openssl parameters in a file. The file will also be used for generating certificate renewal CSR in future.
 	cat <<-EOF >${conf_folder}/host_openssl_config
	[ req ]
	distinguished_name = req_distinguished_name
	req_extensions = ext
	prompt = no

	[ req_distinguished_name ]
	CN=*.${fqdn}
	C=${Country}
	EOF
	if [ "$State" != "" ]; then
	cat <<-EOF >>${conf_folder}/host_openssl_config
	ST=${State}
	EOF
	fi
	cat <<-EOF >>${conf_folder}/host_openssl_config
	L=${Locality}
	O=${Organization}
	OU=${OrgUnit}
	emailAddress=${Email}

	[ ext ]
	keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
	basicConstraints = CA:false
	subjectKeyIdentifier = hash
	subjectAltName=@alt_names

	[alt_names]
	DNS.1=${fqdn}
	DNS.2=*.${fqdn}
	EOF

	openssl req -config ${conf_folder}/host_openssl_config  -out ${conf_folder}/${srv_file_pref}.csr -newkey rsa:2048 -sha256 -nodes -keyout ${conf_folder}/${srv_file_pref}_key.key -new
	if [ $? ]; then
		echo "***SUCCESS***"
		echo "The requested CSR file: \"${conf_folder}/${srv_file_pref}.csr\".  You should submit it to a Certificate Authority."
		echo "The generated private key file: \"${conf_folder}/${srv_file_pref}_key.key\""
		exit 0
	else
		echo "ERROR: the CSR file is not generated."
		exit 1
	fi
}

gen_CSR_for_renewal() {
	echo "**** Generating CSR: ${conf_folder}/${srv_file_pref}.csr for certificate renewal****"
	openssl req -config ${conf_folder}/host_openssl_config -key ${conf_folder}/${srv_file_pref}_key.key -out ${conf_folder}/${srv_file_pref}.csr -sha256 -new
	if [ $? ]; then
		echo "***SUCCESS***"
		echo "The requested CSR file: \"${conf_folder}/${srv_file_pref}.csr\".  You should submit it to a Certificate Authority."
		exit 0
	else
		echo "ERROR: the CSR file is not generated."
		exit 1
	fi
}

view() {
	openssl req -in "$1" -text -noout
}

install_full() {
# We need to create the following files in /etc/apache2/certs:
#    <certificate>
#    <private_key> 
#    host_cert.crt -> <certificate>
#    pbx_cert.crt -> <certificate>
#    host_key.key -> <private_key>
#    pbx_key.key -> <private_key>

	local key="$1"
	local key_fn=${key##*/}   # Get the filename from the full file spec.
	local cert="$2"
	local cert_fn=${cert##*/}
	[ ! -d "$certs_folder" ] && mkdir -p "$certs_folder" || true
	rm -f "$certs_folder"/*_key.key
	rm -f "$certs_folder"/*_cert.crt

	cp "$key" "$cert" "$certs_folder"
	
	# Create symbolic links "pbx_" to the corresponding key and cert files.
	pushd "$certs_folder"
	chmod 640 "${certs_folder}"/"${key_fn}"
	chown .mt "${certs_folder}"/"${key_fn}"
	ln -s "$key_fn" ${pbx_file_pref}_key.key
	
	# It is possible that the priv. key and cert file name is host_key.key and host_cert.crt
	[ ! -f ${srv_file_pref}_key.key ] && ln -s "$key_fn" ${srv_file_pref}_key.key

	ln -s "$cert_fn" ${pbx_file_pref}_cert.crt
	[ ! -f  ${srv_file_pref}_cert.crt ] &&  ln -s "$cert_fn" ${srv_file_pref}_cert.crt
	popd

	echo "***SUCCESS***"
	echo "IMPORTANT: It is necessary to reload Apache2 and restart Kamailio."
	exit 0
}

install_cert() {
	local cert="$1"
	local cert_fn=${cert##*/}
	[ ! -d "$certs_folder" ] && mkdir -p "$certs_folder" || true
	rm -f "$certs_folder"/*_cert.crt

	cp "$cert" "$certs_folder"
	
	# Create symbolic links "pbx_" to the corresponding cert file.
	pushd "$certs_folder"
	ln -s "$cert_fn" ${pbx_file_pref}_cert.crt
	[ ! -f  ${srv_file_pref}_cert.crt ] &&  ln -s "$cert_fn" ${srv_file_pref}_cert.crt
	popd

	echo "***SUCCESS***"
	echo "IMPORTANT: It is necessary to reload Apache2 and restart Kamailio."
	exit 0
}

[ "$#" -lt 1 ] && usage "E: action is not defined"
action=$1
shift
case "$action" in
gen)
	[ "$#" -ne 7 ] && usage "E: Wrong parameters"
	gen "$1" "$2" "$3" "$4" "$5" "$6" "$7"
	;;
renew)
	if [ ! -f ${conf_folder}/${srv_file_pref}_key.key ] || [ ! -f ${conf_folder}/host_openssl_config ]; then
		usage "E: either private key (${conf_folder}/${srv_file_pref}_key.key) or SSL configuration data (${conf_folder}/host_openssl_config) not found"
	fi
	gen_CSR_for_renewal
	;;
view)
	[ "$#" -ne 1 ] && usage "E: Wrong parameters"
	view "$1"
	;;
print)
	[ "$#" -ne 1 ] && usage "E: Wrong parameters"
	[ ! -f "$1" ] && usage "E: file \"${1}\" doesn't exist"
	echo ""
	cat "$1"
	echo ""
	;;
install-full)
	[ "$#" -lt 2 ] && usage "E: Wrong parameters"
	if [ "$#" -eq 3 ]; then
		certs_folder="$3"
		[[ "${certs_folder:0:1}" != "/" ]] && usage "E: A not absolute path is defined as the installation folder"
	fi
	if [ ! -f "$1" ] || [ ! -f "$2" ] ; then
		usage "E: either private key or the certificate file is not found."
	fi
	install_full "$1" "$2"
	;;
install-cert)
	[ "$#" -lt 1 ] && usage "E: Wrong parameters"
	if [ "$#" -eq 2 ]; then
		certs_folder="$2"
		[[ "${certs_folder:0:1}" != "/" ]] && usage "E: A not absolute path is defined as the installation folder"
	fi
	if [ ! -f "$1" ] ; then
		usage "E: the certificate file is not found."
	fi
	install_cert "$1"
	;;*)
	usage "E: Unknown action '$action'"
	;;
esac

