#!/bin/bash # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. ######################################################################## # # mozilla/security/nss/tests/cert/chains.sh # # Script to test certificate chains validity. # # needs to work on all Unix and Windows platforms # # special strings # --------------- # FIXME ... known problems, search for this string # NOTE .... unexpected behavior ######################################################################## ########################### is_httpserv_alive ########################## # local shell function to exit with a fatal error if selfserver is not # running ######################################################################## is_httpserv_alive() { if [ ! -f "${HTTPPID}" ]; then echo "$SCRIPTNAME: Error - httpserv PID file ${HTTPPID} doesn't exist" sleep 5 if [ ! -f "${HTTPPID}" ]; then Exit 9 "Fatal - httpserv pid file ${HTTPPID} does not exist" fi fi if [ "${OS_ARCH}" = "WINNT" ] && \ [ "$OS_NAME" = "CYGWIN_NT" -o "$OS_NAME" = "MINGW32_NT" ]; then PID=${SHELL_HTTPPID} else PID=`cat ${HTTPPID}` fi echo "kill -0 ${PID} >/dev/null 2>/dev/null" kill -0 ${PID} >/dev/null 2>/dev/null || Exit 10 "Fatal - httpserv process not detectable" echo "httpserv with PID ${PID} found at `date`" } ########################### wait_for_httpserv ########################## # local shell function to wait until httpserver is running and initialized ######################################################################## wait_for_httpserv() { echo "trying to connect to httpserv at `date`" echo "tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v" ${BINDIR}/tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v if [ $? -ne 0 ]; then sleep 5 echo "retrying to connect to httpserv at `date`" echo "tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v" ${BINDIR}/tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v if [ $? -ne 0 ]; then html_failed "Waiting for Server" fi fi is_httpserv_alive } ########################### kill_httpserv ############################## # local shell function to kill the httpserver after the tests are done ######################################################################## kill_httpserv() { if [ "${OS_ARCH}" = "WINNT" ] && \ [ "$OS_NAME" = "CYGWIN_NT" -o "$OS_NAME" = "MINGW32_NT" ]; then PID=${SHELL_HTTPPID} else PID=`cat ${HTTPPID}` fi echo "trying to kill httpserv with PID ${PID} at `date`" if [ "${OS_ARCH}" = "WINNT" -o "${OS_ARCH}" = "WIN95" -o "${OS_ARCH}" = "OS2" ]; then echo "${KILL} ${PID}" ${KILL} ${PID} else echo "${KILL} -USR1 ${PID}" ${KILL} -USR1 ${PID} fi wait ${PID} # On Linux httpserv needs up to 30 seconds to fully die and free # the port. Wait until the port is free. (Bug 129701) if [ "${OS_ARCH}" = "Linux" ]; then echo "httpserv -b -p ${NSS_AIA_PORT} 2>/dev/null;" until ${BINDIR}/httpserv -b -p ${NSS_AIA_PORT} 2>/dev/null; do echo "RETRY: httpserv -b -p ${NSS_AIA_PORT} 2>/dev/null;" sleep 1 done fi echo "httpserv with PID ${PID} killed at `date`" rm ${HTTPPID} html_detect_core "kill_httpserv core detection step" } ########################### start_httpserv ############################# # local shell function to start the httpserver with the parameters required # for this test and log information (parameters, start time) # also: wait until the server is up and running ######################################################################## start_httpserv() { HTTP_METHOD=$1 if [ -n "$testname" ] ; then echo "$SCRIPTNAME: $testname ----" fi echo "httpserv starting at `date`" ODDIR="${HOSTDIR}/chains/OCSPD" echo "httpserv -D -p ${NSS_AIA_PORT} ${SERVER_OPTIONS} \\" echo " -A OCSPRoot -C ${ODDIR}/OCSPRoot.crl -A OCSPCA1 -C ${ODDIR}/OCSPCA1.crl \\" echo " -A OCSPCA2 -C ${ODDIR}/OCSPCA2.crl -A OCSPCA3 -C ${ODDIR}/OCSPCA3.crl \\" echo " -O ${HTTP_METHOD} -d ${ODDIR}/ServerDB/ -f ${ODDIR}/ServerDB/dbpasswd \\" echo " -i ${HTTPPID} $verbose &" ${PROFTOOL} ${BINDIR}/httpserv -D -p ${NSS_AIA_PORT} ${SERVER_OPTIONS} \ -A OCSPRoot -C ${ODDIR}/OCSPRoot.crl -A OCSPCA1 -C ${ODDIR}/OCSPCA1.crl \ -A OCSPCA2 -C ${ODDIR}/OCSPCA2.crl -A OCSPCA3 -C ${ODDIR}/OCSPCA3.crl \ -O ${HTTP_METHOD} -d ${ODDIR}/ServerDB/ -f ${ODDIR}/ServerDB/dbpasswd \ -i ${HTTPPID} $verbose & RET=$? # The PID $! returned by the MKS or Cygwin shell is not the PID of # the real background process, but rather the PID of a helper # process (sh.exe). MKS's kill command has a bug: invoking kill # on the helper process does not terminate the real background # process. Our workaround has been to have httpserv save its PID # in the ${HTTPPID} file and "kill" that PID instead. But this # doesn't work under Cygwin; its kill command doesn't recognize # the PID of the real background process, but it does work on the # PID of the helper process. So we save the value of $! in the # SHELL_HTTPPID variable, and use it instead of the ${HTTPPID} # file under Cygwin. (In fact, this should work in any shell # other than the MKS shell.) SHELL_HTTPPID=$! wait_for_httpserv if [ "${OS_ARCH}" = "WINNT" ] && \ [ "$OS_NAME" = "CYGWIN_NT" -o "$OS_NAME" = "MINGW32_NT" ]; then PID=${SHELL_HTTPPID} else PID=`cat ${HTTPPID}` fi echo "httpserv with PID ${PID} started at `date`" } ############################# chains_init ############################## # local shell function to initialize this script ######################################################################## chains_init() { if [ -z "${CLEANUP}" ] ; then # if nobody else is responsible for CLEANUP="${SCRIPTNAME}" # cleaning this script will do it fi if [ -z "${INIT_SOURCED}" ] ; then cd ../common . ./init.sh fi SCRIPTNAME="chains.sh" CHAINS_DIR="${HOSTDIR}/chains" mkdir -p ${CHAINS_DIR} cd ${CHAINS_DIR} CHAINS_SCENARIOS="${QADIR}/chains/scenarios/scenarios" CERT_SN_CNT=$(date '+%m%d%H%M%S' | sed "s/^0*//") CERT_SN_FIX=$(expr ${CERT_SN_CNT} - 1000) PK7_NONCE=${CERT_SN_CNT} SCEN_CNT=${CERT_SN_CNT} AIA_FILES="${HOSTDIR}/aiafiles" CU_DATA=${HOSTDIR}/cu_data CRL_DATA=${HOSTDIR}/crl_data DEFAULT_AIA_BASE_PORT=$(expr ${PORT:-8631} + 10) NSS_AIA_PORT=${NSS_AIA_PORT:-$DEFAULT_AIA_BASE_PORT} DEFAULT_UNUSED_PORT=$(expr ${PORT:-8631} + 11) NSS_UNUSED_PORT=${NSS_UNUSED_PORT:-$DEFAULT_UNUSED_PORT} NSS_AIA_HTTP=${NSS_AIA_HTTP:-"http://${HOSTADDR}:${NSS_AIA_PORT}"} NSS_AIA_PATH=${NSS_AIA_PATH:-$HOSTDIR/aiahttp} NSS_AIA_OCSP=${NSS_AIA_OCSP:-$NSS_AIA_HTTP/ocsp} NSS_OCSP_UNUSED=${NSS_AIA_OCSP_UNUSED:-"http://${HOSTADDR}:${NSS_UNUSED_PORT}"} html_head "Certificate Chains Tests" } chains_run_httpserv() { HTTP_METHOD=$1 if [ -n "${NSS_AIA_PATH}" ]; then HTTPPID=${NSS_AIA_PATH}/http_pid.$$ mkdir -p "${NSS_AIA_PATH}" SAVEPWD=`pwd` cd "${NSS_AIA_PATH}" # Start_httpserv sets environment variables, which are required for # correct cleanup. (Running it in a subshell doesn't work, the # value of $SHELL_HTTPPID wouldn't arrive in this scope.) start_httpserv ${HTTP_METHOD} cd "${SAVEPWD}" fi } chains_stop_httpserv() { if [ -n "${NSS_AIA_PATH}" ]; then kill_httpserv fi } ############################ chains_cleanup ############################ # local shell function to finish this script (no exit since it might be # sourced) ######################################################################## chains_cleanup() { html "
" cd ${QADIR} . common/cleanup.sh } ############################ print_cu_data ############################# # local shell function to print certutil input data ######################################################################## print_cu_data() { echo "=== Certutil input data ===" cat ${CU_DATA} echo "===" } set_cert_sn() { if [ -z "${SERIAL}" ]; then CERT_SN_CNT=$(expr ${CERT_SN_CNT} + 1) CERT_SN=${CERT_SN_CNT} else echo ${SERIAL} | cut -b 1 | grep '+' > /dev/null if [ $? -eq 0 ]; then CERT_SN=$(echo ${SERIAL} | cut -b 2-) CERT_SN=$(expr ${CERT_SN_FIX} + ${CERT_SN}) else CERT_SN=${SERIAL} fi fi } ############################# create_db ################################ # local shell function to create certificate database ######################################################################## create_db() { DB=$1 [ -d "${DB}" ] && rm -rf ${DB} mkdir -p ${DB} echo "${DB}passwd" > ${DB}/dbpasswd TESTNAME="Creating DB ${DB}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -N -d ${DB} -f ${DB}/dbpasswd" ${BINDIR}/certutil -N -d ${DB} -f ${DB}/dbpasswd html_msg $? 0 "${SCENARIO}${TESTNAME}" } ########################### create_root_ca ############################# # local shell function to generate self-signed root certificate ######################################################################## create_root_ca() { ENTITY=$1 ENTITY_DB=${ENTITY}DB set_cert_sn date >> ${NOISE_FILE} 2>&1 CTYPE_OPT= if [ -n "${CTYPE}" ]; then CTYPE_OPT="-k ${CTYPE}" fi echo "5 6 9 n y -1 n 5 6 7 9 n " > ${CU_DATA} TESTNAME="Creating Root CA ${ENTITY}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -s \"CN=${ENTITY} ROOT CA, O=${ENTITY}, C=US\" -S -n ${ENTITY} ${CTYPE_OPT} -t CTu,CTu,CTu -v 600 -x -d ${ENTITY_DB} -1 -2 -5 -f ${ENTITY_DB}/dbpasswd -z ${NOISE_FILE} -m ${CERT_SN} < ${CU_DATA}" print_cu_data ${BINDIR}/certutil -s "CN=${ENTITY} ROOT CA, O=${ENTITY}, C=US" -S -n ${ENTITY} ${CTYPE_OPT} -t CTu,CTu,CTu -v 600 -x -d ${ENTITY_DB} -1 -2 -5 -f ${ENTITY_DB}/dbpasswd -z ${NOISE_FILE} -m ${CERT_SN} < ${CU_DATA} html_msg $? 0 "${SCENARIO}${TESTNAME}" TESTNAME="Exporting Root CA ${ENTITY}.der" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -L -d ${ENTITY_DB} -r -n ${ENTITY} -o ${ENTITY}.der" ${BINDIR}/certutil -L -d ${ENTITY_DB} -r -n ${ENTITY} -o ${ENTITY}.der html_msg $? 0 "${SCENARIO}${TESTNAME}" } ########################### create_cert_req ############################ # local shell function to generate certificate sign request ######################################################################## create_cert_req() { ENTITY=$1 TYPE=$2 ENTITY_DB=${ENTITY}DB REQ=${ENTITY}Req.der date >> ${NOISE_FILE} 2>&1 CTYPE_OPT= if [ -n "${CTYPE}" ]; then CTYPE_OPT="-k ${CTYPE}" fi CA_FLAG= EXT_DATA= OPTIONS= if [ "${TYPE}" != "EE" ]; then CA_FLAG="-2" EXT_DATA="y -1 y " fi process_crldp echo "${EXT_DATA}" > ${CU_DATA} TESTNAME="Creating ${TYPE} certifiate request ${REQ}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -s \"CN=${ENTITY} ${TYPE}, O=${ENTITY}, C=US\" ${CTYPE_OPT} -R ${CA_FLAG} -d ${ENTITY_DB} -f ${ENTITY_DB}/dbpasswd -z ${NOISE_FILE} -o ${REQ} ${OPTIONS} < ${CU_DATA}" print_cu_data ${BINDIR}/certutil -s "CN=${ENTITY} ${TYPE}, O=${ENTITY}, C=US" ${CTYPE_OPT} -R ${CA_FLAG} -d ${ENTITY_DB} -f ${ENTITY_DB}/dbpasswd -z ${NOISE_FILE} -o ${REQ} ${OPTIONS} < ${CU_DATA} html_msg $? 0 "${SCENARIO}${TESTNAME}" } ############################ create_entity ############################# # local shell function to create certificate chain entity ######################################################################## create_entity() { ENTITY=$1 TYPE=$2 if [ -z "${ENTITY}" ]; then echo "Configuration error: Unnamed entity" exit 1 fi DB=${ENTITY}DB ENTITY_DB=${ENTITY}DB case "${TYPE}" in "Root") create_db "${DB}" create_root_ca "${ENTITY}" ;; "Intermediate" | "Bridge" | "EE") create_db "${DB}" create_cert_req "${ENTITY}" "${TYPE}" ;; "*") echo "Configuration error: Unknown type ${TYPE}" exit 1 ;; esac } ######################################################################## # List of global variables related to certificate extensions processing: # # Generated by process_extensions and functions called from it: # OPTIONS - list of command line policy extensions # DATA - list of inpud data related to policy extensions # # Generated by parse_config: # POLICY - list of certificate policies # MAPPING - list of policy mappings # INHIBIT - inhibit flag # AIA - AIA list ######################################################################## ############################ process_policy ############################ # local shell function to process policy extension parameters and # generate input for certutil ######################################################################## process_policy() { if [ -n "${POLICY}" ]; then OPTIONS="${OPTIONS} --extCP" NEXT= for ITEM in ${POLICY}; do if [ -n "${NEXT}" ]; then DATA="${DATA}y " fi NEXT=1 DATA="${DATA}${ITEM} 1 n " done DATA="${DATA}n n " fi } ########################### process_mapping ############################ # local shell function to process policy mapping parameters and # generate input for certutil ######################################################################## process_mapping() { if [ -n "${MAPPING}" ]; then OPTIONS="${OPTIONS} --extPM" NEXT= for ITEM in ${MAPPING}; do if [ -n "${NEXT}" ]; then DATA="${DATA}y " fi NEXT=1 IDP=`echo ${ITEM} | cut -d: -f1` SDP=`echo ${ITEM} | cut -d: -f2` DATA="${DATA}${IDP} ${SDP} " done DATA="${DATA}n n " fi } ########################### process_inhibit############################# # local shell function to process inhibit extension and generate input # for certutil ######################################################################## process_inhibit() { if [ -n "${INHIBIT}" ]; then OPTIONS="${OPTIONS} --extIA" DATA="${DATA}${INHIBIT} n " fi } ############################# process_aia ############################## # local shell function to process AIA extension parameters and # generate input for certutil ######################################################################## process_aia() { if [ -n "${AIA}" ]; then OPTIONS="${OPTIONS} --extAIA" DATA="${DATA}1 " for ITEM in ${AIA}; do PK7_NONCE=`expr $PK7_NONCE + 1` echo ${ITEM} | grep ":" > /dev/null if [ $? -eq 0 ]; then CERT_NICK=`echo ${ITEM} | cut -d: -f1` CERT_ISSUER=`echo ${ITEM} | cut -d: -f2` CERT_LOCAL="${CERT_NICK}${CERT_ISSUER}.der" CERT_PUBLIC="${HOST}-$$-${CERT_NICK}${CERT_ISSUER}-${PK7_NONCE}.der" else CERT_LOCAL="${ITEM}.p7" CERT_PUBLIC="${HOST}-$$-${ITEM}-${PK7_NONCE}.p7" fi DATA="${DATA}7 ${NSS_AIA_HTTP}/${CERT_PUBLIC} " if [ -n "${NSS_AIA_PATH}" ]; then cp ${CERT_LOCAL} ${NSS_AIA_PATH}/${CERT_PUBLIC} 2> /dev/null chmod a+r ${NSS_AIA_PATH}/${CERT_PUBLIC} echo ${NSS_AIA_PATH}/${CERT_PUBLIC} >> ${AIA_FILES} fi done DATA="${DATA}0 n n" fi } process_ocsp() { if [ -n "${OCSP}" ]; then OPTIONS="${OPTIONS} --extAIA" if [ "${OCSP}" = "offline" ]; then MY_OCSP_URL=${NSS_OCSP_UNUSED} else MY_OCSP_URL=${NSS_AIA_OCSP} fi DATA="${DATA}2 7 ${MY_OCSP_URL} 0 n n " fi } process_crldp() { if [ -n "${CRLDP}" ]; then OPTIONS="${OPTIONS} -4" EXT_DATA="${EXT_DATA}1 " for ITEM in ${CRLDP}; do CRL_PUBLIC="${HOST}-$$-${ITEM}-${SCEN_CNT}.crl" EXT_DATA="${EXT_DATA}7 ${NSS_AIA_HTTP}/${CRL_PUBLIC} " done EXT_DATA="${EXT_DATA}-1 -1 -1 n n " fi } process_ku_ns_eku() { if [ -n "${EXT_KU}" ]; then OPTIONS="${OPTIONS} --keyUsage ${EXT_KU}" fi if [ -n "${EXT_NS}" ]; then EXT_NS_KEY=$(echo ${EXT_NS} | cut -d: -f1) EXT_NS_CODE=$(echo ${EXT_NS} | cut -d: -f2) OPTIONS="${OPTIONS} --nsCertType ${EXT_NS_KEY}" DATA="${DATA}${EXT_NS_CODE} -1 n " fi if [ -n "${EXT_EKU}" ]; then OPTIONS="${OPTIONS} --extKeyUsage ${EXT_EKU}" fi } copy_crl() { if [ -z "${NSS_AIA_PATH}" ]; then return; fi CRL_LOCAL="${COPYCRL}.crl" CRL_PUBLIC="${HOST}-$$-${COPYCRL}-${SCEN_CNT}.crl" cp ${CRL_LOCAL} ${NSS_AIA_PATH}/${CRL_PUBLIC} 2> /dev/null chmod a+r ${NSS_AIA_PATH}/${CRL_PUBLIC} echo ${NSS_AIA_PATH}/${CRL_PUBLIC} >> ${AIA_FILES} } ########################## process_extension ########################### # local shell function to process entity extension parameters and # generate input for certutil ######################################################################## process_extensions() { OPTIONS= DATA= process_policy process_mapping process_inhibit process_aia process_ocsp process_ku_ns_eku } ############################## sign_cert ############################### # local shell function to sign certificate sign reuqest ######################################################################## sign_cert() { ENTITY=$1 ISSUER=$2 TYPE=$3 [ -z "${ISSUER}" ] && return ENTITY_DB=${ENTITY}DB ISSUER_DB=${ISSUER}DB REQ=${ENTITY}Req.der CERT=${ENTITY}${ISSUER}.der set_cert_sn EMAIL_OPT= if [ "${TYPE}" = "Bridge" ]; then EMAIL_OPT="-7 ${ENTITY}@${ISSUER}" [ -n "${EMAILS}" ] && EMAILS="${EMAILS}," EMAILS="${EMAILS}${ENTITY}@${ISSUER}" fi process_extensions echo "${DATA}" > ${CU_DATA} TESTNAME="Creating certficate ${CERT} signed by ${ISSUER}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -C -c ${ISSUER} -v 60 -d ${ISSUER_DB} -i ${REQ} -o ${CERT} -f ${ISSUER_DB}/dbpasswd -m ${CERT_SN} ${EMAIL_OPT} ${OPTIONS} < ${CU_DATA}" print_cu_data ${BINDIR}/certutil -C -c ${ISSUER} -v 60 -d ${ISSUER_DB} -i ${REQ} -o ${CERT} -f ${ISSUER_DB}/dbpasswd -m ${CERT_SN} ${EMAIL_OPT} ${OPTIONS} < ${CU_DATA} html_msg $? 0 "${SCENARIO}${TESTNAME}" TESTNAME="Importing certificate ${CERT} to ${ENTITY_DB} database" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -A -n ${ENTITY} -t u,u,u -d ${ENTITY_DB} -f ${ENTITY_DB}/dbpasswd -i ${CERT}" ${BINDIR}/certutil -A -n ${ENTITY} -t u,u,u -d ${ENTITY_DB} -f ${ENTITY_DB}/dbpasswd -i ${CERT} html_msg $? 0 "${SCENARIO}${TESTNAME}" } ############################# create_pkcs7############################## # local shell function to package bridge certificates into pkcs7 # package ######################################################################## create_pkcs7() { ENTITY=$1 ENTITY_DB=${ENTITY}DB TESTNAME="Generating PKCS7 package from ${ENTITY_DB} database" echo "${SCRIPTNAME}: ${TESTNAME}" echo "cmsutil -O -r \"${EMAILS}\" -d ${ENTITY_DB} > ${ENTITY}.p7" ${BINDIR}/cmsutil -O -r "${EMAILS}" -d ${ENTITY_DB} > ${ENTITY}.p7 html_msg $? 0 "${SCENARIO}${TESTNAME}" } ############################# import_key ############################### # local shell function to import private key + cert into database ######################################################################## import_key() { KEY_NAME=$1.p12 DB=$2 KEY_FILE=../OCSPD/${KEY_NAME} TESTNAME="Importing p12 key ${KEY_NAME} to ${DB} database" echo "${SCRIPTNAME}: ${TESTNAME}" echo "${BINDIR}/pk12util -d ${DB} -i ${KEY_FILE} -k ${DB}/dbpasswd -W nssnss" ${BINDIR}/pk12util -d ${DB} -i ${KEY_FILE} -k ${DB}/dbpasswd -W nssnss html_msg $? 0 "${SCENARIO}${TESTNAME}" } export_key() { KEY_NAME=$1.p12 DB=$2 TESTNAME="Exporting $1 as ${KEY_NAME} from ${DB} database" echo "${SCRIPTNAME}: ${TESTNAME}" echo "${BINDIR}/pk12util -d ${DB} -o ${KEY_NAME} -n $1 -k ${DB}/dbpasswd -W nssnss" ${BINDIR}/pk12util -d ${DB} -o ${KEY_NAME} -n $1 -k ${DB}/dbpasswd -W nssnss html_msg $? 0 "${SCENARIO}${TESTNAME}" } ############################# import_cert ############################## # local shell function to import certificate into database ######################################################################## import_cert() { IMPORT=$1 DB=$2 CERT_NICK=`echo ${IMPORT} | cut -d: -f1` CERT_ISSUER=`echo ${IMPORT} | cut -d: -f2` CERT_TRUST=`echo ${IMPORT} | cut -d: -f3` if [ "${CERT_ISSUER}" = "x" ]; then CERT_ISSUER= CERT=${CERT_NICK}.cert CERT_FILE="${QADIR}/libpkix/certs/${CERT}" elif [ "${CERT_ISSUER}" = "d" ]; then CERT_ISSUER= CERT=${CERT_NICK}.der CERT_FILE="../OCSPD/${CERT}" else CERT=${CERT_NICK}${CERT_ISSUER}.der CERT_FILE=${CERT} fi IS_ASCII=`grep -c -- "-----BEGIN CERTIFICATE-----" ${CERT_FILE}` ASCII_OPT= if [ "${IS_ASCII}" -gt 0 ]; then ASCII_OPT="-a" fi TESTNAME="Importing certificate ${CERT} to ${DB} database" echo "${SCRIPTNAME}: ${TESTNAME}" echo "certutil -A -n ${CERT_NICK} ${ASCII_OPT} -t \"${CERT_TRUST}\" -d ${DB} -f ${DB}/dbpasswd -i ${CERT_FILE}" ${BINDIR}/certutil -A -n ${CERT_NICK} ${ASCII_OPT} -t "${CERT_TRUST}" -d ${DB} -f ${DB}/dbpasswd -i ${CERT_FILE} html_msg $? 0 "${SCENARIO}${TESTNAME}" } import_crl() { IMPORT=$1 DB=$2 CRL_NICK=`echo ${IMPORT} | cut -d: -f1` CRL_FILE=${CRL_NICK}.crl if [ ! -f "${CRL_FILE}" ]; then return fi TESTNAME="Importing CRL ${CRL_FILE} to ${DB} database" echo "${SCRIPTNAME}: ${TESTNAME}" echo "crlutil -I -d ${DB} -f ${DB}/dbpasswd -i ${CRL_FILE}" ${BINDIR}/crlutil -I -d ${DB} -f ${DB}/dbpasswd -i ${CRL_FILE} html_msg $? 0 "${SCENARIO}${TESTNAME}" } create_crl() { ISSUER=$1 ISSUER_DB=${ISSUER}DB CRL=${ISSUER}.crl DATE=$(date -u '+%Y%m%d%H%M%SZ') DATE_LAST="${DATE}" UPDATE=$(expr $(date -u '+%Y') + 1)$(date -u '+%m%d%H%M%SZ') echo "update=${DATE}" > ${CRL_DATA} echo "nextupdate=${UPDATE}" >> ${CRL_DATA} TESTNAME="Create CRL for ${ISSUER_DB}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "crlutil -G -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL}" echo "=== Crlutil input data ===" cat ${CRL_DATA} echo "===" ${BINDIR}/crlutil -G -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL} < ${CRL_DATA} html_msg $? 0 "${SCENARIO}${TESTNAME}" } revoke_cert() { ISSUER=$1 ISSUER_DB=${ISSUER}DB CRL=${ISSUER}.crl set_cert_sn DATE=$(date -u '+%Y%m%d%H%M%SZ') while [ "${DATE}" = "${DATE_LAST}" ]; do sleep 1 DATE=$(date -u '+%Y%m%d%H%M%SZ') done DATE_LAST="${DATE}" echo "update=${DATE}" > ${CRL_DATA} echo "addcert ${CERT_SN} ${DATE}" >> ${CRL_DATA} TESTNAME="Revoking certificate with SN ${CERT_SN} issued by ${ISSUER}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "crlutil -M -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL}" echo "=== Crlutil input data ===" cat ${CRL_DATA} echo "===" ${BINDIR}/crlutil -M -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL} < ${CRL_DATA} html_msg $? 0 "${SCENARIO}${TESTNAME}" } ######################################################################## # List of global variables related to certificate verification: # # Generated by parse_config: # DB - DB used for testing # FETCH - fetch flag (used with AIA extension) # POLICY - list of policies # TRUST - trust anchor # TRUST_AND_DB - Examine both trust anchors and the cert db for trust # VERIFY - list of certificates to use as vfychain parameters # EXP_RESULT - expected result # REV_OPTS - revocation options ######################################################################## ############################# verify_cert ############################## # local shell function to verify certificate validity ######################################################################## verify_cert() { ENGINE=$1 DB_OPT= FETCH_OPT= POLICY_OPT= TRUST_OPT= VFY_CERTS= VFY_LIST= TRUST_AND_DB_OPT= if [ -n "${DB}" ]; then DB_OPT="-d ${DB}" fi if [ -n "${FETCH}" ]; then FETCH_OPT="-f" if [ -z "${NSS_AIA_HTTP}" ]; then echo "${SCRIPTNAME} Skipping test using AIA fetching, NSS_AIA_HTTP not defined" return fi fi if [ -n "${TRUST_AND_DB}" ]; then TRUST_AND_DB_OPT="-T" fi for ITEM in ${POLICY}; do POLICY_OPT="${POLICY_OPT} -o ${ITEM}" done for ITEM in ${TRUST}; do echo ${ITEM} | grep ":" > /dev/null if [ $? -eq 0 ]; then CERT_NICK=`echo ${ITEM} | cut -d: -f1` CERT_ISSUER=`echo ${ITEM} | cut -d: -f2` CERT=${CERT_NICK}${CERT_ISSUER}.der TRUST_OPT="${TRUST_OPT} -t ${CERT}" else TRUST_OPT="${TRUST_OPT} -t ${ITEM}" fi done for ITEM in ${VERIFY}; do CERT_NICK=`echo ${ITEM} | cut -d: -f1` CERT_ISSUER=`echo ${ITEM} | cut -d: -f2` if [ "${CERT_ISSUER}" = "x" ]; then CERT="${QADIR}/libpkix/certs/${CERT_NICK}.cert" VFY_CERTS="${VFY_CERTS} ${CERT}" VFY_LIST="${VFY_LIST} ${CERT_NICK}.cert" elif [ "${CERT_ISSUER}" = "d" ]; then CERT="../OCSPD/${CERT_NICK}.der" VFY_CERTS="${VFY_CERTS} ${CERT}" VFY_LIST="${VFY_LIST} ${CERT_NICK}.cert" else CERT=${CERT_NICK}${CERT_ISSUER}.der VFY_CERTS="${VFY_CERTS} ${CERT}" VFY_LIST="${VFY_LIST} ${CERT}" fi done VFY_OPTS_TNAME="${DB_OPT} ${ENGINE} ${TRUST_AND_DB_OPT} ${REV_OPTS} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${TRUST_OPT}" VFY_OPTS_ALL="${DB_OPT} ${ENGINE} -vv ${TRUST_AND_DB_OPT} ${REV_OPTS} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${VFY_CERTS} ${TRUST_OPT}" TESTNAME="Verifying certificate(s) ${VFY_LIST} with flags ${VFY_OPTS_TNAME}" echo "${SCRIPTNAME}: ${TESTNAME}" echo "vfychain ${VFY_OPTS_ALL}" if [ -z "${MEMLEAK_DBG}" ]; then VFY_OUT=$(${BINDIR}/vfychain ${VFY_OPTS_ALL} 2>&1) RESULT=$? echo "${VFY_OUT}" else VFY_OUT=$(${RUN_COMMAND_DBG} ${BINDIR}/vfychain ${VFY_OPTS_ALL} 2>> ${LOGFILE}) RESULT=$? echo "${VFY_OUT}" fi echo "${VFY_OUT}" | grep "ERROR -5990: I/O operation timed out" > /dev/null E5990=$? echo "${VFY_OUT}" | grep "ERROR -8030: Server returned bad HTTP response" > /dev/null E8030=$? if [ $E5990 -eq 0 -o $E8030 -eq 0 ]; then echo "Result of this test is not valid due to network time out." html_unknown "${SCENARIO}${TESTNAME}" return fi echo "Returned value is ${RESULT}, expected result is ${EXP_RESULT}" if [ "${EXP_RESULT}" = "pass" -a ${RESULT} -eq 0 ]; then html_passed "${SCENARIO}${TESTNAME}" elif [ "${EXP_RESULT}" = "fail" -a ${RESULT} -ne 0 ]; then html_passed "${SCENARIO}${TESTNAME}" else html_failed "${SCENARIO}${TESTNAME}" fi } check_ocsp() { OCSP_CERT=$1 CERT_NICK=`echo ${OCSP_CERT} | cut -d: -f1` CERT_ISSUER=`echo ${OCSP_CERT} | cut -d: -f2` if [ "${CERT_ISSUER}" = "x" ]; then CERT_ISSUER= CERT=${CERT_NICK}.cert CERT_FILE="${QADIR}/libpkix/certs/${CERT}" elif [ "${CERT_ISSUER}" = "d" ]; then CERT_ISSUER= CERT=${CERT_NICK}.der CERT_FILE="../OCSPD/${CERT}" else CERT=${CERT_NICK}${CERT_ISSUER}.der CERT_FILE=${CERT} fi # sample line: # URI: "http://ocsp.server:2601" OCSP_HOST=$(${BINDIR}/pp -w -t certificate -i ${CERT_FILE} | grep URI | sed "s/.*:\/\///" | sed "s/:.*//") OCSP_PORT=$(${BINDIR}/pp -w -t certificate -i ${CERT_FILE} | grep URI | sed "s/^.*:.*:\/\/.*:\([0-9]*\).*$/\1/") echo "tstclnt -h ${OCSP_HOST} -p ${OCSP_PORT} -q -t 20" tstclnt -h ${OCSP_HOST} -p ${OCSP_PORT} -q -t 20 return $? } ############################ parse_result ############################## # local shell function to process expected result value # this function was created for case that expected result depends on # some conditions - in our case type of cert DB # # default results are pass and fail # this function added parsable values in format: # type1:value1 type2:value2 .... typex:valuex # # allowed types are dbm, sql, all (all means all other cases) # allowed values are pass and fail # # if this format is not used, EXP_RESULT will stay unchanged (this also # covers pass and fail states) ######################################################################## parse_result() { for RES in ${EXP_RESULT} do RESTYPE=$(echo ${RES} | cut -d: -f1) RESSTAT=$(echo ${RES} | cut -d: -f2) if [ "${RESTYPE}" = "${NSS_DEFAULT_DB_TYPE}" -o "${RESTYPE}" = "all" ]; then EXP_RESULT=${RESSTAT} break fi done } ############################ parse_config ############################## # local shell function to parse and process file containing certificate # chain configuration and list of tests ######################################################################## parse_config() { SCENARIO= LOGNAME= while read KEY VALUE do case "${KEY}" in "entity") ENTITY="${VALUE}" TYPE= ISSUER= CTYPE= POLICY= MAPPING= INHIBIT= AIA= CRLDP= OCSP= DB= EMAILS= EXT_KU= EXT_NS= EXT_EKU= SERIAL= EXPORT_KEY= ;; "type") TYPE="${VALUE}" ;; "issuer") if [ -n "${ISSUER}" ]; then if [ -z "${DB}" ]; then create_entity "${ENTITY}" "${TYPE}" fi sign_cert "${ENTITY}" "${ISSUER}" "${TYPE}" fi ISSUER="${VALUE}" POLICY= MAPPING= INHIBIT= AIA= EXT_KU= EXT_NS= EXT_EKU= ;; "ctype") CTYPE="${VALUE}" ;; "policy") POLICY="${POLICY} ${VALUE}" ;; "mapping") MAPPING="${MAPPING} ${VALUE}" ;; "inhibit") INHIBIT="${VALUE}" ;; "aia") AIA="${AIA} ${VALUE}" ;; "crldp") CRLDP="${CRLDP} ${VALUE}" ;; "ocsp") OCSP="${VALUE}" ;; "db") DB="${VALUE}DB" create_db "${DB}" ;; "import") IMPORT="${VALUE}" import_cert "${IMPORT}" "${DB}" import_crl "${IMPORT}" "${DB}" ;; "import_key") IMPORT="${VALUE}" import_key "${IMPORT}" "${DB}" ;; "crl") ISSUER="${VALUE}" create_crl "${ISSUER}" ;; "revoke") REVOKE="${VALUE}" ;; "serial") SERIAL="${VALUE}" ;; "export_key") EXPORT_KEY=1 ;; "copycrl") COPYCRL="${VALUE}" copy_crl "${COPYCRL}" ;; "verify") VERIFY="${VALUE}" TRUST= TRUST_AND_DB= POLICY= FETCH= EXP_RESULT= REV_OPTS= USAGE_OPT= ;; "cert") VERIFY="${VERIFY} ${VALUE}" ;; "testdb") if [ -n "${VALUE}" ]; then DB="${VALUE}DB" else DB= fi ;; "trust") TRUST="${TRUST} ${VALUE}" ;; "trust_and_db") TRUST_AND_DB=1 ;; "fetch") FETCH=1 ;; "result") EXP_RESULT="${VALUE}" parse_result ;; "rev_type") REV_OPTS="${REV_OPTS} -g ${VALUE}" ;; "rev_flags") REV_OPTS="${REV_OPTS} -h ${VALUE}" ;; "rev_mtype") REV_OPTS="${REV_OPTS} -m ${VALUE}" ;; "rev_mflags") REV_OPTS="${REV_OPTS} -s ${VALUE}" ;; "scenario") SCENARIO="${VALUE}: " CHAINS_DIR="${HOSTDIR}/chains/${VALUE}" mkdir -p ${CHAINS_DIR} cd ${CHAINS_DIR} if [ -n "${MEMLEAK_DBG}" ]; then LOGNAME="libpkix-${VALUE}" LOGFILE="${LOGDIR}/${LOGNAME}" fi SCEN_CNT=$(expr ${SCEN_CNT} + 1) ;; "sleep") sleep ${VALUE} ;; "break") break ;; "check_ocsp") TESTNAME="Test that OCSP server is reachable" check_ocsp ${VALUE} if [ $? -ne 0 ]; then html_failed "$TESTNAME" break; else html_passed "$TESTNAME" fi ;; "ku") EXT_KU="${VALUE}" ;; "ns") EXT_NS="${VALUE}" ;; "eku") EXT_EKU="${VALUE}" ;; "usage") USAGE_OPT="-u ${VALUE}" ;; "") if [ -n "${ENTITY}" ]; then if [ -z "${DB}" ]; then create_entity "${ENTITY}" "${TYPE}" fi sign_cert "${ENTITY}" "${ISSUER}" "${TYPE}" if [ "${TYPE}" = "Bridge" ]; then create_pkcs7 "${ENTITY}" fi if [ -n "${EXPORT_KEY}" ]; then export_key "${ENTITY}" "${DB}" fi ENTITY= fi if [ -n "${VERIFY}" ]; then verify_cert "-pp" if [ -n "${VERIFY_CLASSIC_ENGINE_TOO}" ]; then verify_cert "" verify_cert "-p" fi VERIFY= fi if [ -n "${REVOKE}" ]; then revoke_cert "${REVOKE}" "${DB}" REVOKE= fi ;; *) if [ `echo ${KEY} | cut -b 1` != "#" ]; then echo "Configuration error: Unknown keyword ${KEY}" exit 1 fi ;; esac done if [ -n "${MEMLEAK_DBG}" ]; then log_parse html_msg $? 0 "${SCENARIO}Memory leak checking" fi } process_scenario() { SCENARIO_FILE=$1 > ${AIA_FILES} parse_config < "${QADIR}/chains/scenarios/${SCENARIO_FILE}" while read AIA_FILE do rm ${AIA_FILE} 2> /dev/null done < ${AIA_FILES} rm ${AIA_FILES} } # process ocspd.cfg separately chains_ocspd() { process_scenario "ocspd.cfg" } # process ocsp.cfg separately chains_method() { process_scenario "method.cfg" } ############################# chains_main ############################## # local shell function to process all testing scenarios ######################################################################## chains_main() { while read LINE do [ `echo ${LINE} | cut -b 1` != "#" ] || continue [ ${LINE} != 'ocspd.cfg' ] || continue [ ${LINE} != 'method.cfg' ] || continue process_scenario ${LINE} done < "${CHAINS_SCENARIOS}" } ################################ main ################################## chains_init VERIFY_CLASSIC_ENGINE_TOO= chains_ocspd VERIFY_CLASSIC_ENGINE_TOO=1 chains_run_httpserv get chains_method chains_stop_httpserv chains_run_httpserv post chains_method chains_stop_httpserv VERIFY_CLASSIC_ENGINE_TOO= chains_run_httpserv random chains_main chains_stop_httpserv chains_run_httpserv get-unknown chains_main chains_stop_httpserv chains_cleanup