#!/bin/bash # # idea... only. # I've to create ~2100 ssl certificates from database # export SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P ) DEFAULT_DOMAIN='reverse.com' DEFAULT_IP='123.123.123.123' declare -A DIR_NAME DIR_NAME[cnf]='etc' DIR_NAME[db]='db' DIR_NAME[private]='private' DIR_NAME[public]='public' DIR_NAME[intermediateDir]='intermediate' DIR_NAME[lookup]='lookup' DIR_NAME[caRoot]='ca' DIR_NAME[caEmail]='ca-email' DIR_NAME[caSoftware]='ca-software' DIR_NAME[caTls]='ca-tls' DIR_NAME[crtEmail]='crt-email' DIR_NAME[crtSoftware]='crt-software' DIR_NAME[crtTls]='crt-tls' DIR_NAME[email]='email' DIR_NAME[software]='software' DIR_NAME[tls]='tls' declare -r DIR_NAME declare -A FILE_NAME FILE_NAME[cnf]='%s.%s.cnf' FILE_NAME[csr]='%s.%s.csr' FILE_NAME[p12]='%s.%s.p12' FILE_NAME[crt]='%s.%s.crt' FILE_NAME[crtPem]='%s.%s.crt.pem' FILE_NAME[cer]='%s.%s.cer' FILE_NAME[chainPem]='%s.%s.chain.pem' FILE_NAME[chainP7c]='%s.%s.chain.p7c' FILE_NAME[crtDb]='%s.%s.crt.db' FILE_NAME[crtSrl]='%s.%s.crt.srl' FILE_NAME[crl]='%s.%s.crl' FILE_NAME[crlPem]='%s.%s.crl.pem' FILE_NAME[crlSrl]='%s.%s.crl.srl' FILE_NAME[key]='%s.%s.key' FILE_NAME[keyPem]='%s.%s.key.pem' FILE_NAME[password]='%s.%s.pwd' declare -r FILE_NAME declare -A DIRECTORIES_CA_ROOT DIRECTORIES_CA_ROOT[caPath]="${DIR_NAME[caRoot]}" DIRECTORIES_CA_ROOT[dbPath]="${DIR_NAME[caRoot]}/${DIR_NAME[db]}" DIRECTORIES_CA_ROOT[cnfPath]="${DIR_NAME[caRoot]}/${DIR_NAME[cnf]}" DIRECTORIES_CA_ROOT[privatePath]="${DIR_NAME[caRoot]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CA_ROOT declare -A DIRECTORIES_CA_EMAIL DIRECTORIES_CA_EMAIL[caPath]="${DIR_NAME[caEmail]}" DIRECTORIES_CA_EMAIL[dbPath]="${DIR_NAME[caEmail]}/${DIR_NAME[db]}" DIRECTORIES_CA_EMAIL[cnfPath]="${DIR_NAME[caEmail]}/${DIR_NAME[cnf]}" DIRECTORIES_CA_EMAIL[privatePath]="${DIR_NAME[caEmail]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CA_EMAIL declare -A DIRECTORIES_CRT_EMAIL DIRECTORIES_CRT_EMAIL[crtPath]="${DIR_NAME[crtEmail]}" DIRECTORIES_CRT_EMAIL[cnfPath]="${DIR_NAME[crtEmail]}/${DIR_NAME[cnf]}" DIRECTORIES_CRT_EMAIL[privatePath]="${DIR_NAME[crtEmail]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CRT_EMAIL declare -A DIRECTORIES_CA_SOFTWARE DIRECTORIES_CA_SOFTWARE[caPath]="${DIR_NAME[caSoftware]}" DIRECTORIES_CA_SOFTWARE[dbPath]="${DIR_NAME[caSoftware]}/${DIR_NAME[db]}" DIRECTORIES_CA_SOFTWARE[cnfPath]="${DIR_NAME[caSoftware]}/${DIR_NAME[cnf]}" DIRECTORIES_CA_SOFTWARE[privatePath]="${DIR_NAME[caSoftware]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CA_SOFTWARE declare -A DIRECTORIES_CRT_SOFTWARE DIRECTORIES_CRT_SOFTWARE[crtPath]="${DIR_NAME[crtSoftware]}" DIRECTORIES_CRT_SOFTWARE[cnfPath]="${DIR_NAME[crtSoftware]}/${DIR_NAME[cnf]}" DIRECTORIES_CRT_SOFTWARE[privatePath]="${DIR_NAME[crtSoftware]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CRT_SOFTWARE declare -A DIRECTORIES_CA_TLS DIRECTORIES_CA_TLS[caPath]="${DIR_NAME[caTls]}" DIRECTORIES_CA_TLS[dbPath]="${DIR_NAME[caTls]}/${DIR_NAME[db]}" DIRECTORIES_CA_TLS[cnfPath]="${DIR_NAME[caTls]}/${DIR_NAME[cnf]}" DIRECTORIES_CA_TLS[privatePath]="${DIR_NAME[caTls]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CA_TLS declare -A DIRECTORIES_CRT_TLS DIRECTORIES_CRT_TLS[crtPath]="${DIR_NAME[crtTls]}" DIRECTORIES_CRT_TLS[cnfPath]="${DIR_NAME[crtTls]}/${DIR_NAME[cnf]}" DIRECTORIES_CRT_TLS[privatePath]="${DIR_NAME[crtTls]}/${DIR_NAME[private]}" declare -r DIRECTORIES_CRT_TLS declare -A DIRECTORIES_PUB DIRECTORIES_PUB[email]="${DIR_NAME[public]}/${DIR_NAME[email]}" DIRECTORIES_PUB[software]="${DIR_NAME[public]}/${DIR_NAME[software]}" DIRECTORIES_PUB[tls]="${DIR_NAME[public]}/${DIR_NAME[tls]}" declare -r DIRECTORIES_PUB check_result() { if [ $1 -ne 0 ]; then echo -e "\e[91m Error\e[39m $2" exit $1 fi echo -e "\e[92m Ok\e[39m" } warn_result() { if [ $1 -ne 0 ]; then echo -e "\e[93m Warning\e[39m $2" fi } check_prompt() { if [ $1 -ne 0 ]; then warn_result "$@" read -p 'Would you like to continue [y/n]: ' answer if [ "$answer" != 'y' ] && [ "$answer" != 'Y' ]; then echo 'Goodbye' exit 1 fi fi } writeNewCert() { local domain=$1 local x=$(printf '%-64s' "create certificates for") local y=$(printf '%-64s' "$domain") local z=$(printf '%-64s' '') echo -e "\e[90m$z\e[39m" echo -e "\e[92m$x\e[39m" echo -e "\e[96m$y\e[39m" echo -e "\e[90m$z\e[39m" } writeDelCert() { local domain=$1 local x=$(printf '%-64s' "delete certificates for") local y=$(printf '%-64s' "$domain") local z=$(printf '%-64s' '') echo -e "\e[90m$z\e[39m" echo -e "\e[91m$x\e[39m" echo -e "\e[96m$y\e[39m" echo -e "\e[90m$z\e[39m" } writeRevCert() { local domain=$1 local x=$(printf '%-64s' "revoke certificates for") local y=$(printf '%-64s' "$domain") local z=$(printf '%-64s' '') echo -e "\e[90m$z\e[39m" echo -e "\e[93m$x\e[39m" echo -e "\e[96m$y\e[39m" echo -e "\e[90m$z\e[39m" } writeNewType() { local type=$1 echo -e "\e[97m• \e[92mcreate\e[97m $type\e[39m" } writeDelType() { local type=$1 echo -e "\e[97m• \e[91mdelete\e[97m $type\e[39m" } writeNewItem() { local item=$1 echo -e "\e[90m \e[92m+\e[90m $item\e[39m" } writeDelItem() { local item=$1 echo -e "\e[90m \e[91m-\e[90m $item\e[39m" } writeDelItem2() { local item=$1 echo -e "\e[90m \e[91m-\e[90m $item\e[39m" } writeNewItem2() { local item=$1 echo -e "\e[90m \e[92m+\e[90m $item\e[39m" } # # certificate reverse.com domain.com create tls-server ssl # certificate() { local reverseDomain=$1 local domain=$2 local action=$3 local configType=$4 local fileNameInfix=$5 local subject=$6 ############################################################## # # bootstrap # ############################################################## local fileName="$fileNameInfix;;$domain" getDomainPath() { local reverseDomain=$1 local domain=$2 local lookup="$reverseDomain/lookup/$domain" if [ -f $lookup ]; then echo $(head -n 1 "$lookup") fi } getBaseType() { local type=$1 case "$type" in email) echo 'email' ;; tls-server|tls-server-external|tls-client|tls-client-external) echo 'tls' ;; code-signing) echo 'software' ;; *) check_result 1 "invalid request type $type; {email|tls-client|tls-client-external|tls-server|tls-server-external|code-signing}" esac } declare -A FILES declare -A DIRS getFiles() { local domain=$1 local domainPath=$2 local baseType=$3 local configType=$4 local fileName=$5 local caType local crtType DIRS[ca]=$domainPath DIRS[pub]=$domainPath/${DIR_NAME[public]} case "$baseType" in email) local caType=${DIR_NAME[caEmail]} local crtType=${DIR_NAME[crtEmail]} DIRS[caDb]=$domainPath/${DIRECTORIES_CA_EMAIL[dbPath]} DIRS[caCnf]=$domainPath/${DIRECTORIES_CA_EMAIL[cnfPath]} DIRS[caPrivate]=$domainPath/${DIRECTORIES_CA_EMAIL[privatePath]} DIRS[crt]=$domainPath/${DIRECTORIES_CRT_EMAIL[crtPath]} DIRS[crtCnf]=$domainPath/${DIRECTORIES_CRT_EMAIL[cnfPath]} DIRS[crtPrivate]=$domainPath/${DIRECTORIES_CRT_EMAIL[privatePath]} DIRS[pubCrt]=$domainPath/${DIRECTORIES_PUB[email]} ;; tls) local caType=${DIR_NAME[caTls]} local crtType=${DIR_NAME[crtTls]} DIRS[caDb]=$domainPath/${DIRECTORIES_CA_TLS[dbPath]} DIRS[caCnf]=$domainPath/${DIRECTORIES_CA_TLS[cnfPath]} DIRS[caPrivate]=$domainPath/${DIRECTORIES_CA_TLS[privatePath]} DIRS[crt]=$domainPath/${DIRECTORIES_CRT_TLS[crtPath]} DIRS[crtCnf]=$domainPath/${DIRECTORIES_CRT_TLS[cnfPath]} DIRS[crtPrivate]=$domainPath/${DIRECTORIES_CRT_TLS[privatePath]} DIRS[pubCrt]=$domainPath/${DIRECTORIES_PUB[tls]} ;; software) local caType=${DIR_NAME[caSoftware]} local crtType=${DIR_NAME[crtSoftware]} DIRS[caDb]=$domainPath/${DIRECTORIES_CA_SOFTWARE[dbPath]} DIRS[caCnf]=$domainPath/${DIRECTORIES_CA_SOFTWARE[cnfPath]} DIRS[caPrivate]=$domainPath/${DIRECTORIES_CA_SOFTWARE[privatePath]} DIRS[crt]=$domainPath/${DIRECTORIES_CRT_SOFTWARE[crtPath]} DIRS[crtCnf]=$domainPath/${DIRECTORIES_CRT_SOFTWARE[cnfPath]} DIRS[crtPrivate]=$domainPath/${DIRECTORIES_CRT_SOFTWARE[privatePath]} DIRS[pubCrt]=$domainPath/${DIRECTORIES_PUB[software]} ;; *) check_result 1 "invalid request baseType $baseType; {email|tls|software}" esac FILES[caChainPem]=${DIRS[ca]}/$(printf ${FILE_NAME[chainPem]} $domain $caType) FILES[caCrl]=${DIRS[caDb]}/$(printf ${FILE_NAME[crl]} $domain $caType) FILES[caCnf]=${DIRS[caCnf]}/$(printf ${FILE_NAME[cnf]} $domain $caType) FILES[caPwd]=${DIRS[caPrivate]}/$(printf ${FILE_NAME[password]} $domain $caType) FILES[crt]=${DIRS[crt]}/$(printf ${FILE_NAME[crt]} $fileName $configType) FILES[crtCsr]=${DIRS[crt]}/$(printf ${FILE_NAME[csr]} $fileName $configType) FILES[crtP12]=${DIRS[crt]}/$(printf ${FILE_NAME[p12]} $fileName $configType) FILES[crtChainPem]=${DIRS[crt]}/$(printf ${FILE_NAME[chainPem]} $fileName $configType) FILES[crtCnf]=${DIRS[crtCnf]}/$(printf ${FILE_NAME[cnf]} $domain $configType) FILES[crtKey]=${DIRS[crtPrivate]}/$(printf ${FILE_NAME[key]} $fileName $configType) FILES[pubCaCrl]=${DIRS[pub]}/$(printf ${FILE_NAME[crl]} $domain $caType) FILES[pubCer]=${DIRS[pubCrt]}/$(printf ${FILE_NAME[cer]} $fileName $configType) FILES[pubChainP7c]=${DIRS[pubCrt]}/$(printf ${FILE_NAME[chainP7c]} $fileName $configType) FILES[pubKeyPem]=${DIRS[pubCrt]}/$(printf ${FILE_NAME[keyPem]} $fileName $configType) FILES[pubCrtPem]=${DIRS[pubCrt]}/$(printf ${FILE_NAME[crtPem]} $fileName $configType) } local domainPath=$(getDomainPath $reverseDomain $domain) local baseType=$(getBaseType $configType) getFiles $domain $domainPath $baseType $configType $fileName local lvl=$(grep -o '/intermediate/' <<< "$domainPath" | wc -l) case "$lvl" in 0) export CA_0_SCRIPT_PATH="$domainPath" ;; 1) export CA_1_SCRIPT_PATH="$domainPath" ;; 2) export CA_2_SCRIPT_PATH="$domainPath" ;; esac ############################################################## # # actions # ############################################################## case "$action" in create) writeNewCert "$4: $5" if [ -e ${FILES[crt]} ]; then writeDelType "old $4: $5" certificate "$1" "$2" revoke "$4" "$5" fi case "$configType" in tls-server) writeNewType "$4: $5" writeNewItem 'csr + key' export SAN="DNS:$domain,DNS:*.$domain" openssl req -new \ -config ${FILES[crtCnf]} \ -out ${FILES[crtCsr]} \ -keyout ${FILES[crtKey]} \ -subj "/C=BE/ST=Antwerp/O=### Network $domain/CN=$domain" check_result $? 'unable to create csr + key' openssl ca \ -batch \ -config ${FILES[caCnf]} \ -in ${FILES[crtCsr]} \ -out ${FILES[crt]} \ -passin file:${FILES[caPwd]} \ -extensions server_ext \ > /dev/null 2>&1 check_result $? 'unable to create crt' writeNewItem 'dump' head -3 ${FILES[crtKey]} head -3 ${FILES[crtCsr]} head -3 ${FILES[crt]} writeNewItem "verify" openssl verify -CAfile ${FILES[caChainPem]} ${FILES[crt]} writeNewItem 'p12' openssl pkcs12 -export \ -name "$domain: $fileNameInfix (TLS Network Component)" \ -inkey ${FILES[crtKey]} \ -passout pass:\ -in ${FILES[crt]} \ -certfile ${FILES[caChainPem]} \ -out ${FILES[crtP12]} \ > /dev/null 2>&1 check_result $? 'unable to create p12' writeNewItem 'pem key from p12' openssl pkcs12 -nocerts -nodes \ -in ${FILES[crtP12]} \ -passin pass:\ -out ${FILES[pubKeyPem]} \ > /dev/null 2>&1 check_result $? 'unable to create pem key' writeNewItem 'passfree pem key' openssl rsa \ -in ${FILES[pubKeyPem]} \ -out ${FILES[pubKeyPem]} \ > /dev/null 2>&1 check_result $? 'unable to create passfree pem key' writeNewItem 'pem crt from p12' openssl pkcs12 -clcerts -nokeys \ -in ${FILES[crtP12]} \ -passin pass:\ -out ${FILES[pubCrtPem]} \ > /dev/null 2>&1 check_result $? 'unable to create p12' ;; esac ;; delete) writeDelCert "$4: $5" if [ -e ${FILES[crt]} ]; then certificate "$1" "$2" revoke "$4" "$5" fi writeDelType 'files' writeDelItem ${FILES[crt]} rm ${FILES[crt]} > /dev/null 2>&1 writeDelItem ${FILES[crtCsr]} rm ${FILES[crtCsr]} > /dev/null 2>&1 writeDelItem ${FILES[crtP12]} rm ${FILES[crtP12]} > /dev/null 2>&1 writeDelItem ${FILES[crtKey]} rm ${FILES[crtKey]} > /dev/null 2>&1 writeDelItem ${FILES[pubCrtPem]} rm ${FILES[pubCrtPem]} > /dev/null 2>&1 writeDelItem ${FILES[pubKeyPem]} rm ${FILES[pubKeyPem]} > /dev/null 2>&1 ;; revoke) writeRevCert "$4: $5" if [ -e ${FILES[crt]} ]; then local lastSrl=$(openssl x509 -in ${FILES[crt]} -serial -noout) local lastFnr=$(openssl x509 -in ${FILES[crt]} -fingerprint -noout) local revokationReason case "$configType" in email) revokationReason=affiliationChanged ;; tls-server|tls-server-external|tls-client|tls-client-external) revokationReason=affiliationChanged ;; code-signing) revokationReason=affiliationChanged ;; esac check_prompt 1 "certificate $fileName.$configType.crt exists as \n\t$lastSrl\n\t$lastFnr\n" echo "Please set the revokation reason, default CRL reason for type $configType is $revokationReason." echo '[1] unspecified' echo '[2] keyCompromise' echo '[3] CACompromise' echo '[4] affiliationChanged' echo '[5] superseded' echo '[6] cessationOfOperation' echo '[7] certificateHold' echo '[8] removeFromCRL' echo '[n] set no reason' read -p 'Please set the revokation reason [1-8]: ' answer case "$answer" in 1) revokationReason=unspecified ;; 2) revokationReason=keyCompromise ;; 3) revokationReason=CACompromise ;; 4) revokationReason=affiliationChanged ;; 5) revokationReason=superseded ;; 6) revokationReason=cessationOfOperation ;; 7) revokationReason=certificateHold ;; 8) revokationReason=removeFromCRL ;; 'n'|'N') revokationReason=no ;; *) warn_result 1 "Nothing selected. Continue with default and set $revokationReason" esac if [ $revokationReason == 'no' ]; then openssl ca \ -config ${FILES[caCnf]} \ -revoke ${FILES[crt]} \ -passin file:${FILES[caPwd]} \ > /dev/null 2>&1 else openssl ca \ -config ${FILES[caCnf]} \ -revoke ${FILES[crt]} \ -passin file:${FILES[caPwd]} \ -crl_reason $revokationReason \ > /dev/null 2>&1 fi openssl ca -gencrl \ -config ${FILES[caCnf]} \ -out ${FILES[caCrl]} \ -passin file:${FILES[caPwd]} \ > /dev/null 2>&1 openssl crl \ -in ${FILES[caCrl]} \ -out ${FILES[pubCaCrl]} \ -outform der \ > /dev/null 2>&1 fi ;; esac }