#! /bin/bash
#Copyirght (C) 2021 CloudFabrix Software Inc. All rights reserved.

logerror() {
    echo -e "rdaf-error:   $*"
}
logwarning() {
    echo -e "rdaf-warning: $*"
}
loginfo() {
    echo -e "rdaf-info:    $*"
}

function export_to_pkcs12() {
    # $1 - Client Key
    # $2 - Client Cert
    # $3 - output p12 format file
    # $4 - Password
    # $5 - CA Cert File.
    rm -rf ${CERT_LOG}
    openssl pkcs12 \
        -export \
        -inkey $1 \
        -in $2 \
        -out $3 \
        -certfile $5 \
        -password pass:$4 >> ${CERT_LOG} 2>&1
    exit_code=$?
    if [ $exit_code -ne 0 ] ; then
        logerror "Failed to export to p12"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
        exit $exit_code
    fi
    rm -rf ${CERT_LOG}
    return 0
}

function gen_truststore() {
    rm -rf ${CERT_LOG}
    $KEYTOOL -import \
        -file       $2 \
        -alias      "self.signed" \
        -storepass  $3 \
        -keystore   $1 \
        -noprompt  >> ${CERT_LOG} 2>&1
    exit_code=$?
    if [ $exit_code -ne 0 ] ; then
        logerror "Failed to import ca cert to truststore"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
        exit $exit_code
    fi
    rm -rf ${CERT_LOG}
    return 0
}
    
function gen_keystore() {
    # $1 - Keystore name
    # $2 - source p12
    # $3 - Source Password
    # $4 - keystore password
    rm -rf ${CERT_LOG}
    # remove the dest keystore if it is present
    rm -f $1
    $KEYTOOL -importkeystore \
        -destkeystore   $1 \
        -srckeystore    $2 \
        -srcstoretype   pkcs12 \
        -srcstorepass   $3 \
        -deststorepass  $4 >> ${CERT_LOG} 2>&1
    exit_code=$?
        
    if [ $exit_code -ne 0 ] ; then
        logerror "Failed to generate keystore $1"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
        exit $exit_code
    fi
    rm -rf ${CERT_LOG}
    return 0
}

function copy_ca_cert() {
	loginfo "Copying RDAF Platform Self-Signed CA certificate"
	cp ${RDAF_CERTS_DIR}/rdafplatform.key $1
	cp ${RDAF_CERTS_DIR}/rdafplatform.crt $2
	cp ${RDAF_CERTS_DIR}/rdafplatform.pem $3
	rm -rf ${CERT_LOG}
}

function gen_cert() {
    # $1 - server or client
    # $2 - Key name
    # $3 - Request File name
    # $4 - Cert file name
    # $5 - CA Key
    # $6 - CA Cert
    # $7 - PEM Format.
    # $8 - IP or Hostname
    rm -rf ${CERT_LOG}
	#loginfo "Now generating the $1 server certificate"
	openssl genrsa -out $2 2048 >> ${CERT_LOG} 2>&1
	exit_code=$?
	if [ $exit_code -ne 0 ] ; then
	    logerror "Failed to generate $1 key"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
    	    exit $exit_code
	fi
	openssl req \
	    -sha256 \
	    -new \
	    -key $2 \
	    -out $3 \
	    -subj "/C=US/ST=CA/L=Pleasanton/O=$1/OU=$1/CN=${CERT_CN}/emailAddress=$1.cert@local.com" >> ${CERT_LOG} 2>&1

	exit_code=$?
	
	if [ $exit_code -ne 0 ] ; then
	    logerror "Failed to generate $1 server certificate request"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
    	    exit $exit_code
	fi
	
	#loginfo "Now granting the $1 client certificate"
	openssl x509 \
	    -req \
	    -in $3 \
	    -CA $6 \
	    -set_serial "0x$(openssl rand -hex 16)" \
	    -CAkey $5 \
	    -days 3650 \
	    -outform PEM \
	    -extfile $BASEDIR/rdaf-cert-extensions \
	    -extensions rdaf_self_signed \
	    -out $4  \
	    -sha256 >> ${CERT_LOG} 2>&1
	    
	exit_code=$?
	
	if [ $exit_code -ne 0 ] ; then
	    logerror "Failed to grant the $1 server certificate"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
    	    exit $exit_code
	else
	    rm -rf $3
	fi
	#Making the pem with client cert, ca cert and client cert key.
	cat $4 $6 $2 | tee $7 >> ${CERT_LOG} 2>&1
	exit_code=$?
	if [ $exit_code -ne 0 ] ; then
	    logerror "Failed to generate the server certificate PEM Format"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
    	    exit $exit_code
	fi
	rm -rf ${CERT_LOG}
	return 0
}

echo
BASEDIR=$(dirname "$0")
RDAF_CERTS_DIR=`(cd $BASEDIR/../certs; pwd)`
TRUST_STORE=${RDAF_CERTS_DIR}/rdafplatform.jks
CERT_LOG=/tmp/rdaf_cert.log

#check for openssl
rm -rf ${CERT_LOG}
command -v openssl >> ${CERT_LOG} 2>&1
if [ $? -ne 0 ]
then 
    loginfo "openssl is not installed. Please install openssl"
	cat ${CERT_LOG}
	rm -rf ${CERT_LOG}        
    exit $?
fi
#check for keytool
command -v /opt/java/bin/keytool >> ${CERT_LOG} 2>&1
if [ $? -eq 0 ]
then
	KEYTOOL="/opt/java/bin/keytool"
else
	command -v keytool >> ${CERT_LOG} 2>&1
	exit_code=$?
	if [ $exit_code -ne 0 ]
	then
    	loginfo "keytool is not installed. Please install java and set the path correctly."
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
    	exit $exit_code
	fi
	KEYTOOL="keytool"
fi

CERTS_DIR=${CERTS_ROOT_DIR}
# Notations Used:
# ca.key - CA Key
# ca.crt - CA Certificate
# ca_truststore - CA Truststore
: ${CA_CRT_DIR:=${CERTS_ROOT_DIR}/ca}
: ${CA_CRT:=${CA_CRT_DIR}/ca.crt}
: ${CA_KEY:=${CA_CRT_DIR}/ca.key}
: ${CA_CRT_PEM:=${CA_CRT_DIR}/ca.pem}
: ${CA_TRUSTSTORE:=${CERTS_ROOT_DIR}/truststore/ca_truststore}

if [ -n "$CERT_CA_GENERATE" ]
then
    mkdir -p ${CA_CRT_DIR}
    mkdir -p ${CERTS_ROOT_DIR}/truststore/
    loginfo "Certificate for: Self Signed CA"
    loginfo "Location: ${CA_CRT_DIR}"
    if [ -f $CA_KEY ] && [ -f $CA_CRT ] && [ -z "$CERT_OVERWRITE" ]
    then
      logwarning "Certificate **ALREADY** present. Will use existing."
    else
      copy_ca_cert ${CA_KEY} ${CA_CRT} ${CA_CRT_PEM}
    fi
    if [ -n "$CERT_OVERWRITE" ]
    then
      # we have been asked to generate the CA certs and truststore
      # and overwrite any existing files. So we delete any existing
      # truststore file
      rm -f ${CA_TRUSTSTORE}
    fi
    #CA trust store.
    loginfo "Importing RDAF Trusted CAs into Trust store"
    $KEYTOOL -importkeystore \
        -srcstorepass   "3QZ4rNbRIG1gIrhP461jazn6HXw2jJiz1YYoF4p3E/0=" \
        -srckeystore    $TRUST_STORE \
        -destkeystore   ${CA_TRUSTSTORE} \
        -deststorepass  ${KEYSTORE_PASSWORD} \
        -noprompt   >> ${CERT_LOG} 2>&1
    exit_code=$?
    if [ $exit_code -ne 0 ] ; then
        logerror "Failed to Import Trust CAs into Trust store: ${CA_TRUSTSTORE}"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
        exit $exit_code
    fi
    loginfo "Updating CA Certificates into Trust store"
    gen_truststore ${CA_TRUSTSTORE} ${CA_CRT} ${KEYSTORE_PASSWORD}
    exit_code=$?
    if [ $exit_code -ne 0 ] ; then
        logerror "Failed to Import Trust CAs into Trust store: ${CA_TRUSTSTORE}"
        cat ${CERT_LOG}
        rm -rf ${CERT_LOG}
        exit $exit_code
    fi
    loginfo "CA Certificate generation - Success"
    echo
fi

if [ -z "$CERT_FOR" ]
then
	logerror "CERT_FOR Environment variable is not set. Aborting."
	exit 1
fi
loginfo "Certificate for: ${CERT_FOR}"
loginfo "Location: ${CERTS_DIR}/${CERT_FOR}"
mkdir -p ${CERT_FOR}
SERVER_CERT="${CERT_FOR}/${CERT_FOR}.cert"
SERVER_KEY="${CERT_FOR}/${CERT_FOR}.key"
SERVER_REQ="${CERT_FOR}/${CERT_FOR}.req"
SERVER_PEM="${CERT_FOR}/${CERT_FOR}.pem"
SERVER_P12="${CERT_FOR}/${CERT_FOR}.p12"
SERVER_STORE="${CERT_FOR}/${CERT_FOR}.jks"

if [ -f $SERVER_CERT ] && [ -f $SERVER_KEY ] && [ -f $SERVER_STORE ] && [ -z "$CERT_OVERWRITE" ]
then
    logwarning "Certificate **ALREADY** present. Will use existing."
else
	gen_cert ${CERT_FOR} ${SERVER_KEY} ${SERVER_REQ} ${SERVER_CERT} ${CA_KEY} ${CA_CRT} ${SERVER_PEM}
	export_to_pkcs12 ${SERVER_KEY} ${SERVER_CERT} ${SERVER_P12} ${KEYSTORE_PASSWORD} ${CA_CRT}
	gen_keystore ${SERVER_STORE} ${SERVER_P12} ${KEYSTORE_PASSWORD} ${KEYSTORE_PASSWORD}
	loginfo "Certificate generation - Success"
fi
rm -rf ${CERT_LOG}