#!/bin/bash

# Bash shell script for generating self-signed certs.

failIfError() {
    if [ "$1" != "0" ]; then
        echo "some error has occured when trying to generate certificate"
        echo $1
        unset PASSPHRASE
        exit 2
    fi
}

usage() {
    echo "Usage: ${0##*/} [-c | --clean] [-t | --days] [-D | --distribute] [-d | --domain] [-f | --fqdn] [-h | --hostname] [-l | --list] [-k | --keylen] [-o | --outdir] [-r | --request] [-s | --selfsigned] [-v | --verbose] [-?|--help]"
    echo "   ${0##*/} -c      clean all distributed certs"
    echo "   ${0##*/} -s      create and distribute selfsigned certificate"
    echo "   ${0##*/} -r      create certificate request"
    echo "   ${0##*/} -R      resign selfsigned certificate request"
    echo "   ${0##*/} -D      distribute /data/cert.pem and /data/key.pem"
    echo "   ${0##*/} -l      list installed certs in /data and subdirs (use -v for more details)"
}

#try to autodetect defaults
OUTDIR="/data"
HOSTNAME="$(cat /etc/hostname | awk '{print tolower($0)}')"
DOMAIN="$(cat /etc/resolv.conf | grep search | sed 's/search //g')"
DOMAIN=${DOMAIN// /}
SELFSIGNED=0
REQUEST=0
VERBOSE=0
KEYLEN=4096
DAYS=730
CLEAN=0

ARGS=$(getopt -o cd:Df:h:k:lLo:rRst:v --long clean,days,didtribute,domain,help,hostname,fqdn,keylen,list,outdir,request,selfsigned,verbose -n "${0##*/}" -- "$@")
if [ $? != 0 ]; then
    echo "Terminating..." >&2
    exit 1
fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$ARGS"
while true; do
    case "$1" in
    -c | --clean)
        CLEAN=1
        shift 1
        ;;
    -d | --domain)
        DOMAIN=$2
        shift 2
        ;;
    -D | --distribute)
        DISTRIBUTE=1
        shift 1
        ;;
    -t | --days)
        DAYS=$2
        shift 2
        ;;
    -f | --fqdn)
        FQDN=$2
        shift 2
        ;;
    -h | --hostname)
        HOSTNAME=$2
        shift 2
        ;;
    -k | --keylen)
        KEYLEN=$2
        shift 2
        ;;
    -l | --list)
        LIST=1
        shift 1
        ;;
    -o | --outdir)
        OUTDIR=$2
        shift 2
        ;;
    -r | --request)
        REQUEST=1
        shift 1
        ;;
    -R | --resign)
        SELFSIGNED=1
        shift 1
        ;;
    -s | --selfsigned)
        REQUEST=1    
        SELFSIGNED=1
        shift 1
        ;;
    -v | --verbose)
        VERBOSE=1
        shift 1
        ;;
    --help)
        usage
        exit
        ;;
    --)
        shift
        break
        ;;
    *)
        echo "Internal error!"
        exit 1
        ;;
    esac
done

if [ "${LIST}" == "1" ]; then
    if [ "${VERBOSE}" == "1" ]; then
        for cert in $(find /data -name "cert.pem"); do
            echo "$cert"
            openssl x509 -text -noout -in "$cert"
            echo ""
        done
    else
        for cert in $(find /data -name "cert.pem"); do
            echo "$cert"
            #openssl x509 -text -noout -certopt no_header,no_version,no_serial,no_signame,no_pubkey,no_sigdump,no_aux -in "$cert"
            openssl x509 -text -noout -in "$cert" | egrep "Issuer:|Validity|Not Before:|Not After :|Subject:|X509v3 extensions:|X509v3 Subject Alternative Name:|DNS:|IP Address:"
            echo ""
        done
    fi
    exit
fi

if [ "${CLEAN}" == "1" ]; then
    if [ -e /etc/pki/tls/certs/cert.pem ]; then
        rm /etc/pki/tls/certs/cert.pem
    fi
    if [ -e /etc/pki/tls/private/key.pem ]; then
        rm /etc/pki/tls/private/key.pem
    fi

    if [ -e /etc/cockpit/ws-certs.d/ssl.cert ]; then
        rm /etc/cockpit/ws-certs.d/ssl.cert
    fi
    systemctl restart cockpit

    if [ -e /data/cert.pem ]; then
        rm /data/cert.pem
    fi
    if [ -e /data/key.pem ]; then
        rm /data/key.pem
    fi
    if [ -e /data/tmpkey.pem ]; then
        rm /data/tmpkey.pem
    fi
    if [ -e /data/req.pem ]; then
        rm /data/req.pem
    fi
fi

if [ "$SELFSIGNED" == "1" -o "$REQUEST" == "1" ]; then
    if [ -z "$DOMAIN" ]; then
        echo "no domain given"
        usage
        exit 3
    fi

    if [ -z "$HOSTNAME" ]; then
        echo "no hostname given"
        usage
        exit 4
    fi

    if [ -z ${FQDN} ]; then
        FQDN="${HOSTNAME}.${DOMAIN}"
    fi

    if [ -z "${FQDN}" ]; then
        echo "no fqdn given"
        usage
        exit 5
    fi

    SAN="DNS:${FQDN},DNS:${HOSTNAME}"
    SUBJECT="CN=${FQDN}"

    #for j in $(for i in $(omgsysteminfo --filter="ip.*.scope=global" | cut -d "=" -f 1); do omgsysteminfo --filter=${i/scope/address} --val; done); do
    for j in $(ip addr | grep global | sed -e "s/  //g" | cut -d " " -f 2 | cut -d "/" -f 1); do
        SAN="${SAN},IP:${j}"
    done
    
    if [ "${VERBOSE}" == "1" ]; then
        echo "hostname=\"${HOSTNAME}\""
        echo "  domain=\"${DOMAIN}\""
        echo "    fqdn=\"${FQDN}\""
        echo "     san=\"${SAN}\""
    fi
    
    #prepare conf file
    CONFFILE=${OUTDIR}/cert.config
    if [ -z "${CONFFILE}" ]; then
        echo "can't create tmp file"
    fi
    
    cat >${CONFFILE} <<EOF
   
[ req ]
prompt = no
distinguished_name = req_distinguished_name
string_mask = nombstr
req_extensions = v3_req
x509_extensions = v3_req

[ req_distinguished_name ]
${SUBJECT}

[ v3_req ]
subjectAltName = ${SAN}

EOF

    if [ "${VERBOSE}" == "1" ]; then
        echo "############################"
        cat ${CONFFILE}
        echo "############################"
    fi

    if [ "$REQUEST" == "1" ]; then
        if [ "${VERBOSE}" == "1" ]; then
            echo "openssl req -new -newkey rsa:${KEYLEN} -nodes -out ${OUTDIR}/req.pem -keyout ${OUTDIR}/key.pem -config ${CONFFILE}"
        fi

        rm -f ${OUTDIR}/req.pem
        openssl req -new -newkey rsa:${KEYLEN} -nodes -out ${OUTDIR}/req.pem -keyout ${OUTDIR}/key.pem -config ${CONFFILE}
        rc=$?
        
        if [ "$SELFSIGNED" != "1" ]; then
                cp ${OUTDIR}/key.pem ${OUTDIR}/tmpkey.pem
        fi
        
        if [ "${VERBOSE}" == "1" ]; then
            openssl req -in ${OUTDIR}/req.pem -text -noout -verify
        fi
    fi

    if [ "$SELFSIGNED" == "1" ]; then
        if [ "${VERBOSE}" == "1" ]; then
            echo "openssl x509 -signkey ${OUTDIR}/key.pem -in ${OUTDIR}/req.pem -req -days ${DAYS} -out ${OUTDIR}/cert.pem"
        fi
        openssl req -x509 -new -nodes -days ${DAYS} -key ${OUTDIR}/key.pem -out ${OUTDIR}/cert.pem -config ${CONFFILE}

        rc=$?
        if [ "${VERBOSE}" == "1" ]; then
            openssl x509 -in ${OUTDIR}/cert.pem -text -noout
        fi

        DISTRIBUTE=1
    fi    
    
    if [ -e ${CONFFILE} ]; then
        rm ${CONFFILE}
    fi

    failIfError ${rc}
 fi

if [ "${DISTRIBUTE}" == "1" ]; then
    cp ${OUTDIR}/cert.pem /etc/pki/tls/certs/
    cp ${OUTDIR}/key.pem /etc/pki/tls/private/
    chmod -R 600 /etc/pki/tls/private/key.pem

    if [ -e /etc/cockpit/ws-certs.d/0-self-signed-ca.pem ]; then
            rm /etc/cockpit/ws-certs.d/0-self-signed-ca.pem
    fi
    if [ -e /etc/cockpit/ws-certs.d/0-self-signed.cert ]; then
            rm /etc/cockpit/ws-certs.d/0-self-signed.cert
    fi
    if [ -e /etc/cockpit/ws-certs.d/0-self-signed.key ]; then
            rm /etc/cockpit/ws-certs.d/0-self-signed.key
    fi
    cp ${OUTDIR}/cert.pem /etc/cockpit/ws-certs.d/ssl.cert
    cat ${OUTDIR}/key.pem >>/etc/cockpit/ws-certs.d/ssl.cert
    systemctl restart cockpit
fi





