#!/bin/bash

cur_dir=$(dirname ${BASH_SOURCE[0]})
source utils

##? Command for managing certificates
##? Usage:
##?     certs ca [--interactive]
##?     certs root <rootname>
##?     certs branch <branchname> <rootname>
##?     certs req <certname>
##?     certs crl <signername> [<serialnumbers>...]
##?     certs pkcs12 <certname> [--addkey]
##?     certs sign <certname> <branchname>
##?     certs verify <certname> <branchname> <rootname>

help=$(getHelp)
eval_opts "${help}" $@

ROOT_DAYS=3650
BRANCH_DAYS=1825
CRL_DAYS=180
ENDUSER_DAYS=180

CONFIG=$(mktemp)
CONFIG_CA_DATABASE=$(mktemp)
CONFIG_CA_CRLNUMBER=$(mktemp)
CONFIG_CONTENTS="
[ ca ]
default_ca = CA_default

[ CA_default ]
database = $CONFIG_CA_DATABASE
crlnumber = $CONFIG_CA_CRLNUMBER
crl_extensions = ext_crl
default_md = SHA256

[ ext_crl ]
authorityKeyIdentifier=keyid:always

[ req ]
distinguished_name = req_distinguished_name
x509_extensions = ext_root
string_mask = utf8only
default_md = SHA256

[ req_distinguished_name ]

[ ext_root ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:TRUE, pathlen:1
keyUsage = critical, cRLSign, keyCertSign
"
echo "unique_subject = no" > $CONFIG_CA_DATABASE.attr
echo "01" > $CONFIG_CA_CRLNUMBER
echo -e "$CONFIG_CONTENTS" > $CONFIG

EXT_BRANCH="
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:TRUE, pathlen:0
keyUsage = critical, cRLSign, keyCertSign
"

EXT_ENDUSER="
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, dataEncipherment, keyEncipherment, keyAgreement
"

BRANCHES="
client
other
"

rm_config_files() { rm -f $CONFIG $CONFIG_CA_DATABASE $CONFIG_CA_DATABASE.attr $CONFIG_CA_CRLNUMBER $CONFIG_CA_CRLNUMBER.old; }
gen_uuid() { echo "0x$(uuidgen | tr -d '-')"; }
gen_key() { openssl genrsa -out "${1}_key.pem" 2048; }
req() { openssl req -config $CONFIG -new -key "${1}_key.pem" -out "${1}_req.pem" -subj "/C=BR/O=tcc-client-auth/CN=${1}/"; }
x509() { openssl x509 -sha256 -CA "${1}_cert.pem" -CAkey "${1}_key.pem" -req -in "${2}_req.pem" -out "${2}_cert.pem" -days "$3" -set_serial $(gen_uuid) -extfile <(echo -e "$4"); }
pkcs12() {
	if $2; then KEY="-inkey ${1}_key.pem"
	else KEY="-nokeys"; fi
	#Password is hardcoded since we don't rely on it for security
	openssl pkcs12 -name "alias" -passout pass:uselesspw $KEY -in "${1}_cert.pem" -export -out "${1}.p12"
}

if $root; then
	gen_key ${rootname}
	openssl req -config $CONFIG -new -x509 -key "${rootname}_key.pem" -days $ROOT_DAYS -set_serial $(gen_uuid) -subj "/C=BR/O=tcc-client-auth/CN=${rootname}/" -out "${rootname}_cert.pem"
elif $branch; then
	gen_key ${branchname}
	req ${branchname}
	x509 ${rootname} ${branchname} $BRANCH_DAYS "$EXT_BRANCH"
elif $req; then
	gen_key ${certname}
	req ${certname}
elif $crl; then
	# Each line contains 6 fields separated by tab:
	# [VRE] creationtime revocationtime serial unknown subject
	# V=valid, R=revoked, E=expired; unknown and subject are not important; time format: yymmddHHMMSSZ (Z = Zulu = GMT)
	for serial in ${serialnumbers[@]}; do
		echo -en "${CADB}R\t" >> $CONFIG_CA_DATABASE
		echo -en "${CADB}$(date -u +%y%m%d%H%M%S)Z\t" >> $CONFIG_CA_DATABASE
		echo -en "${CADB}$(date -u +%y%m%d%H%M%S)Z\t" >> $CONFIG_CA_DATABASE
		echo -e "${CADB}$serial\tunknown\tsubject" >> $CONFIG_CA_DATABASE
	done
	openssl ca -config $CONFIG -gencrl -keyfile "${signername}_key.pem" -cert "${signername}_cert.pem" -out "${signername}_crl.pem" -crldays $CRL_DAYS
elif $pkcs12; then
	pkcs12 ${certname} ${addkey}
elif $sign; then
	x509 ${branchname} ${certname} $ENDUSER_DAYS "$EXT_ENDUSER"
elif $verify; then
	openssl verify -crl_check -CAfile <(cat "${rootname}_cert.pem" "${rootname}_crl.pem") "${branchname}_cert.pem"
	openssl verify -crl_check -CAfile <(cat "${rootname}_cert.pem" "${rootname}_crl.pem" "${branchname}_cert.pem" "${branchname}_crl.pem") "${certname}_cert.pem"
elif $ca; then
	echo "Create root"
	./certificates-generator-script root root 2> /dev/null

	for branch in $BRANCHES; do
		echo "Create $branch branch"
		./certificates-generator-script branch $branch root 2> /dev/null
		./certificates-generator-script pkcs12 $branch --addkey
	done

	echo -e "\nCreate truststore"
	for i in *_cert.pem; do
		CERT=$(echo $i | sed 's/_cert.pem//')
		keytool -importcert -storetype PKCS12 -keystore truststore.p12 -alias $CERT -storepass uselesspw -file ${CERT}_cert.pem -noprompt
	done

	SYMMETRIC_PASSWORD="$(head -c 16 /dev/random | base64)"
	openssl enc -aes-256-cbc -e -base64 -pass pass:"$SYMMETRIC_PASSWORD" < root_key.pem > root_key.pem.enc

	SS="$(echo -en "$SYMMETRIC_PASSWORD" | sudo ssss-split -Q -t 3 -n 5 | sed -r 's/([a-z0-9]{4})/\1 /g')"
	if $interactive; then
		SS_LENGTH="$(echo -e "$SS" | head -n 1 | wc -c)"
		echo -e "\nSecrets for the root_key.pem symmetric encryption key (press enter to print the next one):"
		for ((i = 1; $i <= $(echo -e "$SS" | wc -l); i++)); do
			read; echo -en "\e[1A\r"
			echo -en "$(echo -e "$SS" | sed "${i}q; d")"
			read; echo -en "\e[1A\r"
			printf "%$(($SS_LENGTH-1))s"
		done
		echo
	else
		echo -e "\nSecrets for the root_key.pem symmetric encryption key:"
		echo -e "$SS"
	fi

	shred -u root_key.pem
fi

rm_config_files
