fruffl icon

SSL from CA certificate chain factory

fruffl | 11/14/15 06:14:04 AM UTC | 0 ⭐ | 321 👁️ | Never ⏰ | []
Bash |

16.31 KB

|

None

|

0 👍

/

0 👎

#!/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
}

Comments