diff --git a/ssl/issue_certificate.sh b/ssl/issue_certificate.sh new file mode 100755 index 0000000..1bf243b --- /dev/null +++ b/ssl/issue_certificate.sh @@ -0,0 +1,190 @@ +#!/bin/bash + +# +# requires CA.pl from OpenSSL: https://github.com/openssl/openssl/blob/master/apps/CA.pl.in +# +# generating CA.pl from OpenSSL source: +# /usr/bin/perl "-I." -Mconfigdata "util/dofile.pl" \ +# "-oMakefile" apps/CA.pl.in > "apps/CA.pl" +# sudo cp apps/CA.pl /usr/local/bin +# +# This script requires that a CA certificate has already been created and +# that the CA private key passphrase can be found in $CA_ROOT/cacert.pass +# +# NB: OpenSSL doesn't handle concurrent access to the CA database. +# Wrap this script with flock command or use some other method to serialize access. +# + +CAPL_ORIG=/usr/lib/ssl/misc/CA.pl +OPENSSL=/usr/bin/openssl + +function display_help() { + echo "${0} Usage :" + echo -e "\t--country\tSpecify the Country of the certificate" + echo -e "\t--cadir\t\tSpecify the CA directory" + echo -e "\t--cn\t\tSpecify the CN of the certificate" + echo -e "\t--locality\tSpecify the Locality of the certificate" + echo -e "\t--mail\t\tSpecify the Mail of the certificate" + echo -e "\t--organization\tSpecify the Organization of the certificate" + echo -e "\t--st\t\tSpecify the State or Province of the certificate" + echo -e "\t--days\t\tSpecify the validty of the certificate in days (default 1095)" + echo -e "\t--newca\t\tGenerate a new Certificate Authority. Can't use with --newcert" + echo -e "\t--newcert\tGenerate a new Certificate. Can't use with --newca" + echo -e "\t--updateca\tAdd certificate or CA to update-ca-certificates" + echo -e "\t--genpub\t\tGenerate Public key of the certificate" + echo -e "\t-h or --help\tThis help" + echo "" + echo "Examples :" + echo "./issue_certificate.sh --newca --cadir /tmp/cademo --country FR --cn \"BLORAND Test CA\" --locality DINAN --mail webmaster@blorand.org --organization BLORAND --st BRETAGNE --days \$((365 * 30)) --updatca" + echo "./issue_certificate.sh --newcert --cadir /tmp/cademo --country FR --cn benoit.blorand.local --locality DINAN --mail webmaster@blorand.org --organization BLORAND --st BRETAGNE --days \$((365 * 30)) --genpub" +} + +GET_OPT=`getopt -o h --long help,country:,cadir:,cn:,locality:,mail:,organization:,st:,days:,newca,newcert,updateca,genpub -n "$0 parameters" -- "$@"` +if [ ! "${?}" == "0" ] ; then + display_help + exit 1 +fi +eval set -- "$GET_OPT" +while true ; do + case ${1} in + --country) + CERT_COUNTRY="${2}" + shift 2 + ;; + --cadir) + CADIR=/tmp/demoCA + shift 2 + ;; + --cn) + CERT_CN="${2}" + shift 2 + ;; + --locality) + CERT_LOCALITY="${2}" + shift 2 + ;; + --mail) + CERT_MAIL="${2}" + shift 2 + ;; + --organization) + CERT_ORGANIZATION="${2}" + shift 2 + ;; + --st) + CERT_ST="${2}" + shift 2 + ;; + --days) + CERT_DAYS="-days ${2}" + shift 2 + ;; + --newca) + NEWCA=1 + shift + ;; + --newcert) + NEWCERT=1 + shift + ;; + --updateca) + UPDATECA=1 + shift + ;; + --genpub) + GENPUB=1 + shift + ;; + -h|--help) + display_help + exit 0 + ;; + --) + shift + break + ;; + *) + display_help >&2 + exit 1 + ;; + esac +done + +if [ ! -z "${NEWCA}" -a ! -z "${NEWCERT}" ] ; then + echo "Only one of --newca or --newcert is possible" >&2 + display_help >&2 + exit 1 +fi + +if [ -z "${CERT_COUNTRY}" -o -z "${CERT_CN}" -o -z "${CERT_LOCALITY}" -o -z "${CERT_MAIL}" -o -z "${CERT_ORGANIZATION}" -o -z "${CERT_ST}" ] ; then + echo "Almost one of --country --cadir --cn --locality --mail --organization --st is missing..." >&2 + display_help >&2 + exit 1 +fi +CERT_BASE=${CADIR}/certs + +if [ ! -z "${NEWCA}" ] ; then + if [ ! -d "${CADIR}" -o ! -f "${CADIR}/serial" ]; then + echo "No Certificate Authority Root found in current directory." + if [ -d "$CADIR" ]; then + rm -r ${CADIR}-backup > /dev/null 2>&1 + mv $CADIR ${CADIR}-backup + fi + mkdir -p "${CADIR}" + sed "s@\./demoCA@${CADIR}@g" /etc/ssl/openssl.cnf > "${CADIR}/openssl.cnf" + CAPL="${CADIR}/CA.pl" + sed "s@\./demoCA@${CADIR}@g" ${CAPL_ORIG} > ${CAPL} + chmod +x ${CAPL} + ORIG_UMASK=`umask` + umask 0077 + pass=`openssl rand -base64 18 | tee "${CADIR}/cacert.pass"` + umask ${ORIG_UMASK} + SUBJECT="/C=${CERT_COUNTRY}/L=${CERT_LOCALITY}/ST=${CERT_ST}/O=${CERT_ORGANIZATION}/CN=${CERT_CN}/emailAddress=${CERT_MAIL}" + echo "" | OPENSSL_CONFIG="-config '${CADIR}/openssl.cnf'" OPENSSL=${OPENSSL} ${CAPL} -newca -extra-req "-passout file:'${CADIR}/cacert.pass' -subj '${SUBJECT}' ${CERT_DAYS} -batch" -extra-ca "-passin file:'${CADIR}/cacert.pass' ${CERT_DAYS} -batch" + if [ ! -z "${UPDATECA}" ] ; then + mkdir -p /usr/local/share/ca-certificates/extra + ln -s ${CADIR}/cacert.pem "/usr/local/share/ca-certificates/extra/${CERT_CN}.crt" + /usr/sbin/update-ca-certificates + fi + else + echo "There is already a $CADIR folder !" + exit 1 + fi + exit 0 +fi + +if [ ! -z "${NEWCERT}" ]; then + CAPL="${CADIR}/CA.pl" + if [ ! -e "${CADIR}/certs/${CERT_CN}.pem" ] ; then + + pass=`openssl rand -base64 18 | tee "${CADIR}/certs/${CERT_CN}.pass"` + echo "issuing certificate for ${CERT_CN}" + + # create certificate request + SUBJECT="/C=${CERT_COUNTRY}/L=${CERT_LOCALITY}/ST=${CERT_ST}/O=${CERT_ORGANIZATION}/CN=${CERT_CN}/emailAddress=${CERT_MAIL}" + OPENSSL_CONFIG="-config '${CADIR}/openssl.cnf'" OPENSSL=${OPENSSL} ${CAPL} -newreq -extra-req "-passout file:'${CADIR}/certs/${CERT_CN}.pass' -subj '${SUBJECT}' ${CERT_DAYS} -batch" + + # sign certificate request + OPENSSL_CONFIG="-config '${CADIR}/openssl.cnf'" OPENSSL=${OPENSSL} ${CAPL} -sign -extra-ca "-passin file:'${CADIR}/cacert.pass' ${CERT_DAYS} -batch" + if [ "$?" -ne 0 ]; then + echo "FATAL: failed to sign, aborting" + exit 1 + fi + + cat newkey.pem newcert.pem > "${CADIR}/certs/${CERT_CN}.pem" + chmod 600 "${CADIR}/certs/${CERT_CN}.pem" + rm newkey.pem newcert.pem newreq.pem + + if [ ! -z "${GENPUB}" ] ; then + OPENSSL_CONFIG="-config '${CADIR}/openssl.cnf'" ${OPENSSL} rsa -in "${CADIR}/certs/${CERT_CN}.pem" -out "${CADIR}/certs/${CERT_CN}-public.pem" -outform PEM -pubout -passin file:"${CADIR}/certs/${CERT_CN}.pass" + fi + else + echo "Certificate '${CADIR}/${CERT_CN}.pem' already exist" + echo "Can't continue" + exit 1 + fi + exit 0 +fi + +exit 0 +