diff options
Diffstat (limited to 'security/nss/tests/chains/chains.sh')
-rwxr-xr-x | security/nss/tests/chains/chains.sh | 1308 |
1 files changed, 1308 insertions, 0 deletions
diff --git a/security/nss/tests/chains/chains.sh b/security/nss/tests/chains/chains.sh new file mode 100755 index 000000000..4c3fa57a0 --- /dev/null +++ b/security/nss/tests/chains/chains.sh @@ -0,0 +1,1308 @@ +#!/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 "</TABLE><BR>" + 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}" ] && \ + [ -z "$NSS_DISABLE_LIBPKIX" ]; then + verify_cert "-pp" + if [ -n "${VERIFY_CLASSIC_ENGINE_TOO}" ] && \ + [ -z "$NSS_DISABLE_LIBPKIX" ]; 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 |