#!/bin/bash # Certificate Autority Operator # (c) 2009, Dennis Leeuw # # 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # A copy of the license can be obtained from # http://www.gnu.org/licenses/gpl-2.0.html # or a written copy can be obtained from # Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301 USA VERSION="0.10.2" #----------------------------------------------------------------------# # This script helps you to create and maintain a certificate authority # # For the complete documentation about OpenSSL CA # # see: http://pig.made-it.com/ # #----------------------------------------------------------------------# # stuff you can change: # The directory under which everything else will be stored: CAO_ROOT=/etc/cao CAO_USR=root CAO_GRP=root CAO_WEBUSR=apache CAO_WEBGRP=apache #----------------- NOTHING TO BE DONE BELOW THIS LINE -----------------# #-------------------------# # The configuration files # #-------------------------# function create_opensslcnf { echo "# openssl.cnf file [ ca ] # Entry point when signing a CSR # Used by: openssl ca # cao functions: revoke, sign, create crl default_ca = CA_default [ CA_default ] # Used by: openssl ca # Referenced from: [ ca ] dir = \${ENV::CA_DOMAIN_ROOT} serial = \${ENV::CAO_SERIALDB_FILE} database = \${ENV::CAO_INDEXDB_FILE} certs = \${ENV::CAO_SIGNED_CERTS_DIR} new_certs_dir = \${ENV::CAO_CRT_DIR} certificate = \${ENV::CAO_CACRT_FILE} private_key = \${ENV::CAO_CAKEY_FILE} RANDFILE = \${ENV::CAO_RAND_FILE} crl_dir = \${ENV::CAO_SSL_ROOT} crl = \${ENV::CAO_CRL_FILE} crl_number = \${ENV::CAO_CRLDB_FILE} x509_extensions = usr_cert default_days = \${ENV::DEFAULTDAYS} default_md = \${ENV::DEFAULTMD} preserve = no default_crl_days = 30 nameopt = default_ca certopt = default_ca email_in_dn = no policy = policy #copy_extensions = copy [ policy ] # Referenced from: [ CA_default ] countryName = \${ENV::C_POLICY} stateOrProvinceName = \${ENV::ST_POLICY} localityName = \${ENV::L_POLICY} organizationName = \${ENV::O_POLICY} organizationalUnitName = \${ENV::OU_POLICY} commonName = \${ENV::CN_POLICY} emailAddress = \${ENV::EMAIL_POLICY} [ req ] # Settings for a CSR # And a self-signed root CRT # Used by: openssl req # cao functions: create_ca_cert (-x509), create_csr default_bits = \${ENV::KEYBITS} default_keyfile = key.pem # name of generated keys default_md = \${ENV::DEFAULTMD} string_mask = nombstr # permitted characters # RH uses MASK:0x2002 prompt = no # do not ask for DN distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca crl_extensions = crl_ext [ req_distinguished_name ] # Questions to ask when creating a CSR # Referenced from: [ req ] # Settings for prompt = no C = \${ENV::DN_C_DEFAULT} ST = \${ENV::DN_ST_DEFAULT} L = \${ENV::DN_L_DEFAULT} O = \${ENV::DN_O_DEFAULT} OU = \${ENV::DN_OU_DEFAULT} CN = \${ENV::DN_CN_DEFAULT} emailAddress = \${ENV::DN_MAIL_DEFAULT} [ req_attributes ] # # Referenced from [ req ] [ usr_cert ] # X.509 section to be used when signing a CSR # openssl req -x509 # Referenced from [ CA_default ] basicConstraints = \${ENV::BASICCONSTRAINTS} subjectKeyIdentifier = hash authorityKeyIdentifier = \${ENV::AUTHORITYKEYIDENTIFIER} # PKIX recommendation subjectAltName = email:copy issuerAltName = issuer:copy nsComment = \${ENV::NSCOMMENT} nsCertType = \${ENV::NSCERTTYPE} keyUsage = \${ENV::KEYUSAGE} extendedKeyUsage = \${ENV::EXTENDEDKEYUSAGE} nsBaseUrl = \${ENV::CAO_BASE_URL} nsCaRevocationUrl = \${ENV::CAO_CRL_URL} nsCaPolicyUrl = \${ENV::CAO_CAPOLICY_URL} nsRevocationUrl = \${ENV::CAO_REVOKE_URL} nsRenewalUrl = \${ENV::CAO_RENEW_URL} issuerAltName = URI:\${ENV::CAO_CACRT_URL} [ v3_req ] # Extensions to add to a certificate request basicConstraints = \${ENV::BASICCONSTRAINTS} keyUsage = \${ENV::KEYUSAGE} nsCertType = \${ENV::NSCERTTYPE} [ v3_ca ] # Extensions for a typical CA subjectKeyIdentifier = hash authorityKeyIdentifier = \${ENV::AUTHORITYKEYIDENTIFIER} basicConstraints = \${ENV::BASICCONSTRAINTS} keyUsage = \${ENV::KEYUSAGE} nsCertType = \${ENV::NSCERTTYPE} subjectAltName = email:copy issuerAltName = issuer:copy nsBaseUrl = \${ENV::CAO_BASE_URL} nsCaRevocationUrl = \${ENV::CAO_CRL_URL} nsCaPolicyUrl = \${ENV::CAO_CAPOLICY_URL} nsRevocationUrl = \${ENV::CAO_REVOKE_URL} nsRenewalUrl = \${ENV::CAO_RENEW_URL} issuerAltName = URI:\${ENV::CAO_CACRT_URL} [ x509_extensions ] # Used for signing the CA root certificate subjectKeyIdentifier = hash authorityKeyIdentifier = \${ENV::AUTHORITYKEYIDENTIFIER} basicConstraints = \${ENV::BASICCONSTRAINTS} keyUsage = \${ENV::KEYUSAGE} nsCertType = \${ENV::NSCERTTYPE} subjectAltName = email:copy issuerAltName = issuer:copy nsBaseUrl = \${ENV::CAO_BASE_URL} nsCaRevocationUrl = \${ENV::CAO_CRL_URL} nsCaPolicyUrl = \${ENV::CAO_CAPOLICY_URL} nsRevocationUrl = \${ENV::CAO_REVOKE_URL} nsRenewalUrl = \${ENV::CAO_RENEW_URL} issuerAltName = URI:\${ENV::CAO_CACRT_URL} [ crl_ext ] # Options when revoking a CRT # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier = keyid:always,issuer:always " > ${CAO_SSLCNF_FILE} if [ $? != 0 ]; then echo "Could not create ${CAO_SSLCNF_FILE}!" exit 1 else chmod 640 ${CAO_SSLCNF_FILE} fi } function create_domaincnf { echo "# Default DN settings for ${CAO_MY_DOMAIN} NSCOMMENT=\"${NSCOMMENT}\" DEFAULTDAYS=\"365\" CADAYS=\"3650\" KEYBITS=\"2048\" ENCRYPTION=\"des3\" DEFAULTMD=\"sha256\" DN_C_DEFAULT=\"${DN_C_DEFAULT}\" DN_ST_DEFAULT=\"${DN_ST_DEFAULT}\" DN_L_DEFAULT=\"${DN_L_DEFAULT}\" DN_O_DEFAULT=\"${DN_O_DEFAULT}\" DN_OU_DEFAULT=\"${DN_OU_DEFAULT}\" DN_CN_DEFAULT=\"${DN_CN_DEFAULT}\" DN_MAIL_DEFAULT=\"${DN_MAIL_DEFAULT}\" CAO_CA_FQDN=\"${CAO_CA_FQDN}\" " > ${CA_DOMAIN_ROOT}/dn-data.cnf if [ $? != 0 ]; then echo "Could not create ${CA_DOMAIN_ROOT}/dn-data.cnf!" exit 1 else chmod 640 ${CA_DOMAIN_ROOT}/dn-data.cnf fi } #-----------------# # Setup Functions # #-----------------# function get_ca_fqdn { # Get FQDN address of CA server if not set if [ "x${CAO_CA_FQDN}" = "x" ]; then read -p "CA server FQDN (www.domain.com): " CAO_CA_FQDN fi # This is the base URL for all others URL addresses if not supplied CAO_BASE_URL="http://${CAO_CA_FQDN}/" # This is the link where to download the latest # Certificate Revocation List (CRL) CAO_CRL_URL="https://${CAO_CA_FQDN}/${CAO_CRL_FILE#${CAO_SSL_ROOT}/}" # This is the link where the CA policy can be found CAO_CAPOLICY_URL="http://${CAO_CA_FQDN}/policy.html" # The issuer certificate CAO_CACRT_URL="http://${CAO_CA_FQDN}/${CAO_CACRT_FILE#${CAO_NOSSL_ROOT}/}" # This is the link where to revoke the certificate CAO_REVOKE_URL="." # This is the location where the certificate can be renewed CAO_RENEW_URL="." } function request_dn_data { # make sure N is empty N="" # Get country data if [ "x${DN_C_DEFAULT}" = "x" ]; then DN_C_DEFAULT="NL" fi until [ ${#N} = 2 ]; do read -p "2 letter country code [${DN_C_DEFAULT}]: " N if [ "x${N}" = "x" ]; then N=11 fi done if [ $N != 11 ]; then DN_C_DEFAULT=$N fi # Get state or province data if [ "x${DN_ST_DEFAULT}" = "x" ]; then DN_ST_DEFAULT="Utrecht" fi read -p "The state or province [${DN_ST_DEFAULT}]: " N if [ "x$N" != "x" ]; then DN_ST_DEFAULT=$N fi # Get city data if [ "x${DN_L_DEFAULT}" = "x" ]; then DN_L_DEFAULT="Utrecht" fi read -p "Where your are located [${DN_L_DEFAULT}]: " N if [ "x$N" != "x" ]; then DN_L_DEFAULT=$N fi # Get organization name if [ "x${DN_O_DEFAULT}" = "x" ]; then DN_O_DEFAULT="Made IT" fi read -p "Name of the organisation [${DN_O_DEFAULT}]: " N if [ "x$N" != "x" ]; then DN_O_DEFAULT=$N fi # Get organization name if [ "x${DN_OU_DEFAULT}" = "x" ]; then DN_OU_DEFAULT="System Administration" fi read -p "Unit name within the organization [${DN_OU_DEFAULT}]: " N if [ "x$N" != "x" ]; then DN_OU_DEFAULT=$N fi # Get common name if [ "x${DN_CN_DEFAULT}" = "x" ]; then DN_CN_DEFAULT="www.example.com" fi read -p "The common name [${DN_CN_DEFAULT}]: " N if [ "x$N" != "x" ]; then DN_CN_DEFAULT=$N fi # Get organization name if [ "x${DN_MAIL_DEFAULT}" = "x" ]; then DN_MAIL_DEFAULT="admin@example.com" fi read -p "E-mail address for the common name contact [${DN_MAIL_DEFAULT}]: " N if [ "x$N" != "x" ]; then DN_MAIL_DEFAULT=$N fi } #-------------------# # Setting Functions # #-------------------# # FIXME possible KEYUSAGE values: digitalSignature, nonRepudiation, keyEncipherment, # dataEncipherment, keyAgreement, keyCertSign, cRLSign, # encipherOnly, decipherOnly function ca_settings { BASICCONSTRAINTS="CA:TRUE,pathlen:0" AUTHORITYKEYIDENTIFIER="keyid:always,issuer:always" KEYUSAGE="cRLSign,keyCertSign,digitalSignature" NSCERTTYPE="sslCA,emailCA,objCA" EXTENDEDKEYUSAGE="1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4,1.3.6.1.5.5.7.3.8,1.3.6.1.5.5.7.3.9" C_POLICY=match ST_POLICY=match L_POLICY=match O_POLICY=match OU_POLICY=optional CN_POLICY=supplied EMAIL_POLICY=optional } function usr_settings { BASICCONSTRAINTS="CA:FALSE" AUTHORITYKEYIDENTIFIER="keyid,issuer:always" KEYUSAGE="nonRepudiation,digitalSignature,keyEncipherment" C_POLICY=optional ST_POLICY=optional L_POLICY=optional O_POLICY=optional OU_POLICY=optional CN_POLICY=supplied EMAIL_POLICY=optional } function create_dirs { if [ -d ${CAO_ROOT} ]; then echo "${CAO_ROOT} already exists" exit 1 fi mkdir -p ${CAO_ROOT} chown ${CAO_USR}.${CAO_WEBGRP} ${CAO_ROOT} chmod 750 ${CAO_ROOT} # DB directories mkdir -p ${CAO_DB_ROOT} chown ${CAO_USR}.${CAO_GRP} ${CAO_ROOT} chmod 770 ${CAO_DB_ROOT} # Public directories mkdir -p ${CAO_PUBLIC_ROOT} chown ${CAO_USR}.${CAO_WEBGRP} ${CAO_PUBLIC_ROOT} chmod 750 ${CAO_PUBLIC_ROOT} mkdir -p ${CAO_NOSSL_ROOT} chown ${CAO_USR}.${CAO_WEBGRP} ${CAO_NOSSL_ROOT} chmod 770 ${CAO_NOSSL_ROOT} mkdir -p ${CAO_SSL_ROOT} chown ${CAO_USR}.${CAO_WEBGRP} ${CAO_SSL_ROOT} chmod 770 ${CAO_SSL_ROOT} mkdir -p ${CAO_CSR_DIR} chown ${CAO_USR}.${CAO_WEBGRP} ${CAO_CSR_DIR} chmod 770 ${CAO_CSR_DIR} mkdir -p ${CAO_CRT_DIR} chown ${CAO_USR}.${CAO_WEBGRP} ${CAO_CRT_DIR} chmod 770 ${CAO_CRT_DIR} # Private directories mkdir -p ${CAO_PRIVATE_ROOT} chown ${CAO_USR}.${CAO_GRP} ${CAO_PRIVATE_ROOT} chmod 750 ${CAO_PRIVATE_ROOT} mkdir ${CAO_PRIVATE_CA_DIR} chown ${CAO_USR}.${CAO_GRP} ${CAO_PRIVATE_CA_DIR} chmod 750 ${CAO_PRIVATE_CA_DIR} mkdir ${CAO_USRKEY_DIR} chown ${CAO_USR}.${CAO_GRP} ${CAO_USRKEY_DIR} chmod 750 ${CAO_USRKEY_DIR} mkdir ${CAO_SIGNED_CERTS_DIR} chown ${CAO_USR}.${CAO_GRP} ${CAO_SIGNED_CERTS_DIR} chmod 750 ${CAO_SIGNED_CERTS_DIR} } function create_db_files { if [ ! -d ${CAO_DB_ROOT} ]; then echo "${CAO_DB_ROOT} does not exist" exit 1 fi echo "101010" > ${CAO_SERIALDB_FILE} chmod 600 ${CAO_SERIALDB_FILE} echo -n > ${CAO_INDEXDB_FILE} chmod 600 ${CAO_INDEXDB_FILE} echo "101010" > ${CAO_CRLDB_FILE} chmod 600 ${CAO_CRLDB_FILE} # FIXME what to do with CAO_RAND_FILE } function set_locations { # Set root dirs CAO_DB_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN}/db CAO_PRIVATE_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN}/private CAO_PUBLIC_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN}/public CAO_SSLCNF_FILE=${CAO_ROOT}/${CAO_MY_DOMAIN}/openssl.cnf # Database directory CAO_SERIALDB_FILE=${CAO_DB_ROOT}/serial CAO_INDEXDB_FILE=${CAO_DB_ROOT}/index CAO_CRLDB_FILE=${CAO_DB_ROOT}/crl_number CAO_RAND_FILE=${CAO_DB_ROOT}/random # Our private directory CAO_PRIVATE_CA_DIR=${CAO_PRIVATE_ROOT}/CA CAO_CAKEY_FILE=${CAO_PRIVATE_CA_DIR}/cakey.pem CAO_USRKEY_DIR=${CAO_PRIVATE_CA_DIR}/keys CAO_SIGNED_CERTS_DIR=${CAO_PRIVATE_CA_DIR}/certs # Our public directory CAO_NOSSL_ROOT=${CAO_PUBLIC_ROOT}/nossl CAO_CACRT_FILE=${CAO_NOSSL_ROOT}/cacert.pem CAO_SSL_ROOT=${CAO_PUBLIC_ROOT}/ssl CAO_CRL_FILE=${CAO_SSL_ROOT}/crl.pem CAO_CSR_DIR=${CAO_SSL_ROOT}/csr CAO_CRT_DIR=${CAO_SSL_ROOT}/crt } function export_vars { export AUTHORITYKEYIDENTIFIER \ BASICCONSTRAINTS \ C_POLICY \ CA_DOMAIN_ROOT \ CN_POLICY \ DEFAULTDAYS \ DEFAULTMD \ DN_C_DEFAULT \ DN_CN_DEFAULT \ DN_L_DEFAULT \ DN_MAIL_DEFAULT \ DN_O_DEFAULT \ DN_OU_DEFAULT \ DN_ST_DEFAULT \ EMAIL_POLICY \ EXTENDEDKEYUSAGE \ ISSUERCRT \ KEYBITS \ KEYUSAGE \ L_POLICY \ NSCERTTYPE \ NSCOMMENT \ O_POLICY \ OU_POLICY \ ST_POLICY \ CAO_ROOT \ CAO_DB_ROOT \ CAO_PRIVATE_ROOT \ CAO_PUBLIC_ROOT \ CAO_SERIALDB_FILE \ CAO_INDEXDB_FILE \ CAO_CRLDB_FILE \ CAO_RAND_FILE \ CAO_PRIVATE_CA_DIR \ CAO_CAKEY_FILE \ CAO_USRKEY_DIR \ CAO_SIGNED_CERTS_DIR \ CAO_NOSSL_ROOT \ CAO_CACRT_FILE \ CAO_SSL_ROOT \ CAO_CRL_FILE \ CAO_CSR_DIR \ CAO_CRT_DIR \ CAO_BASE_URL \ CAO_CRL_URL \ CAO_CAPOLICY_URL \ CAO_REVOKE_URL \ CAO_RENEW_URL \ CAO_CACRT_URL } #---------------# # Key functions # #---------------# function create_param { export_vars # Create parameters for dsa, dh openssl ${KEY}param ${KEYBITS} -out ${PRM_FILE} if [ $? != 0 ]; then echo "Could not create parameters file for ${KEY}" exit 1 fi chmod 600 ${PRM_FILE} } function create_key { export_vars if [ "x${KEY}" = "xdsa" ]; then OPTIONS="${DSA_PARAM_FILE}" elif [ "x${KEY}" = "xrsa" ]; then OPTIONS="${KEYBITS}" fi echo "Creating a ${KEY} key" openssl gen${KEY} -${ENCRYPTION} -out ${KEY_FILE} ${OPTIONS} 2>/dev/null if [ $? != 0 ]; then echo "Could not create the ${KEY} key file" exit 1 fi chmod 600 ${KEY_FILE} } #-----------------------# # Certificate functions # #-----------------------# function get_cert_type { # CA objects # EXTENDEDKEYUSAGE="1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4,1.3.6.1.5.5.7.3.8,1.3.6.1.5.5.7.3.9" CA=N KEYUSAGE="nonRepudiation,digitalSignature,keyEncipherment" read -p "Is this a CA certificate? [N] " N if [ "$N" = "Y" ] || [ "$N" = "y" ]; then CA=Y KEYUSAGE="cRLSign,keyCertSign" fi read -p "Certificate type : " N local OLD_IFS="${IFS}" local IFS='\,' for ELM in $N; do if [ ${ELM} = "server" ]; then NSTYPE="server" EKU="1.3.6.1.5.5.7.3.1" if [ "$CA" = "Y" ]; then NSTYPE="sslCA" EKU="" fi elif [ ${ELM} = "client" ]; then NSTYPE="client" EKU="1.3.6.1.5.5.7.3.2" elif [ ${ELM} = "code" ]; then NSTYPE="objsign" EKU="1.3.6.1.5.5.7.3.3" if [ "$CA" = "Y" ]; then NSTYPE="objCA" EKU="" fi elif [ ${ELM} = "email" ]; then NSTYPE="email" EKU="1.3.6.1.5.5.7.3.4" if [ "$CA" = "Y" ]; then NSTYPE="emailCA" EKU="" fi elif [ ${ELM} = "timestamp" ]; then NSTYPE="" EKU="1.3.6.1.5.5.7.3.8" elif [ ${ELM} = "ocspsign" ]; then NSTYPE="" EKU="1.3.6.1.5.5.7.3.9" fi # Create NSCERTTYPE if [ "x${NSTYPE}" != "x" ]; then if [ "x${NSCERTTYPE}" = "x" ]; then NSCERTTYPE="${NSTYPE}" else NSCERTTYPE="${NSCERTTYPE},${NSTYPE}" fi fi # Create EXTENDEDKEYUSAGE if [ "x${EKU}" != "x" ]; then if [ "x${EXTENDEDKEYUSAGE}" = "x" ]; then EXTENDEDKEYUSAGE="${EKU}" else EXTENDEDKEYUSAGE="${EXTENDEDKEYUSAGE},${EKU}" fi fi done IFS="${OLD_IFS}" } function create_csr { request_dn_data get_cert_type # Set user stuff usr_settings get_ca_fqdn export_vars create_key echo "Creating CSR... " openssl req -new -config ${CAO_SSLCNF_FILE} \ -reqexts v3_req \ -key ${KEY_FILE} -out ${CSR_FILE} if [ $? != 0 ]; then echo "Could not create ${CSR_FILE}" exit 1 fi } function create_pkcs12 { openssl pkcs12 -chain -export -in /etc/cao/CA/private/CA/certs/dbg-win.op.umcutrecht.nl.pem -inkey /etc/cao/CA/private/CA/keys/dbg-win.op.umcutrecht.nl.key -out file.p12 -CSP "DBG-WIN Certificate" } #----------------# # Main Functions # #----------------# function create_ca_cert { # Syntax # create_ca_cert type KEY=$1 if [ "x${KEY}" = "xdsa" ]; then PARM_FILE=${PARM_DIR}/dsaparam.pem create_dsa_param fi KEY_FILE=${CAO_CAKEY_FILE} CERT_FILE=${CAO_CACRT_FILE} DEFAULTDAYS=${CADAYS} # Create the CA certificate # create_key echo "Signing CA certificate" get_ca_fqdn export_vars # Create CA CSR openssl req -config ${CAO_SSLCNF_FILE} -new -newkey ${KEY}:${KEYBITS} -out ${CAO_CACRT_FILE%.pem}.csr -keyout ${KEY_FILE} # Create a selfsigned certificate openssl x509 -trustout -extfile ${CAO_SSLCNF_FILE} \ -extensions v3_ca \ -days ${CADAYS} -signkey ${KEY_FILE} \ -trustout -req -in ${CAO_CACRT_FILE%.pem}.csr \ -out ${CAO_CACRT_FILE} -outform PEM if [ $? != 0 ]; then echo "Could not create ${CAO_CACRT_FILE}" exit 1 fi # Create DER version openssl x509 -in ${CAO_CACRT_FILE} -outform DER \ -out ${CAO_CACRT_FILE%.pem}.der # Create HASH version CAO_CA_HASH=`openssl x509 -noout -hash -in ${CAO_CACRT_FILE}` cp ${CAO_CACRT_FILE} ${CAO_CACRT_FILE%/*}/${CAO_CA_HASH}.0 } function check_certs_check { # Exit codes # 0 valid # 1 error # 253 expires within a month # 254 invalid CURR_DATE[0]=`date +%Y` CURR_DATE[1]=`date +%b` # Get the Not After field if [ -f $1 ]; then CRT_LINE=`openssl x509 -noout -enddate -in $1` CRT_ARR=(`echo ${CRT_LINE#*=}`) # 0 month # 1 day # 2 time # 3 year # 4 zone else echo "Cert: $1 does not exits" exit 1 fi # Compare year less then if [ ${CRT_ARR[3]} -lt ${CURR_DATE[0]} ]; then return 254 fi # Compare year greater then if [ ${CRT_ARR[3]} -gt ${CURR_DATE[0]} ]; then return 0 fi # Next test is only when the years are equal months=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) for ((I=0; $I <= ${#months[*]}; I=$(($I+1)) )); do if [ "${CRT_ARR[0]}" = "${months[$I]}" ]; then M_CRT_N=$I break fi done for ((I=0; $I <= ${#months[*]}; I=$(($I+1)) )); do if [ "${CURR_DATE[1]}" = "${months[$I]}" ]; then M_NOW_N=$I break fi done if [ ${M_CRT_N} -lt ${M_NOW_N} ]; then return 254 fi if [ $((${M_CRT_N}-1)) -lt ${M_NOW_N} ]; then echo "$CERT expires in a month" return 253 fi echo return return 0 } function check_certs { # First check CA certificate check_certs_check ${CA_DOMAIN_ROOT}/cacert.pem local I=0 if [ $? = 253 ]; then MONTH_ARRAY=[$I]="cacert.pem expires within a month" I=$(($I+1)) elif [ $? = 254 ]; then MONTH_ARRAY=[$I]="cacert.pem is invalid" I=$(($I+1)) fi # Check other Certificates for CERT in `ls ${CA_DOMAIN_ROOT}/newcerts/*`; do check_certs_check ${CERT} if [ $? = 253 ]; then MONTH_ARRAY[$I]="${CERT} expires within a month" I=$(($I+1)) elif [ $? = 254 ]; then MONTH_ARRAY=[$I]="${CERT} is invalid" I=$(($I+1)) fi done # Output our findings if [ ${#MONTH_ARRAY[*]} != 0 ]; then echo ${MONTH_ARRAY[*]} fi exit 0 } #----------------# # Help Functions # #----------------# function print_version { COMM=${0##*/} echo "$COMM version: ${VERSION}" } function print_license { cat < part is omitted the root CA" echo "is assumed. Sub authorities can be created by filling in the domain." echo "$COMM [init|remove]" echo " init - initializes a domain" echo " remove - removes a domain" echo echo "$COMM create [cacert] [rsa|dsa]" echo echo "$COMM create [key|csr] [rsa|dsa] " echo " [key|csr] create a key or a CSR, csr will create a new key" echo " [rsa|dsa] type of key to be created" echo " the name for the object, a FQDN for systems or" echo " an e-mail address for an e-mail certificate" echo echo "$COMM sign " echo echo "$COMM revoke " echo " Put the certificate with on the CRL list." echo " can be on of: keyCompromise, CACompromise," echo " affiliationChanged, superseded, cessationOfOperation, " echo " removeFromCRL, privilegeWithdrawn, aACompromise" echo " If none is given unspecified is used." echo echo "$COMM hold " echo " Puts a certificate on hold and gives an action to be taken" echo " can be: holdInstructionCallIssuer or" echo " holdInstructionReject (which is the default)" echo echo "$COMM check certs" echo echo "$COMM create crl" echo echo "$COMM [version|license|help]" echo " Outputs the $COMM version, license or help and exits" } #----------------# # Main functions # #----------------# function main_init { set_locations create_dirs create_db_files export_vars # if openssl.cnf does not exist create it if [ ! -f ${CAO_SSLCNF_FILE} ]; then create_opensslcnf fi # Get the CA domain data get_ca_fqdn request_dn_data # Output data NSCOMMENT="${DN_O_DEFAULT} Generated Certificate" create_domaincnf echo "Check the settings in:" echo " ${CA_DOMAIN_ROOT}/dn-data.cnf" } function main_remove { rm -rf ${CA_DOMAIN_ROOT} } function main_create { set_locations case $1 in cacert) ca_settings create_ca_cert $2 ;; crl) ca_settings get_ca_fqdn export_vars openssl ca -config ${CAO_SSLCNF_FILE} \ -gencrl -out ${CAO_CRL_FILE} -crlexts crl_ext ;; key|csr) # Get the key type to be used if [ "x$2" != "x" ]; then KEY=$2 else print_help exit 1 fi # Set the files to be used if [ "x$3" != "x" ]; then KEY_FILE=${CAO_USRKEY_DIR}/${3}.key CSR_FILE=${CAO_CSR_DIR}/${3}.csr DN_CN_DEFAULT=$3 else print_help exit 1 fi create_$1 ;; *) print_help exit 1 ;; esac } function main_sign { set_locations if [ "x$1" != "x" ]; then CSR_FILE=${CAO_CSR_DIR}/${1}.csr CRT_FILE=${CAO_SIGNED_CERTS_DIR}/${1}.pem else print_help exit 1 fi usr_settings get_ca_fqdn get_cert_type export_vars echo "Signing the CSR file... " openssl ca -config ${CAO_SSLCNF_FILE} -days ${DEFAULTDAYS} \ -in ${CSR_FILE} -out ${CRT_FILE} -batch if [ $? != 0 ]; then echo "Could not sign ${CSR_FILE}" exit 1 #else # Clean up CSR stuff #rm -f ${CSR_FILE} fi } function main_check { case $1 in certs) check_certs ;; *) print_help exit 1 ;; esac } function main_revoke { NSCERTTYPE="." EXTENDEDKEYUSAGE="." case $2 in keyCompromise|CACompromise|affiliationChanged|superseded|cessationOfOperation|removeFromCRL|privilegeWithdrawn|aACompromise) REVOKE_REASON=$2 ;; *) REVOKE_REASON="unspecified" ;; esac # FIXME: we should do something with -crl_CA_compromise time and -crl_compromise time set_locations ca_settings get_ca_fqdn export_vars if [ -f ${CAO_CRT_DIR}/${1}.pem ]; then openssl ca -config ${CAO_SSLCNF_FILE} \ -revoke ${CAO_CRT_DIR}/${1}.pem \ -crl_reason ${REVOKE_REASON} else echo "Certificate for $1 does not exits" exit 1 fi } function main_hold { # Indicates the action to be taken after encountering a certificate # that has been placed on hold. NSCERTTYPE="." EXTENDEDKEYUSAGE="." case $2 in holdInstructionCallIssuer|holdInstructionReject) HOLD_REASON=$2 ;; *) # RFC3280 says that holdInstructionNone is # depricated so the safe bet is to act as # if the certificate is revoked HOLD_REASON="holdInstructionReject" ;; esac set_locations ca_settings get_ca_fqdn export_vars if [ -f ${CAO_CRT_DIR}/${1}.pem ]; then openssl ca -config ${CAO_SSLCNF_FILE} \ -revoke ${CAO_CRT_DIR}/${1}.pem \ -crl_reason certificateHold \ -crl_hold ${HOLD_REASON} else echo "Certificate for $1 does not exits" exit 1 fi } function main_renew { # FIXME # See x509 man page openssl x509 -x509toreq -signkey private.key -out newcsr.csr -in oldcert.pem # resign csr } function sub_main { case $1 in init|remove|create|sign|revoke|check|renew) # check if we have been in this function before if [ "x${CAO_MY_DOMAIN}" = "x" ]; then CAO_MY_DOMAIN=CA fi # Set directory and load settings if possible CA_DOMAIN_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN} if [ -d ${CA_DOMAIN_ROOT} ]; then . ${CA_DOMAIN_ROOT}/dn-data.cnf fi export_vars # Call the right function local function=$1 shift main_$function $@ exit 0 ;; version) print_version exit 0 ;; help) print_help exit 0 ;; license) print_license exit 0 ;; *) if [ "x$1" = "x" ]; then print_help exit 0 else # FIXME echo "Sub domain function is not implemented yet!" exit 0 CAO_MY_DOMAIN=$1 shift sub_main $@ fi ;; esac } #------# # Main # #------# # FIXME dh en dsa key generation sub_main $@ exit 0 # END #