#!/bin/bash

set -e

ca_file_pref=ca
srv_file_pref=host
pbx_file_pref=pbx
certs_folder="/etc/apache2/certs"

myname=$(basename "$0")
usage() {
	[ "$#" -gt 0 ] && echo >&2 "$@"
	echo >&2 "Usage: $myname {action} [arguments]"
	echo >&2 "  Actions:"
	echo >&2 "      gen <FQDN> <Country> <Organization> <Organization Unit>  # generate selfsigned wildcard certificate"
	echo >&2 "         FQDN             -  Fully Qualified Domain Name ('CN' and 'subjectAltName')"
	echo >&2 "                             The certificate 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 certificate '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 "         Organization      - organization name ('O'). For example: \"My Company\""
	echo >&2 "         Organization Unit - organization unit name ('OU'). For example: \"Technical Support\""
	echo >&2 ""
	echo >&2 "      view    <certificate file name>  - view content of a certificate"
	echo >&2 "      install [<full path folder>]     - install the certificate. Default folder: /etc/apache2/certs"
	exit 1
}

gen() {
	fqdn=$1
	Country=$2
	Organization=$3
	OrgUnit=$4
	
	set +e
	rm ./*{crt,csr,key}
	set -e
	
	echo "**** Genereate CA keys and CA certificate: ${ca_file_pref}_key.key and ${ca_file_pref}_cert.crt ****"

	ca_openssl_config="
	[ req ]
	distinguished_name = req_distinguished_name
	prompt = no

	[ req_distinguished_name ]
	CN = Multi-TenantPBX-CA
	C=\"${Country}\"
	O=\"${Organization}\"
	OU=\"${OrgUnit}\"

	[ ext ]
	keyUsage = critical, cRLSign, keyCertSign
	basicConstraints = critical,CA:true
	subjectKeyIdentifier = hash
	"

	openssl req -config <(echo "$ca_openssl_config") -extensions ext -days 3650 -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout ${ca_file_pref}_key.key \
	    -out ${ca_file_pref}_cert.crt -set_serial $RANDOM -batch -text

	echo "**** Genereate the server key and CSR: ${srv_file_pref}_key.key and ${srv_file_pref}.csr ****"

	host_openssl_config="
	[ req ]
	distinguished_name = req_distinguished_name
	req_extensions = ext
	prompt = no

	[ req_distinguished_name ]
	CN=*.${fqdn}
	C=${Country}
	O=${Organization}
	OU=${OrgUnit}

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

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

	openssl req -config <(echo "$host_openssl_config")  -out ${srv_file_pref}.csr -newkey rsa:2048 -sha256 -nodes -keyout ${srv_file_pref}_key.key -new

	echo "**** Genereate the server wildcard certificate: ${srv_file_pref}_cert.crt ****"

	openssl x509 -req -extfile <(echo "$host_openssl_config") -extensions ext -in ${srv_file_pref}.csr -CA ${ca_file_pref}_cert.crt \
	     -CAkey ${ca_file_pref}_key.key -out ${srv_file_pref}_cert.crt -days 3650 -set_serial $RANDOM -text
	echo "***SUCCESS***"
	exit 0
}

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

install() {
	[ ! -d "$1" ] && mkdir -p "$1" || true
	cp ${srv_file_pref}_key.key ${srv_file_pref}_cert.crt "$1"
	# Create symbolic links "pbx_" to the corresponding $srv_file_pref files. It is because 
	# we are not sure that all of commercial CA are capable to create the wildcard certificates that
	# also include the base domain as subjectAltName. On the other side we want to have the
	# same Apache site configuration file that is not depended on the certificate type.
	chmod 640 "$1"/${srv_file_pref}_key.key
	chown .mt "$1"/${srv_file_pref}_key.key
	rm -f "$1"/${pbx_file_pref}_key.key
	rm -f "$1"/${pbx_file_pref}_cert.crt
	ln -s "$1"/${srv_file_pref}_key.key "$1"/${pbx_file_pref}_key.key
	ln -s "$1"/${srv_file_pref}_cert.crt "$1"/${pbx_file_pref}_cert.crt
	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 4 ] && usage "E: Wrong parameters"
	gen "$1" "$2" "$3" "$4"
	;;
view)
	[ "$#" -ne 1 ] && usage "E: Wrong parameters"
	view "$1"
	;;
install)
	[ "$#" -gt 1 ] && usage "E: Wrong parameters"
	if [ "$#" -eq 1 ]; then
		certs_folder="$1"
		[[ "${certs_folder:0:1}" != "/" ]] && usage "E: A not absolute path is defined as the installation folder"
	fi
	install "$certs_folder"
	;;
*)
	usage "E: Unknown action '$action'"
	;;
esac

