fruffl icon

Certificate Factory

fruffl | 11/15/15 10:33:51 AM UTC | 0 ⭐ | 383 👁️ | Never ⏰ | []
Bash |

108.34 KB

|

None

|

0 👍

/

0 👎

#!/bin/bash
 
export SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P )
 
# create an empty directory and execute this script.
# the initializer is demo(); @see end of this file
 
DEFAULT_DOMAIN='reverse.com'
DEFAULT_IP='192.168.0.42'
 
#local DEFAULT_CA_RSA_KEYSIZE_PASSWORD=8192
#local DEFAULT_CA_RSA_KEYSIZE_PRIVATE_KEY=8192
#local DEFAULT_CA_RSA_KEYSIZE_REQUEST=4096
 
DEFAULT_CA_RSA_KEYSIZE_PASSWORD=4096
DEFAULT_CA_PWD_GEN_PUBEXP=7
DEFAULT_CA_RSA_KEYSIZE_PRIVATE_KEY=8192
DEFAULT_CA_RSA_KEYSIZE_REQUEST=8192
DEFAULT_CA_MD_REQUEST=sha512
DEFAULT_CA_MD=sha512
 
DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY=4096
DEFAULT_CRT_PWD_GEN_PUBEXP=7
DEFAULT_CRT_RSA_KEYSIZE_REQUEST=2048
DEFAULT_CRT_MD_REQUEST=sha512
 
#rm -rf $SCRIPT_PATH/$DEFAULT_DOMAIN/* > /dev/null 2>&1
#exit 1
#find $SCRIPT_PATH/$DEFAULT_DOMAIN/ -name "*.*" -type f|xargs rm -f
 
##############################################################
#
# constants
#
##############################################################
 
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
 
    
##############################################################
#
# consolol
#
##############################################################
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"
}
writeRevType()
{
    local type=$1
    echo -e "\e[97m• \e[93mrevoke\e[97m $type\e[39m"
}
 
writeNewItem()
{
    local item=$1
    echo -e "\e[90m  \e[92m+\e[90m $item\e[39m"
}
 
writeNewItem2()
{
    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"
}
 
do_unlock()
{
    rm -rf "/var/lock/$DEFAULT_DOMAIN"
}
 
do_exit()
{
    if [ $1 -ne 30 ]; then
        do_unlock
    fi
    exit $1
}
 
check_result()
{
    if [ $1 -ne 0 ]; then
        echo -e "\e[91m        Error\e[39m $2"
        do_exit "$1"
    else
        echo -e "\e[92m        OK\e[39m"
    fi
}
 
idle_result()
{
    if [ $1 -ne 0 ]; then
        echo -e "\e[93m     Nothing to do.\e[39m $2"
        return $1
    fi
    echo -e "\e[92m     Ok\e[39m"
}
 
warn_result()
{
    if [ $1 -ne 0 ]; then
        echo -e "\e[93mWarning\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'
            do_exit "$1"
        fi
    fi
}
 
 
 
 
 
 
certificate()
{
    # entry point
    local reverseDomain=$1
    # registered domain; MUST avail in lookup folder
    local domain=$2
    # what you want to do; {create|delete|revoke}
    local action=$3
    # the certificate type; {email|tls-client|tls-client-external|tls-server|tls-server-external|code-signing}
    local configType=$4
    # infix/prefix... for new files.
    # the given name should be related to the cert; e.g. foo.com for tls-server-external
    local fileNameInfix=$5
    
    # optional named arg san
    # used for $ENV:SAN=$envVar in tls-server-external; if not present: $ENV:SAN="DNS:$fileNameInfix,DNS:*.$fileNameInfix"
    local san
    # optional named arg password
    # used for personal certificates and is required for email, tls-client, and tls-client-external
    local password
    
    # subj defaults
    # we have to redefine the common name in tls-server as $domain
    declare -A SUBJ_DEFAULT
    SUBJ_DEFAULT[C]='BE'
    SUBJ_DEFAULT[ST]='Antwerp'
    SUBJ_DEFAULT[L]='Antwerp'
    SUBJ_DEFAULT[O]="### Network $domain"
    SUBJ_DEFAULT[OU]=''
    SUBJ_DEFAULT[CN]="### Network $domain"
    
    # subjects cust
    declare -A SUBJ
    
    while [[ ${6} ]]; do
        case "${6}" in
            -san)
                # used for $ENV:SAN=$envVar in tls-server-external; if not present: $ENV:SAN="DNS:$fileNameInfix,DNS:*.$fileNameInfix"
                local san=${7}
                shift
            ;;
            -password)
                # used for personal certificates and is required for email, tls-client, and tls-client-external
                local password=${7}
                shift
            ;;
            # certificate subjects
            -C)
                SUBJ[C]=${7}
                shift
            ;;
            -ST)
                SUBJ[ST]=${7}
                shift
            ;;
            -L)
                SUBJ[L]=${7}
                shift
            ;;
            -O)
                SUBJ[O]=${7}
                shift
            ;;
            -OU)
                SUBJ[OU]=${7}
                shift
            ;;
            -CN)
                SUBJ[CN]=${7}
                shift
            ;;
            -emailAddress)
                SUBJ[emailAddress]=${7}
                shift
            ;;
            *)
            echo "Unknown parameter: ${6}" >&2
                return 1
        esac
        
        if ! shift; then
                echo 'Missing parameter argument.' >&2
                return 1
        fi
    done
    
    local lookupPath="$SCRIPT_PATH/$reverseDomain/lookup"
    
    if [ ! -d $lookupPath ]; then
        check_result 1 "Lookup directory for $reverseDomain is not here."
    fi
    
    if [ ! -f "$lookupPath/$domain" ]; then
        check_result 1 "$domain is not here :("
    fi
    
    ##############################################################
    #
    # bootstrap
    #
    ##############################################################
    
    local fileName="$fileNameInfix;;$domain"
        
    getDomainPath()
    {
        local lookupPath=$1
        local domain=$2
        echo $(head -n 1 $lookupPath/$domain)
    }
    
    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
        
        # the directories are always present
        for index in "${!DIRS[@]}"
        do
            if [ ! -d "${DIRS[$index]}" ]; then
                check_result 1 'directory not found'
            fi
        done
        
        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)
        
        # the CA files are always present
        for index in "${!FILES[@]}"
        do
            if [ ! -f "${FILES[$index]}" ]; then
                check_result 1 "Required CA file ${FILES[$index]} not found"
            fi
        done
        
        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 $lookupPath $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
    
    testPassword()
    {
        local password=$1
        if [ -z "$password" ]; then
            check_result 1 "A password is required but was not set or ist empty.\n You can add it with parameter -password"
        fi
    }
    
    testSubject()
    {
        local type=$1
        local name=$2
        local insert=$3
        local default=$4
        
        case "$type" in
            match)
                if [ ! -z "$insert" ]; then
                    if [ "$default" != "$insert" ]; then
                        check_result 1 "Invalid data for subject /$name=$insert\nThis field must match with the CA policy /$name=$default\nRemove the argument -$name and I will set it for you."
                    fi
                fi
            ;;
            supplied)
                if [ -z "$insert" ]; then
                    check_result 1 "Invalid data for subject /$name=\nThis field must be present and can not be empty.\nYou have to add the parameter -$name"
                fi
            ;;
        esac
    }
    
    concatSubj()
    {
        declare -A MERGED
        local result=""
        
        for index in "${!SUBJ_DEFAULT[@]}"
        do
            MERGED[$index]=${SUBJ_DEFAULT[$index]}
        done
        
        for index in "${!SUBJ[@]}"
        do
            MERGED[$index]=${SUBJ[$index]}
        done
        
        for index in "${!MERGED[@]}"
        do
            result="${result}/${index}=${MERGED[$index]}"
        done
        
        echo $result
    }
    
    ##############################################################
    #
    # actions
    #
    ##############################################################
    
    case "$action" in
        create)
            local subject=$(concatSubj)
            
            writeNewCert "$configType: $fileNameInfix"
            
            revokeAfterValidation()
            {
                if [ -e ${FILES[crt]} ]; then
                    writeRevType "This certificate exists. We have to revoke it."
                    certificate "$reverseDomain" "$domain" revoke "$configType" "$fileNameInfix"
                    writeNewType "$subject"
                fi
            }
            
            writeNewType "new $subject"
            case "$configType" in
                code-signing)
                    # see CA policy
                    testSubject 'match' 'C' "${SUBJ[C]}" "${SUBJ_DEFAULT[C]}"
                    testSubject 'match' 'O' "${SUBJ[O]}" "${SUBJ_DEFAULT[O]}"
                    testSubject 'supplied' 'CN' "${SUBJ[CN]}" "${SUBJ_DEFAULT[CN]}"
                    testPassword $password
                    
                    revokeAfterValidation
                    
                    writeNewItem 'key'
                    openssl genpkey \
                        -algorithm RSA \
                        -out ${FILES[crtKey]} \
                        -pkeyopt rsa_keygen_bits:$DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY \
                        -pkeyopt rsa_keygen_pubexp:$DEFAULT_CRT_PWD_GEN_PUBEXP
                    check_result $? 'unable to create key'
                    
                    writeNewItem 'csr'
                    openssl req -new \
                        -config ${FILES[crtCnf]} \
                        -out ${FILES[crtCsr]} \
                        -key ${FILES[crtKey]} \
                        -subj "$subject" \
                        -passout pass:$password
                    check_result $? 'unable to create csr'
                    
                    writeNewItem 'create crt'
                    openssl ca \
                        -batch \
                        -config ${FILES[caCnf]} \
                        -in ${FILES[crtCsr]} \
                        -out ${FILES[crt]} \
                        -passin file:${FILES[caPwd]} \
                        -extensions codesign_ext \
                            > /dev/null 2>&1
                    check_result $? 'unable to create crt'
                    
                    writeNewItem 'verify sslclient'
                    openssl verify -purpose sslclient -CAfile ${FILES[caChainPem]} ${FILES[crt]}
                    
                    writeNewItem 'publish as p12'
                    openssl pkcs12 -export \
                        -name "$domain: $fileNameInfix (Software Certificate)" \
                        -inkey ${FILES[crtKey]} \
                        -in ${FILES[crt]} \
                        -certfile ${FILES[caChainPem]} \
                        -out ${FILES[crtP12]} \
                        -passout pass:$password \
                        -passin pass:$password \
                            > /dev/null 2>&1
                    check_result $? 'unable to create p12'
                ;;
                email)
                    # see CA policy
                    testSubject 'match' 'C' "${SUBJ[C]}" "${SUBJ_DEFAULT[C]}"
                    testSubject 'match' 'O' "${SUBJ[O]}" "${SUBJ_DEFAULT[O]}"
                    testSubject 'supplied' 'CN' "${SUBJ[CN]}" "${SUBJ_DEFAULT[CN]}"
                    testSubject 'supplied' 'emailAddress' "${SUBJ[emailAddress]}"
                    testPassword $password
                    
                    revokeAfterValidation
                    
                    writeNewItem 'key'
                    openssl genpkey \
                        -algorithm RSA \
                        -out ${FILES[crtKey]} \
                        -pkeyopt rsa_keygen_bits:$DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY \
                        -pkeyopt rsa_keygen_pubexp:$DEFAULT_CRT_PWD_GEN_PUBEXP
                    check_result $? 'unable to create key'
                    
                    writeNewItem 'csr'
                    openssl req -new \
                        -config ${FILES[crtCnf]} \
                        -out ${FILES[crtCsr]} \
                        -key ${FILES[crtKey]} \
                        -subj "$subject" \
                        -passout pass:$password
                    check_result $? 'unable to create csr'
                    
                    writeNewItem 'create crt'
                    openssl ca \
                        -batch \
                        -config ${FILES[caCnf]} \
                        -notext \
                        -in ${FILES[crtCsr]} \
                        -out ${FILES[crt]} \
                        -passin file:${FILES[caPwd]} \
                        -extensions email_ext
                    check_result $? 'unable to create crt'
                    
                    writeNewItem 'verify sslclient'
                    openssl verify -purpose sslclient -CAfile ${FILES[caChainPem]} ${FILES[crt]}
                    
                    writeNewItem 'publish as p12'
                    openssl pkcs12 -export \
                        -name "${SUBJ[emailAddress]} (Email Address)" \
                        -inkey ${FILES[crtKey]} \
                        -in ${FILES[crt]} \
                        -certfile ${FILES[caChainPem]} \
                        -out ${FILES[crtP12]} \
                        -passout pass:$password \
                        -passin pass:$password \
                            > /dev/null 2>&1
                    check_result $? 'unable to create p12'
                ;;
                tls-client|tls-client-external)
                    
                    case "$configType" in
                        tls-client)
                            # see CA policy
                            testSubject 'match' 'C' "${SUBJ[C]}" "${SUBJ_DEFAULT[C]}"
                            testSubject 'match' 'O' "${SUBJ[O]}" "${SUBJ_DEFAULT[O]}"
                            testSubject 'supplied' 'CN' "${SUBJ[CN]}" "${SUBJ_DEFAULT[CN]}"
                            testPassword $password
                            
                            revokeAfterValidation
                            
                            writeNewItem 'key'
                            openssl genpkey \
                                -algorithm RSA \
                                -out ${FILES[crtKey]} \
                                -pkeyopt rsa_keygen_bits:$DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY \
                                -pkeyopt rsa_keygen_pubexp:$DEFAULT_CRT_PWD_GEN_PUBEXP
                            check_result $? 'unable to create key'
                            
                            writeNewItem 'csr'
                            openssl req -new \
                                -config ${FILES[crtCnf]} \
                                -out ${FILES[crtCsr]} \
                                -key ${FILES[crtKey]} \
                                -subj "$subject" \
                                -passout pass:$password
                            check_result $? 'unable to create csr'
                            
                            writeNewItem 'create crt'
                            openssl ca \
                                -batch \
                                -config ${FILES[caCnf]} \
                                -in ${FILES[crtCsr]} \
                                -out ${FILES[crt]} \
                                -passin file:${FILES[caPwd]} \
                                -extensions client_ext \
                                    > /dev/null 2>&1
                            check_result $? 'unable to create crt'
                        ;;
                        tls-client-external)
                            # see CA policy
                            testSubject 'supplied' 'C' "${SUBJ[C]}" "${SUBJ_DEFAULT[C]}"
                            testSubject 'supplied' 'O' "${SUBJ[O]}" "${SUBJ_DEFAULT[O]}"
                            testSubject 'supplied' 'CN' "${SUBJ[CN]}" "${SUBJ_DEFAULT[CN]}"
                            testPassword $password
                            
                            revokeAfterValidation
                            
                            writeNewItem 'key'
                            openssl genpkey \
                                -algorithm RSA \
                                -out ${FILES[crtKey]} \
                                -pkeyopt rsa_keygen_bits:$DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY \
                                -pkeyopt rsa_keygen_pubexp:$DEFAULT_CRT_PWD_GEN_PUBEXP
                            check_result $? 'unable to create key'
                            
                            writeNewItem 'csr'
                            openssl req -new \
                                -config ${FILES[crtCnf]} \
                                -out ${FILES[crtCsr]} \
                                -key ${FILES[crtKey]} \
                                -subj "$subject" \
                                -passout pass:$password
                            check_result $? 'unable to create csr'
                            
                            writeNewItem 'create crt'
                            openssl ca \
                                -batch \
                                -config ${FILES[caCnf]} \
                                -in ${FILES[crtCsr]} \
                                -out ${FILES[crt]} \
                                -passin file:${FILES[caPwd]} \
                                -extensions client_ext \
                                -policy extern_pol \
                                    > /dev/null 2>&1
                            check_result $? 'unable to create crt'
                        ;;
                    esac
                    
                    writeNewItem 'verify sslclient'
                    openssl verify -purpose sslclient -CAfile ${FILES[caChainPem]} ${FILES[crt]}
                    
                    writeNewItem 'publish as p12'
                    openssl pkcs12 -export \
                        -name "$fileNameInfix (TLS Network Access)" \
                        -inkey ${FILES[crtKey]} \
                        -in ${FILES[crt]} \
                        -certfile ${FILES[caChainPem]} \
                        -out ${FILES[crtP12]} \
                        -passout pass:$password \
                        -passin pass:$password \
                            > /dev/null 2>&1
                    check_result $? 'unable to create p12'
                    
                    #???
                    #writeNewItem 'pem key from p12'
                    #openssl pkcs12 -nocerts \
                    #   -in ${FILES[crtP12]} \
                    #   -out ${FILES[pubKeyPem]} \
                    #       > /dev/null 2>&1
                    #check_result $? 'unable to create pem key'
                    #
                    #writeNewItem 'pem crt from p12'
                    #openssl pkcs12 -clcerts -nokeys \
                    #   -in ${FILES[crtP12]} \
                    #   -out ${FILES[pubCrtPem]} \
                    #       > /dev/null 2>&1
                    #check_result $? 'unable to create p12'
                ;;
                tls-server|tls-server-external)
                    case "$configType" in
                        tls-server)
                            SUBJ_DEFAULT[CN]=$domain
                            # see CA policy
                            testSubject 'match' 'C' "${SUBJ[C]}" "${SUBJ_DEFAULT[C]}"
                            testSubject 'match' 'O' "${SUBJ[O]}" "${SUBJ_DEFAULT[O]}"
                            testSubject 'match' 'CN' "${SUBJ[CN]}" "${SUBJ_DEFAULT[CN]}"
                            
                            revokeAfterValidation
                            
                            export SAN="DNS:$domain,DNS:*.$domain"
                            
                            writeNewItem 'key'
                            openssl genpkey \
                                -algorithm RSA \
                                -out ${FILES[crtKey]} \
                                -pkeyopt rsa_keygen_bits:$DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY \
                                -pkeyopt rsa_keygen_pubexp:$DEFAULT_CRT_PWD_GEN_PUBEXP
                            check_result $? 'unable to create key'
                            
                            writeNewItem 'csr'
                            openssl req -new \
                                -config ${FILES[crtCnf]} \
                                -out ${FILES[crtCsr]} \
                                -key ${FILES[crtKey]} \
                                -subj "$subject"
                            check_result $? 'unable to create csr'
                            
                            writeNewItem 'create crt'
                            openssl ca \
                                -batch \
                                -config ${FILES[caCnf]} \
                                -in ${FILES[crtCsr]} \
                                -out ${FILES[crt]} \
                                -passin file:${FILES[caPwd]} \
                                -extensions server_ext
                            check_result $? 'unable to create crt'
                        ;;
                        tls-server-external)
                            # see CA policy
                            testSubject 'supplied' 'C' "${SUBJ[C]}" "${SUBJ_DEFAULT[C]}"
                            testSubject 'supplied' 'O' "${SUBJ[O]}" "${SUBJ_DEFAULT[O]}"
                            testSubject 'supplied' 'CN' "${SUBJ[CN]}" "${SUBJ_DEFAULT[CN]}"
                            
                            revokeAfterValidation
                            
                            if [ -z $san ]; then
                                local san="DNS:$fileNameInfix,DNS:*.$fileNameInfix"
                            fi
                            export SAN="$san"
                            
                            writeNewItem 'key'
                            openssl genpkey \
                                -algorithm RSA \
                                -out ${FILES[crtKey]} \
                                -pkeyopt rsa_keygen_bits:$DEFAULT_CRT_RSA_KEYSIZE_PRIVATE_KEY \
                                -pkeyopt rsa_keygen_pubexp:$DEFAULT_CRT_PWD_GEN_PUBEXP
                            check_result $? 'unable to create key'
                            
                            writeNewItem 'csr'
                            openssl req -new \
                                -config ${FILES[crtCnf]} \
                                -out ${FILES[crtCsr]} \
                                -key ${FILES[crtKey]} \
                                -subj "$subject"
                            check_result $? 'unable to create csr'
                            
                            writeNewItem 'create crt'
                            openssl ca \
                                -batch \
                                -config ${FILES[caCnf]} \
                                -in ${FILES[crtCsr]} \
                                -out ${FILES[crt]} \
                                -passin file:${FILES[caPwd]} \
                                -extensions server_ext \
                                -policy extern_pol \
                                    > /dev/null 2>&1
                            check_result $? 'unable to create crt'
                        ;;
                    esac
                    
                    writeNewItem 'verify sslclient'
                    openssl verify -purpose sslclient -CAfile ${FILES[caChainPem]} ${FILES[crt]}
                    
                    writeNewItem 'publish as p12'
                    openssl pkcs12 -export \
                        -name "$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'
                    
                    cat ${FILES[crt]} ${FILES[caChainPem]} > ${FILES[crtChainPem]}
                
                    writeNewItem 'publish crt as application/pkix-cert'
                    openssl x509 \
                        -in ${FILES[crt]} \
                        -out ${FILES[pubCer]} \
                        -outform der
                
                    writeNewItem 'publish pem chain as application/pkcs7-mime'
                    openssl crl2pkcs7 -nocrl \
                        -certfile ${FILES[crtChainPem]} \
                        -out ${FILES[pubChainP7c]} \
                        -outform der
                    
                ;;
            esac
        ;;
        delete)
            writeDelCert "$configType: $fileNameInfix"
            declare -A REMOVE
            
            for type in crt crtCsr crtP12 crtKey pubCrtPem pubKeyPem pubCer pubChainP7c
            do
                if [ -e ${FILES[$type]} ]; then
                    writeDelItem ${FILES[$type]}
                    REMOVE[$type]=${FILES[$type]}
                fi
            done
            
            check_prompt 1 'Files will be permanently removed from disk!'
            
            if [ -e ${FILES[crt]} ]; then
                writeRevType "existing $configType: $fileNameInfix"
                certificate "$reverseDomain" "$domain" revoke "$configType" "$fileNameInfix"
            fi
            
            writeDelType 'files'
            for index in "${!REMOVE[@]}"
            do
                writeDelItem ${REMOVE[$index]}
                rm ${REMOVE[$index]} > /dev/null 2>&1
                check_result $? 'unable to delete file'
            done
        ;;
        revoke)
            writeRevCert "$configType: $fileNameInfix"
            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)
                        local revokationReason=affiliationChanged
                    ;;
                    tls-server|tls-server-external|tls-client|tls-client-external)
                        local revokationReason=affiliationChanged
                    ;;
                    code-signing)
                        local revokationReason=affiliationChanged
                    ;;
                esac
                
                check_prompt 1 "certificate $fileName.$configType.crt exists as \n\t$lastSrl\n\t$lastFnr\n"
                
                echo ""
                echo -e "Please set the revokation reason. Default CRL reason for type $configType is $revokationReason."
                echo -e "   [1] unspecified"
                echo -e "   [2] keyCompromise"
                echo -e "   [3] CACompromise"
                echo -e "   [4] affiliationChanged"
                echo -e "   [5] superseded"
                echo -e "   [6] cessationOfOperation"
                echo -e "   [7] certificateHold"
                echo -e "   [8] removeFromCRL"
                echo -e "   [n] set no reason"
                echo ""
                read -p "Please set the revokation reason or nothing for default: " answer
                echo ""
                
                case "$answer" in
                    1)
                        local revokationReason=unspecified
                    ;;
                    2)
                        local revokationReason=keyCompromise
                    ;;
                    3)
                        local revokationReason=CACompromise
                    ;;
                    4)
                        local revokationReason=affiliationChanged
                    ;;
                    5)
                        local revokationReason=superseded
                    ;;
                    6)
                        local revokationReason=cessationOfOperation
                    ;;
                    7)
                        local revokationReason=certificateHold
                    ;;
                    8)
                        local revokationReason=removeFromCRL
                    ;;
                    'n'|'N')
                        local revokationReason=no
                    ;;
                esac
                
                writeNewType 'revokation'
                if [ $revokationReason == 'no' ]; then
                    writeNewItem "revoke without reason"
                    openssl ca \
                        -config ${FILES[caCnf]} \
                        -revoke ${FILES[crt]} \
                        -passin file:${FILES[caPwd]} \
                             > /dev/null 2>&1
                    idle_result $? 'unable to revoke'
                else
                    writeNewItem "revoke with $revokationReason"
                    openssl ca \
                        -config ${FILES[caCnf]} \
                        -revoke ${FILES[crt]} \
                        -passin file:${FILES[caPwd]} \
                        -crl_reason $revokationReason \
                             > /dev/null 2>&1
                    idle_result $? 'unable to revoke'
                fi
                
                writeNewItem 'update crl'
                openssl ca -gencrl \
                    -config ${FILES[caCnf]} \
                    -out ${FILES[caCrl]} \
                    -passin file:${FILES[caPwd]} \
                        > /dev/null 2>&1
                check_result $? 'unable to update crl'
                    
                writeNewItem 'publish crl as application/pkix-crl'
                openssl crl \
                    -in ${FILES[caCrl]} \
                    -out ${FILES[pubCaCrl]} \
                    -outform der \
                        > /dev/null 2>&1
                check_result $? 'unable to publish crl'
            fi
        ;;
        *)
            check_result 1 "invalid action '$action' {create|delete|revoke}"
    esac
}
 
 
 
 
 
 
 
 
##############################################################
#
# asynch?
#
##############################################################
if [ -d "/var/lock/$DEFAULT_DOMAIN" ]; then
    check_result 30 "Already locked"
fi
 
mkdir "/var/lock/$DEFAULT_DOMAIN"
check_result $? "Lock failed"
 
 
 
##
# Create a simple CA-chain.
#
# create some CAs
# root_ca 'reverse.com' 'domain1.com;domain2.com' 'sub1;sub2'
# root_ca 'reverse.com' 'domain1.com' 'sub3'
# root_ca 'reverse.com' 'domain2.com' 'sub4'
# root_ca 'reverse.com' 'domain3.com'
#
# result
#   - ./reverse.com
#       - reverse.com.ca.crt (root CA)
#       - reverse.com.ca-tls.crt
#       - ./intermediate
#           - ./domain1.com
#               - domain1.com.ca.crt (sub root CA)
#               - domain1.com.ca-tls.crt
#               - domain1.com.ca-email.crt
#               - domain1.com.ca-software.crt
#               - ./intermediate
#                   - ./sub1.domain1.com
#                       - sub1.domain1.com.ca.crt (sub sub root CA)
#                       - sub1.domain1.com.ca-tls.crt
#                       - sub1.domain1.com.ca-email.crt
#                       - sub1.domain1.com.ca-software.crt
#                   - ./sub2.domain1.com
#                       - sub2.domain1.com.ca.crt (sub sub root CA)
#                       - sub2.domain1.com.ca-tls.crt
#                       - sub2.domain1.com.ca-email.crt
#                       - sub2.domain1.com.ca-software.crt
#                   - ./sub3.domain1.com
#                       - sub3.domain1.com.ca.crt (sub sub root CA)
#                       - sub3.domain1.com.ca-tls.crt
#                       - sub3.domain1.com.ca-email.crt
#                       - sub3.domain1.com.ca-software.crt
#           - ./domain2.com
#               - domain2.com.ca.crt (sub root CA)
#               - domain2.com.ca-tls.crt
#               - domain2.com.ca-email.crt
#               - domain2.com.ca-software.crt
#               - ./intermediate
#                   - ./sub1.domain1.com
#                       - sub1.domain2.com.ca.crt (sub sub root CA)
#                       - sub1.domain2.com.ca-tls.crt
#                       - sub1.domain2.com.ca-email.crt
#                       - sub1.domain2.com.ca-software.crt
#                   - ./sub2.domain1.com
#                       - sub2.domain2.com.ca.crt (sub sub root CA)
#                       - sub2.domain2.com.ca-tls.crt
#                       - sub2.domain2.com.ca-email.crt
#                       - sub2.domain2.com.ca-software.crt
#                   - ./sub4.domain1.com
#                       - sub4.domain2.com.ca.crt (sub sub root CA)
#                       - sub4.domain2.com.ca-tls.crt
#                       - sub4.domain2.com.ca-email.crt
#                       - sub4.domain2.com.ca-software.crt
#           - ./domain3.com
#               - domain3.com.ca.crt (sub root CA)
#               - domain3.com.ca-tls.crt
#               - domain3.com.ca-email.crt
#               - domain3.com.ca-software.crt
# 
#
#
# root_ca reverse-domain [public-domain [subdomain-prefix]]
root_ca()
{
    # the base; the IP or reverse host address.
    # this allows us to use this function for multiple servers on same host.
    # this is the network root CA.
    # this function creates also the reverse host based CA for TLS - signed by the root CA.
    local reverseHost=$1
    
    # list of domains separated by ;
    #   root_ca reverse.tld foo.tld;bar.tld;alice.tld   - for foo.tld, bar.tld, and alice.tld
    #
    # this function creates an intermediate CA for each domain.
    # the intermediate CAs will be signed by the Root CA of reverse host.
    # this function creates also domain based CAs for TLS, email and code signing - signed by the domain based intermediate CA.
    local domainList=$2
    
    # list of subdomain names separated by ;
    #   mail;smtp
    #
    # note that all names in this list will be applied to each given domain.
    # to avoid this you must call this function multiple times.
    # root_ca will not destroy, delete or override previous created CAs
    #   root_ca reverse.tld foo.tld;bar.tld mail;smtp   - for mail.foo.tld, smtp.foo.tld, mail.bar.tld, and smtp.bar.tld
    #   root_ca reverse.tld foo.tld;alice.tld imap      - for imap.foo.tld, and imap.alice.tld
    #
    # this function creates an intermediate CA for each subdomain.
    # the intermediate CAs will be signed by the intermediate CA of their owner domain
    # this function creates also sub domain based CAs for TLS, email and code signing - signed by the subdomain based intermediate CA.
    local subDomainNameList=$3
 
    
    ##############################################################
    #
    # CRT config partial factories
    #
    ##############################################################
    
    makeModulCsrConfigBlock_title()
    {
        local outputFile=$1
        local domain=$2
        local title=$3
        
        {
            echo "# $title certificate request for $domain"
            echo ''
        } >> $outputFile
    }
    
    ##############################################################
    #
    # CRT config factories
    #
    ##############################################################
    
    modulCsrEmailConfig()
    {
        local outputFile=$1
        local domain=$2
        
        {
            makeModulCsrConfigBlock_title $outputFile $domain 'Email'
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CRT_RSA_KEYSIZE_REQUEST                  # RSA key size"
            echo 'encrypt_key             = yes                   # Protect private key'
            echo "default_md              = $DEFAULT_CRT_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = yes                   # Prompt for DN'
            echo 'distinguished_name      = email_dn              # DN template'
            echo 'req_extensions          = email_reqext          # Desired extensions'
            echo ''
            echo "[ email_dn ]"
            echo 'countryName             = "1. Country Name (2 letters) (eg, US)       "'
            echo 'countryName_max         = 2'
            echo 'countryName_default     = "BE"'
            echo 'stateOrProvinceName     = "2. State or Province Name   (eg, region)   "'
            echo 'localityName            = "3. Locality Name            (eg, city)     "'
            echo 'organizationName        = "4. Organization Name        (eg, company)  "'
            echo "organizationName_default = \""### Network $domain\"""
            echo 'organizationalUnitName  = "5. Organizational Unit Name (eg, section)  "'
            echo 'commonName              = "6. Common Name              (eg, full name)"'
            echo 'commonName_max          = 64'
            echo 'emailAddress            = "7. Email Address            (eg, name@fqdn)"'
            echo 'emailAddress_max        = 40'
            echo ''
            echo '[ email_reqext ]'
            echo 'keyUsage                = critical,digitalSignature,keyEncipherment'
            echo 'extendedKeyUsage        = critical,emailProtection,clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'subjectAltName          = email:move'
        } >> $outputFile
    }
    
    modulCsrTlsClientConfig()
    {
        local outputFile=$1
        local domain=$2
        
        {
            makeModulCsrConfigBlock_title $outputFile $domain 'TLS Client'
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CRT_RSA_KEYSIZE_REQUEST                  # RSA key size"
            echo 'encrypt_key             = yes                   # Protect private key'
            echo "default_md              = $DEFAULT_CRT_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = yes                   # Prompt for DN'
            echo 'distinguished_name      = client_dn             # DN template'
            echo 'req_extensions          = client_reqext         # Desired extensions'
            echo ''
            echo "[ client_dn ]"
            echo 'countryName             = "1. Country Name (2 letters) (eg, US)       "'
            echo 'countryName_max         = 2'
            echo 'countryName_default     = "BE"'
            echo 'stateOrProvinceName     = "2. State or Province Name   (eg, region)   "'
            echo 'localityName            = "3. Locality Name            (eg, city)     "'
            echo 'organizationName        = "4. Organization Name        (eg, company)  "'
            echo "organizationName_default = \""### Network $domain\"""
            echo 'organizationalUnitName  = "5. Organizational Unit Name (eg, section)  "'
            echo 'commonName              = "6. Common Name              (eg, full name)"'
            echo 'commonName_max          = 64'
            echo 'emailAddress            = "7. Email Address            (eg, name@fqdn)"'
            echo 'emailAddress_max        = 40'
            echo ''
            echo '[ client_reqext ]'
            echo 'keyUsage                = critical,digitalSignature'
            echo 'extendedKeyUsage        = critical,clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'subjectAltName          = email:move'
        } >> $outputFile
    }
    
    modulCsrTlsClientExternalConfig()
    {
        local outputFile=$1
        local domain=$2
        
        {
            makeModulCsrConfigBlock_title $outputFile $domain 'TLS External Client'
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CRT_RSA_KEYSIZE_REQUEST                  # RSA key size"
            echo 'encrypt_key             = yes                   # Protect private key'
            echo "default_md              = $DEFAULT_CRT_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = yes                   # Prompt for DN'
            echo 'distinguished_name      = client_dn             # DN template'
            echo 'req_extensions          = client_reqext         # Desired extensions'
            echo ''
            echo "[ client_dn ]"
            echo 'countryName             = "1. Country Name (2 letters) (eg, US)       "'
            echo 'countryName_max         = 2'
            echo 'stateOrProvinceName     = "2. State or Province Name   (eg, region)   "'
            echo 'localityName            = "3. Locality Name            (eg, city)     "'
            echo 'organizationName        = "4. Organization Name        (eg, company)  "'
            echo 'organizationalUnitName  = "5. Organizational Unit Name (eg, section)  "'
            echo 'commonName              = "6. Common Name              (eg, full name)"'
            echo 'commonName_max          = 64'
            echo 'emailAddress            = "7. Email Address            (eg, name@fqdn)"'
            echo 'emailAddress_max        = 40'
            echo ''
            echo '[ client_reqext ]'
            echo 'keyUsage                = critical,digitalSignature'
            echo 'extendedKeyUsage        = critical,clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'subjectAltName          = email:move'
        } >> $outputFile
    }
    
    modulCsrTlsServerConfig()
    {
        local outputFile=$1
        local domain=$2
        
        {
            makeModulCsrConfigBlock_title $outputFile $domain 'TLS Server'
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CRT_RSA_KEYSIZE_REQUEST                  # RSA key size"
            echo 'encrypt_key             = no                    # Protect private key'
            echo "default_md              = $DEFAULT_CRT_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = yes                   # Prompt for DN'
            echo 'distinguished_name      = server_dn             # DN template'
            echo 'req_extensions          = server_reqext         # Desired extensions'
            echo ''
            echo "[ server_dn ]"
            echo 'countryName             = "1. Country Name (2 letters) (eg, US)       "'
            echo 'countryName_max         = 2'
            echo 'countryName_default     = "BE"'
            echo 'stateOrProvinceName     = "2. State or Province Name   (eg, region)   "'
            echo 'localityName            = "3. Locality Name            (eg, city)     "'
            echo 'organizationName        = "4. Organization Name        (eg, company)  "'
            echo "organizationName_default = \""### Network $domain\"""
            echo 'organizationalUnitName  = "5. Organizational Unit Name (eg, section)  "'
            echo 'commonName              = "6. Common Name              (eg, full name)"'
            echo 'commonName_max          = 64'
            echo "commonName_default      = \""$domain\"""
            echo 'emailAddress            = "7. Email Address            (eg, name@fqdn)"'
            echo 'emailAddress_max        = 40'
            echo ''
            echo '[ server_reqext ]'
            echo 'keyUsage                = critical,digitalSignature,keyEncipherment'
            echo 'extendedKeyUsage        = serverAuth,clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'subjectAltName          = $ENV::SAN'
        } >> $outputFile
    }
    
    modulCsrTlsServerExternalConfig()
    {
        local outputFile=$1
        local domain=$2
        
        {
            makeModulCsrConfigBlock_title $outputFile $domain 'TLS External Server'
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CRT_RSA_KEYSIZE_REQUEST                  # RSA key size"
            echo 'encrypt_key             = no                    # Protect private key'
            echo "default_md              = $DEFAULT_CRT_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = yes                   # Prompt for DN'
            echo 'distinguished_name      = server_dn             # DN template'
            echo 'req_extensions          = server_reqext         # Desired extensions'
            echo ''
            echo "[ server_dn ]"
            echo 'countryName             = "1. Country Name (2 letters) (eg, US)       "'
            echo 'countryName_max         = 2'
            echo 'stateOrProvinceName     = "2. State or Province Name   (eg, region)   "'
            echo 'localityName            = "3. Locality Name            (eg, city)     "'
            echo 'organizationName        = "4. Organization Name        (eg, company)  "'
            echo 'organizationalUnitName  = "5. Organizational Unit Name (eg, section)  "'
            echo 'commonName              = "6. Common Name              (eg, full name)"'
            echo 'commonName_max          = 64'
            echo 'emailAddress            = "7. Email Address            (eg, name@fqdn)"'
            echo 'emailAddress_max        = 40'
            echo ''
            echo '[ server_reqext ]'
            echo 'keyUsage                = critical,digitalSignature,keyEncipherment'
            echo 'extendedKeyUsage        = serverAuth,clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'subjectAltName          = $ENV::SAN'
        } >> $outputFile
    }
        
    
    modulCsrSoftwareConfig()
    {
        local outputFile=$1
        local domain=$2
        
        {
            makeModulCsrConfigBlock_title $outputFile $domain 'Software'
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CRT_RSA_KEYSIZE_REQUEST                  # RSA key size"
            echo 'encrypt_key             = yes                   # Protect private key'
            echo "default_md              = $DEFAULT_CRT_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = yes                   # Prompt for DN'
            echo 'distinguished_name      = codesign_dn           # DN template'
            echo 'req_extensions          = codesign_reqext       # Desired extensions'
            echo ''
            echo '[ codesign_dn ]'
            echo 'countryName             = "1. Country Name (2 letters) (eg, US)       "'
            echo 'countryName_max         = 2'
            echo 'stateOrProvinceName     = "2. State or Province Name   (eg, region)   "'
            echo 'localityName            = "3. Locality Name            (eg, city)     "'
            echo 'organizationName        = "4. Organization Name        (eg, company)  "'
            echo 'organizationalUnitName  = "5. Organizational Unit Name (eg, section)  "'
            echo 'commonName              = "6. Common Name              (eg, full name)"'
            echo 'commonName_max          = 64'
            echo ''
            echo '[ codesign_reqext ]'
            echo 'keyUsage                = critical,digitalSignature'
            echo 'extendedKeyUsage        = critical,codeSigning'
            echo 'subjectKeyIdentifier    = hash'
        } >> $outputFile
    }
    
    ##############################################################
    #
    # CA config partial factories
    #
    ##############################################################
    
    makeModulCaConfigBlock_title()
    {
        local outputFile=$1
        local title=$2
        
        {
            echo "# $title"
            echo ''
        } >> $outputFile
    }
    
    makeModulCaConfigBlock_section()
    {
        local outputFile=$1
        local title=$2
        
        {
            echo ''
            echo ''
            echo "# $title"
            echo ''
        } >> $outputFile
    }
    
    makeModulCaConfigBlock_default()
    {
        local outputFile=$1
        local domain=$2
        local level=$3
        local type=$4
        
        {
            echo '[ default ]'
            echo "ca                      = $domain"
            echo "ca_type                 = $type"
            echo 'ca_dir                  = $ca_type'
            echo "db_dir                  = \$ca_dir/${DIR_NAME[db]}"
            echo "private_dir             = \$ca_dir/${DIR_NAME[private]}"
            echo "dir                     = \$ENV::CA_${level}_SCRIPT_PATH  # Top dir"
            echo "base_url                = http://$domain # CA base URL"
            echo "ip_url                  = http://$DEFAULT_IP # CA base URL on IP"
            echo 'aia_url                 = $base_url/$ca.$ca_type.cer       # CA certificate URL'
            echo 'ip_aia_url              = $ip_url/$ca.$ca_type.cer         # CA certificate URL'
            echo 'crl_url                 = $base_url/$ca.$ca_type.crl       # CRL distribution point'
            echo 'ip_crl_url              = $ip_url/$ca.$ca_type.cer         # CRL distribution point'
            echo 'name_opt                = multiline,-esc_msb,utf8 # Display UTF-8 characters'
            echo ''
        } >> $outputFile
    }
    
    
    makeModulCaConfigBlock_req()
    {
        local outputFile=$1
        
        {
            echo '[ req ]'
            echo "default_bits            = $DEFAULT_CA_RSA_KEYSIZE_REQUEST                 # RSA key size"
            echo 'encrypt_key             = yes                   # Protect private key'
            echo "default_md              = $DEFAULT_CA_MD_REQUEST                # MD to use"
            echo 'utf8                    = yes                   # Input is UTF-8'
            echo 'string_mask             = utf8only              # Emit UTF-8 strings'
            echo 'prompt                  = no                    # Dont prompt for DN'
            echo 'distinguished_name      = ca_dn                 # DN section'
            echo 'req_extensions          = ca_reqext             # Desired extensions'
            echo ''
        } >> $outputFile
    }
    
    makeModulCaConfigBlock_ca_dn()
    {
        local outputFile=$1
        local oN=$2
        local cN=$3
        
        {
            echo '[ ca_dn ]'
            echo 'countryName             = "BE"'
            echo "organizationName        = \""### Network $oN\"""
            echo 'organizationalUnitName  = "interop"'
            echo "commonName              = \""### Network $cN\"""
            echo ''
        } >> $outputFile
    }
    
    makeModulCaConfigBlock_ca_reqext()
    {
        local outputFile=$1
        local case=$2
        
        if [ "$case" == 'signing' ]; then
            {
                echo '[ ca_reqext ]'
                echo 'keyUsage                = critical,keyCertSign,cRLSign'
                echo 'basicConstraints        = critical,CA:true,pathlen:0'
                echo 'subjectKeyIdentifier    = hash'
                echo ''
            } >> $outputFile
        else
            {
                echo '[ ca_reqext ]'
                echo 'keyUsage                = critical,keyCertSign,cRLSign'
                echo 'basicConstraints        = critical,CA:true'
                echo 'subjectKeyIdentifier    = hash'
                echo ''
            } >> $outputFile
        fi
    }
    
    makeModulCaConfigBlock_ca()
    {
        local outputFile=$1
        local defaultCa=$2
        local x509_extensions=$3
        local copy_extensions=$4
        local policy=$5
        local days=$6
        local crlDays=$7
        
        local keyFileFormat=$(printf ${FILE_NAME[key]} '$ca' '$ca_type')
        local crtSrlFileFormat=$(printf ${FILE_NAME[crtSrl]} '$ca' '$ca_type')
        local crlSrlFileFormat=$(printf ${FILE_NAME[crlSrl]} '$ca' '$ca_type')
        local crtDbFileFormat=$(printf ${FILE_NAME[crtDb]} '$ca' '$ca_type')
        local crtFileFormat=$(printf ${FILE_NAME[crt]} '$ca' '$ca_type')
        
        local pDir='$dir/$private_dir'
        local dDir='$dir/$db_dir'
        
        {
            echo '[ ca ]'
            echo "default_ca              = $defaultCa # The default CA section"
            echo ''
            echo "[ $defaultCa ]"
            echo "certificate             = \$dir/$crtFileFormat                   # The CA cert"
            echo 'new_certs_dir           = $dir/$ca_dir                            # Certificate archive'
            echo "private_key             = $pDir/$keyFileFormat        # CA private key"
            echo "serial                  = $dDir/$crtSrlFileFormat       # Serial number file"
            echo "crlnumber               = $dDir/$crlSrlFileFormat       # CRL number file"
            echo "database                = $dDir/$crtDbFileFormat        # Index file"
            echo 'unique_subject          = yes                  # Require unique subject'
            echo "default_days            = $days          # How long to certify for"
            echo "default_md              = $DEFAULT_CA_MD                  # MD to use"
            echo "policy                  = $policy             # Default naming policy"
            echo 'email_in_dn             = no                    # Add email to cert DN'
            echo 'preserve                = yes                    # Keep passed DN ordering'
            echo 'name_opt                = $name_opt             # Subject DN display options'
            echo 'cert_opt                = ca_default            # Certificate display options'
            echo "copy_extensions         = $copy_extensions                  # Copy extensions from CSR"
            echo "x509_extensions         = $x509_extensions          # Default cert extensions"
            echo "default_crl_days        = $crlDays                    # How long before next CRL"
            echo 'crl_extensions          = crl_ext               # CRL extensions'
            echo ''
        } >> $outputFile
    }
    
    
    
    ##############################################################
    #
    # CA config factories
    #
    ##############################################################
    
    # args: out file, domain, nesting level (required for $ENV)
    modulCaConfig()
    {
        local outputFile=$1
        local domain=$2
        local level=$3
        
        if [ -z "$3" ]; then
            level=0
        fi
        
        local suffix='Certificate Authority'
        if [ $level == '0' ]; then
            suffix="Root $suffix"
        fi
        
        makeModulCaConfigBlock_title            $outputFile "Network $domain $suffix"
        makeModulCaConfigBlock_default          $outputFile $domain $level 'ca'
        makeModulCaConfigBlock_section          $outputFile 'CA certificate request'
        makeModulCaConfigBlock_req              $outputFile
        makeModulCaConfigBlock_ca_dn            $outputFile $domain "$domain $suffix"
        makeModulCaConfigBlock_ca_reqext        $outputFile
        makeModulCaConfigBlock_section          $outputFile 'CA operational settings'
        makeModulCaConfigBlock_ca               $outputFile 'root_ca' 'server_ext' 'none' 'root_ca_pol' '730' '365'
        
        {
            echo '[ root_ca_pol ]'
            echo 'countryName             = match                 # Must match'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = match                 # Must match'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = match                 # Must match'
            echo ''
            echo '[ extension_ca_pol ]'
            echo 'countryName             = match                 # Must match'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = match                 # Must match'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = supplied              # Must be present'
            echo ''
            echo '[ intermediate_ca_pol ]'
            echo 'countryName             = supplied              # Must be present'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = supplied              # Must be present'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = supplied              # Must be present'
            echo ''
            echo ''
            echo '# Extensions'
            echo ''
            echo '[ root_ca_ext ]'
            echo 'keyUsage                = critical,keyCertSign,cRLSign'
            echo 'basicConstraints        = critical,CA:true'
            echo 'subjectKeyIdentifier    = hash'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo ''
            echo '[ signing_ca_ext ]'
            echo 'keyUsage                = critical,keyCertSign,cRLSign'
            echo 'basicConstraints        = critical,CA:true,pathlen:0'
            echo 'subjectKeyIdentifier    = hash'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo 'crlDistributionPoints   = @crl_info'
            echo ''
            echo '[ crl_ext ]'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo ''
            echo '[ issuer_info ]'
            echo 'caIssuers;URI.0         = $aia_url'
            echo 'caIssuers;URI.1         = $ip_aia_url'
            echo ''
            echo '[ crl_info ]'
            echo 'URI.0                   = $crl_url'
            echo 'URI.1                   = $ip_crl_url'
        } >> $outputFile
    }
    
    # args: out file, domain, nesting level (required for $ENV)
    modulCaTlsConfig()
    {
        local outputFile=$1
        local domain=$2
        local level=$3
        
        makeModulCaConfigBlock_title            $outputFile "Network $domain TLS Registration Authority"
        makeModulCaConfigBlock_default          $outputFile $domain $level 'ca-tls'
        makeModulCaConfigBlock_section          $outputFile 'CA certificate request'
        makeModulCaConfigBlock_req              $outputFile
        makeModulCaConfigBlock_ca_dn            $outputFile $domain "$domain TLS Registration Authority"
        makeModulCaConfigBlock_ca_reqext        $outputFile 'signing'
        makeModulCaConfigBlock_section          $outputFile 'CA operational settings'
        makeModulCaConfigBlock_ca               $outputFile 'tls_ca' 'server_ext' 'copy' 'match_pol' '730' '1'
        
        {
            echo '[ match_pol ]'
            echo 'countryName             = match                 # Must match NO'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = match                 # Must match Green AS'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = supplied              # Must be present'
            echo ''
            echo '[ extern_pol ]'
            echo 'countryName             = supplied              # Must be present'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = supplied              # Must be present'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = supplied              # Must be present'
            echo ''
            echo '[ any_pol ]'
            echo 'domainComponent         = optional'
            echo 'countryName             = optional'
            echo 'stateOrProvinceName     = optional'
            echo 'localityName            = optional'
            echo 'organizationName        = optional'
            echo 'organizationalUnitName  = optional'
            echo 'commonName              = optional'
            echo 'emailAddress            = optional'
            echo ''
            echo ''
            echo '# Extensions'
            echo ''
            echo '[ server_ext ]'
            echo 'keyUsage                = critical,digitalSignature,keyEncipherment'
            echo 'basicConstraints        = critical,CA:false'
            echo 'extendedKeyUsage        = serverAuth,clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo 'crlDistributionPoints   = @crl_info'
            echo ''
            echo '[ client_ext ]'
            echo 'keyUsage                = critical,digitalSignature'
            echo 'basicConstraints        = critical,CA:false'
            echo 'extendedKeyUsage        = clientAuth'
            echo 'subjectKeyIdentifier    = hash'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo 'crlDistributionPoints   = @crl_info'
            echo ''
            echo '[ crl_ext ]'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo ''
            echo '[ issuer_info ]'
            echo 'caIssuers;URI.0         = $aia_url'
            echo ''
            echo '[ crl_info ]'
            echo 'URI.0                   = $crl_url'
        } >> $outputFile
    }
    
    # args: out file, domain, nesting level (required for $ENV)
    modulCaEmailConfig()
    {
        local outputFile=$1
        local domain=$2
        local level=$3
        
        makeModulCaConfigBlock_title            $outputFile "Network $domain Email Registration Authority"
        makeModulCaConfigBlock_default          $outputFile $domain $level 'ca-email'
        makeModulCaConfigBlock_section          $outputFile 'CA certificate request'
        makeModulCaConfigBlock_req              $outputFile
        makeModulCaConfigBlock_ca_dn            $outputFile $domain "$domain Email Registration Authority"
        makeModulCaConfigBlock_ca_reqext        $outputFile 'signing'
        makeModulCaConfigBlock_section          $outputFile 'CA operational settings'
        makeModulCaConfigBlock_ca               $outputFile 'email_ca' 'email_ext' 'copy' 'match_pol' '730' '1'
        
        {
            echo '[ match_pol ]'
            echo 'countryName             = match                 # Must match NO'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = match                 # Must match Green AS'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = supplied              # Must be present'
            echo ''
            echo '[ any_pol ]'
            echo 'domainComponent         = optional'
            echo 'countryName             = optional'
            echo 'stateOrProvinceName     = optional'
            echo 'localityName            = optional'
            echo 'organizationName        = optional'
            echo 'organizationalUnitName  = optional'
            echo 'commonName              = optional'
            echo 'emailAddress            = optional'
            echo ''
            echo ''
            echo '# Extensions'
            echo ''
            echo '[ email_ext ]'
            echo 'keyUsage                = critical,digitalSignature,keyEncipherment'
            echo 'basicConstraints        = CA:false'
            echo 'extendedKeyUsage        = emailProtection,clientAuth,anyExtendedKeyUsage'
            echo 'subjectKeyIdentifier    = hash'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo 'crlDistributionPoints   = @crl_info'
            echo ''
            echo '[ crl_ext ]'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo ''
            echo '[ issuer_info ]'
            echo 'caIssuers;URI.0         = $aia_url'
            echo ''
            echo '[ crl_info ]'
            echo 'URI.0                   = $crl_url'
        } >> $outputFile
    }
    
    # args: out file, domain, nesting level (required for $ENV)
    modulCaSoftwareConfig()
    {
        local outputFile=$1
        local domain=$2
        local level=$3
        
        makeModulCaConfigBlock_title            $outputFile "Network $domain Software Registration Authority"
        makeModulCaConfigBlock_default          $outputFile $domain $level 'ca-software'
        makeModulCaConfigBlock_section          $outputFile 'CA certificate request'
        makeModulCaConfigBlock_req              $outputFile
        makeModulCaConfigBlock_ca_dn            $outputFile $domain "$domain Software Registration Authority"
        makeModulCaConfigBlock_ca_reqext        $outputFile 'signing'
        makeModulCaConfigBlock_section          $outputFile 'CA operational settings'
        makeModulCaConfigBlock_ca               $outputFile 'software_ca' 'codesign_ext' 'copy' 'match_pol' '1826' '30'
        
        {
            echo '[ match_pol ]'
            echo 'countryName             = match                 # Must match NO'
            echo 'stateOrProvinceName     = optional              # Included if present'
            echo 'localityName            = optional              # Included if present'
            echo 'organizationName        = match                 # Must match Green AS'
            echo 'organizationalUnitName  = optional              # Included if present'
            echo 'commonName              = supplied              # Must be present'
            echo ''
            echo '[ any_pol ]'
            echo 'domainComponent         = optional'
            echo 'countryName             = optional'
            echo 'stateOrProvinceName     = optional'
            echo 'localityName            = optional'
            echo 'organizationName        = optional'
            echo 'organizationalUnitName  = optional'
            echo 'commonName              = optional'
            echo 'emailAddress            = optional'
            echo ''
            echo ''
            echo '# Extensions'
            echo ''
            echo '[ codesign_ext ]'
            echo 'keyUsage                = critical,digitalSignature'
            echo 'basicConstraints        = CA:false'
            echo 'extendedKeyUsage        = critical,codeSigning'
            echo 'subjectKeyIdentifier    = hash'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo 'crlDistributionPoints   = @crl_info'
            echo ''
            echo '[ crl_ext ]'
            echo 'authorityKeyIdentifier  = keyid:always'
            echo 'authorityInfoAccess     = @issuer_info'
            echo ''
            echo '[ issuer_info ]'
            echo 'caIssuers;URI.0         = $aia_url'
            echo ''
            echo '[ crl_info ]'
            echo 'URI.0                   = $crl_url'
        } >> $outputFile
    }
    
    ##############################################################
    #
    # more factories!!!
    #
    ##############################################################
    
    makeConfigFile()
    {
        local domain=$1
        local modul=$2
        local outputFile=$3
        local level=$4
        
        if [ ! -e "$outputFile" ]; then
            writeNewItem "CA config $modul"
            eval $modul $outputFile $domain $level
            check_result $? 'unable to create config'
        fi
    }
    
    makeCsrConfigFile()
    {
        local domain=$1
        local modul=$2
        local outputFile=$3
        
        if [ ! -e "$outputFile" ]; then
            writeNewItem "certificate request config $modul"
            eval $modul $outputFile $domain
            check_result $? 'unable to create config'
        fi
    }
    
    makeUserTlsCsrFiles()
    {
        local domain=$1
        local cnfPath=$2
        
        makeCsrConfigFile \
            $domain \
            'modulCsrTlsClientConfig' \
            $cnfPath/$(printf ${FILE_NAME[cnf]} $domain 'tls-client')
        
        makeCsrConfigFile \
            $domain \
            'modulCsrTlsClientExternalConfig' \
            $cnfPath/$(printf ${FILE_NAME[cnf]} $domain 'tls-client-external')
            
        makeCsrConfigFile \
            $domain \
            'modulCsrTlsServerConfig' \
            $cnfPath/$(printf ${FILE_NAME[cnf]} $domain 'tls-server')
            
        makeCsrConfigFile \
            $domain \
            'modulCsrTlsServerExternalConfig' \
            $cnfPath/$(printf ${FILE_NAME[cnf]} $domain 'tls-server-external')
    }
    
    makeUserSoftwareCsrFiles()
    {
        local domain=$1
        local cnfPath=$2
        
        makeCsrConfigFile \
            $domain \
            'modulCsrSoftwareConfig' \
            $cnfPath/$(printf ${FILE_NAME[cnf]} $domain 'code-signing')
    }
    
    makeUserEmailCsrFiles()
    {
        local domain=$1
        local cnfPath=$2
        
        makeCsrConfigFile \
            $domain \
            'modulCsrEmailConfig' \
            $cnfPath/$(printf ${FILE_NAME[cnf]} $domain 'email')
    }
    
    makePasswordFile()
    {
        local domain=$1
        local pwdFile=$2
        
        if [ ! -e $pwdFile ]; then
            writeNewItem 'pass'
            openssl genpkey \
                -algorithm RSA \
                -out $pwdFile \
                -pkeyopt rsa_keygen_bits:$DEFAULT_CA_RSA_KEYSIZE_PASSWORD \
                -pkeyopt rsa_keygen_pubexp:$DEFAULT_CA_PWD_GEN_PUBEXP
            check_result $? 'unable to create password'
        fi
    }
    
    makeKeyFile()
    {
        local domain=$1
        local keyFile=$2
        local pwdFile=$3
        
        if [ ! -e $keyFile ]; then
            writeNewItem 'key'
            openssl genrsa -aes256 \
                -passout file:$pwdFile \
                -out $keyFile $DEFAULT_CA_RSA_KEYSIZE_PRIVATE_KEY
            check_result $? 'unable to create private key'
        fi
    }
    
    makeDbFiles()
    {
        local domain=$1
        local database=$2
        local crtSerial=$3
        local crlSerial=$4
        
        local time=$(date +%Y%m%d%H%M%S)001
        local hex=$(echo "obase=16; $time" | bc)
        
        if [ ! -e $database ]; then
            writeNewItem 'database files'
            touch $database
            check_result $? 'unable to create database index'
            writeNewItem 'crt serial'
            echo $hex > $crtSerial
            check_result $? 'unable to create crt serial'
            writeNewItem 'crl serial'
            echo $hex > $crlSerial
            check_result $? 'unable to create crl serial'
        fi
    }
    
    makeCsrFile()
    {
        local domain=$1
        local cnfFile=$2
        local csrFile=$3
        local keyFile=$4
        local pwdFile=$5
        
        if [ ! -e $csrFile ]; then
            writeNewItem 'csr'
            openssl req -new \
                -config $cnfFile \
                -out $csrFile \
                -key $keyFile -passin file:$pwdFile \
                    > /dev/null 2>&1
            check_result $? 'unable to create csr'
        fi
    }
    
    makeCrtFile()
    {
        local domain=$1
        local cnfFile=$2
        local csrFile=$3
        local crtFile=$4
        local pwdFile=$5
        local case=$6
        
        if [ ! -e $crtFile ]; then
            writeNewItem 'crt'
            
            if [ "$case" == 'root_ca' ]; then
                openssl ca -selfsign -batch \
                    -config $cnfFile \
                    -in $csrFile \
                    -passin file:$pwdFile \
                    -out $crtFile \
                    -extensions root_ca_ext \
                    -enddate 20820508235959Z \
                        > /dev/null 2>&1
                check_result $? 'unable to create crt'
            fi
            
            if [ "$case" == 'intermediate_ca' ]; then
                openssl ca -batch \
                    -config $cnfFile \
                    -in $csrFile \
                    -passin file:$pwdFile \
                    -out $crtFile \
                    -extensions root_ca_ext \
                    -policy intermediate_ca_pol \
                    -enddate 20820508235959Z \
                        > /dev/null 2>&1
                check_result $? 'unable to create crt'
            fi
            
            if [ "$case" == 'signing_ca' ]; then
                openssl ca -batch \
                    -config $cnfFile \
                    -in $csrFile \
                    -passin file:$pwdFile \
                    -out $crtFile \
                    -extensions signing_ca_ext \
                    -policy extension_ca_pol \
                    -enddate 20820508235959Z \
                        > /dev/null 2>&1
                check_result $? 'unable to create crt'
            fi
        fi
    }
    
    makeCrlFile()
    {
        local domain=$1
        local cnfFile=$2
        local crlFile=$3
        local pwdFile=$4
        
        if [ ! -e $crlFile ]; then
            writeNewItem 'crl'
            openssl ca -gencrl \
                -config $cnfFile \
                -passin file:$pwdFile \
                -out $crlFile \
                    > /dev/null 2>&1
                check_result $? 'unable to create crl'
            
        fi
    }
    
    makeChain()
    {
        local domain=$1
        local child=$2
        local parents=$3
        local chainPemFile=$4
        local chainP7cFile=$5
        
        if [ ! -e $chainPemFile ]; then
            writeNewItem 'pem chain'
            cat $child $parents > $chainPemFile
            check_result $? 'unable to create pem chain'
        fi
        
    }
    
    # All published certificates must be in DER format.
    # MIME type: application/pkix-cert. [RFC 2585#section-4.1]
    publishCrt()
    {
        local fromCrt=$1
        local toDer=$2
        
        rm $toDer > /dev/null 2>&1
        
        writeNewItem 'publish crt as application/pkix-cert'
        openssl x509 \
            -in $fromCrt \
            -out $toDer \
            -outform der
        check_result $? 'unable to create cer file'
    }
    
    # All published CRLs must be in DER format.
    # MIME type: application/pkix-crl. [RFC 2585#section-4.2]
    publishCACrl()
    {
        local fromCrl=$1
        local toDer=$2
        
        rm $toDer > /dev/null 2>&1
        
        writeNewItem 'publish crl as application/pkix-crl'
        openssl crl \
                -in $fromCrl \
                -out $toDer \
                -outform der
        check_result $? 'unable to create der crl file'
    }
    
    # PKCS#7 is used to bundle two or more certificates.
    # MIME type: application/pkcs7-mime. [RFC 5273#page-3]
    publishCAChain()
    {
        local fromChainPem=$1
        local toChainP7c=$2
        
        rm $toChainP7c > /dev/null 2>&1
        
        writeNewItem 'publish pem chain as application/pkcs7-mime'
        openssl crl2pkcs7 -nocrl \
            -certfile $fromChainPem \
            -out $toChainP7c \
            -outform der
        check_result $? 'unable to create p7c chain file'
    }
    
    ##############################################################
    #
    # CA factories
    #
    ##############################################################
    
    #
    # the root! rooooooooooot!
    #
    # note: we need the env var for openssl config
    #
    # ./reverse root CA
    #
    makeRootCa()
    {
        local domain=$1
        local baseDir=$2
        local cnfFile=$3
        local csrFile=$4
        local keyFile=$5
        local pwdFile=$6
        local crtFile=$7
        local crlFile=$8
        
        export CA_0_SCRIPT_PATH="$baseDir"
        
        makeCsrFile $domain $cnfFile $csrFile $keyFile $pwdFile
        makeCrtFile $domain $cnfFile $csrFile $crtFile $pwdFile 'root_ca'
        makeCrlFile $domain $cnfFile $crlFile $pwdFile
    }
    
    #
    # intermediate CA level 1
    #
    # note: we need the env vars for openssl config
    #
    # ./reverse/domain root CA
    #
    makeIntermediateCa()
    {
        local domain=$1
        local baseDir=$2
        local cnfFile=$3
        local csrFile=$4
        local keyFile=$5
        local pwdFile=$6
        local crtFile=$7
        local crlFile=$8
        local chainPemFile=$9
        local rootBaseDir=${10}
        local rootCnfFile=${11}
        local rootPwdFile=${12}
        local rootCrtFile=${13}
        
        export CA_1_SCRIPT_PATH="$baseDir"
        export CA_0_SCRIPT_PATH="$rootBaseDir"
        
        makeCsrFile $domain $cnfFile $csrFile $keyFile $pwdFile
        makeCrtFile $domain $rootCnfFile $csrFile $crtFile $rootPwdFile 'intermediate_ca'
        makeCrlFile $domain $cnfFile $crlFile $pwdFile
        makeChain   $domain $crtFile $rootCrtFile $chainPemFile
    }
    
    #
    # intermediate CA level 2
    #
    # note: we need the env vars for openssl config
    #
    # ./reverse/domain/subdomain root CA
    #
    makeIntermediateIntermediateCa()
    {
        local domain=$1
        local baseDir=$2
        local cnfFile=$3
        local csrFile=$4
        local keyFile=$5
        local pwdFile=$6
        local crtFile=$7
        local crlFile=$8
        local chainPemFile=$9
        local rootBaseDir=${10}
        local rootCnfFile=${11}
        local rootPwdFile=${12}
        local rootCrtFile=${13}
        
        export CA_2_SCRIPT_PATH="$baseDir"
        export CA_1_SCRIPT_PATH="$rootBaseDir"
        
        makeCsrFile $domain $cnfFile $csrFile $keyFile $pwdFile
        makeCrtFile $domain $rootCnfFile $csrFile $crtFile $rootPwdFile 'intermediate_ca'
        makeCrlFile $domain $cnfFile $crlFile $pwdFile
        makeChain   $domain $crtFile $rootCrtFile $chainPemFile
    }
    
    #
    # signing CA
    #
    # note: we need the env var for openssl config
    #
    # ./reverse-tls
    # ./reverse/domain-[tls|email|software]
    # ./reverse/domain/subdomain-[tls|email|software]
    #
    makeSigningCa()
    {
        local domain=$1
        local baseDir=$2
        local cnfFile=$3
        local csrFile=$4
        local keyFile=$5
        local pwdFile=$6
        local crtFile=$7
        local crlFile=$8
        local chainPemFile=$9
        local rootCnfFile=${10}
        local rootPwdFile=${11}
        local rootCrtFile=${12}
        
        export CA_0_SCRIPT_PATH="$baseDir"
        
        makeCsrFile $domain $cnfFile $csrFile $keyFile $pwdFile
        makeCrtFile $domain $rootCnfFile $csrFile $crtFile $rootPwdFile 'signing_ca'
        makeCrlFile $domain $cnfFile $crlFile $pwdFile
        makeChain   $domain $crtFile $rootCrtFile $chainPemFile
    }
    
    
    ##############################################################
    #
    # output
    #
    ##############################################################
    
    #
    # LEVEL 0 (reverse)
    #
    
    declare -A LEVEL0
    LEVEL0[domain]=$reverseHost
    LEVEL0[path]="$SCRIPT_PATH/$reverseHost"
    
    declare -A LEVEL0_PATH
    # lookup table
    LEVEL0_PATH[lookup]=${LEVEL0[path]}/${DIR_NAME[lookup]}
    # root ca
    LEVEL0_PATH[caPath]=${LEVEL0[path]}/${DIRECTORIES_CA_ROOT[caPath]}
    LEVEL0_PATH[caDbPath]=${LEVEL0[path]}/${DIRECTORIES_CA_ROOT[dbPath]}
    LEVEL0_PATH[caCnfPath]=${LEVEL0[path]}/${DIRECTORIES_CA_ROOT[cnfPath]}
    LEVEL0_PATH[caPrvPath]=${LEVEL0[path]}/${DIRECTORIES_CA_ROOT[privatePath]}
    # tls ca
    LEVEL0_PATH[caTlsPath]=${LEVEL0[path]}/${DIRECTORIES_CA_TLS[caPath]}
    LEVEL0_PATH[caTlsDbPath]=${LEVEL0[path]}/${DIRECTORIES_CA_TLS[dbPath]}
    LEVEL0_PATH[caTlsCnfPath]=${LEVEL0[path]}/${DIRECTORIES_CA_TLS[cnfPath]}
    LEVEL0_PATH[caTlsPrvPath]=${LEVEL0[path]}/${DIRECTORIES_CA_TLS[privatePath]}
    # domains
    LEVEL0_PATH[intermediatePath]=${LEVEL0[path]}/${DIR_NAME[intermediateDir]}
    # tls crt
    LEVEL0_PATH[crtTlsPath]=${LEVEL0[path]}/${DIRECTORIES_CRT_TLS[crtPath]}
    LEVEL0_PATH[crtTlsCnfPath]=${LEVEL0[path]}/${DIRECTORIES_CRT_TLS[cnfPath]}
    LEVEL0_PATH[crtTlsPrvPath]=${LEVEL0[path]}/${DIRECTORIES_CRT_TLS[privatePath]}
    # pub
    LEVEL0_PATH[pub]=${LEVEL0[path]}/${DIR_NAME[public]}
    LEVEL0_PATH[pubTls]=${LEVEL0[path]}/${DIRECTORIES_PUB[tls]}
    
    writeNewCert ${LEVEL0[domain]}
    
    writeNewType 'directories'
    for index in "${!LEVEL0_PATH[@]}"
    do
        writeNewItem ${LEVEL0_PATH[$index]}
        mkdir -p "${LEVEL0_PATH[$index]}" > /dev/null 2>&1
        check_result $? 'unable to create directory'
    done
    
    ##############################################################
    #
    # lookup
    #
    # ca=$(head -n 1 $lookup/$domain)
    #
    ##############################################################
    lookupAdd()
    {
        local domain=$1
        local path=$2
        local lookup=${LEVEL0_PATH[lookup]}
        
        writeNewItem "add $domain"
        rm $lookup/$domain > /dev/null 2>&1
        echo $path >> $lookup/$domain
        check_result $? 'unable to add $domain'
    }
    
    
    writeNewType 'lookup'
    lookupAdd ${LEVEL0[domain]} ${LEVEL0[path]}
 
    writeNewType 'user request configs'
    makeUserTlsCsrFiles \
        ${LEVEL0[domain]} \
        ${LEVEL0_PATH[crtTlsCnfPath]}
    
    #
    # The following part is the worst thing you've ever seen. \o/
    # Thanks to openssl's path party.
    #
    
    #
    # root CA
    #
    writeNewType 'Root CA'
    # ./
    local __0__caCsr=${LEVEL0[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    local __0__caCrt=${LEVEL0[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    # ./ca/db
    local __0__caCrtDb=${LEVEL0_PATH[caDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    local __0__caCrtSrl=${LEVEL0_PATH[caDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    local __0__caCrlSrl=${LEVEL0_PATH[caDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    local __0__caCrl=${LEVEL0_PATH[caDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    # ./ca/etc
    local __0__caConfig=${LEVEL0_PATH[caCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    # ./ca/private
    local __0__caPwd=${LEVEL0_PATH[caPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    local __0__caKey=${LEVEL0_PATH[caPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    # ./public
    local __0__caCrtDer=${LEVEL0_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    local __0__caCrlDer=${LEVEL0_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL0[domain]} ${DIR_NAME[caRoot]})
    
    makeConfigFile \
        ${LEVEL0[domain]} \
        'modulCaConfig' \
        $__0__caConfig \
        '0'
    
    makePasswordFile \
        ${LEVEL0[domain]} \
        $__0__caPwd
    
    makeKeyFile \
        ${LEVEL0[domain]} \
        $__0__caKey \
        $__0__caPwd
        
    makeDbFiles \
        ${LEVEL0[domain]} \
        $__0__caCrtDb \
        $__0__caCrtSrl \
        $__0__caCrlSrl
        
    makeRootCa \
        ${LEVEL0[domain]} \
        ${LEVEL0[path]} \
        $__0__caConfig \
        $__0__caCsr \
        $__0__caKey \
        $__0__caPwd \
        $__0__caCrt \
        $__0__caCrl
    
    publishCrt      $__0__caCrt         $__0__caCrtDer
    publishCACrl    $__0__caCrl         $__0__caCrlDer
    
    #
    # tls CA
    #
    writeNewType 'TLS CA'
    # ./
    local __0__tlsCsr=${LEVEL0[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsCrt=${LEVEL0[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsChainPem=${LEVEL0[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    # ./ca-tls/db
    local __0__tlsCrtDb=${LEVEL0_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsCrtSrl=${LEVEL0_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsCrlSrl=${LEVEL0_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsCrl=${LEVEL0_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    # ./ca-tls/etc
    local __0__tlsConfig=${LEVEL0_PATH[caTlsCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    # ./ca-tls/private
    local __0__tlsPwd=${LEVEL0_PATH[caTlsPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsKey=${LEVEL0_PATH[caTlsPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    # ./public
    local __0__tlsChainP7c=${LEVEL0_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsCrtDer=${LEVEL0_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    local __0__tlsCrlDer=${LEVEL0_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL0[domain]} ${DIR_NAME[caTls]})
    
    makeConfigFile \
        ${LEVEL0[domain]} \
        'modulCaTlsConfig' \
        $__0__tlsConfig \
        '0'
    
    makePasswordFile \
        ${LEVEL0[domain]} \
        $__0__tlsPwd
    
    makeKeyFile \
        ${LEVEL0[domain]} \
        $__0__tlsKey \
        $__0__tlsPwd
        
    makeDbFiles \
        ${LEVEL0[domain]} \
        $__0__tlsCrtDb \
        $__0__tlsCrtSrl \
        $__0__tlsCrlSrl
    
    makeSigningCa \
        ${LEVEL0[domain]} \
        ${LEVEL0[path]} \
        $__0__tlsConfig \
        $__0__tlsCsr \
        $__0__tlsKey \
        $__0__tlsPwd \
        $__0__tlsCrt \
        $__0__tlsCrl \
        $__0__tlsChainPem \
        $__0__caConfig \
        $__0__caPwd \
        $__0__caCrt
    
    publishCrt      $__0__tlsCrt        $__0__tlsCrtDer
    publishCACrl    $__0__tlsCrl        $__0__tlsCrlDer
    publishCAChain  $__0__tlsChainPem   $__0__tlsChainP7c
    
    certificate ${LEVEL0[domain]} ${LEVEL0[domain]} create tls-server ssl
    
    #
    # LEVEL 1 (domain)
    #
    
    # intermediate CA for domain level
    # ./intermediate
    if [ ! -z "$domainList" ]; then
        level1domains=$(echo $domainList | tr ";" "\n")
        for level1domain in $level1domains
        do
            #
            # LEVEL 1 (domain)
            #
            declare -A LEVEL1
            LEVEL1[domain]=$level1domain
            LEVEL1[path]="${LEVEL0_PATH[intermediatePath]}/$level1domain"
            
            declare -A LEVEL1_PATH
            # sub root ca
            LEVEL1_PATH[caPath]=${LEVEL1[path]}/${DIRECTORIES_CA_ROOT[caPath]}
            LEVEL1_PATH[caDbPath]=${LEVEL1[path]}/${DIRECTORIES_CA_ROOT[dbPath]}
            LEVEL1_PATH[caCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CA_ROOT[cnfPath]}
            LEVEL1_PATH[caPrvPath]=${LEVEL1[path]}/${DIRECTORIES_CA_ROOT[privatePath]}
            # email ca
            LEVEL1_PATH[caEmailPath]=${LEVEL1[path]}/${DIRECTORIES_CA_EMAIL[caPath]}
            LEVEL1_PATH[caEmailDbPath]=${LEVEL1[path]}/${DIRECTORIES_CA_EMAIL[dbPath]}
            LEVEL1_PATH[caEmailCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CA_EMAIL[cnfPath]}
            LEVEL1_PATH[caEmailPrvPath]=${LEVEL1[path]}/${DIRECTORIES_CA_EMAIL[privatePath]}
            # software ca
            LEVEL1_PATH[caSoftwarePath]=${LEVEL1[path]}/${DIRECTORIES_CA_SOFTWARE[caPath]}
            LEVEL1_PATH[caSoftwareDbPath]=${LEVEL1[path]}/${DIRECTORIES_CA_SOFTWARE[dbPath]}
            LEVEL1_PATH[caSoftwareCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CA_SOFTWARE[cnfPath]}
            LEVEL1_PATH[caSoftwarePrvPath]=${LEVEL1[path]}/${DIRECTORIES_CA_SOFTWARE[privatePath]}
            # tls ca
            LEVEL1_PATH[caTlsPath]=${LEVEL1[path]}/${DIRECTORIES_CA_TLS[caPath]}
            LEVEL1_PATH[caTlsDbPath]=${LEVEL1[path]}/${DIRECTORIES_CA_TLS[dbPath]}
            LEVEL1_PATH[caTlsCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CA_TLS[cnfPath]}
            LEVEL1_PATH[caTlsPrvPath]=${LEVEL1[path]}/${DIRECTORIES_CA_TLS[privatePath]}
            # email crt
            LEVEL1_PATH[crtEmailPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_EMAIL[crtPath]}
            LEVEL1_PATH[crtEmailCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_EMAIL[cnfPath]}
            LEVEL1_PATH[crtEmailPrvPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_EMAIL[privatePath]}
            # software crt
            LEVEL1_PATH[crtSoftwarePath]=${LEVEL1[path]}/${DIRECTORIES_CRT_SOFTWARE[crtPath]}
            LEVEL1_PATH[crtSoftwareCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_SOFTWARE[cnfPath]}
            LEVEL1_PATH[crtSoftwarePrvPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_SOFTWARE[privatePath]}
            # tls crt
            LEVEL1_PATH[crtTlsPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_TLS[crtPath]}
            LEVEL1_PATH[crtTlsCnfPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_TLS[cnfPath]}
            LEVEL1_PATH[crtTlsPrvPath]=${LEVEL1[path]}/${DIRECTORIES_CRT_TLS[privatePath]}
            # subdomains
            LEVEL1_PATH[intermediatePath]=${LEVEL1[path]}/${DIR_NAME[intermediateDir]}
            # pub
            LEVEL1_PATH[pub]=${LEVEL1[path]}/${DIR_NAME[public]}
            LEVEL1_PATH[pubTls]=${LEVEL1[path]}/${DIRECTORIES_PUB[tls]}
            LEVEL1_PATH[pubSoftware]=${LEVEL1[path]}/${DIRECTORIES_PUB[software]}
            LEVEL1_PATH[pubEmail]=${LEVEL1[path]}/${DIRECTORIES_PUB[email]}
            
            writeNewCert ${LEVEL1[domain]}
            
            writeNewType 'directories'
            for index in "${!LEVEL1_PATH[@]}"
            do
                writeNewItem ${LEVEL1_PATH[$index]}
                mkdir -p "${LEVEL1_PATH[$index]}" > /dev/null 2>&1
                check_result $? 'unable to create directory'
            done
            
            writeNewType 'lookup'
            lookupAdd ${LEVEL1[domain]} ${LEVEL1[path]}
            
            writeNewType 'user request configs'
            makeUserSoftwareCsrFiles \
                ${LEVEL1[domain]} \
                ${LEVEL1_PATH[crtSoftwareCnfPath]}
                
            makeUserEmailCsrFiles \
                ${LEVEL1[domain]} \
                ${LEVEL1_PATH[crtEmailCnfPath]}
            
            makeUserTlsCsrFiles \
                ${LEVEL1[domain]} \
                ${LEVEL1_PATH[crtTlsCnfPath]}
            
            #
            # sub root CA
            #
            writeNewType 'Intermediate CA'
            # ./
            local __1__caCsr=${LEVEL1[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caCrt=${LEVEL1[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caChainPem=${LEVEL1[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            # ./ca/db
            local __1__caCrtDb=${LEVEL1_PATH[caDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caCrtSrl=${LEVEL1_PATH[caDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caCrlSrl=${LEVEL1_PATH[caDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caCrl=${LEVEL1_PATH[caDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            # ./ca/etc
            local __1__caConfig=${LEVEL1_PATH[caCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            # ./ca/private
            local __1__caPwd=${LEVEL1_PATH[caPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caKey=${LEVEL1_PATH[caPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            # ./public
            local __1__caChainP7c=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caCrtDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            local __1__caCrlDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caRoot]})
            
            makeConfigFile \
                ${LEVEL1[domain]} \
                'modulCaConfig' \
                $__1__caConfig \
                '1'
            
            makePasswordFile \
                ${LEVEL1[domain]} \
                $__1__caPwd
            
            makeKeyFile \
                ${LEVEL1[domain]} \
                $__1__caKey \
                $__1__caPwd
                
            makeDbFiles \
                ${LEVEL1[domain]} \
                $__1__caCrtDb \
                $__1__caCrtSrl \
                $__1__caCrlSrl
            
            makeIntermediateCa \
                ${LEVEL1[domain]} \
                ${LEVEL1[path]} \
                $__1__caConfig \
                $__1__caCsr \
                $__1__caKey \
                $__1__caPwd \
                $__1__caCrt \
                $__1__caCrl \
                $__1__caChainPem \
                ${LEVEL0[path]} \
                $__0__caConfig \
                $__0__caPwd \
                $__0__caCrt
                
            publishCrt      $__1__caCrt             $__1__caCrtDer
            publishCACrl    $__1__caCrl             $__1__caCrlDer
            publishCAChain  $__1__caChainPem        $__1__caChainP7c
                
            #
            # tls CA
            #
            writeNewType 'TLS CA'
            # ./
            local __1__tlsCsr=${LEVEL1[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsCrt=${LEVEL1[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsChainPem=${LEVEL1[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            # ./ca-tls/db
            local __1__tlsCrtDb=${LEVEL1_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsCrtSrl=${LEVEL1_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsCrlSrl=${LEVEL1_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsCrl=${LEVEL1_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            # ./ca-tls/etc
            local __1__tlsConfig=${LEVEL1_PATH[caTlsCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            # ./ca-tls/private
            local __1__tlsPwd=${LEVEL1_PATH[caTlsPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsKey=${LEVEL1_PATH[caTlsPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            # ./public
            local __1__tlsChainP7c=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsCrtDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            local __1__tlsCrlDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caTls]})
            
            makeConfigFile \
                ${LEVEL1[domain]} \
                'modulCaTlsConfig' \
                $__1__tlsConfig \
                '1'
            
            makePasswordFile \
                ${LEVEL1[domain]} \
                $__1__tlsPwd
            
            makeKeyFile \
                ${LEVEL1[domain]} \
                $__1__tlsKey \
                $__1__tlsPwd
                
            makeDbFiles \
                ${LEVEL1[domain]} \
                $__1__tlsCrtDb \
                $__1__tlsCrtSrl \
                $__1__tlsCrlSrl
            
            makeSigningCa \
                ${LEVEL1[domain]} \
                ${LEVEL1[path]} \
                $__1__tlsConfig \
                $__1__tlsCsr \
                $__1__tlsKey \
                $__1__tlsPwd \
                $__1__tlsCrt \
                $__1__tlsCrl \
                $__1__tlsChainPem \
                $__1__caConfig \
                $__1__caPwd \
                $__1__caChainPem
            
            publishCrt      $__1__tlsCrt            $__1__tlsCrtDer
            publishCACrl    $__1__tlsCrl            $__1__tlsCrlDer
            publishCAChain  $__1__tlsChainPem       $__1__tlsChainP7c
            
            certificate ${LEVEL0[domain]} ${LEVEL1[domain]} create tls-server ssl
    
            #
            # email CA
            #
            writeNewType 'Email CA'
            # ./
            local __1__emailCsr=${LEVEL1[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailCrt=${LEVEL1[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailChainPem=${LEVEL1[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            # ./ca-email/db
            local __1__emailCrtDb=${LEVEL1_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailCrtSrl=${LEVEL1_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailCrlSrl=${LEVEL1_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailCrl=${LEVEL1_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            # ./ca-email/etc
            local __1__emailConfig=${LEVEL1_PATH[caEmailCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            # ./ca-email/private
            local __1__emailPwd=${LEVEL1_PATH[caEmailPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailKey=${LEVEL1_PATH[caEmailPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            # ./public
            local __1__emailChainP7c=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailCrtDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            local __1__emailCrlDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caEmail]})
            
            makeConfigFile \
                ${LEVEL1[domain]} \
                'modulCaEmailConfig' \
                $__1__emailConfig \
                '1'
            
            makePasswordFile \
                ${LEVEL1[domain]} \
                $__1__emailPwd
            
            makeKeyFile \
                ${LEVEL1[domain]} \
                $__1__emailKey \
                $__1__emailPwd
                
            makeDbFiles \
                ${LEVEL1[domain]} \
                $__1__emailCrtDb \
                $__1__emailCrtSrl \
                $__1__emailCrlSrl
            
            makeSigningCa \
                ${LEVEL1[domain]} \
                ${LEVEL1[path]} \
                $__1__emailConfig \
                $__1__emailCsr \
                $__1__emailKey \
                $__1__emailPwd \
                $__1__emailCrt \
                $__1__emailCrl \
                $__1__emailChainPem \
                $__1__caConfig \
                $__1__caPwd \
                $__1__caChainPem
            
            publishCrt      $__1__emailCrt          $__1__emailCrtDer
            publishCACrl    $__1__emailCrl          $__1__emailCrlDer           
            publishCAChain  $__1__emailChainPem     $__1__emailChainP7c
 
            #
            # software CA
            #
            writeNewType 'Software CA'
            # ./
            local __1__softwareCsr=${LEVEL1[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareCrt=${LEVEL1[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareChainPem=${LEVEL1[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            # ./ca-software/db
            local __1__softwareCrtDb=${LEVEL1_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareCrtSrl=${LEVEL1_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareCrlSrl=${LEVEL1_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareCrl=${LEVEL1_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            # ./ca-software/etc
            local __1__softwareConfig=${LEVEL1_PATH[caSoftwareCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            # ./ca-software/private
            local __1__softwarePwd=${LEVEL1_PATH[caSoftwarePrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareKey=${LEVEL1_PATH[caSoftwarePrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            # ./public
            local __1__softwareChainP7c=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareCrtDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            local __1__softwareCrlDer=${LEVEL1_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL1[domain]} ${DIR_NAME[caSoftware]})
            
            makeConfigFile \
                ${LEVEL1[domain]} \
                'modulCaSoftwareConfig' \
                $__1__softwareConfig \
                '1'
            
            makePasswordFile \
                ${LEVEL1[domain]} \
                $__1__softwarePwd
            
            makeKeyFile \
                ${LEVEL1[domain]} \
                $__1__softwareKey \
                $__1__softwarePwd
                
            makeDbFiles \
                ${LEVEL1[domain]} \
                $__1__softwareCrtDb \
                $__1__softwareCrtSrl \
                $__1__softwareCrlSrl
            
            makeSigningCa \
                ${LEVEL1[domain]} \
                ${LEVEL1[path]} \
                $__1__softwareConfig \
                $__1__softwareCsr \
                $__1__softwareKey \
                $__1__softwarePwd \
                $__1__softwareCrt \
                $__1__softwareCrl \
                $__1__softwareChainPem \
                $__1__caConfig \
                $__1__caPwd \
                $__1__caChainPem
 
            publishCrt      $__1__softwareCrt       $__1__softwareCrtDer
            publishCACrl    $__1__softwareCrl       $__1__softwareCrlDer
            publishCAChain  $__1__softwareChainPem  $__1__softwareChainP7c
 
            #
            # LEVEL 2 (subdomains)
            #
            
            # intermediate intermediate CA for subdomain level
            # ./intermediate/domain/intermediate
            if [ ! -z "$subDomainNameList" ]; then
                level2domains=$(echo $subDomainNameList | tr ";" "\n")
                for level2domain in $level2domains
                do
                    #
                    # LEVEL 2 (subs)
                    #
                    # I don't split anything by '.' - a mail.foo.tld is like bob.mail.foo.tld.
                    # feel free to create the third level for bob.
                    # 
                    # in that case
                    # - intermediate CA @ level 3:
                    #   - you MUST fork the makeIntermediateIntermediateCa function as makeIntermediateIntermediateIntermediateCa (or whatever);
                    #   - you MUST redefine export CA_2_SCRIPT_PATH="$baseDir" and export CA_1_SCRIPT_PATH="$rootBaseDir"
                    #                    as export CA_3_SCRIPT_PATH="$baseDir" and export CA_2_SCRIPT_PATH="$rootBaseDir"
                    #   - you MUST call makeConfigFile with '4' as the fourth parameter
                    #   otherwise openssl fails on relative paths. you can walk through the directories - but that's also nasty.
                    #   @see makeModulCaConfigBlock_default::$level
                    # - signing CAs @ level 3 are fun: s/2/3/ && s/1/2/
                    # 
                    declare -A LEVEL2
                    LEVEL2[domain]="$level2domain.${LEVEL1[domain]}"
                    LEVEL2[path]="${LEVEL1_PATH[intermediatePath]}/$level2domain"
                    
                    declare -A LEVEL2_PATH
                    # sub sub root ca
                    LEVEL2_PATH[caPath]=${LEVEL2[path]}/${DIRECTORIES_CA_ROOT[caPath]}
                    LEVEL2_PATH[caDbPath]=${LEVEL2[path]}/${DIRECTORIES_CA_ROOT[dbPath]}
                    LEVEL2_PATH[caCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CA_ROOT[cnfPath]}
                    LEVEL2_PATH[caPrvPath]=${LEVEL2[path]}/${DIRECTORIES_CA_ROOT[privatePath]}
                    # email ca
                    LEVEL2_PATH[caEmailPath]=${LEVEL2[path]}/${DIRECTORIES_CA_EMAIL[caPath]}
                    LEVEL2_PATH[caEmailDbPath]=${LEVEL2[path]}/${DIRECTORIES_CA_EMAIL[dbPath]}
                    LEVEL2_PATH[caEmailCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CA_EMAIL[cnfPath]}
                    LEVEL2_PATH[caEmailPrvPath]=${LEVEL2[path]}/${DIRECTORIES_CA_EMAIL[privatePath]}
                    # software ca
                    LEVEL2_PATH[caSoftwarePath]=${LEVEL2[path]}/${DIRECTORIES_CA_SOFTWARE[caPath]}
                    LEVEL2_PATH[caSoftwareDbPath]=${LEVEL2[path]}/${DIRECTORIES_CA_SOFTWARE[dbPath]}
                    LEVEL2_PATH[caSoftwareCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CA_SOFTWARE[cnfPath]}
                    LEVEL2_PATH[caSoftwarePrvPath]=${LEVEL2[path]}/${DIRECTORIES_CA_SOFTWARE[privatePath]}
                    # tls ca
                    LEVEL2_PATH[caTlsPath]=${LEVEL2[path]}/${DIRECTORIES_CA_TLS[caPath]}
                    LEVEL2_PATH[caTlsDbPath]=${LEVEL2[path]}/${DIRECTORIES_CA_TLS[dbPath]}
                    LEVEL2_PATH[caTlsCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CA_TLS[cnfPath]}
                    LEVEL2_PATH[caTlsPrvPath]=${LEVEL2[path]}/${DIRECTORIES_CA_TLS[privatePath]}
                    # email crt
                    LEVEL2_PATH[crtEmailPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_EMAIL[crtPath]}
                    LEVEL2_PATH[crtEmailCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_EMAIL[cnfPath]}
                    LEVEL2_PATH[crtEmailPrvPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_EMAIL[privatePath]}
                    # software crt
                    LEVEL2_PATH[crtSoftwarePath]=${LEVEL2[path]}/${DIRECTORIES_CRT_SOFTWARE[crtPath]}
                    LEVEL2_PATH[crtSoftwareCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_SOFTWARE[cnfPath]}
                    LEVEL2_PATH[crtSoftwarePrvPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_SOFTWARE[privatePath]}
                    # tls crt
                    LEVEL2_PATH[crtTlsPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_TLS[crtPath]}
                    LEVEL2_PATH[crtTlsCnfPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_TLS[cnfPath]}
                    LEVEL2_PATH[crtTlsPrvPath]=${LEVEL2[path]}/${DIRECTORIES_CRT_TLS[privatePath]}
                    # pub
                    LEVEL2_PATH[pub]=${LEVEL2[path]}/${DIR_NAME[public]}
                    LEVEL2_PATH[pubTls]=${LEVEL2[path]}/${DIRECTORIES_PUB[tls]}
                    LEVEL2_PATH[pubSoftware]=${LEVEL2[path]}/${DIRECTORIES_PUB[software]}
                    LEVEL2_PATH[pubEmail]=${LEVEL2[path]}/${DIRECTORIES_PUB[email]}
            
                    writeNewCert ${LEVEL2[domain]}
                    
                    writeNewType 'directories'
                    for index in "${!LEVEL2_PATH[@]}"
                    do
                        writeNewItem ${LEVEL1_PATH[$index]}
                        mkdir -p "${LEVEL2_PATH[$index]}" > /dev/null 2>&1
                        check_result $? 'unable to create directory'
                    done
                    
                    writeNewType 'lookup'
                    lookupAdd ${LEVEL2[domain]} ${LEVEL2[path]}
            
                    writeNewType 'user request configs'
                    makeUserSoftwareCsrFiles \
                        ${LEVEL2[domain]} \
                        ${LEVEL2_PATH[crtSoftwareCnfPath]}
                        
                    makeUserEmailCsrFiles \
                        ${LEVEL2[domain]} \
                        ${LEVEL2_PATH[crtEmailCnfPath]}
                    
                    makeUserTlsCsrFiles \
                        ${LEVEL2[domain]} \
                        ${LEVEL2_PATH[crtTlsCnfPath]}
                    
                    #
                    # sub sub root CA
                    #
                    writeNewType 'Intermediate CA'
                    # ./
                    local __2__caCsr=${LEVEL2[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caCrt=${LEVEL2[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caChainPem=${LEVEL2[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    # ./ca/db
                    local __2__caCrtDb=${LEVEL2_PATH[caDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caCrtSrl=${LEVEL2_PATH[caDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caCrlSrl=${LEVEL2_PATH[caDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caCrl=${LEVEL2_PATH[caDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    # ./ca/etc
                    local __2__caConfig=${LEVEL2_PATH[caCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    # ./ca/private
                    local __2__caPwd=${LEVEL2_PATH[caPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caKey=${LEVEL2_PATH[caPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    # ./public
                    local __2__caChainP7c=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caCrtDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    local __2__caCrlDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caRoot]})
                    
                    makeConfigFile \
                        ${LEVEL2[domain]} \
                        'modulCaConfig' \
                        $__2__caConfig \
                        '2'
                    
                    makePasswordFile \
                        ${LEVEL2[domain]} \
                        $__2__caPwd
                    
                    makeKeyFile \
                        ${LEVEL2[domain]} \
                        $__2__caKey \
                        $__2__caPwd
                        
                    makeDbFiles \
                        ${LEVEL2[domain]} \
                        $__2__caCrtDb \
                        $__2__caCrtSrl \
                        $__2__caCrlSrl
                    
                    makeIntermediateIntermediateCa \
                        ${LEVEL2[domain]} \
                        ${LEVEL2[path]} \
                        $__2__caConfig \
                        $__2__caCsr \
                        $__2__caKey \
                        $__2__caPwd \
                        $__2__caCrt \
                        $__2__caCrl \
                        $__2__caChainPem \
                        ${LEVEL1[path]} \
                        $__1__caConfig \
                        $__1__caPwd \
                        $__1__caChainPem
                    
                    publishCrt      $__2__caCrt             $__2__caCrtDer
                    publishCACrl    $__2__caCrl             $__2__caCrlDer
                    publishCAChain  $__2__caChainPem        $__2__caChainP7c
                    
                    #
                    # tls CA
                    #
                    writeNewType 'TLS CA'
                    # ./
                    local __2__tlsCsr=${LEVEL2[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsCrt=${LEVEL2[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsChainPem=${LEVEL2[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    # ./ca-tls/db
                    local __2__tlsCrtDb=${LEVEL2_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsCrtSrl=${LEVEL2_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsCrlSrl=${LEVEL2_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsCrl=${LEVEL2_PATH[caTlsDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    # ./ca-tls/etc
                    local __2__tlsConfig=${LEVEL2_PATH[caTlsCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    # ./ca-tls/private
                    local __2__tlsPwd=${LEVEL2_PATH[caTlsPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsKey=${LEVEL2_PATH[caTlsPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    # ./public
                    local __2__tlsChainP7c=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsCrtDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    local __2__tlsCrlDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caTls]})
                    
                    makeConfigFile \
                        ${LEVEL2[domain]} \
                        'modulCaTlsConfig' \
                        $__2__tlsConfig \
                        '2'
                    
                    makePasswordFile \
                        ${LEVEL2[domain]} \
                        $__2__tlsPwd
                    
                    makeKeyFile \
                        ${LEVEL2[domain]} \
                        $__2__tlsKey \
                        $__2__tlsPwd
                        
                    makeDbFiles \
                        ${LEVEL2[domain]} \
                        $__2__tlsCrtDb \
                        $__2__tlsCrtSrl \
                        $__2__tlsCrlSrl
                    
                    makeSigningCa \
                        ${LEVEL2[domain]} \
                        ${LEVEL2[path]} \
                        $__2__tlsConfig \
                        $__2__tlsCsr \
                        $__2__tlsKey \
                        $__2__tlsPwd \
                        $__2__tlsCrt \
                        $__2__tlsCrl \
                        $__2__tlsChainPem \
                        $__2__caConfig \
                        $__2__caPwd \
                        $__2__caChainPem
                    
                    publishCrt      $__2__tlsCrt            $__2__tlsCrtDer
                    publishCACrl    $__2__tlsCrl            $__2__tlsCrlDer
                    publishCAChain  $__2__tlsChainPem       $__2__tlsChainP7c
            
                    certificate ${LEVEL0[domain]} ${LEVEL2[domain]} create tls-server ssl
                    
                    #
                    # email CA
                    #
                    writeNewType 'Email CA'
                    # ./
                    local __2__emailCsr=${LEVEL2[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailCrt=${LEVEL2[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailChainPem=${LEVEL2[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    # ./ca-email/db
                    local __2__emailCrtDb=${LEVEL2_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailCrtSrl=${LEVEL2_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailCrlSrl=${LEVEL2_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailCrl=${LEVEL2_PATH[caEmailDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    # ./ca-email/etc
                    local __2__emailConfig=${LEVEL2_PATH[caEmailCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    # ./ca-email/private
                    local __2__emailPwd=${LEVEL2_PATH[caEmailPrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailKey=${LEVEL2_PATH[caEmailPrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    # ./public
                    local __2__emailChainP7c=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailCrtDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    local __2__emailCrlDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caEmail]})
                    
                    makeConfigFile \
                        ${LEVEL2[domain]} \
                        'modulCaEmailConfig' \
                        $__2__emailConfig \
                        '2'
                    
                    makePasswordFile \
                        ${LEVEL2[domain]} \
                        $__2__emailPwd
                    
                    makeKeyFile \
                        ${LEVEL2[domain]} \
                        $__2__emailKey \
                        $__2__emailPwd
                        
                    makeDbFiles \
                        ${LEVEL2[domain]} \
                        $__2__emailCrtDb \
                        $__2__emailCrtSrl \
                        $__2__emailCrlSrl
                    
                    makeSigningCa \
                        ${LEVEL2[domain]} \
                        ${LEVEL2[path]} \
                        $__2__emailConfig \
                        $__2__emailCsr \
                        $__2__emailKey \
                        $__2__emailPwd \
                        $__2__emailCrt \
                        $__2__emailCrl \
                        $__2__emailChainPem \
                        $__2__caConfig \
                        $__2__caPwd \
                        $__2__caChainPem
                    
                    publishCrt      $__2__emailCrt          $__2__emailCrtDer
                    publishCACrl    $__2__emailCrl          $__2__emailCrlDer                   
                    publishCAChain  $__2__emailChainPem     $__2__emailChainP7c
 
                    #
                    # software CA
                    #
                    writeNewType 'Software CA'
                    # ./
                    local __2__softwareCsr=${LEVEL2[path]}/$(printf ${FILE_NAME[csr]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareCrt=${LEVEL2[path]}/$(printf ${FILE_NAME[crt]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareChainPem=${LEVEL2[path]}/$(printf ${FILE_NAME[chainPem]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    # ./ca-software/db
                    local __2__softwareCrtDb=${LEVEL2_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crtDb]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareCrtSrl=${LEVEL2_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crtSrl]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareCrlSrl=${LEVEL2_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crlSrl]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareCrl=${LEVEL2_PATH[caSoftwareDbPath]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    # ./ca-software/etc
                    local __2__softwareConfig=${LEVEL2_PATH[caSoftwareCnfPath]}/$(printf ${FILE_NAME[cnf]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    # ./ca-software/private
                    local __2__softwarePwd=${LEVEL2_PATH[caSoftwarePrvPath]}/$(printf ${FILE_NAME[password]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareKey=${LEVEL2_PATH[caSoftwarePrvPath]}/$(printf ${FILE_NAME[key]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    # ./public
                    local __2__softwareChainP7c=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[chainP7c]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareCrtDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[cer]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    local __2__softwareCrlDer=${LEVEL2_PATH[pub]}/$(printf ${FILE_NAME[crl]} ${LEVEL2[domain]} ${DIR_NAME[caSoftware]})
                    
                    makeConfigFile \
                        ${LEVEL2[domain]} \
                        'modulCaSoftwareConfig' \
                        $__2__softwareConfig \
                        '2'
                    
                    makePasswordFile \
                        ${LEVEL2[domain]} \
                        $__2__softwarePwd
                    
                    makeKeyFile \
                        ${LEVEL2[domain]} \
                        $__2__softwareKey \
                        $__2__softwarePwd
                        
                    makeDbFiles \
                        ${LEVEL2[domain]} \
                        $__2__softwareCrtDb \
                        $__2__softwareCrtSrl \
                        $__2__softwareCrlSrl
                    
                    makeSigningCa \
                        ${LEVEL2[domain]} \
                        ${LEVEL2[path]} \
                        $__2__softwareConfig \
                        $__2__softwareCsr \
                        $__2__softwareKey \
                        $__2__softwarePwd \
                        $__2__softwareCrt \
                        $__2__softwareCrl \
                        $__2__softwareChainPem \
                        $__2__caConfig \
                        $__2__caPwd \
                        $__2__caChainPem
                    
                    publishCrt      $__2__softwareCrt       $__2__softwareCrtDer
                    publishCACrl    $__2__softwareCrl       $__2__softwareCrlDer
                    publishCAChain  $__2__softwareChainPem  $__2__softwareChainP7c
                done
            fi
        done
    fi
    
    do_unlock
}
 
 
demo()
{
    local pass='UDUslpOy:lsp.amsCw,Z09o&ooYx:lko123---0'
    root_ca $DEFAULT_DOMAIN 'example.com;example2.com' 'mail;smtp'
    certificate $DEFAULT_DOMAIN example.com create code-signing fruffi -CN 'fruffi IRC BOT' -password $pass
    certificate $DEFAULT_DOMAIN example.com create email lucas -password $pass -CN 'lucas' -emailAddress '[email protected]'
    certificate $DEFAULT_DOMAIN example.com create tls-client lucas -CN 'Luc' -password $pass
    certificate $DEFAULT_DOMAIN example.com create tls-client-external luc-external -CN 'Luc' -O 'frufflwochen' -C 'NL' -password $pass
    certificate $DEFAULT_DOMAIN example.com create tls-server 1337
    certificate $DEFAULT_DOMAIN example.com create tls-server-external example.com -CN 'external.com' -O 'frufflwochen' -C 'NL' -password $pass
}

Comments