#!/usr/bin/sh #---------------------------------------------------------------------------------------- # /var/install/bin/certs-create-tls-certs - create and manage TLS certificates # # Copyright (c) 2001-2025 The Eisfair Team, team(at)eisfair(dot)org # # Creation: 2003-09-09 jed # Last Update: $Id$ # # Parameters: # # certs-create-tls-certs ca batch - start in CA mode # certs-create-tls-certs client batch [Cert-Name] - start in client server mode # certs-create-tls-certs client batch [alternate [alternate-Keyname][Cert-Name]] - start in client server mode # certs-create-tls-certs crl batch [--passfile] - start in CRL mode # certs-create-tls-certs mail batch - start in mail server mode # certs-create-tls-certs web batch [Server-Domainname] - start in web server mode # certs-create-tls-certs web batch [alternate [alternate-Keyname][Server-Domainname]] - start in web server mode # # if you add one of the words 'ca', 'client', 'mail' or 'web' # as first parameter the right menu will be displayed automatically. # # if you add the word 'batch' as second parameter the menu # will not be displayed and the required commands are processed. # in the right order. # if you add the word 'alternate' as third parameter the fourth # parameter will be taken as alternate key name and the fifth # parameter will be taken as certificate name # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. #---------------------------------------------------------------------------------------- # include eislib . /var/install/include/eislib . /var/install/include/jedlib # activate debug output #debug_certs=true if ${debug_certs:-false} then exec 2> /tmp/$(basename ${0})-trace$$.log set -x ask_debug=true export ask_debug fi pgmname=`basename $0` tmpdir=/tmp ssldir=/usr/local/ssl certdir=${ssldir}/certs crldir=${ssldir}/crl newcertdir=${ssldir}/newcerts oldcertdir=${certdir}/old privdir=${ssldir}/private revdir=$ssldir/revoked reqdir=${ssldir}/csr homedir=/root/.certs sslbindir=/usr/bin/ssl apache2file=/etc/config.d/apache2 basefile=/etc/config.d/base certsfile=/etc/config.d/certs localesfile=/etc/config.d/locales passfile=${homedir}/certs-capass ask_bin=/var/install/bin/ask openssl_bin=/usr/bin/openssl email_bin=/usr/bin/send_file_from_cmd.sh ### load configuration ### . ${certsfile} chmod 600 ${certsfile} # set individual crl file name crl_file_name='crl.pem' if [ -f ${apache2file} ] then # read apache2 parameters APACHE2_SERVER_NAME=`grep "^APACHE2_SERVER_NAME=" ${apache2file} | sed -e 's/#.*$//' -e "s/^.*=['\"]\(.*\)['\"].*$/\1/" -e 's#/ *$##'` # override default apache2 servername if [ -n "${CERTS_WEBSERVER_NAME}" ] then # use individual fqdn webserver name APACHE2_SERVER_NAME=`echo "${CERTS_WEBSERVER_NAME}" | cut -d: -f1` fi crl_file_name="${APACHE2_SERVER_NAME}-crl.pem" fi if [ -z "${TIME_ZONE}" ] then # time zone not set if [ -f ${localesfile} ] then # read time zone from locales configuration . ${localesfile} TIME_ZONE=${LOCALES_TIME_ZONE} elif [ -f ${basefile} ] then # read time zone from base configuration . ${basefile} # TIME_ZONE=${TIME_ZONE} else # set default time zone TIME_ZONE=CET fi fi keytype="client/server" keyname='' altkeyname='' altkeybits='' domainname="myserver.mydomain.de" usagesec="Server_CA" default_ca_days=3650 default_cert_days=365 default_crl_days=30 default_dh_bits=2048 # OpenSSL program default is '512' default_cert_symlinks=" apache2 ldapserver mail mini_httpd partimg proftpd pure-ftpd ssmtp " default_key_symlinks=" apache2 " default_reserved_names=" apache slapd exim imapd ipop3d mini_httpd partimaged proftpd pure-ftpd ssmtp " ask_tmpfile=/tmp/certs-ask.$$ # change default signature algorithm from '-sha1' to '-sha512' to improve security. case "${CERTS_HASH_ALGORITHM}" in sha1|sha224|sha256|sha384|sha512 ) default_signature_algorithm="-${CERTS_HASH_ALGORITHM}" ;; * ) # set default signature algorithm to '-sha384' instead of '-sha1' to improve security. CERTS_HASH_ALGORITHM='sha384' default_signature_algorithm="-${CERTS_HASH_ALGORITHM}" ;; esac # change default RSA key bit value from '512' to '2048' bits to improve security. case "${CERTS_RSA_KEYBITS}" in 1024|2048|4096|8192|secp256k1|secp384r1|secp521r1 ) ;; * ) # set default RSA key bit value to '2048' bits CERTS_RSA_KEYBITS='2048' ;; esac no_ca_file=${ssldir}/certs-no-ca-home.txt if [ -f ${passfile} ] then # set ca password file access rights chown -R root ${homedir} chgrp -R root ${homedir} chmod -R 0600 ${homedir} fi # check files if [ ! -f ${ssldir}/serial ] then echo "01" > ${ssldir}/serial fi if [ ! -f ${ssldir}/index.txt ] then touch ${ssldir}/index.txt fi # initialize variables endflag=0 for MNAME in mstat3 mstat4 mstat5 mstat10 mstat11 mstat12 mstat13 mstat14 mstat15 mstat16 do export $MNAME="_" >/dev/null done # set configuration file export OPENSSL_CONF=${ssldir}/openssl.cnf #---------------------------------------------------------------------------------------- # check if OpenSSL file isn't empty and contains valid data # # input: $1 - crt|crl|csr|dh|ec|eckey|rsakey|privkey|key # $2 - file name # # output: 0 - valid file # 1 - file is empty # 2 - file doesn't contain required block #---------------------------------------------------------------------------------------- is_valid_openssl_file () { _ivof_ret=2 _ivof_type=$1 _ivof_file="$2" if [ -n "${_ivof_type}" -a -n "${_ivof_file}" -a -f "${_ivof_file}" ] then case ${_ivof_type} in crt|cert ) _ivof_pattern="CERTIFICATE" ;; crl ) _ivof_pattern="X509 CRL" ;; csr ) _ivof_pattern="CERTIFICATE REQUEST" ;; dh ) _ivof_pattern="DH PARAMETERS" ;; ec ) _ivof_pattern="EC PARAMETERS" ;; eckey ) _ivof_pattern="EC PRIVATE KEY" ;; rsakey ) _ivof_pattern="PRIVATE KEY:RSA PRIVATE KEY" ;; privkey ) _ivof_pattern="ENCRYPTED PRIVATE KEY" ;; key ) _ivof_pattern="PRIVATE KEY:EC PRIVATE KEY:RSA PRIVATE KEY:ENCRYPTED PRIVATE KEY" ;; esac if [ -s ${_ivof_file} ] then # file not empty _ifs="${IFS}" IFS=':' for PATTERN in ${_ivof_pattern} do grep -q "^-----BEGIN ${PATTERN}-----" "${_ivof_file}" _ivof_rc1=$? grep -q "^-----END ${PATTERN}-----" "${_ivof_file}" _ivof_rc2=$? if [ ${_ivof_rc1} -eq 0 -a ${_ivof_rc2} -eq 0 ] then # valid data block found _ivof_ret=0 break fi done IFS=${_ifs} else # file is empty _ivof_ret=1 fi fi return ${_ivof_ret} } #---------------------------------------------------------------------------------------- # is certificate startdate in the future? # input: $1 - start date string #---------------------------------------------------------------------------------------- is_date_in_future () { _idif_ret=1 _idif_utc_startdatetime=`echo "$1" | sed 's/Z$//'` _idif_curr_datetime=`date +'%Y-%m-%d %T'` # _idif_curr_utc_datetime=`date --utc +'%y%m%d%H%M%S' -d "${_idif_curr_datetime} ${TIME_ZONE}"` _idif_curr_utc_datetime=`date --utc +'%y%m%d%H%M%S' --date="TZ=\"${TIME_ZONE}\" ${_idif_curr_datetime}"` if [ ${_idif_utc_startdatetime} -gt ${_idif_curr_utc_datetime} ] then _idif_ret=0 fi return ${_idif_ret} } #---------------------------------------------------------------------------------------- # set function status based on existence of files #---------------------------------------------------------------------------------------- set_function_status () { # set function status # check if ca key file is valid if [ -f "${privdir}/ca.key" ] then if ! is_valid_openssl_file 'key' "${privdir}/ca.key" then # delete invalid file echo "Invalid CA key file '${privdir}/ca.key' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${privdir}/ca.key" fi fi fi if [ -f "${privdir}/ca.key" ] then # step finished export mstat3="--info ✓" elif [ -n "${keyname}" ] then # recommended step export mstat3="--warn >" else export mstat3="_" fi # check if ca certificate file is valid if [ -f "${newcertdir}/ca.crt" ] then if ! is_valid_openssl_file 'crt' "${newcertdir}/ca.crt" then # delete invalid file echo "Invalid CA certificate file '${newcertdir}/ca.crt' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${newcertdir}/ca.crt" fi fi fi if [ -f "${newcertdir}/ca.crt" ] then # step finished # read ca certificate validity date ca_raw_valdate="`${openssl_bin} x509 -in ${newcertdir}/ca.crt -noout -enddate | sed 's/notAfter=//g'`" ca_format_valdate="`date -d "${ca_raw_valdate}" +"%d.%m.%Y"`" export mstat4="--info ✓" export mstat4validity="(valid until: ${ca_format_valdate})" elif [ "${mstat3}" = "--info ✓" ] then # recommended step export mstat4="--warn >" export mstat4validity='' else export mstat4="_" export mstat4validity='' fi # check if ca certificate file is valid if [ -f "${certdir}/ca.pem" ] then if ! is_valid_openssl_file 'crt' "${certdir}/ca.pem" then # delete invalid file echo "Invalid CA certificate file '${certdir}/ca.pem' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${certdir}/ca.pem" fi fi fi if [ -f "${certdir}/ca.pem" ] then # step finished export mstat5="--info ✓" elif [ "${mstat4}" = "--info ✓" ] then # recommended step export mstat5="--warn >" else export mstat5="_" fi mstat8validity='' if [ -f "${crldir}/${crl_file_name}" ] then grep -q "^-----BEGIN X509 CRL-----" "${crldir}/${crl_file_name}" if [ $? -eq 0 ] then crl_raw_valdate="`${openssl_bin} crl -in ${crldir}/${crl_file_name} -nextupdate -noout | sed 's/nextUpdate=//g'`" crl_format_valdate="`date -d "${crl_raw_valdate}" +"%d.%m.%Y %H:%Mh"`" export mstat8validity="(valid until: ${crl_format_valdate})" fi fi if [ "${keytype}" != "ca" ] then # check if key file(s) are valid if [ -f "${privdir}/${keyname}.key" ] then if ! is_valid_openssl_file 'key' "${privdir}/${keyname}.key" then # delete invalid file echo "Invalid key file '${privdir}/${keyname}.key' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${privdir}/${keyname}.key" fi fi fi if [ -f "${privdir}/${altkeyname}.key" ] then if ! is_valid_openssl_file 'key' "${privdir}/${altkeyname}.key" then # delete invalid file echo "Invalid key file '${privdir}/${altkeyname}.key' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${privdir}/${altkeyname}.key" fi fi fi if [ -f "${privdir}/${keyname}.key" -o -f "${privdir}/${altkeyname}.key" ] then # step finished export mstat10="--info ✓" elif [ -n "${keyname}" ] then # recommended step export mstat10="--warn >" else export mstat10="_" fi # check if certificate request file is valid if [ -f "${reqdir}/${keyname}.csr" ] then if ! is_valid_openssl_file 'csr' "${reqdir}/${keyname}.csr" then # delete invalid file echo "Invalid certificate request file '${reqdir}/${keyname}.csr' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${reqdir}/${keyname}.csr" fi fi fi if [ -f "${reqdir}/${keyname}.csr" ] then # step finished export mstat11="--info ✓" elif [ "${mstat10}" = "--info ✓" ] then # recommended step export mstat11="--warn >" else export mstat11="_" fi # check if certificate file is valid if [ -f "${newcertdir}/${keyname}.crt" ] then if ! is_valid_openssl_file 'crt' "${newcertdir}/${keyname}.crt" then # delete invalid file echo "Invalid certificate file '${newcertdir}/${keyname}.crt' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${newcertdir}/${keyname}.crt" fi fi fi if [ -f "${newcertdir}/${keyname}.crt" ] then # step finished export mstat12="--info ✓" elif [ "${mstat11}" = "--info ✓" ] then # recommended step export mstat12="--warn >" else export mstat12="_" fi # check if dh file is valid if [ -f "${newcertdir}/${keyname}.dh" ] then if ! is_valid_openssl_file 'dh' "${newcertdir}/${keyname}.dh" then # delete invalid file echo "Invalid Diffie-Hellman file '${newcertdir}/${keyname}.dh' detected." if ${ask_bin} "Do you want to delete it" 'n' then rm -f "${newcertdir}/${keyname}.dh" fi fi fi if [ -f "${newcertdir}/${keyname}.dh" ] then # step finished export mstat13="--info ✓" elif [ "${mstat12}" = "--info ✓" ] then # recommended step export mstat13="--warn >" else export mstat13="_" fi if [ -f "${certdir}/${keyname}.pem" ] then # step finished export mstat14="--info ✓" elif [ "${mstat13}" = "--info ✓" ] then # recommended step export mstat14="--warn >" else export mstat14="_" fi # a PKCS#12 document file cannot be automatically checked if it # is a valid file because it is usually a binary file secured # with a passphrase, therefore only check if it exists if [ -f "${newcertdir}/${keyname}.p12" ] then # step finished export mstat15="--info ✓" elif [ "${mstat14}" = "--info ✓" ] then # recommended step export mstat15="--warn >" else export mstat15="_" fi if [ "${mstat16}" != "--info ✓" ] then if [ "${mstat15}" = "--info ✓" ] then # recommended step export mstat16="--warn >" else export mstat16="_" fi fi fi } #---------------------------------------------------------------------------------------- # create menu selection - This function reformats the given selection lists # to a more readable format. Example: # # Input : "1 2 6 10 11 12 13 14 15 16 17 19" # Output: "1-2,6,10-17,19" # # input: $1 - string of available menu values # # output: reformated string #---------------------------------------------------------------------------------------- create_menu_selection () { _cms_values=" $* " _cms_new_val='' _cms_prev_val='' _cms_range_flag=0 for VAL in ${_cms_values} do # process input string if [ -z "${_cms_new_val}" ] then # add primary value _cms_new_val="${VAL}" else # additional values given... if [ `expr ${_cms_prev_val} + 1` -eq ${VAL} ] then # previous value + 1 is equal current value => range condition if [ ${_cms_range_flag} -eq 0 ] then # range _cms_new_val="${_cms_new_val}-" _cms_range_flag=1 fi else # previous value +1 is less than current value => list condition if [ ${_cms_range_flag} -eq 1 ] then _cms_new_val="${_cms_new_val}${_cms_prev_val},${VAL}" else _cms_new_val="${_cms_new_val},${VAL}" fi _cms_range_flag=0 fi fi # save current value for next loop _cms_prev_val=${VAL} done if [ ${_cms_range_flag} -eq 1 ] then # add final value if range condition has not been finalized _cms_new_val="${_cms_new_val}${_cms_prev_val}" fi echo "${_cms_new_val}" } #---------------------------------------------------------------------------------------- # check if valid menu selection # # input: $1 - value to check # $2 - string of available menu values # # output: 0 - valid value, entry found # 1 - invalid value, entry not found #---------------------------------------------------------------------------------------- is_valid_menu_selection () { _ivms_sval=$1 # value to check if [ -z "${_ivms_sval}" ] then # empty string - invalid value _ivms_ret=1 else shift _ivms_sel_values=" $* " # string of available menu values echo "${_ivms_sel_values}" | grep -q " ${_ivms_sval} " _ivms_ret=$? fi return ${_ivms_ret} } #---------------------------------------------------------------------------------------- # print main management menu #---------------------------------------------------------------------------------------- print_main_menu () { sel_values='' # print menue clrhome if [ -f "${no_ca_file}" ] then _pmm_header_line="Certificate generation (No CA home!)" else _pmm_header_line="Certificate generation" fi mecho --info "${_pmm_header_line}" echo echo "Parameters" if [ ${override} -eq 0 ] then echo -n " 1 - change/set certificate type: " sel_values="1" else echo -n " = - change/set certificate type: " fi if [ -z "${keyname}" ] then mecho --warn "${keytype}" else mecho --info "${keytype}" fi if [ "${keytype}" = "client/server" -o "${keytype}" = "mail" ] then echo -n " 2 - change/set certificate name: " sel_values="${sel_values} 2" else echo -n " = - change/set certificate name: " fi if [ -z "${keyname}" ] then mecho --warn "" else # check if a reserved name is used echo "${default_reserved_names}" | grep -q " ${keyname} " if [ $? -eq 0 ] then mecho -n --info "${keyname}"; mecho --warn " (reserved name used!)" else mecho --info "${keyname}" fi fi echo " " if [ "${keytype}" = "ca" ] then # show sha information for CA echo -n "Certificate Authority (CA) (" if [ "${CERTS_HASH_ALGORITHM}" = "sha1" ] then mecho -n --error "${CERTS_HASH_ALGORITHM}" else mecho -n --info "${CERTS_HASH_ALGORITHM}" fi echo -n ") (" case ${CERTS_RSA_KEYBITS} in secp* ) # ECDSA mecho -n --info "${CERTS_RSA_KEYBITS}" ;; * ) # RSA mecho -n --info "${CERTS_RSA_KEYBITS}bits" ;; esac echo ")" else echo "Certificate Authority (CA)" fi if [ "${keytype}" = "ca" ] then echo -n " 3 - ["; mecho -n ${mstat3}; echo "] create a CA key" echo -n " 4 - ["; mecho -n ${mstat4}; echo "] create a self-signed CA certificate ${mstat4validity}" sel_values="${sel_values} 3 4" fi if [ "${keytype}" = "ca" -a -n "${keyname}" ] then echo -n " 5 - ["; mecho -n ${mstat5}; echo "] create .pem CA certificate and copy it to ${certdir}" sel_values="${sel_values} 5" fi if [ -f "${certdir}/ca.pem" ] then echo " 6 - show CA key and certificate file location" sel_values="${sel_values} 6" else echo " = - show CA key and certificate file location" fi if [ "${keytype}" = "ca" ] then echo " 7 - revoke a certificate" echo " 8 - update revocation list ${mstat8validity}" sel_values="${sel_values} 7 8" fi if [ "${keytype}" != "ca" ] then echo echo -n "Server/service/client certificate (" if [ "${CERTS_HASH_ALGORITHM}" = "sha1" ] then mecho -n --error "${CERTS_HASH_ALGORITHM}" else mecho -n --info "${CERTS_HASH_ALGORITHM}" fi echo -n ") (" case ${CERTS_RSA_KEYBITS} in secp* ) # ECDSA mecho -n --info "${CERTS_RSA_KEYBITS}" ;; * ) # RSA mecho -n --info "${CERTS_RSA_KEYBITS}bits" ;; esac echo ")" if [ -n "${keyname}" ] then if [ -z "${altkeyname}" ] then if [ -f "${privdir}/${keyname}.key" ] then # if key file already exists, set 'SELECTED' status altkeyname="${keyname}" # 2015-02-26/JED - do not forget to add ECDSA check! altkeybits=`${openssl_bin} rsa -in ${privdir}/${keyname}.key -noout -text | head -n1 | sed 's/^.*: (\([0-9]*\).*$/\1/'` echo -n " 10 - ["; mecho -n ${mstat10}; echo -n "] create new key/select existing one [${altkeyname}] ("; mecho -n --info "${altkeybits}bits"; echo ")" else echo -n " 10 - ["; mecho -n ${mstat10}; echo "] create new key/select existing one [${keyname}]" fi sel_values="${sel_values} 10" elif [ "${altkeyname}" != "no-ca" ] then altkeybits=`${openssl_bin} rsa -in ${privdir}/${altkeyname}.key -noout -text | head -n1 | sed 's/^.*: (\([0-9]*\).*$/\1/'` echo -n " 10 - ["; mecho -n ${mstat10}; echo -n "] create new key/select existing one [${altkeyname}] ("; mecho -n --info "${altkeybits}bits"; echo ")" sel_values="${sel_values} 10" else echo -n " 10 - ["; mecho -n ${mstat10}; echo "] create new key/select existing one [${altkeyname}]" fi echo -n " 11 - ["; mecho -n ${mstat11}; echo "] create certificate request ${mstat11ext}" sel_values="${sel_values} 11" if [ ! -f ${no_ca_file} ] then echo -n " 12 - ["; mecho -n ${mstat12}; echo "] sign certificate request with CA key" sel_values="${sel_values} 12" else echo -n " == - ["; mecho -n ${mstat12}; echo "] sign certificate request with CA key" fi else echo -n " == - ["; mecho -n ${mstat10}; echo "] create a new key or select an existing one" echo -n " == - ["; mecho -n ${mstat11}; echo "] create certificate request" echo -n " == - ["; mecho -n ${mstat12}; echo "] sign certificate request with CA key" fi if [ -n "${keyname}" ] then echo -n " 13 - ["; mecho -n ${mstat13}; echo "] create Diffie-Hellman parameters (takes appr. 5min)" sel_values="${sel_values} 13" echo -n " 14 - ["; mecho -n ${mstat14}; echo "] create .pem certificate and copy it to ${certdir}" sel_values="${sel_values} 14" else echo -n " == - ["; mecho -n ${mstat13}; echo "] create Diffie-Hellman parameters (takes appr. 5min)" echo -n " == - ["; mecho -n ${mstat14}; echo "] create .pem certificate and copy it to ${certdir}" fi if [ -n "${keyname}" ] then echo -n " 15 - ["; mecho -n ${mstat15}; echo "] create PKCS#12 document" sel_values="${sel_values} 15" else echo -n " == - ["; mecho -n ${mstat15}; echo "] create PKCS#12 document" fi if [ -n "${keyname}" ] then echo -n " 16 - ["; mecho -n ${mstat16}; echo "] check package dependent symbolic links" echo " 17 - show certificate file details" sel_values="${sel_values} 16 17" else echo -n " == - ["; mecho -n ${mstat16}; echo "] check package dependent symbolic links" echo " == - show certificate file details" fi fi echo if [ \( "${keytype}" = "ca" -a "${mstat4}" != "_" -a "${mstat5}" != "_" \) -o \ \( "${keytype}" != "ca" -a "${mstat4}" != "_" -a \( "${mstat14}" != "_" -o "${mstat15}" != "_" \) \) ] then # allow to send certificates by email echo -n "Please select (`create_menu_selection "${sel_values}"`), change (b)its/(h)ash, (e)mail certs, (q)uit? " else echo -n "Please select (`create_menu_selection "${sel_values}"`), change (b)its/(h)ash, (q)uit? " fi } #---------------------------------------------------------------------------------------- # get list of certificates #---------------------------------------------------------------------------------------- get_list_of_certs () { ls ${certdir}/*.pem 2>/dev/null | grep -q -v "ca.pem" if [ $? -eq 0 ] then # files found, go on ... _glof_cname_list=`find ${certdir} -maxdepth 1 \( -type f -or -type l \) -name "*.pem" -printf '%f\n' | \ sort | tr '\n' ':' | sed -e 's#(#\\\(#g' -e 's#)#\\\)#g' -e 's# #\\\ #g'` _glof_idx=1 _ifs="${IFS}" IFS=':' for CNAME in ${_glof_cname_list} do if [ -L "${certdir}/${CNAME}" ] then # symbolic link _glof_org_file="`readlink -e "${certdir}/${CNAME}"`" eval cert_name_${_glof_idx}=\"`basename "${CNAME}" '.pem'`#`basename "${_glof_org_file}" '.pem'`\" else eval cert_name_${_glof_idx}=\"`basename "${CNAME}" '.pem'`\" fi cert_name_n=${_glof_idx} _glof_idx=`expr ${_glof_idx} + 1` done IFS=${_ifs} else # no files found cert_name_n=0 fi } #---------------------------------------------------------------------------------------- # set certificate type #---------------------------------------------------------------------------------------- set_cert_type () { # change/set certificate type _sct_exit=0 while [ ${_sct_exit} -eq 0 ] do # show menu clrhome mecho --info "change certificate type" echo echo " 1 - Certificate Authority (CA)" echo " 2 - Client/server certificate" echo ${ask_bin} "Please choose key type" 'q' '1-2' 'q' > ${ask_tmpfile} rc=$? read _sct_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_sct_num} in [qQ] ) # quit _sct_exit=1 ;; [12] ) # numeric value case ${_sct_num} in 1 ) # ca keytype="ca" keyname="ca" ;; 2 ) # client/server keytype="client/server" keyname='' altkeyname='' domainname="myserver.mydomain.de" ;; esac export mstat16="_" _sct_exit=1 ;; * ) print_not_in_range anykey ;; esac done } #---------------------------------------------------------------------------------------- # set certificate name #---------------------------------------------------------------------------------------- set_cert_name () { _scn_exit=0 while [ ${_scn_exit} -eq 0 ] do # set new certificate name clrhome mecho --info "Change/set certificate name" echo echo "Do you want to create a (n)ew certificate or" ${ask_bin} "select and (e)xisting certificate, (q)uit" 'q' '+' > ${ask_tmpfile} rc=$? read _scn_sel < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_scn_sel} in [qQ] ) # quit _scn_exit=1 ;; [nN] ) # create a new certificate (no spaces allowed in file name) echo echo "Please enter a certificate name," ${ask_bin} "e.g. 'my-server.local.lan', (q)uit" 'q' '+' > ${ask_tmpfile} rc=$? _scn_fname=`cat ${ask_tmpfile} | sed 's/ *//g'` rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_scn_fname} in [qQ] ) # quit _scn_exit=1 ;; * ) if [ -n "${_scn_fname}" ] then keyname="`basename "${_scn_fname}" ".pem"`" altkeyname='' export mstat16="_" fi ;; esac _scn_exit=1 ;; [eE] ) # select an existing key get_list_of_certs set_alternate_cert_name export mstat16="_" _scn_exit=1 ;; * ) print_not_in_range anykey ;; esac if [ -n "${keyname}" ] then # check if a reserved name is used echo "${default_reserved_names}" | grep -q " ${keyname} " if [ $? -eq 0 ] then echo mecho -n --warn "You've selected the reserved key name '"; mecho -n "${keyname}"; mecho --warn "' which is normally" mecho --warn "used to create symbolic links. It is recommended to use the FQDN as" mecho --warn "name for the certificate file and to create a symbolic link to that" mecho --warn "file using menu entry '16'." echo anykey fi fi done } #---------------------------------------------------------------------------------------- # change RSA key bits #---------------------------------------------------------------------------------------- change_rsa_keybits () { # change RSA key bits _crk_exit=0 while [ ${_crk_exit} -eq 0 ] do # show menu clrhome mecho --info "Change key bits" echo echo -n " 1 - RSA-1024 - "; mecho --warn "possibly unsecure, not recommended!" echo -n " 2 - RSA-2048 - "; mecho --info "default" echo " 3 - RSA-4096" echo " 4 - RSA-8192" echo " 5 - ECDSA (256bit prime)" echo " 6 - ECDSA (384bit prime)" echo " 7 - ECDSA (521bit prime)" echo ${ask_bin} "Please select the desired key size (1-4), (d)efault, (q)uit" 'q' '+' > ${ask_tmpfile} rc=$? read _bit_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_bit_num} in [qQ] ) # quit _crk_exit=1 ;; [1-7]|[dD] ) # ECDSA elliptic curve algorithms (openssl ecparam -list_curves) # # OpenSSL 1.0.1k-fips 8 Jan 2015 # # - secp112r1 : SECG/WTLS curve over a 112 bit prime field # - secp112r2 : SECG curve over a 112 bit prime field # - secp128r1 : SECG curve over a 128 bit prime field # - secp128r2 : SECG curve over a 128 bit prime field # - secp160k1 : SECG curve over a 160 bit prime field # - secp160r1 : SECG curve over a 160 bit prime field # - secp160r2 : SECG/WTLS curve over a 160 bit prime field # - secp192k1 : SECG curve over a 192 bit prime field # - secp224k1 : SECG curve over a 224 bit prime field # - secp224r1 : NIST/SECG curve over a 224 bit prime field # = secp256k1 : SECG curve over a 256 bit prime field # = secp384r1 : NIST/SECG curve over a 384 bit prime field # = secp521r1 : NIST/SECG curve over a 521 bit prime field # - prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field # - prime192v2: X9.62 curve over a 192 bit prime field # - prime192v3: X9.62 curve over a 192 bit prime field # - prime239v1: X9.62 curve over a 239 bit prime field # - prime239v2: X9.62 curve over a 239 bit prime field # - prime239v3: X9.62 curve over a 239 bit prime field # - prime256v1: X9.62/SECG curve over a 256 bit prime field # - wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field # - wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field # - wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field # - wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field # - wap-wsg-idm-ecid-wtls12: WTLS curvs over a 224 bit prime field case ${_bit_num} in 1 ) # RSA-1024 CERTS_RSA_KEYBITS='1024' ;; [2dD] ) # default value # RSA-2048 CERTS_RSA_KEYBITS='2048' ;; 3 ) # RSA-4096 CERTS_RSA_KEYBITS='4096' ;; 4 ) # RSA-8192 CERTS_RSA_KEYBITS='8192' ;; 5 ) # ECDSA - SECG curve over a 256 bit prime field CERTS_RSA_KEYBITS='secp256k1' ;; 6 ) # ECDSA - NIST/SECG curve over a 384 bit prime field CERTS_RSA_KEYBITS='secp384r1' ;; 7 ) # ECDSA - NIST/SECG curve over a 521 bit prime field CERTS_RSA_KEYBITS='secp521r1' ;; esac _crk_exit=1 ;; * ) print_not_in_range anykey ;; esac done } #---------------------------------------------------------------------------------------- # change secure hash algorithm #---------------------------------------------------------------------------------------- change_hash_algorithm () { # change secure hash algorithm _cha_exit=0 while [ ${_cha_exit} -eq 0 ] do # show menu clrhome mecho --info "Change secure hash algorithm" echo echo -n " 1 - sha1 - "; mecho --warn "unsecure, not recommended!" echo " 2 - sha224" echo " 3 - sha256" echo -n " 4 - sha384 - "; mecho --info "default" echo " 5 - sha512" echo ${ask_bin} "Please select the desired hash algorithm (1-5), (d)efault, (q)uit" 'q' '+' > ${ask_tmpfile} rc=$? read _sha_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_sha_num} in [qQ] ) # quit _cha_exit=1 ;; [1-5]|[dD] ) case ${_sha_num} in 1 ) CERTS_HASH_ALGORITHM='sha1' ;; 2 ) CERTS_HASH_ALGORITHM='sha224' ;; 3 ) CERTS_HASH_ALGORITHM='sha256' ;; [4dD] ) # default value CERTS_HASH_ALGORITHM='sha384' ;; 5 ) CERTS_HASH_ALGORITHM='sha512' ;; esac default_signature_algorithm="-${CERTS_HASH_ALGORITHM}" _cha_exit=1 ;; * ) print_not_in_range anykey ;; esac done } #---------------------------------------------------------------------------------------- # print header of certificate list #---------------------------------------------------------------------------------------- print_cert_list_header () { clrhome mecho --info "Certificate selection" echo techo --begin 4r 35 4 35 techo --row -info "Nbr " --info "Certificate Name(s)" --info "(->" --info "Symbolic Link to..)" } #---------------------------------------------------------------------------------------- # set alternate certificate name e.g. if you want # to update a certificate #---------------------------------------------------------------------------------------- set_alternate_cert_name () { print_cert_list_header row=4 if [ ${cert_name_n} -gt 0 ] then # files found, go on ... _sacn_exit=0 _sacn_idx=1 _sacn_start_idx=${_sacn_idx} while [ ${_sacn_idx} -le ${cert_name_n} -a ${_sacn_exit} -eq 0 ] do eval _sacn_cname_org='$cert_name_'${_sacn_idx} # check for symbolic link echo ${_sacn_cname_org} | grep -q '#' if [ $? -eq 0 ] then # symbolic link, reformat string _sacn_cname_1=`echo ${_sacn_cname_org} | cut -d# -f1` _sacn_cname_2=`echo ${_sacn_cname_org} | cut -d# -f2` else # non-symbolic link _sacn_cname_1="${_sacn_cname_org}" _sacn_cname_2='' fi if [ -z "${_sacn_cname_2}" ] then techo --row ${_sacn_idx} "${_sacn_cname_1}" else techo --row ${_sacn_idx} "${_sacn_cname_1}" " ->" --warn "${_sacn_cname_2}" fi if [ "${act_pmode}" = 'tty' ] then if [ ${row} -eq ${maxrownum} -o ${_sacn_idx} -ge ${cert_name_n} ] then _sacn_end_idx=${_sacn_idx} # last entry of list echo ${ask_bin} "Which certificate should be used (${_sacn_start_idx}-${_sacn_end_idx})[${cert_name_n}], ENTER, (q)uit:" '' '*' > ${ask_tmpfile} rc=$? read _sacn_cnum < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_sacn_cnum} in [qQ] ) # quit _sacn_exit=1 ;; * ) if is_numeric ${_sacn_cnum} then # numeric if [ ${_sacn_cnum} -ge ${_sacn_start_idx} -a ${_sacn_cnum} -le ${_sacn_end_idx} ] then eval keyname='$cert_name_'${_sacn_cnum} # check for symbolic link echo "${keyname}" | grep -q '#' if [ $? -eq 0 ] then keyname=`echo "${keyname}" | cut -d# -f2` fi _sacn_exit=1 else print_not_in_range anykey print_cert_list_header _sacn_idx=${_sacn_start_idx} fi else # non-numeric if [ ${_sacn_idx} -le ${cert_name_n} ] then print_cert_list_header _sacn_start_idx=${_sacn_idx} fi fi ;; esac row=4 fi fi _sacn_idx=`expr ${_sacn_idx} + 1` row=`expr ${row} + 1` done techo --end else print_no_cert_found fi echo } #---------------------------------------------------------------------------------------- # get list of keys #---------------------------------------------------------------------------------------- get_list_of_keys () { ls ${privdir}/*.key 2>/dev/null | grep -q -v "ca.key" if [ $? -eq 0 ] then # files found, go on ... _glok_kname_list=`find ${privdir} -maxdepth 1 \( -type f -or -type l \) -name "*.key" -not -name "ca.key" -printf '%f\n' | \ sort | tr '\n' ':' | sed -e 's#(#\\\(#g' -e 's#)#\\\)#g' -e 's# #\\\ #g'` _glok_idx=1 _ifs="${IFS}" IFS=':' for KNAME in ${_glok_kname_list} do _glok_key_name="`basename "${KNAME}" '.key'`" if [ -L "${privdir}/${KNAME}" ] then # symbolic link _glok_org_file="`readlink -e "${privdir}/${KNAME}"`" # read key bits _glok_key_bits=`${openssl_bin} rsa -in ${_glok_org_file} -noout -text | head -n1 | sed 's/^.*: (\([0-9]*\).*$/\1/'` eval key_name_${_glok_idx}=\"${_glok_key_name}#`basename "${_glok_org_file}" '.key'`#${_glok_key_bits}\" else # read key bits _glok_key_bits=`${openssl_bin} rsa -in ${privdir}/${KNAME} -noout -text | head -n1 | sed 's/^.*: (\([0-9]*\).*$/\1/'` eval key_name_${_glok_idx}=\"`basename "${KNAME}" '.key'`##${_glok_key_bits}\" fi key_name_n=${_glok_idx} _glok_idx=`expr ${_glok_idx} + 1` done IFS=${_ifs} else # no files found key_name_n=0 fi } #---------------------------------------------------------------------------------------- # print header of keyificate list #---------------------------------------------------------------------------------------- print_key_list_header () { clrhome mecho --info "Key selection" echo techo --begin 4r 35 4 35 techo --row -info "Nbr " --info "Key Name(s)" --info "(->" --info "Symbolic Link to..)" } #---------------------------------------------------------------------------------------- # set alternate key name e.g. if you want to create a new # certificate request (CSR) without generating a new key #---------------------------------------------------------------------------------------- set_alternate_key_name () { print_key_list_header row=4 if [ ${key_name_n} -gt 0 ] then # files found, go on ... _sakn_exit=0 _sakn_idx=1 _sakn_start_idx=${_sakn_idx} while [ ${_sakn_idx} -le ${key_name_n} -a ${_sakn_exit} -eq 0 ] do eval _sakn_kname_org='$key_name_'${_sakn_idx} # check for symbolic link echo ${_sakn_kname_org} | grep -q '#' if [ $? -eq 0 ] then # symbolic link, reformat string _sakn_kname_1=`echo ${_sakn_kname_org} | cut -d# -f1` _sakn_kname_2=`echo ${_sakn_kname_org} | cut -d# -f2` else # non-symbolic link _sakn_kname_1="${_sakn_kname_org}" _sakn_kname_2='' fi if [ -z "${_sakn_kname_2}" ] then techo --row ${_sakn_idx} "${_sakn_kname_1}" else techo --row ${_sakn_idx} "${_sakn_kname_1}" " ->" --warn "${_sakn_kname_2}" fi if [ "${act_pmode}" = 'tty' ] then if [ ${row} -eq ${maxrownum} -o ${_sakn_idx} -ge ${key_name_n} ] then sakn_end_idx=${_sakn_idx} # last entry of list echo ${ask_bin} "Which key should be used (${_sakn_start_idx}-${sakn_end_idx})[${key_name_n}], ENTER, (q)uit:" '' '*' > ${ask_tmpfile} rc=$? read _sakn_knum < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_sakn_knum} in [qQ] ) # quit _sakn_exit=1 ;; * ) if is_numeric ${_sakn_knum} then # numeric if [ ${_sakn_knum} -ge ${_sakn_start_idx} -a ${_sakn_knum} -le ${sakn_end_idx} ] then eval tmpkeyname='$key_name_'${_sakn_knum} altkeyname=`echo "${tmpkeyname}" | cut -d# -f1` altkeybits=`echo "${tmpkeyname}" | cut -d# -f3` # check for symbolic link echo "${tmpkeyname}" | grep -q '##' if [ $? -ne 0 ] then # symbolic link altkeyname=`echo "${tmpkeyname}" | cut -d# -f2` fi _sakn_exit=1 else print_not_in_range anykey print_key_list_header _sakn_idx=${_sakn_start_idx} fi else # non-numeric if [ ${_sakn_idx} -le ${key_name_n} ] then print_key_list_header _sakn_start_idx=${_sakn_idx} fi fi ;; esac row=4 fi fi _sakn_idx=`expr ${_sakn_idx} + 1` row=`expr ${row} + 1` done techo --end else mecho --error "No key files found!" fi echo } #---------------------------------------------------------------------------------------- # set key name #---------------------------------------------------------------------------------------- set_key_name () { # set new key name if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create new key/select existing one" echo echo "Do you want to create a (n)ew key or" ${ask_bin} "select an (e)xisting key, (q)uit" 'q' '+' > ${ask_tmpfile} rc=$? read _skn_sel < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi else # batch mode _skn_sel="n" fi case ${_skn_sel} in [qQ] ) # quit ;; [nN] ) # create a new key create_key ;; [eE] ) # select an existing key get_list_of_keys set_alternate_key_name ;; * ) print_not_in_range ;; esac } #---------------------------------------------------------------------------------------- # set usage type #---------------------------------------------------------------------------------------- set_usage_type () { # change/set usage type if [ "${runmode}" != "interactive" -a \( "${keytype}" = "mail" -o "${keytype}" = "web" \) ] then # server usagesec="Server_CA" else # interactive _sat_exit=0 while [ ${_sat_exit} -eq 0 ] do echo echo " 1 - Server usage (server)" echo " 2 - Client usage (email)" echo ${ask_bin} "Please choose usage type" '1' '1-2' > ${ask_tmpfile} rc=$? read _sut_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_sut_num} in 1 ) # server usagesec="Server_CA" _sat_exit=1 ;; 2 ) # client usagesec="User_CA" _sat_exit=1 ;; * ) print_not_in_range ;; esac done fi } #---------------------------------------------------------------------------------------- # set validity_period (start and end date) #---------------------------------------------------------------------------------------- set_validity_period () { # 24.01.2015/JED # to prevent an 'error 9 at 1 depth lookup:certificate is not yet valid' # error message, the entered date and time is converted to UTC time twice. _svp_curr_datetime=`date +'%Y-%m-%d %T'` # change/set start date _svp_exit1=0 while [ ${_svp_exit1} -eq 0 ] do if [ "${runmode}" = "interactive" ] then # server echo echo " 1 - use default start date/validity: ${_svp_curr_datetime} / ${default_cert_days} days" echo " 2 - set individual start date/validity" echo ${ask_bin} "Please choose desired option" '1' '1-2' > ${ask_tmpfile} rc=$? read _svp_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi else _svp_num="1" fi case ${_svp_num} in 2 ) _svp_acc_datetime='' _svp_acc_days='' _svp_exit2=0 while [ ${_svp_exit2} -eq 0 ] do echo ${ask_bin} "Please enter date/time (YYYY-MM-DD HH:MM:SS)" "${_svp_curr_datetime}" '+' > ${ask_tmpfile} rc=$? read _svp_datetime < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi _svp_new_date=`echo ${_svp_datetime} | cut -d' ' -f1` _svp_new_time=`echo ${_svp_datetime} | cut -d' ' -f2` if is_date ${_svp_new_date} then if is_time ${_svp_new_time} then _svp_acc_datetime="${_svp_datetime}" _svp_exit2=1 else _svp_datetime='' mecho --error "invalid time format '${_svp_new_date}'!" anykey fi else _svp_datetime='' mecho --error "invalid date format '${_svp_new_date}'!" anykey fi done # while [ ${_svp_exit2} -eq 0 ] _svp_exit3=0 while [ ${_svp_exit3} -eq 0 ] do echo ${ask_bin} "Please enter number of validity days" "${default_cert_days}" '+' > ${ask_tmpfile} rc=$? read _svp_days < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi if [ -z "${_svp_days}" ] then _svp_days=${default_cert_days} fi _svp_new_days=`echo ${_svp_days} | sed 's/[+a-zA-Z-]*//g'` _svp_multidays=`echo ${_svp_days} | sed 's/[0-9]*//g'` if is_numeric ${_svp_new_days} then case ${_svp_multidays} in [wW] ) # week _svp_acc_days=`expr ${_svp_new_days} \* 7` _svp_exit3=1 ;; [mM] ) # month _svp_acc_days=`expr ${_svp_new_days} \* 30` _svp_exit3=1 ;; [yY] ) # year _svp_acc_days=`expr ${_svp_new_days} \* 365` _svp_exit3=1 ;; '' ) # no multiplier given _svp_acc_days=${_svp_new_days} _svp_exit3=1 ;; * ) _svp_days='' mecho --error "invalid day multiplier '${_svp_multidays}'!" anykey ;; esac else _svp_days='' mecho --error "invalid day format '${_svp_new_days}'!" anykey fi done # while [ ${_svp_exit3} -eq 0 ] # 16.12.2007/JED # When the parameters '-startdate DATE -days DAYS' are used OpenSSL is # calculating the valid end-date based on the current date and and not # on the given start-date. Therefore the enddate will explicitely # calculated. # Nevertheless OpenSSL still shows the incorrect number of days when # signing the certificate request. # 24.01.2015/JED # to prevent an 'error 9 at 1 depth lookup:certificate is not yet valid' # error message, the entered date and time is converted to UTC time. # _svp_acc_utc_datetime=`date --utc +'%Y-%m-%d %T' -d "${_svp_acc_datetime} ${TIME_ZONE}"` _svp_acc_utc_datetime=`date --utc +'%Y-%m-%d %T' --date="TZ=\"${TIME_ZONE}\" ${_svp_acc_datetime}"` startdate=`date +'%y%m%d%H%M%S' -d "${_svp_acc_utc_datetime}"`Z enddate=`date +'%y%m%d%H%M%S' -d "${_svp_acc_utc_datetime} ${_svp_acc_days} days"`Z _svp_exit1=1 ;; * ) # set default values # 24.01.2015/JED # to prevent an 'error 9 at 1 depth lookup:certificate is not yet valid' # error message, the entered date and time is converted to UTC time. # _svp_curr_utc_datetime=`date --utc +'%Y-%m-%d %T' -d "${_svp_curr_datetime} ${TIME_ZONE}"` _svp_curr_utc_datetime=`date --utc +'%Y-%m-%d %T' --date="TZ=\"${TIME_ZONE}\" ${_svp_curr_datetime}"` startdate=`date +'%y%m%d%H%M%S' -d "${_svp_curr_utc_datetime}"`Z enddate=`date +'%y%m%d%H%M%S' -d "${_svp_curr_utc_datetime} ${default_cert_days} days"`Z _svp_exit1=1 ;; esac done } #---------------------------------------------------------------------------------------- # create a new CA key #---------------------------------------------------------------------------------------- create_ca_key () { # create a ca key if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create CA key" fi # create ca key if [ ! -f "${privdir}/ca.key" ] then echo echo "You will be asked to enter the following data, after pressing ENTER:" echo echo " 1. Passphrase of your CA key." echo anykey case ${CERTS_RSA_KEYBITS} in secp* ) # ECDSA - create key and encrypt it ${openssl_bin} ecparam -genkey -name ${CERTS_RSA_KEYBITS} | ${openssl_bin} pkey -aes-256-cbc -out "${privdir}/ca.key" # ${openssl_bin} genpkey -algorithm EC -aes-256-cbc \ # -pkeyopt ec_param_enc:named_curve -pkeyopt ec_paramgen_curve:P-384 -out "${privdir}/ca.key" ;; * ) # RSA (aes-256 is faster than des3) ${openssl_bin} genpkey -algorithm RSA -aes-256-cbc \ -pkeyopt rsa_keygen_bits:${CERTS_RSA_KEYBITS} -out "${privdir}/ca.key" ;; esac else mecho --error "CA key ${privdir}/ca.key already exists!" fi } #---------------------------------------------------------------------------------------- # create a new CA certificate #---------------------------------------------------------------------------------------- create_ca_cert () { # create a ca certificate request if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create CA certificate" fi _ccc_yesno1='n' if [ -f "${newcertdir}/ca.crt" ] then if [ "${runmode}" = "interactive" ] then # CA certificate already exists _ccc_ca_valdate="`date -d "${ca_raw_valdate}" +"%d.%m.%Y %T %Z"`" echo echo "A CA certificate ${newcertdir}/ca.crt already exists," echo -n "which is valid until: "; mecho --info "${_ccc_ca_valdate}"; echo "." echo mecho --warn "The CA certificate MUST normally NOT be replaced!" echo echo "Remove previously generated files (.crt, .pem, .p12)," if ${ask_bin} "proceed anyway" 'n' then _ccc_yesno1='y' fi fi else _ccc_yesno1='y' fi case ${_ccc_yesno1} in [yY] ) # always ask if files should be deleted if [ "${runmode}" = "interactive" ] then # check if files exist which should be deleted if check_files_to_delete 'csr' then # show files which should be deleted echo show_files_to_delete 'csr' fi fi if check_files_to_delete 'csr' then echo if ${ask_bin} "Do you really want to remove these files" 'n' then # delete files remove_files 'csr' echo else # abort csr creation _ccc_yesno1='n' fi fi if [ "${_ccc_yesno1}" = 'y' ] then if [ -z "${CERTS_CA_ADMIN_NAME}" ] then CERTS_CA_ADMIN_NAME=' ' fi if [ -z "${CERTS_CA_ADMIN_EMAIL}" ] then CERTS_CA_ADMIN_EMAIL='.' fi # questions to ask _ccc_askcount=7 _ccc_ask1="C:Country code (2 letter code):${CERTS_CA_CCODE}:2:2:+" _ccc_ask2="ST:State or province name:${CERTS_CA_STATE}:0:0:+" _ccc_ask3="L:Locality name:${CERTS_CA_LOCALITY}:0:0:+" _ccc_ask4="O:Organization or company name:${CERTS_CA_ORGA_NAME}:0:0:+" _ccc_ask5="OU:Organizational unit or section name:${CERTS_CA_ORGA_UNIT}:0:0:+" _ccc_ask6="CN:Name of the Administrator, e.g. (YOUR name):${CERTS_CA_ADMIN_NAME}:0:64:+" _ccc_ask7="emailAddress:Email address:${CERTS_CA_ADMIN_EMAIL}:0:60:*" _ccc_subj='' _ccc_idx=1 while [ ${_ccc_idx} -le ${_ccc_askcount} ] do _ccc_next=0 # build question eval _ccc_question="\$_ccc_ask${_ccc_idx}" _ccc_label=`echo "${_ccc_question}" | cut -d: -f1` _ccc_ask=`echo "${_ccc_question}" | cut -d: -f2` _ccc_def=`echo "${_ccc_question}" | cut -d: -f3` _ccc_min=`echo "${_ccc_question}" | cut -d: -f4` _ccc_max=`echo "${_ccc_question}" | cut -d: -f5` _ccc_mask=`echo "${_ccc_question}" | cut -d: -f6` # ask question _ccc_answer='' ${ask_bin} "${_ccc_ask}" "${_ccc_def}" "${_ccc_mask}" > ${ask_tmpfile} rc=$? # remove invalid characters from answer _ccc_answer=`cat ${ask_tmpfile} | sed -e 's#[;/\\(\)\[]*##g' -e 's#]##g'` rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi # echo "INPUT:${_ccc_answer}:" if [ "${_ccc_answer}" = 'q' -o "${_ccc_answer}" = 'Q' ] then # quit break fi # check input length _ccc_again=0 _ccc_length=`expr length "${_ccc_answer}"` if [ ${_ccc_min} -gt 0 -a ${_ccc_length} -lt ${_ccc_min} ] then # input to short print_string_to_short ${ask_min} _ccc_again=1 elif [ ${_ccc_max} -gt 0 -a ${_ccc_length} -gt ${_ccc_max} ] then # input to long print_string_to_long ${ask_max} _ccc_again=1 fi if [ ${_ccc_again} -eq 0 ] then # build subject string # /C=US/ST=Oregon/L=New York/O=eisfair CA/OU=My eisfair Certificate Authority/CN=Name of Root/emailAddress=root@local.lan case ${_ccc_label} in C ) # country _ccc_subj="/${_ccc_label}=`echo "${_ccc_answer}" | tr 'a-z' 'A-Z'`" _ccc_next=1 ;; CN|ST|L|O|OU ) # state/location/organisation/organisation unit if [ -n "${_ccc_answer}" -a "${_ccc_answer}" != '.' ] then _ccc_subj="${_ccc_subj}/${_ccc_label}=${_ccc_answer}" fi _ccc_next=1 ;; emailAddress ) # email address if [ -n "${_ccc_answer}" -a "${_ccc_answer}" != '.' ] then echo "${_ccc_answer}" | grep -q '@' if [ $? -eq 0 ] then _ccc_subj="${_ccc_subj}/${_ccc_label}=${_ccc_answer}" _ccc_next=1 else print_no_valid_email_address fi else _ccc_next=1 fi ;; * ) everything else ;; esac fi if [ ${_ccc_next} -eq 1 ] then # jump to next question _ccc_idx=`expr ${_ccc_idx} + 1` fi done if [ "${_ccc_answer}" != 'q' -a "${_ccc_answer}" != 'Q' ] then # check if an email address has been entered echo "${_ccc_subj}" | grep -q "emailAddress=" if [ $? -eq 0 ] then # create custom openssl.cnf _ccc_config_file=${ssldir}/openssl-tmp.cnf # 20150301/JED - From Firefox 36.x onwards the rules to # verify certificates has been set tighter. Firefox # throws out an 'sec_error_bad_der' error if e.g. a # 'X509v3 Subject Alternative Name' parameter is set # although no email address has been entered. # To solve this problem the 'subjectAltName = email:copy', # and if necessary the 'issuerAltName = issuer:copy', # parameter will only be activated if an email address # has been found in the certificate request. sed '/\[ SCA_ext \]/,/\[ UCA_ext \]/{/\[ SCA_ext \]/n;/\[ UCA_ext \]/!{s/^#subjectAltName/subjectAltName/g;s/^#issuerAltName/issuerAltName/g}}' ${ssldir}/openssl.cnf > ${_ccc_config_file} else _ccc_config_file=${ssldir}/openssl.cnf fi # echo "SUBJ:${_ccc_subj}:" echo if ${ask_bin} "Do you want to continue" 'n' then # create CA certificate echo echo "You will be asked to enter the following data, after pressing ENTER:" echo echo " 1. Passphrase of your CA key." echo anykey ${openssl_bin} req -new -x509 ${default_signature_algorithm} -days ${default_ca_days} \ -key ${privdir}/ca.key -out ${newcertdir}/ca.crt -subj "${_ccc_subj}" \ -config ${_ccc_config_file} if [ $? -eq 0 ] then echo "... done." else mecho --warn "... CA certificate generation unsuccessful!" fi fi fi echo fi ;; * ) # do nothing ;; esac } #---------------------------------------------------------------------------------------- # create a HTML message #---------------------------------------------------------------------------------------- create_html_msg () { ### mime types ### # application/x-x509-ca-cert cacert # application/x-x509-email-cert ecert email # application/x-x509-server-cert scert servercert # application/x-x509-user-cert ucert usercert rm -f "${tmpdir}/importcert.htm" { echo "" echo "" echo " " echo " Certificates" echo " " echo " " echo "

Import certificates

" echo echo "

The CA certificate" if [ "${keyname}" != "ca" ] then if [ -f "${newcertdir}/${keyname}.p12" ] then echo "
" echo " " echo " Your user certificate in PKCS#12-format" fi if [ -f "${certdir}/${keyname}.pem" ] then echo "
" echo " " echo " Your user certificate in PEM-format" fi fi echo "

" echo " " echo "" } > "${tmpdir}/importcert.htm" } #---------------------------------------------------------------------------------------- # send new certificate by email #---------------------------------------------------------------------------------------- send_cert_email () { clrhome mecho --info "Show certificate by email" echo _sce_errflag=0 _sce_mail_options='' if [ -f "${newcertdir}/ca.crt" ] then ln -sf "${newcertdir}/ca.crt" "${newcertdir}/ca.cacert" ln -sf "${newcertdir}/ca.crt" "${newcertdir}/ca.pem" _sce_mail_options="${newcertdir}/ca.cacert ${newcertdir}/ca.crt ${newcertdir}/ca.pem" else mecho --error "Error: couldn't find certificate ${newcertdir}/ca.crt!" mecho --error " Function aborted!" echo _sce_errflag=1 fi if [ "${keyname}" != "ca" ] then _sce_pem=0 _sce_p12=0 if [ -f "${newcertdir}/${keyname}.p12" ] then _sce_p12=1 fi if [ -f "${certdir}/${keyname}.pem" ] then _sce_pem=1 fi if [ ${_sce_p12} -eq 0 -a ${_sce_pem} -eq 0 ] then mecho --error "Error: couldn't find any certificate file (${keyname}.p12," mecho --error " ${keyname}.pem), Function aborted!" echo _sce_errflag=1 fi fi if [ ${_sce_errflag} -eq 0 ] then # go on... _sce_mail_addr='' if [ -f "${newcertdir}/${keyname}.p12" ] then _sce_mail_options="${_sce_mail_options} ${newcertdir}/${keyname}.p12" fi if [ -f "${certdir}/${keyname}.pem" ] then if [ "${keyname}" != "ca" ] then # create temporary symbolic link to make certificate import easier ln -sf ${certdir}/${keyname}.pem ${certdir}/${keyname}.crt _sce_mail_options="${_sce_mail_options} ${certdir}/${keyname}.pem ${certdir}/${keyname}.crt" fi _sce_mail_addr=`${openssl_bin} x509 -in ${certdir}/${keyname}.pem -noout -email` # run a basic check if it might be an email address echo "${_sce_mail_addr}" | grep -q '@' if [ $? -ne 0 ] then # no email address _sce_mail_addr='' for PNAME in mail ssmtp vmail do if [ "`/usr/bin/eisman check ${PNAME}`" = 'installed' ] then _sce_mail_addr="postmaster@`/var/install/config.d/${PNAME} getdomain`" break fi done fi fi echo "Sending certificates ..." echo "`printf " - %s\n" ${_sce_mail_options}`" echo _sce_exit=0 while [ ${_sce_exit} -eq 0 ] do if [ -f ${email_bin} ] then # script to send email exists echo "Please enter the email address to which the certificates" ${ask_bin} "should be send (q)uit" "${_sce_mail_addr}" '+' > ${ask_tmpfile} rc=$? read _sce_maddr < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_sce_maddr} in [qQ] ) # quit _sce_exit=1 ;; * ) _sce_mail_addr="${_sce_maddr}" if [ -n "${_sce_mail_addr}" ] then # run a basic check if it might be an email address echo "${_sce_mail_addr}" | grep -q '@' if [ $? -eq 0 ] then if [ "${keyname}" = "ca" ] then # send only ca certificate { echo "Attached you will find the certification of the Certification Authority (CA)." echo "Please save all attachments in a directory and open the HTML file to import the" echo "certificates into your certificates database." } | ${email_bin} -f "CA master " \ -s "Your certificates - check attachements" -t "${_sce_mail_addr}" \ -u "${tmpdir}/importcert.htm ${_sce_mail_options}" else # send ca and normal certificate { echo "Attached you will find the certification of the Certification Authority (CA)" echo "and your personal PKCS#12/PEM document. Please save all attachments in a directory" echo "and open the HTML file to import the certificates into your certificates" echo "database." } | ${email_bin} -f "CA master " \ -s "Your certificates - check attachements" -t "${_sce_mail_addr}" \ -u "${tmpdir}/importcert.htm ${_sce_mail_options}" fi echo "... done." echo _sce_exit=1 else print_no_valid_email_address fi else print_no_valid_email_address fi ;; esac else mecho --error "A script which is used to send that email couldn't be found on your server." mecho --error "Please make sure that the script'${email_bin}' exists" mecho --error "before you start this function again." echo _sce_exit=1 fi done # while [ ${sce_exit} -eq 0 ] rm -f "${tmpdir}/importcert.htm" if [ "${keyname}" != "ca" ] then # remove temporary symbolic link rm -f ${certdir}/${keyname}.crt fi anykey fi } #---------------------------------------------------------------------------------------- # check files which could be deleted # input: $1 - type (cert/csr/key) #---------------------------------------------------------------------------------------- check_files_to_delete () { # check for key and cert files to be deleted _cftd_ret=1 case $1 in cert|crt ) _cftd_files="${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; csr ) _cftd_files="${reqdir}/${keyname}.csr ${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; key|* ) _cftd_files="${privdir}/${keyname}.key ${reqdir}/${keyname}.csr ${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; esac for FNAME in ${_cftd_files} do if [ -f "${FNAME}" ] then _cftd_ret=0 break fi done return ${_cftd_ret} } #---------------------------------------------------------------------------------------- # show files which will be deleted # input: $1 - type (cert/csr/key) #---------------------------------------------------------------------------------------- show_files_to_delete () { # check for key and cert files to be deleted case $1 in cert|crt ) _sftd_files="${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; csr ) _sftd_files="${reqdir}/${keyname}.csr ${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; key|* ) _sftd_files="${privdir}/${keyname}.key ${reqdir}/${keyname}.csr ${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; esac for FNAME in ${_sftd_files} do if [ -f "${FNAME}" ] then echo " ${FNAME}" #lrwxrwxrwx 1 root root 25 Jan 6 11:46 /usr/local/ssl/private/myone.local.lan -> my-server.local.lan #-rw-r--r-- 1 root root 1679 May 25 2003 /usr/local/ssl/private/my-server.local.lan _sftd_path="`dirname ${FNAME}`" _sftd_ext="`echo "${FNAME}" | awk -F . '{print $NF}'`" _sftd_fname="`basename "${FNAME}" .${ext}`" for LNAME in `ls -l ${_sftd_path}/*.${_sftd_ext} | grep "^l.*${_sftd_fname}" | tr -s ' ' '#' | cut -d# -f9` do echo " ${LNAME}" done fi done } #---------------------------------------------------------------------------------------- # remove existing files # input: $1 - type (cert/csr/key) #---------------------------------------------------------------------------------------- remove_files () { # delete existing key and cert _rf_tmpfile=/tmp/certs-filelist.$$ rm -f ${_rf_tmpfile} case $1 in cert|crt ) _rf_files="${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; csr ) _rf_files="${reqdir}/${keyname}.csr ${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; key|* ) _rf_files="${privdir}/${keyname}.key ${reqdir}/${keyname}.csr ${newcertdir}/${keyname}.crt ${certdir}/${keyname}.pem ${newcertdir}/${keyname}.p12" ;; esac for FNAME in ${_rf_files} do if [ -f "${FNAME}" ] then echo "${FNAME}" >> ${_rf_tmpfile} #lrwxrwxrwx 1 root root 25 Jan 6 11:46 /usr/local/ssl/private/myone.local.lan -> my-server.local.lan #-rw-r--r-- 1 root root 1679 May 25 2003 /usr/local/ssl/private/my-server.local.lan _rf_path="`dirname ${FNAME}`" _rf_ext="`echo "${FNAME}" | awk -F . '{print $NF}'`" _rf_fname="`basename "${FNAME}" .${ext}`" for LNAME in `ls -l ${_rf_path}/*.${_rf_ext} | grep "^l.*${_rf_fname}" | tr -s ' ' '#' | cut -d# -f9` do echo "${LNAME}" >> ${_rf_tmpfile} done fi done if [ -s ${_rf_tmpfile} ] then # move existing files to an archive tar czf ${oldcertdir}/${keyname}-`date +'%Y%m%d-%H%M%S'`.tgz --files-from=${_rf_tmpfile} --remove-files 2>/dev/null if [ $? -eq 0 ] then echo "... archived." else mecho --warn "A problem appeared during '$1' archiving!" fi rm -f ${_rf_tmpfile} fi } #---------------------------------------------------------------------------------------- # create key #---------------------------------------------------------------------------------------- create_key () { # create new key _ck_yesno1='n' if [ -f "${privdir}/${keyname}.key" ] then echo echo "A key ${privdir}/${keyname}.key already exists." echo "Remove previously generated files (.key, .csr, .crt, .pem, .p12)," if ${ask_bin} "proceed anyway" 'n' then _ck_yesno1='y' fi else # no key found _ck_yesno1='y' fi case ${_ck_yesno1} in [yY] ) # always ask if files should be deleted if [ "${runmode}" = "interactive" ] then # check if files exist which should be deleted if check_files_to_delete 'key' then # show files which should be deleted echo show_files_to_delete 'key' fi fi if check_files_to_delete 'key' then echo if ${ask_bin} "Do you really want to remove these files" 'n' then # delete files remove_files 'key' echo else # abort key generation _ck_yesno1='n' fi fi case ${_ck_yesno1} in [yY] ) if [ "${runmode}" = "interactive" ] then echo echo "No data have to be entered." echo anykey fi case ${CERTS_RSA_KEYBITS} in secp* ) # ECDSA ${openssl_bin} ecparam -genkey -name ${CERTS_RSA_KEYBITS} -out "${privdir}/${keyname}.key" # ${openssl_bin} genpkey -algorithm EC -pkeyopt ec_param_enc:named_curve \ # -pkeyopt ec_paramgen_curve:P-384 -out "${privdir}/ca.key" ;; * ) # RSA ${openssl_bin} genpkey -algorithm RSA \ -pkeyopt rsa_keygen_bits:${CERTS_RSA_KEYBITS} -out "${privdir}/${keyname}.key" ;; esac if [ $? -eq 0 ] then if [ "${runmode}" = 'interactive' ] then echo "... done." echo fi else mecho --warn "... key generation unsuccessful!" echo fi ;; * ) # do nothing ;; esac ;; * ) # do nothing ;; esac } #---------------------------------------------------------------------------------------- # create a certificate request #---------------------------------------------------------------------------------------- create_cert_req () { # create a certificate request if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create certificate request" fi _ccr_yesno1='n' if [ -f "${reqdir}/${keyname}.csr" ] then # CSR already exists echo echo "A certificate request ${reqdir}/${keyname}.csr already exists." echo "Remove previously generated files (.csr, .crt, .pem, .p12)," if ${ask_bin} "proceed anyway" 'n' then _ccr_yesno1='y' fi else _ccr_yesno1='y' fi case ${_ccr_yesno1} in [yY] ) # always ask if files should be deleted if [ "${runmode}" = "interactive" ] then # check if files exist which should be deleted if check_files_to_delete 'csr' then # show files which should be deleted echo show_files_to_delete 'csr' fi fi if check_files_to_delete 'csr' then echo if ${ask_bin} "Do you really want to remove these files" 'n' then # delete files remove_files 'csr' echo else # abort csr creation _ccr_yesno1='n' fi fi if [ "${_ccr_yesno1}" = 'y' ] then if [ `echo "${keyname}" | grep -o '\.' | wc -l` -ge 2 ] then # more than 2 dots in name, use it as domain name _ccr_domainname="${keyname}" else # use default _ccr_domainname="${domainname}" fi if [ "${runmode}" = 'interactive' ] then _ccr_domaindefault=' ' else _ccr_domaindefault="${_ccr_domainname}" fi echo if [ -z "${CERTS_CERT_REQ_EMAIL}" ] then CERTS_CERT_REQ_EMAIL='.' fi # questions to ask _ccr_askcount=7 _ccr_ask1="C:Country code (2 letter code):${CERTS_CERT_CCODE}:2:2:+" _ccr_ask2="ST:State or province name:${CERTS_CERT_STATE}:0:0:+" _ccr_ask3="L:Locality name:${CERTS_CERT_LOCALITY}:0:0:+" _ccr_ask4="O:Organization or company name:${CERTS_CERT_ORGA_NAME}:0:0:+" _ccr_ask5="OU:Organizational unit or section name:${CERTS_CERT_ORGA_UNIT}:0:0:+" _ccr_ask6="CN:Common name, e.g. (${_ccr_domainname}):${_ccr_domaindefault}:0:0:+" _ccr_ask7="emailAddress:Email address:${CERTS_CERT_REQ_EMAIL}:0:60:*" _ccr_subj='' _ccr_idx=1 while [ ${_ccr_idx} -le ${_ccr_askcount} ] do _ccr_next=0 # build question eval _ccr_question="\$_ccr_ask${_ccr_idx}" _ccr_label=`echo "${_ccr_question}" | cut -d: -f1` _ccr_ask=`echo "${_ccr_question}" | cut -d: -f2` _ccr_def=`echo "${_ccr_question}" | cut -d: -f3` _ccr_min=`echo "${_ccr_question}" | cut -d: -f4` _ccr_max=`echo "${_ccr_question}" | cut -d: -f5` _ccr_mask=`echo "${_ccr_question}" | cut -d: -f6` # ask question _ccr_answer='' ${ask_bin} "${_ccr_ask}" "${_ccr_def}" "${_ccr_mask}" > ${ask_tmpfile} rc=$? # remove invalid characters from answer _ccr_answer=`cat ${ask_tmpfile} | sed -e 's#[;/\\(\)\[]*##g' -e 's#]##g' -e 's#^ *##' -e 's# *$##'` rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi # echo "INPUT:${_ccr_answer}:" if [ "${_ccr_answer}" = 'q' -o "${_ccr_answer}" = 'Q' ] then # quit break fi # check input length _ccr_again=0 _ccr_length=`expr length "${_ccr_answer}"` if [ ${_ccr_min} -gt 0 -a ${_ccr_length} -lt ${_ccr_min} ] then # input to short print_string_to_short ${ask_min} _ccr_again=1 elif [ ${_ccr_max} -gt 0 -a ${_ccr_length} -gt ${_ccr_max} ] then # input to long print_string_to_long ${ask_max} _ccr_again=1 fi if [ ${_ccr_again} -eq 0 ] then # build subject string # /C=US/ST=Oregon/L=New York/O=private/OU=my-eisfair/CN=us-dumbo.local.lan/emailAddress=root@local.lan case ${_ccr_label} in C ) # country _ccr_subj="/${_ccr_label}=`echo "${_ccr_answer}" | tr 'a-z' 'A-Z'`" _ccr_next=1 ;; CN ) # common name if [ -n "${_ccr_answer}" ] then _ccr_cncount=0 _ccr_domain='' _ccr_ipaddr='' _ccr_wildcard=0 # check if a wildcard certificate should be created _ccr_first_char="`echo "${_ccr_answer}" | sed 's/^DNS: *//' | cut -c1`" if [ "${_ccr_first_char}" = '*' ] then # wildcard certificate _ccr_wildcard=1 fi _ccr_cn_entry='' # check if a user certificate should be created echo "${_ccr_answer}" | grep -E -i -q "^USR:|^USER:" if [ $? -eq 0 ] then # create user certificate, (withspaces in CN allowed) _ccr_cn_entry="`echo "${_ccr_answer}" | sed -e 's/^USR: *//' -e 's/^USER: *//'`" else _ifs=${IFS} IFS=',' for ENTRY in ${_ccr_answer} do # get rid of all whitespaces ENTRY=`echo "${ENTRY}" | sed 's/ *//g'` case ${ENTRY} in '' ) # empty string ;; IP:* ) # IP address given if [ -z "${_ccr_ipaddr}" ] then _ccr_ipaddr="`echo "${ENTRY}" | sed 's/^IP: *//'`" else _ccr_ipaddr="${_ccr_ipaddr} `echo "${ENTRY}" | sed 's/^IP: *//'`" fi _ccr_cncount=`expr ${_ccr_cncount} + 1` ;; DNS:* ) # DNS name given if [ -z "${_ccr_domain}" ] then _ccr_domain="`echo "${ENTRY}" | sed 's/^DNS: *//'`" else _ccr_domain="${_ccr_domain} `echo "${ENTRY}" | sed 's/^DNS: *//'`" fi _ccr_cncount=`expr ${_ccr_cncount} + 1` ;; * ) # default, check if IPv4 address echo "${ENTRY}" | grep -q -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" if [ $? -eq 0 ] then # IPv4 address if [ -z "${_ccr_ipaddr}" ] then _ccr_ipaddr="${ENTRY}" else _ccr_ipaddr="${_ccr_ipaddr} ${ENTRY}" fi else # domain name if [ -z "${_ccr_domain}" ] then _ccr_domain="${ENTRY}" else _ccr_domain="${_ccr_domain} ${ENTRY}" fi fi _ccr_cncount=`expr ${_ccr_cncount} + 1` ;; esac done IFS=${_ifs} # use first domain or ip address for CN if [ -n "${_ccr_domain}" ] then _ccr_cn_entry=`echo "${_ccr_domain}" | cut -d' ' -f1` elif [ -n "${_ccr_ipaddr}" ] then _ccr_cn_entry=`echo "${_ccr_ipaddr}" | cut -d' ' -f1` fi fi if [ -n "${_ccr_cn_entry}" ] then _ccr_subj="${_ccr_subj}/${_ccr_label}=${_ccr_cn_entry}" _ccr_next=1 fi fi ;; ST|L|O|OU ) # state/location/organisation/organisation unit if [ -n "${_ccr_answer}" -a "${_ccr_answer}" != '.' ] then _ccr_subj="${_ccr_subj}/${_ccr_label}=${_ccr_answer}" fi _ccr_next=1 ;; emailAddress ) # email address if [ -n "${_ccr_answer}" -a "${_ccr_answer}" != '.' ] then echo "${_ccr_answer}" | grep -q '@' if [ $? -eq 0 ] then _ccr_subj="${_ccr_subj}/${_ccr_label}=${_ccr_answer}" _ccr_next=1 else print_no_valid_email_address fi else _ccr_next=1 fi ;; * ) # I currently don't know how to handle extra parameters # therefore these will be ignored for the moment # # Attributes: # challengePassword :test # unstructuredName :opt-comp ;; esac fi if [ ${_ccr_next} -eq 1 ] then # jump to next question _ccr_idx=`expr ${_ccr_idx} + 1` fi done if [ "${_ccr_answer}" != 'q' -a "${_ccr_answer}" != 'Q' ] then if [ ${_ccr_cncount} -ge 1 ] then # found additional DNS/IP to process _ccr_config_file=${ssldir}/openssl-tmp.cnf _ccr_options="-reqexts v3_req" # create custom openssl.cnf rm -f ${_ccr_config_file} cp ${ssldir}/openssl.cnf ${_ccr_config_file} if [ -n "${_ccr_domain}" ] then # append additional domain names to config file # echo "Domain name(s): ${_ccr_domain}" { _ccr_idx=1 for DNAME in ${_ccr_domain} do echo "DNS.${_ccr_idx} = ${DNAME}" _ccr_idx=`expr ${_ccr_idx} + 1` done } >> ${_ccr_config_file} fi if [ -n "${_ccr_ipaddr}" ] then # append additional ip addresses to config file # echo "IP address(es): ${_ccr_ipaddr}" { _ccr_idx=1 for IP in ${_ccr_ipaddr} do echo "IP.${_ccr_idx} = ${IP}" _ccr_idx=`expr ${_ccr_idx} + 1` done } >> ${_ccr_config_file} fi else # no additional DNS/IP to process found _ccr_config_file=${ssldir}/openssl.cnf _ccr_options='' fi if [ -n "${altkeyname}" ] then _ccr_key_file=${privdir}/${altkeyname}.key else _ccr_key_file=${privdir}/${keyname}.key fi # echo "SUBJ:${_ccr_subj}:" _ccr_yesno2='n' if [ "${runmode}" = 'interactive' ] then echo if ${ask_bin} "Do you want to continue" 'n' then _ccr_yesno2='y' fi else _ccr_yesno2='y' fi if [ "${_ccr_yesno2}" = 'y' ] then # create CSR file ${openssl_bin} req -new ${default_signature_algorithm} -key ${_ccr_key_file} \ -out ${reqdir}/${keyname}.csr -subj "${_ccr_subj}" -config ${_ccr_config_file} \ ${_ccr_options} if [ $? -eq 0 ] then if [ "${runmode}" = 'interactive' ] then echo "... done." fi else mecho --warn "... certificate request generation unsuccessful!" fi fi # delete temporary file rm -f ${ssldir}/openssl-tmp.cnf fi if [ "${runmode}" = 'interactive' ] then echo fi fi ;; * ) # do nothing ;; esac } #---------------------------------------------------------------------------------------- # sign a certificate request with your CA key #---------------------------------------------------------------------------------------- sign_cert_req () { # sign the certificate request with your CA key if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Sign certificate request with CA key" echo fi check_if_valid_cert_exists "${keyname}" _scr_yesno1='n' if [ -f "${newcertdir}/${keyname}.crt" ] then echo "The certificate ${newcertdir}/${keyname}.crt already exists." echo "Remove previously generated files (.crt, .pem, .p12)," if ${ask_bin} "proceed anyway" 'n' then _scr_yesno1='y' fi else _scr_yesno1='y' fi case ${_scr_yesno1} in [yY] ) # always ask if files should really be deleted if [ "${runmode}" = "interactive" ] then # check if files exist which should be deleted if check_files_to_delete 'cert' then # show files which should be deleted echo show_files_to_delete 'cert' fi fi if check_files_to_delete 'cert' then echo if ${ask_bin} "Do you really want to remove these files" 'n' then # delete files remove_files 'cert' echo else # abort csr creation _scr_yesno1='n' fi fi if [ "${_scr_yesno1}" = 'y' ] then # check if SAN are being requested _scr_options='' _scr_san=`${openssl_bin} req -in ${reqdir}/${keyname}.csr -noout -text | \ sed -n '/X509v3 Subject Alternative Name:/{n;p;}' | sed 's/^[[:space:]] *//'` echo "${_scr_san}" | grep -q -E "DNS:|IP Address:" if [ $? -eq 0 ] then # SAN requested _scr_options="-extensions v3_req" fi # check if email address has been given in subject _scr_subject_email=0 ${openssl_bin} req -in ${reqdir}/${keyname}.csr -noout -subject | grep -q "emailAddress=" if [ $? -eq 0 ] then _scr_subject_email=1 fi # check if email address has been given in issuer _scr_issuer_email=0 ${openssl_bin} x509 -in ${newcertdir}/ca.crt -noout -issuer | grep -q "emailAddress=" if [ $? -eq 0 ] then _scr_issuer_email=1 fi if [ "${runmode}" = "interactive" ] then # interactive mode # time of last modification, seconds since epoch index_num_date=`stat -c %Y ${ssldir}/index.txt` index_mod_date=`date -d @${index_num_date} +%d.%m.%Y` curr_num_date=`date +%s` if [ `expr ${index_num_date} + 86400` -lt ${curr_num_date} ] then # ask to update the database if it is older than 24h echo echo "The certificate database hasn't been updated" if ${ask_bin} "since ${index_mod_date}, update it now" 'y' then # update certificate index file echo echo "0. Passphrase of your CA key." echo anykey ${openssl_bin} ca -updatedb clrhome mecho --info "Sign certificate request with CA key" echo fi fi mecho --info "CSR details:" echo # print out CSR details ${openssl_bin} req -in ${reqdir}/${keyname}.csr -noout -text | \ grep -E "Public Key Algorithm:|Public-Key:" | sed 's/^[[:space:]]*/ /g' echo ${openssl_bin} req -in ${reqdir}/${keyname}.csr -noout -text | \ grep -E "Subject:" | sed 's/^[[:space:]]*/ /g' if [ -n "${_scr_options}" ] then echo " X509v3 Subject Alternative Name: ${_scr_san}" fi echo ${openssl_bin} req -in ${reqdir}/${keyname}.csr -noout -text | \ grep -E "Signature Algorithm:" | sed 's/^[[:space:]]*/ /g' fi if [ -n "${_scr_options}" -o ${_scr_subject_email} -eq 1 -o ${_scr_issuer_email} -eq 1 ] then # create custom openssl.cnf _scr_config_file=${ssldir}/openssl-tmp.cnf rm -f ${_scr_config_file} if [ ${_scr_subject_email} -eq 1 -a ${_scr_issuer_email} -eq 1 ] then # 20150301/JED - From Firefox 36.x onwards the rules to # verify certificates has been set tighter. Firefox # throws out an 'sec_error_bad_der' error if e.g. a # 'X509v3 Subject Alternative Name' parameter is set # although no email address has been entered. # To solve this problem the 'subjectAltName = email:copy', # and if necessary the 'issuerAltName = issuer:copy', # parameter will only be activated if an email address # has been found in the certificate request. sed -e '/[ SCA_ext ]/s/^#subjectAltName/subjectAltName/' \ -e 's/^#issuerAltName/issuerAltName/' ${ssldir}/openssl.cnf > ${_scr_config_file} elif [ ${_scr_subject_email} -eq 1 ] then sed '/[ SCA_ext ]/s/^#subjectAltName/subjectAltName/' ${ssldir}/openssl.cnf > ${_scr_config_file} elif [ ${_scr_issuer_email} -eq 1 ] then sed '/[ SCA_ext ]/s/^#issuerAltName/issuerAltName/' ${ssldir}/openssl.cnf > ${_scr_config_file} else cp ${ssldir}/openssl.cnf ${_scr_config_file} fi if [ -n "${_scr_options}" ] then # found additional DNS/IP to process _scr_domain='' _scr_ipaddr='' _scr_dnsidx=1 _scr_ipidx=1 _ifs=${IFS} IFS=',' for ENTRY in ${_scr_san} do # remove leading spaces ENTRY=`echo "${ENTRY}" | sed 's/^ *//g'` case ${ENTRY} in '' ) # empty string ;; DNS:* ) # DNS entry given if [ -z "${_scr_domain}" ] then _scr_domain="DNS.${_scr_dnsidx} = `echo "${ENTRY}" | sed 's/^DNS: *//'`\n" else _scr_domain="${_scr_domain}DNS.${_scr_dnsidx} = `echo "${ENTRY}" | sed 's/^DNS: *//'`\n" fi _scr_dnsidx=`expr ${_scr_dnsidx} + 1` ;; 'IP Address:'* ) # IP address given if [ -z "${_scr_ipaddr}" ] then _scr_ipaddr="IP.${_scr_ipidx} = `echo "${ENTRY}" | sed 's/^IP Address: *//'`\n" else _scr_ipaddr="${_scr_ipaddr}IP.${_scr_ipidx} = `echo "${ENTRY}" | sed 's/^IP Address: *//'`\n" fi _scr_ipidx=`expr ${_scr_ipidx} + 1` ;; esac done IFS=${_ifs} # add additional DNS names and IP addresses to temporary config file { printf "%b\n" "${_scr_domain}" printf "%b\n" "${_scr_ipaddr}" } >> ${_scr_config_file} fi else _scr_config_file=${ssldir}/openssl.cnf fi echo _scr_yesno2='n' if [ "${runmode}" = 'interactive' ] then if ${ask_bin} "Do you want to continue" 'n' then _scr_yesno2='y' fi else _scr_yesno2='y' fi if [ "${_scr_yesno2}" = 'y' ] then echo echo "You will be asked to enter the following data, after pressing ENTER:" if [ "${runmode}" != "interactive" -a \( "${keytype}" = "mail" -o "${keytype}" = "web" \) ] then echo else echo echo " 1 - Select key usage." echo " 2 - Select start date/validity." fi echo " 3 - Passphrase of your CA key." echo anykey set_usage_type set_validity_period # -name arg - The particular CA definition to use # -in file - The input PEM encoded certificate request(s) # -out file - Where to put the output file(s) # -config file - A config file # -startdate YYMMDDHHMMSSZ - certificate validity notBefore # -enddate YYMMDDHHMMSSZ - certificate validity notAfter (overrides -days) eval ${openssl_bin} ca -name ${usagesec} -md ${CERTS_HASH_ALGORITHM} -in ${reqdir}/${keyname}.csr \ -out ${newcertdir}/${keyname}.crt -config ${_scr_config_file} -startdate ${startdate} \ -enddate ${enddate} ${_scr_options} if [ -s ${newcertdir}/${keyname}.crt ] then ${openssl_bin} verify -CAfile ${newcertdir}/ca.crt ${newcertdir}/${keyname}.crt _scr_ret=$? else _scr_ret=111 fi case ${_scr_ret} in 0 ) # 0 - the operation was successful. if [ "${runmode}" = 'interactive' ] then echo "... done." fi ;; 9 ) # 9 - the certificate is not yet valid: the notBefore date is after the # current time. if is_date_in_future "${startdate}" then echo echo "If you've generated a new certificate with a start-date in the future" echo "then remember to copy the new certificate to the certificate store" echo "(menu point 14) not before the old certificate has become invalid!" fi ;; 111 ) mecho --warn "... certificate generation unsuccessful!" mecho --warn " A valid certificate file wasn't found." ;; * ) # an error appeared - check the following website for a description of the # different error codes: https://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS mecho --warn "... certificate generation unsuccessful! The error codes are explained here:" mecho --warn " https://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS" ;; esac echo # delete temporary file rm -f ${ssldir}/openssl-tmp.cnf fi # if [ "${_scr_yesno2}" = 'y' ] fi # if [ "${_scr_yesno1}" = 'y' ] ;; * ) # do nothing ;; esac } #---------------------------------------------------------------------------------------- # create a Diffie Hellman parameters file #---------------------------------------------------------------------------------------- create_dh_params () { # create Diffie-Hellman parameters if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create Diffie-Hellman parameters" fi _cdp_yesno='n' if [ -f "${newcertdir}/${keyname}.dh" ] then echo echo "The DH parameters file ${newcertdir}/${keyname}.dh" if ${ask_bin} "does already exist, proceed anyway" 'n' then _cdp_yesno='y' fi else _cdp_yesno='y' fi case ${_cdp_yesno} in [yY] ) if [ "${runmode}" = 'interactive' ] then echo echo "No data has to be entered." echo anykey fi ${openssl_bin} dhparam -out ${newcertdir}/${keyname}.dh ${default_dh_bits} echo ;; * ) # do nothing ;; esac } #---------------------------------------------------------------------------------------- # print header of package dependent symbolic link list # input: $1 - crt|key #---------------------------------------------------------------------------------------- show_symlinks_header () { clrhome mecho --info "Show/set package dependent symbolic links" echo if [ "$1" = "key" ] then # key echo -n "Key name: " if [ -z "${altkeyname}" ] then mecho --info "${keyname}" else mecho --info "${altkeyname}" fi else # certificate echo -n "Certificate name: "; mecho --info "${keyname}" fi echo techo --begin 4r 35 4 35 techo --row -info "Nbr " --info "Certificate Name(s)" --info "(->" --info "Symbolic Link to..)" } #---------------------------------------------------------------------------------------- # check package dependent symbolic links #---------------------------------------------------------------------------------------- check_symlinks () { _cpdsl_exit=0 _cpdsl_type='crt' if [ "${runmode}" = 'interactive' ] then # interactive mode while [ ${_cpdsl_exit} -eq 0 ] do show_symlinks_header "${_cpdsl_type}" if [ "${_cpdsl_type}" = "key" ] then # key if [ -z "${altkeyname}" ] then _cpdsl_keyname="${keyname}" else _cpdsl_keyname="${altkeyname}" fi _cpdsl_path="${privdir}" _cpdsl_ext='key' _cpdsl_symlinks="${default_key_symlinks}" else # certificate _cpdsl_keyname="${keyname}" _cpdsl_path="${certdir}" _cpdsl_ext='pem' _cpdsl_symlinks="${default_cert_symlinks}" fi _cpdsl_packages='' _cpdsl_idx=1 for PNAME in ${_cpdsl_symlinks} do if [ "`/usr/bin/eisman check ${PNAME}`" = 'installed' ] then techo --row "${_cpdsl_idx}" "checking '${PNAME}' requirements ..." # package installed, check certificates case ${PNAME} in apache2 ) _cpdsl_files='apache' ;; ldapserver ) _cpdsl_files='slapd' ;; mail ) _cpdsl_files='exim imapd ipop3d' ;; partimg ) _cpdsl_files='partimaged' ;; * ) _cpdsl_files="${PNAME}" ;; esac for FNAME in ${_cpdsl_files} do if [ -L "${_cpdsl_path}/${FNAME}.${_cpdsl_ext}" ] then _cpdsl_org_file="`readlink -e "${_cpdsl_path}/${FNAME}.${_cpdsl_ext}"`" techo --row "" "- ${FNAME}.${_cpdsl_ext}" --warn " ->" --warn "`basename "${_cpdsl_org_file}"`" elif [ -f ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} ] then techo --row "" "- ${FNAME}.${_cpdsl_ext}" "" "" else if [ "${_cpdsl_type}" = "key" ] then # It is not necessary to have key files with default names in the directory. # Therefore no 'warning' color is used when displaying this files. techo --row "" "- ${FNAME}.${_cpdsl_ext}" " ->" "file doesn't exist!" else techo --row "" "- ${FNAME}.${_cpdsl_ext}" --warn " ->" --warn "file doesn't exist!" fi fi done echo _cpdsl_packages="${_cpdsl_packages}${PNAME} " _cpdsl_idx=`expr ${_cpdsl_idx} + 1` fi done _cpdsl_max=`expr ${_cpdsl_idx} - 1` techo --end # # ${ask_bin} "Do you want to change a symbolic link (y/n) or (t)oggle key/certificate" 'n' '+' > ${ask_tmpfile} ${ask_bin} "Do you want to change a symbolic link (y/n)" 'n' '+' > ${ask_tmpfile} rc=$? read _cpdsl_yesno < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_cpdsl_yesno} in [nNqQ] ) # quit _cpdsl_exit=1 ;; # [tT] ) # toggle between key and certificate # if [ "${_cpdsl_type}" = "crt" ] # then # _cpdsl_type='key' # else # _cpdsl_type='crt' # fi # ;; [yY] ) ${ask_bin} "Which symbolic links do you want to change (a)ll" '' "1-${_cpdsl_max}" 'a' 'q' > ${ask_tmpfile} rc=$? read _cpdsl_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_cpdsl_num} in [qQ] ) # quit _cpdsl_exit=1 ;; [aA] ) echo echo "The following symbolic links will be (re)created:" _cpdsl_all_files='' for sel_package in ${_cpdsl_packages} do if [ -f ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ] then if [ ! -L ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ] then # certificate file exists case ${sel_package} in apache2 ) _cpdsl_files='apache' ;; ldapserver ) _cpdsl_files='slapd' ;; mail ) _cpdsl_files='exim imapd ipop3d' ;; partimg ) _cpdsl_files='partimaged' ;; * ) _cpdsl_files="${sel_package}" ;; esac for FNAME in ${_cpdsl_files} do echo "${FNAME}.${_cpdsl_ext} -> ${_cpdsl_keyname}.${_cpdsl_ext}" done _cpdsl_all_files="${_cpdsl_all_files}${_cpdsl_files} " fi fi done echo if ${ask_bin} "Do you want to continue" 'n' then # (re)creation of symbolic links confirmed, go on... for FNAME in ${_cpdsl_all_files} do if [ ! -f ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} -o -L ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} ] then echo "creating symbolic link '${FNAME}.${_cpdsl_ext}' -> '${_cpdsl_keyname}.${_cpdsl_ext}' ..." ln -sf ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} if [ $? -eq 0 ] then echo "done." else mecho --error "unable to create symbolic link!" fi else # file exists as non-symlink echo mecho --error "Error: symbolic link target already exists as a valid file!" echo fi done fi # if ${ask_bin} "Do you want to continue" 'n' ;; * ) if is_numeric ${_cpdsl_num} then # numeric if [ ${_cpdsl_num} -ge 1 -a ${_cpdsl_num} -le ${_cpdsl_max} ] then echo sel_package=`echo "${_cpdsl_packages}" | cut -d' ' -f${_cpdsl_num}` if [ -f ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ] then if [ ! -L ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ] then # certificate file exists case ${sel_package} in apache2 ) _cpdsl_files='apache' ;; ldapserver ) _cpdsl_files='slapd' ;; mail ) _cpdsl_files='exim imapd ipop3d' ;; partimg ) _cpdsl_files='partimaged' ;; * ) _cpdsl_files="${sel_package}" ;; esac echo "The following symbolic links will be (re)created:" for FNAME in ${_cpdsl_files} do echo "${FNAME}.${_cpdsl_ext} -> ${_cpdsl_keyname}.${_cpdsl_ext}" done echo if ${ask_bin} "Do you want to continue" 'n' then # (re)creation of symbolic links confirmed, go on... for FNAME in ${_cpdsl_files} do if [ ! -f ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} -o -L ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} ] then echo "creating symbolic link '${FNAME}.${_cpdsl_ext}' -> '${_cpdsl_keyname}.${_cpdsl_ext}' ..." ln -sf ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} if [ $? -eq 0 ] then echo "done." else mecho --error "unable to create symbolic link!" fi else # file exists as non-symlink echo mecho --error "Error: symbolic link target already exists as a valid file!" echo fi anykey done fi # if ${ask_bin} "Do you want to continue" 'n' else # symbolic links not allowed echo mecho --error "Error: symbolic links not allowed, please try again!" echo anykey fi # if [ ! -L ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ] else # certificate file doesn't exist print_no_cert_name anykey fi # if [ -f ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ] fi # if [ ${_cpdsl_num} -ge 1 -a ${_cpdsl_num} -le ${_cpdsl_max} fi # if is_numeric ${_cpdsl_num} ;; esac # case ${_cpdsl_num} in ;; esac # case ${_cpdsl_yesno} in done else # automatic mode case ${_cpdsl_type} in key ) # key if [ -z "${altkeyname}" ] then _cpdsl_keyname="${keyname}" else _cpdsl_keyname="${altkeyname}" fi _cpdsl_path="${privdir}" _cpdsl_ext='key' _cpdsl_symlinks="${default_key_symlinks}" ;; * ) # certificate _cpdsl_keyname="${keyname}" _cpdsl_path="${certdir}" _cpdsl_ext='pem' _cpdsl_symlinks="${default_cert_symlinks}" ;; esac # check if a valid package name has been given echo "${default_cert_symlinks}" | grep -q "${packname}" if [ $? -eq 0 ] then # supported package found case ${packname} in apache|apache2 ) _cpdsl_files='apache' ;; ldapserver ) _cpdsl_files='slapd' ;; mail ) _cpdsl_files='exim imapd ipop3d' ;; partimg ) _cpdsl_files='partimaged' ;; * ) _cpdsl_files="${sel_package}" ;; esac # (re)creation of symbolic links confirmed, go on... for FNAME in ${_cpdsl_files} do if [ ! -f ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} -o -L ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} ] then echo "creating symbolic link '${FNAME}.${_cpdsl_ext}' -> '${_cpdsl_keyname}.${_cpdsl_ext}' ..." ln -sf ${_cpdsl_path}/${_cpdsl_keyname}.${_cpdsl_ext} ${_cpdsl_path}/${FNAME}.${_cpdsl_ext} if [ $? -ne 0 ] then mecho --error "unable to create symbolic link!" fi else # file exists as non-symlink mecho --error "Error: symbolic link target already exists as a valid file!" fi done else mecho --warn "Warning: unsupported package name '${packname}' given!" fi fi } #---------------------------------------------------------------------------------------- # copy certificate to ../certs directory # input: $1 - 'ca' oder 'cert' #---------------------------------------------------------------------------------------- copy_cert () { # copy the certificate to $certdir _cc_type="$1" if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create .pem certificate and copy it to ${certdir}" fi _cc_yesno='n' if [ -f "${certdir}/${keyname}.pem" ] then echo echo "The certificate ${certdir}/${keyname}.pem" if ${ask_bin} "does already exist, proceed anyway" 'n' then _cc_yesno='y' fi else _cc_yesno='y' fi case ${_cc_yesno} in [yY] ) # backup previous file certificate if [ -f "${certdir}/${keyname}.pem" ] then cp "${certdir}/${keyname}.pem" "${oldcertdir}/${keyname}-`date +%Y.%m.%d`.pem" fi if [ "${runmode}" = "interactive" ] then echo echo "No data have to be entered." echo anykey fi # creating .pem file { if [ "${_cc_type}" != 'ca' ] then # add key to certificate file if it isn't a ca key if [ -f "${privdir}/${keyname}.key" -a -z "${altkeyname}" ] then cat "${privdir}/${keyname}.key" elif [ -f "${privdir}/${altkeyname}.key" ] then cat "${privdir}/${altkeyname}.key" fi echo fi if [ -f "${newcertdir}/${keyname}.dh" ] then cat "${newcertdir}/${keyname}.dh" echo fi sed -n '/-BEGIN/,/-END/p' "${newcertdir}/${keyname}.crt" } > "${certdir}/${keyname}.pem" # recreate hash links echo "updating hashes ..." /var/install/bin/certs-update-hashes --quiet --certdir if [ "${runmode}" = "interactive" ] then echo "... done." echo fi ;; * ) # do nothing ;; esac } #---------------------------------------------------------------------------------------- # create a PKCS#12 document which can better be imported into browsers #---------------------------------------------------------------------------------------- create_pksc_doc () { # create PKCS#12 document if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Create PKCS#12 document" fi _cpd_yesno='n' if [ "${keytype}" = "client/server" ] then # client mode if [ -f "${newcertdir}/${keyname}.p12" ] then echo echo "The PKCS#12 document ${newcertdir}/${keyname}.p12" if ${ask_bin} "does already exist, proceed anyway" 'n' then _cpd_yesno='y' fi else _cpd_yesno='y' fi case ${_cpd_yesno} in [yY] ) echo echo "You have to enter the following data:" echo echo " 1. Export password." echo anykey echo if [ -f "${privdir}/${keyname}.key" -a -z "${altkeyname}" ] then ${openssl_bin} pkcs12 -export -clcerts -in "${newcertdir}/${keyname}.crt" \ -inkey "${privdir}/${keyname}.key" -out "${newcertdir}/${keyname}.p12" else ${openssl_bin} pkcs12 -export -clcerts -in "${newcertdir}/${keyname}.crt" \ -inkey "${privdir}/${altkeyname}.key" -out "${newcertdir}/${keyname}.p12" fi ;; * ) # do nothing ;; esac fi } #---------------------------------------------------------------------------------------- # show certificate and file details #---------------------------------------------------------------------------------------- show_cert_menu () { _scm_exit=0 while [ ${_scm_exit} -eq 0 ] do # show menu _scm_max=1 clrhome mecho --info "show certificate file details" echo echo " 1 - show key and certificate file location" if is_valid_openssl_file 'csr' "${reqdir}/${keyname}.csr" then echo " 2 - show certificate request content (${keyname}.csr)" _scm_max=`expr ${_scm_max} + 1` fi if is_valid_openssl_file 'crt' "${certdir}/${keyname}.pem" then echo " 3 - show certificate content (${keyname}.pem)" _scm_cert_file="${certdir}/${keyname}.pem" _scm_max=`expr ${_scm_max} + 1` elif is_valid_openssl_file 'crt' "${newcertdir}/${keyname}.crt" then echo " 3 - show certificate content (${keyname}.crt)" _scm_cert_file="${newcertdir}/${keyname}.crt" _scm_max=`expr ${_scm_max} + 1` fi echo ${ask_bin} "Please choose key type" 'q' "1-${_scm_max}" 'q' > ${ask_tmpfile} rc=$? read _scm_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_scm_num} in [qQ] ) # quit _scm_exit=1 ;; [0-9] ) # numeric value if [ ${_scm_num} -le ${_scm_max} ] then case ${_scm_num} in 1 ) show_cert_location ;; 2 ) clrhome mecho --info "certificate signing request content (${keyname}.csr)" echo { echo "If you are asked to copy the certificate signing request data," echo "you usually need to copy the whole block, including the" echo "'-----BEGIN CERTIFICATE REQUEST-----' and" echo "'-----END CERTIFICATE REQUEST-----' lines." echo ${openssl_bin} req -in ${reqdir}/${keyname}.csr -text } > ${ask_tmpfile} # show GUI # /var/install/bin/show-doc.cui ${color} ${frame} --title "certificate signing request content '${reqdir}/${keyname}.csr'" ${ask_tmpfile} # no GUI more ${ask_tmpfile} rm -f ${ask_tmpfile} ;; 3 ) clrhome mecho --info "certificate content (${keyname}.pem/crt)" echo { echo "If you are asked to copy the certificate data, you usually need to copy" echo "the whole block, including" the "'-----BEGIN CERTIFICATE REQUEST-----'" echo "and '-----END CERTIFICATE REQUEST-----' lines." echo ${openssl_bin} x509 -in ${_scm_cert_file} -text } > ${ask_tmpfile} # show GUI # /var/install/bin/show-doc.cui ${color} ${frame} --title "certificate content '${_scm_cert_file}'" ${ask_tmpfile} more ${ask_tmpfile} rm -f ${ask_tmpfile} ;; esac anykey else print_not_in_range fi ;; * ) print_not_in_range ;; esac done } #---------------------------------------------------------------------------------------- # show certificates and all relevante files # input: $1 - overwrite key name #---------------------------------------------------------------------------------------- show_cert_location () { # show key an certificate location if [ -n "$1" ] then _scl_keyname="$1" _scl_altkeyname='' else _scl_keyname="${keyname}" _scl_altkeyname="${altkeyname}" fi if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Show key and certificate location" fi echo if [ -f "${privdir}/${_scl_keyname}.key" -o -f "${privdir}/${_scl_altkeyname}.key" ] then if [ -f "${privdir}/${_scl_keyname}.key" -a -z "${_scl_altkeyname}" ] then if [ -f "${privdir}/${_scl_keyname}.key" ] then _scl_keyfilename=${privdir}/${_scl_keyname}.key else _scl_keyfilename='' fi elif [ -f "${privdir}/${_scl_altkeyname}.key" ] then if [ -f "${privdir}/${_scl_altkeyname}.key" ] then _scl_keyfilename=${privdir}/${_scl_altkeyname}.key else _scl_keyfilename='' fi fi else # keyfile(s) doesn't exist _scl_keyfilename='' fi ls -1 -p ${_scl_keyfilename} ${certdir}/${_scl_keyname}.pem ${newcertdir}/${_scl_keyname}.p12 2>/dev/null echo } #---------------------------------------------------------------------------------------- # show files to revoke #---------------------------------------------------------------------------------------- show_files_to_revoke () { # print menue clrhome mecho --info "Certificate selection" echo echo "Certificates" echo rev_name_n=0 ls -F ${certdir}/*.pem | grep -v '@' >/dev/null 2>/dev/null if [ $? -eq 0 ] then # files found _sftk_cname_list=`find ${certdir} -maxdepth 1 -type f -name "*.pem" -printf '%f\n' | sort | tr '\n' ':'` _ifs="${IFS}" IFS=':' for CNAME in ${_sftk_cname_list} do CNAME=`basename "${CNAME}" '.pem'` rev_name_n=`expr ${rev_name_n} + 1` _sftk_tmpname=`echo "${CNAME}" | sed -e 's#(#\\\(#g' -e 's#)#\\\)#g' -e 's# #\\\ #g'` eval rev_name_${rev_name_n}="${_sftk_tmpname}" if [ ${rev_name_n} -gt 9 ] then # > 9 echo " ${rev_name_n} - ${CNAME}" else # <= 9 echo " ${rev_name_n} - ${CNAME}" fi done IFS=${_ifs} else print_no_cert_found fi echo } #---------------------------------------------------------------------------------------- # select revocation reason #---------------------------------------------------------------------------------------- select_revocation_reason () { # -crl_reason reason # # The matching of reason is case insensitive. Where reason is one of: # # 1. keyCompromise - The key has been compromised. (Das Zertifikat wurde # kompromittiert, hat seine Vertraulichkeit verloren) # # 2. CACompromise - The CA has been compromised. (Das Ausstellerzertifikat # wurde kompromittiert - hat seine Vertraulichkeit verloren) # # 3. unspecified - No reason has been given why the certificate has been revoked. # (This parameter will make the CRL v2) Ein genauer Sperrgrund # wurde nicht angegeben. Der Parameter erzeugt eine CRL v2.) # # 4. affiliationChanged - The name or other information of the certificate owner # has been changed. The certificate has NOT been compromised! # (Der Name oder eine andere Information des Zertifikatsinhabers # hat sich geaendert. Das Zertifikat wurde NICHT kompromittiert!) # # 5. superseded - The certificate has been replaced. The certificate has NOT # been compromised! (Das Zertifikat wurde ersetzt. Das # Zertifikat wurde NICHT kompromittiert!) # # 6. cessationOfOperation - The certificate is no longer required. The certificate has # NOT been compromised! (Das Zertifikat wird nicht laenger # benoetigt. Das Zertifikat wurde NICHT kompromittiert.) # #(7. certificateHold - The certificate has temporarily been withdrawn. (Das Zertifikat # wurde temporaer zurueckgezogen.) # # 8. removeFromCRL - The certificate has been unlocked. This parameter is not # particularly useful because it is only used in delta CRLs # which are not currently implemented. (Das Zertifikat wurde # entsperrt und kann wieder benutzt werden. Dieser Parameter # ist nicht wirklich nuetzlich, da er nur in Delta-CRLs # verwendet wird, welche aktuell nicht unterstuetzt werden. #) crlreason='' _srr_exit=0 while [ ${_srr_exit} -eq 0 ] do # show selection echo echo " 1 - key has been compromised." echo " 2 - CA has been compromised." echo " 3 - no reason given." echo " 4 - information of the certificate owner has been changed." echo " 5 - certificate has been replaced." echo " 6 - certificate no longer required." # echo " 7 - certificate has temporarily withdrawn." # echo " 8 - certificate has been unlocked." echo ${ask_bin} "Please select" '' '1-6' > ${ask_tmpfile} rc=$? read _srr_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi case ${_srr_num} in 1 ) crlreason="keyCompromise" _srr_exit=1 ;; 2 ) crlreason="CACompromise" _srr_exit=1 ;; 3 ) crlreason="unspecified" _srr_exit=1 ;; 4 ) crlreason="affiliationChanged" _srr_exit=1 ;; 5 ) crlreason="superseded" _srr_exit=1 ;; 6 ) crlreason="cessationOfOperation" _srr_exit=1 ;; * ) print_not_in_range ;; esac done } #---------------------------------------------------------------------------------------- # select revocation due days or hours #---------------------------------------------------------------------------------------- set_revocation_validity () { # -crldays days / -crlhours hours # # -crldays days - Days is when the next CRL is due # -crlhours hours - Hours is when the next CRL is due # change/set CRL validity _srv_exit1=0 while [ ${_srv_exit1} -eq 0 ] do if [ "${runmode}" = "interactive" ] then echo echo " 1 - use default CRL validity: ${default_crl_days} days" echo " 2 - set individual CRL validity" echo ${ask_bin} "Please choose desired option" '1' '1-2' > ${ask_tmpfile} rc=$? read _srv_num < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi else _srv_num='1' fi case ${_srv_num} in 2 ) _srv_exit2=0 while [ ${_srv_exit2} -eq 0 ] do echo ${ask_bin} "Please enter number of validity days or hours (e.g. 8h)" "${default_crl_days}" '+' > ${ask_tmpfile} rc=$? read _srv_period < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi if [ -z "${_srv_period}" ] then _srv_period=${default_crl_days} fi _srv_new_days=`echo ${_srv_period} | sed 's/[+a-zA-Z-]*//g'` _srv_multidays=`echo ${_srv_period} | sed 's/[0-9]*//g'` if is_numeric ${_srv_new_days} then case ${_srv_multidays} in [wW] ) # week _srv_acc_days=`expr ${_srv_new_days} \* 7` _srv_acc_hours='' _srv_exit2=1 ;; [mM] ) # month _srv_acc_days=`expr ${_srv_new_days} \* 30` _srv_acc_hours='' _srv_exit2=1 ;; [yY] ) # year _srv_acc_days=`expr ${_srv_new_days} \* 365` _srv_acc_hours='' _srv_exit2=1 ;; [hH] ) # hours _srv_acc_days='' _srv_acc_hours=${_srv_new_days} _srv_exit2=1 ;; '' ) _srv_acc_days=${_srv_new_days} _srv_acc_hours='' _srv_exit2=1 ;; * ) _srv_period='' mecho --error "invalid day multiplier '${_srv_multidays}'!" anykey ;; esac else _srv_period='' mecho --error "invalid day format '${_srv_new_days}'!" anykey fi done crldays=${_srv_acc_days} crlhours=${_srv_acc_hours} _srv_exit1=1 ;; * ) # set default crldays=${default_crl_days} crlhours='' _srv_exit1=1 ;; esac done } #---------------------------------------------------------------------------------------- # revoke a certificate #---------------------------------------------------------------------------------------- revoke_cert () { # certificate number to be revoked (file name incl. .pem extension!) eval _rc_cname='$rev_name_'${1} _rc_yesno='n' if [ "${runmode}" = "interactive" ] then # interactive mode clrhome mecho --info "Revoke certificate" echo # show key an certificate location mecho --info "Certificate details:" echo echo " File name: ${certdir}/${_rc_cname}.pem" echo # check if SAN are being requested _rc_options='' _rc_san=`${openssl_bin} x509 -in "${certdir}/${_rc_cname}.pem" -noout -text | \ sed -n '/X509v3 Subject Alternative Name:/{n;p;}' | sed 's/^[[:space:]] *//'` echo "${_rc_san}" | grep -q -E "DNS:|IP Address:" if [ $? -eq 0 ] then # SAN requested _rc_options="-extensions v3_req" fi ${openssl_bin} x509 -in "${certdir}/${_rc_cname}.pem" -noout -text | \ grep -E "Public Key Algorithm:|Public-Key:" | sed 's/^[[:space:]]*/ /g' echo ${openssl_bin} x509 -in "${certdir}/${_rc_cname}.pem" -noout -text | \ grep -E "Subject:" | sed 's/^[[:space:]]*/ /g' if [ -n "${_rc_options}" ] then echo " X509v3 Subject Alternative Name: ${_rc_san}" fi echo ${openssl_bin} x509 -in "${certdir}/${_rc_cname}.pem" -noout -text | \ grep -E "Signature Algorithm:" | head -n1 | sed 's/^[[:space:]]*/ /g' echo # output serial number as decimal and hexadecimal value # Serial=98 (0x62) _rc_serial_hex=`${openssl_bin} x509 -in "${certdir}/${_rc_cname}.pem" -noout -serial | sed 's/serial=//'` _rc_serial_dec=`echo "ibase=16; ${_rc_serial_hex}" | bc` printf " Serial = ${_rc_serial_dec} (0x${_rc_serial_hex})\n" # notBefore=Nov 3 14:54:52 2017 GMT # notAfter =Nov 3 14:54:52 2018 GMT ${openssl_bin} x509 -in "${certdir}/${_rc_cname}.pem" -noout -startdate -enddate | \ sed -e 's/notAfter=/notAfter =/' -e 's/=\([^ ]\)/= \1/g' -e 's/^[[:space:]]*/ /g' echo if ${ask_bin} "Do you want to continue" 'n' then _rc_yesno='y' fi else _rc_yesno='y' fi if [ "${_rc_yesno}" = 'y' ] then echo echo "You have to enter the following data:" echo echo " 1. Select revocation reason." echo " 2. Passphrase of your CA key." echo anykey select_revocation_reason if [ -n "${crlreason}" ] then ${openssl_bin} ca -revoke "${certdir}/${_rc_cname}.pem" -crl_reason ${crlreason} \ -config "${ssldir}/openssl.cnf" if [ $? -eq 0 ] then # update certificate index file ${openssl_bin} ca -updatedb # remove PEM certificate mv "${certdir}/${_rc_cname}.pem" "${revdir}/${_rc_cname}-`date +%Y.%m.%d.%H.%M`.pem" # remove PKCS#12 certificate if [ -f "${newcertdir}/${_rc_cname}.p12" ] then mv "${newcertdir}/${_rc_cname}.p12" "${revdir}/${_rc_cname}-`date +%Y.%m.%d.%H.%M`.p12" fi # recreate hash links echo "updating hashes ..." /var/install/bin/certs-update-hashes --quiet --certdir fi fi if ${ask_bin} "Update revocation list now" 'n' then create_or_update_crl fi fi } #---------------------------------------------------------------------------------------- # create or update a certificate revocation list #---------------------------------------------------------------------------------------- create_or_update_crl () { if [ "${runmode}" = "interactive" ] then echo echo "You have to enter the following data:" echo echo " 1. Select CRL due days." echo " 2. Passphrase of your CA key." echo anykey elif [ -z "${caoption}" ] then echo echo "You have to enter the following data:" echo echo " 1. Passphrase of your CA key." fi set_revocation_validity if [ -z "${crlhours}" ] then # CRL is only valid for the given number of days ${openssl_bin} ca ${caoption} -gencrl -crldays ${crldays} \ -out "${crldir}/${crl_file_name}" -config "${ssldir}/openssl.cnf" else # CRL is only valid for the given number of hours ${openssl_bin} ca ${caoption} -gencrl -crlhours ${crlhours} \ -out "${crldir}/${crl_file_name}" -config "${ssldir}/openssl.cnf" fi # convert to DER format because otherwise most browser cannot handle it ${openssl_bin} crl -in "${crldir}/${crl_file_name}" -outform der -out "${crldir}/`echo "${crl_file_name}" | sed 's/\.pem$/\.der/'`" if [ "${crl_file_name}" != 'crl.pem' ] then # remove legacy crl files rm -f ${crldir}/crl.pem ${crldir}/crl.der fi # make sure that the symbolic web link is up-to-date /var/install/bin/certs-update-crl-uri --quiet --batch # recreate hash links echo "updating hashes ..." /var/install/bin/certs-update-hashes --quiet --crldir if [ "${runmode}" = "interactive" ] then echo fi } #---------------------------------------------------------------------------------------- # print 'No email address' error message #---------------------------------------------------------------------------------------- print_no_valid_email_address () { # no email address mecho --error "No email address given, try again!" } #---------------------------------------------------------------------------------------- # print 'string to short' error message # input: $1 - minimum length #---------------------------------------------------------------------------------------- print_string_to_short () { # string to short if [ -z "$1" ] then mecho --error "Error: input to short, try again!" else mecho --error "Error: input to short, need to be at least $1 characters long!" fi } #---------------------------------------------------------------------------------------- # print 'string to long' error message # input: $1 - maximum length #---------------------------------------------------------------------------------------- print_string_to_long () { # string to long if [ -z "$1" ] then mecho --error "Error: input to long, try again!" else mecho --error "Error: input to long, no more than $1 characters are allowed!" fi } #---------------------------------------------------------------------------------------- # print 'not in range' error message #---------------------------------------------------------------------------------------- print_not_in_range () { # not in range echo mecho --error "Error: input not in range, try again!" echo } #---------------------------------------------------------------------------------------- # print 'missing certificate name' error message #---------------------------------------------------------------------------------------- print_no_cert_name () { # no certificate name set echo mecho --error "Error: please enter a valid certificate name and try again!" echo } #---------------------------------------------------------------------------------------- # print 'missing key name' error message #---------------------------------------------------------------------------------------- print_no_key_name () { # no key name set echo mecho --error "Error: please enter a valid key name and try again!" echo } #---------------------------------------------------------------------------------------- # print 'missing certificate file' error message # input: $1 - cert file name #---------------------------------------------------------------------------------------- print_no_cert_found () { # no cert found echo if [ -z "$1" ] then mecho --error "Error: No certificate file found!" else mecho --error "Error: Certificate file '$1' not found!" fi echo } #---------------------------------------------------------------------------------------- # print 'missing key file' error message # input: $1 - key file name #---------------------------------------------------------------------------------------- print_no_key_found () { # no cert found echo if [ -z "$1" ] then mecho --error "Error: No key file found!" else mecho --error "Error: Key file '$1' not found!" fi echo } #---------------------------------------------------------------------------------------- # check input and run command # Input : $1 - entered selection #---------------------------------------------------------------------------------------- check_input_and_run_command () { if is_valid_menu_selection $1 ${sel_values} then # allow selection, go on ... case "$1" in 1 ) # change/set key type if [ ${override} -eq 0 ] then set_cert_type else print_not_in_range anykey fi ;; 2 ) # change/set certificate name if [ "${keytype}" = "client/server" -o "${keytype}" = "mail" ] then set_cert_name else print_not_in_range anykey fi ;; 3 ) # create CA key if [ "${keytype}" = "ca" ] then create_ca_key else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 4 ) # create a self-signed CA certificate if [ "${keytype}" = "ca" ] then create_ca_cert else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 5 ) # copy the certificate to $certdir if [ "${keytype}" = "ca" ] then if [ -n "${keyname}" ] then copy_cert 'ca' else print_no_key_name fi else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 6 ) # show CA key and certificate location show_cert_location 'ca' anykey ;; 7 ) # revoke client certificate if [ "${keytype}" = "ca" ] then show_files_to_revoke ${ask_bin} "Which certificate should be revoked" '' "1-${rev_name_n}" 'q' > ${ask_tmpfile} rc=$? read revnum < ${ask_tmpfile} rm -f ${ask_tmpfile} if [ ${rc} = 255 ] then exit 1 fi # revoke cerificate if is_numeric ${revnum} then if [ ${revnum} -ge 1 -a ${revnum} -le ${rev_name_n} ] then revoke_cert ${revnum} fi fi else print_not_in_range fi anykey ;; 8 ) # update revocation list if [ "${keytype}" = "ca" ] then if [ "${runmode}" = "interactive" ] then if ${ask_bin} "Update revocation list now" 'n' then create_or_update_crl fi else # batch mode create_or_update_crl fi fi ;; 10 ) # create new key if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then set_key_name else print_no_key_name fi else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 11 ) # create a certificate request if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then if is_valid_openssl_file 'key' "${privdir}/${keyname}.key" then create_cert_req else print_no_key_found "${privdir}/${keyname}.key" fi elif [ -n "${altkeyname}" ] then if is_valid_openssl_file 'key' "${privdir}/${altkeyname}.key" then create_cert_req else print_no_key_found "${privdir}/${altkeyname}.key" fi else print_no_key_name fi else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 12 ) # sign the certificate request with your CA key if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then sign_cert_req else print_no_key_name fi else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 13 ) # create Diffie-Hellman parameters if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then create_dh_params else print_no_key_name fi else print_not_in_range fi anykey ;; 14 ) # copy the certificate to $certdir if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then copy_cert 'cert' else print_no_key_name fi else print_not_in_range fi if [ "${runmode}" = "interactive" ] then anykey fi ;; 15 ) # create PKCS#12 document if [ "${keytype}" = "client/server" ] then if [ -n "${keyname}" ] then create_pksc_doc else print_no_key_name fi else print_not_in_range fi anykey ;; 16 ) # check package dependent symbolic certificate links if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then check_symlinks export mstat16="--info ✓" else print_no_key_name fi else print_not_in_range fi anykey ;; 17 ) # show certificate and file details if [ "${keytype}" != "ca" ] then if [ -n "${keyname}" ] then show_cert_menu else print_no_key_name fi else print_not_in_range fi anykey ;; [eE] ) # send certs by email # mstat4 - ca.crt existiert # mstat5 - ca.pem existiert # mstat14 - keyname.pem existiert # mstat15 - keyname.p12 existiert if [ \( "${keytype}" = "ca" -a "${mstat4}" != "_" -a "${mstat5}" != "_" \) -o \ \( "${keytype}" != "ca" -a "${mstat4}" != "_" -a \( "${mstat14}" != "_" -o \ "${mstat15}" != "_" \) \) ] then create_html_msg send_cert_email "${keyname}" else print_not_in_range fi anykey ;; * ) # input not valid print_not_in_range anykey ;; esac else # input not valid print_not_in_range anykey fi } #---------------------------------------------------------------------------------------- # check if a valid certificate exists # input : $1 - certificate request # return: 0 - no valid certificate file exists # 1 - a valid certificate file already exists #---------------------------------------------------------------------------------------- check_if_valid_cert_exists () { _civce_ret=0 if [ "${CERTS_UNIQUE_SUBJECT}" = 'yes' ] then # get subject from csr _civce_csr_subject=`${openssl_bin} req -subject -noout -in ${reqdir}/${1}.csr | \ sed -e 's/^subject=//' -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'` # check if a certificate with the same name already exists # V 190221132322Z 58 unknown /C=DE/ST=Nordrhein Westfalen/L=... _civce_crt_serial=`grep -E "V[[:space:]].*[[:space:]]${_civce_csr_subject}" ${ssldir}/index.txt | \ sed 's/^V[[:space:]]*[0-9Z]*[[:space:]]*\([0-9]*\)[[:space:]]*.*$/\1/'` if [ -n "${_civce_crt_serial}" ] then # a valid certificate was found _civce_ret=1 if [ "${runmode}" = 'interactive' ] then # read date in UTC format (..Z) from index.txt _civce_crt_raw_valdate=`grep -E "V[[:space:]].*[[:space:]]${_civce_csr_subject}" ${ssldir}/index.txt | \ sed -e 's/^V[[:space:]]*\([0-9]*\)Z[[:space:]]*[0-9]*[[:space:]]*.*$/\1/' \ -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/20\1-\2-\3 \4:\5:\6 UTC/'` # convert date to local format _civce_crt_format_valdate="`date -d "TZ=\\\"${TIME_ZONE}\\\" ${_civce_crt_raw_valdate}" +'%d.%m.%Y %T %Z'`" # output a warning message mecho --warn "ATTENTION! The certificates subject must to be UNIQUE but a" mecho --warn " certificate with the used subject already exists!" echo mecho --warn "Subject : ${_civce_csr_subject}" mecho --warn "Serial : ${_civce_crt_serial}" mecho --warn "Valid until: ${_civce_crt_format_valdate}" echo fi fi fi return ${_civce_ret} } #========================================================================================= # main #========================================================================================= # set defaults caoption='' override=0 autorun='' runmode='interactive' color='' frame='' if [ -f /etc/config.d/setup ] then if $(grep -qE "^MENU=['\"]/var/install/bin/show-menu['\"]" /etc/config.d/setup) then color='--nocolor' frame='--noframe' fi fi act_pmode=`get_printmode` # check if screensize handling is available if [ -n "${_EISLIB_SCREENSIZE_Y}" ] then if check_screensize then # # define maxrownum = _EISLIB_SCREENSIZE # - 3 Header Lines # - 1 Footer Lines # ask line maxrownum=`expr ${_EISLIB_SCREENSIZE_Y} - 4` true else mecho --info "Return to calling script" exit 1 fi else # default if screensize handling is not available maxrownum=18 fi # show current screensize on the screen #echo "X:$_EISLIB_SCREENSIZE_X"; echo "Y:$_EISLIB_SCREENSIZE_Y"; echo "M:$maxrownum"; anykey # batch or interactive mode? if [ $# -gt 1 -a "$2" = "batch" ] then runmode='batch' else runmode='interactive' clrhome fi # get parameter case "$1" in ca ) # ca keytype="ca" keyname="ca" override=1 autorun="3 4 5" ;; client ) # client/server keytype="client/server" packname='' # need to be implemented, if required here! if [ "${runmode}" = "batch" ] then if [ "$3" = "alternate" ] then keyname="$5" altkeyname="$4" else keyname="$3" altkeyname='' fi else keyname='' altkeyname='' fi domainname="myserver.mydomain.de" override=1 autorun="10 11 12 13 14 15" ;; crl ) # revocation list keytype="ca" keyname="ca" override=1 autorun="8" if [ "$3" = "--passfile" -a -s ${passfile} ] then # read ca password from file caoption="-passin file:${passfile}" fi ;; mail ) # mail server keytype='mail' packname='mail' keyname='mail.mydomain.de' domainname='mail.mydomain.de' override=1 autorun="10 11 12 13 14 16" ;; web ) # mail server keytype='web' packname='apache' keyname='www.mydomain.de' if [ "${runmode}" = "batch" ] then if [ "$3" = "alternate" ] then packname="$4" keyname="$5" domainname="$5" else domainname="$3" fi else domainname='www.mydomain.de' fi override=1 autorun="10 11 12 13 14 16" ;; * ) # normal mode if [ -f "${no_ca_file}" ] then override=1 else override=0 fi ;; esac # check if more than one command line parameter if [ "${runmode}" = 'batch' ] then # batch mode if [ -f "${no_ca_file}" ] then if [ "${keytype}" != 'ca' ] then # suppress output for ca requests to prevent that this message # is shown twice, one time for the ca creation and another one # for the certificate creation echo mecho --warn "Important hint!" echo # 1 2 3 4 5 6 7 # 12345678901234567890123456789012345678901234567890123456789012345678901234567890 echo "You have decided to use a different computer as 'CA-Home', your central" echo "certificate authority, in your network to manage your certificates." echo "Please create a valid server key and certificate on that CA-Home computer" echo "and copy the files to this eisfair server." echo echo "1. Copy the key, e.g. server.local.lan.key, to /usr/local/ssl/private" echo "2. Copy the certificate, e.g. server.local.lan.pem, to /usr/local/ssl/certs" echo "3. Copy the CA-certificate 'ca.pem' to /usr/local/ssl/certs" echo "4. Update the hashes by running 'openssl rehash -compat /usr/local/ssl/certs" echo anykey fi else sel_values="${autorun}" set_function_status for NBR in ${autorun} do # check input check_input_and_run_command "${NBR}" done fi else # interactive mode endflag=0 until [ ${endflag} -eq 1 ] do # interactive mode set_function_status print_main_menu read SEL case ${SEL} in [bB] ) # change RSA key bits change_rsa_keybits ;; [hH] ) # change secure hash algorithm change_hash_algorithm ;; [eE] ) # send certificate files by email # mstat4 - ca.crt existiert # mstat5 - ca.pem existiert # mstat14 - keyname.pem existiert # mstat15 - keyname.p12 existiert if [ \( "${keytype}" = "ca" -a "${mstat4}" != "_" -a "${mstat5}" != "_" \) -o \ \( "${keytype}" != "ca" -a "${mstat4}" != "_" -a \( "${mstat14}" != "_" -o "${mstat15}" != "_" \) \) ] then create_html_msg send_cert_email "${keyname}" else print_not_in_range anykey fi ;; [qQ] ) # quit endflag=1 ;; [1-9]|1[0-9] ) # check input and run command check_input_and_run_command "${SEL}" ;; * ) # error print_not_in_range anykey ;; esac done fi #========================================================================================= # end #=========================================================================================