Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 #!/bin/bash
2 #
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 ########################################################################
8 #
9 # mozilla/security/nss/tests/cert/chains.sh
10 #
11 # Script to test certificate chains validity.
12 #
13 # needs to work on all Unix and Windows platforms
14 #
15 # special strings
16 # ---------------
17 # FIXME ... known problems, search for this string
18 # NOTE .... unexpected behavior
19 ########################################################################
21 ########################### is_httpserv_alive ##########################
22 # local shell function to exit with a fatal error if selfserver is not
23 # running
24 ########################################################################
25 is_httpserv_alive()
26 {
27 if [ ! -f "${HTTPPID}" ]; then
28 echo "$SCRIPTNAME: Error - httpserv PID file ${HTTPPID} doesn't exist"
29 sleep 5
30 if [ ! -f "${HTTPPID}" ]; then
31 Exit 9 "Fatal - httpserv pid file ${HTTPPID} does not exist"
32 fi
33 fi
35 if [ "${OS_ARCH}" = "WINNT" ] && \
36 [ "$OS_NAME" = "CYGWIN_NT" -o "$OS_NAME" = "MINGW32_NT" ]; then
37 PID=${SHELL_HTTPPID}
38 else
39 PID=`cat ${HTTPPID}`
40 fi
42 echo "kill -0 ${PID} >/dev/null 2>/dev/null"
43 kill -0 ${PID} >/dev/null 2>/dev/null || Exit 10 "Fatal - httpserv process not detectable"
45 echo "httpserv with PID ${PID} found at `date`"
46 }
48 ########################### wait_for_httpserv ##########################
49 # local shell function to wait until httpserver is running and initialized
50 ########################################################################
51 wait_for_httpserv()
52 {
53 echo "trying to connect to httpserv at `date`"
54 echo "tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v"
55 ${BINDIR}/tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v
56 if [ $? -ne 0 ]; then
57 sleep 5
58 echo "retrying to connect to httpserv at `date`"
59 echo "tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v"
60 ${BINDIR}/tstclnt -p ${NSS_AIA_PORT} -h ${HOSTADDR} -q -v
61 if [ $? -ne 0 ]; then
62 html_failed "Waiting for Server"
63 fi
64 fi
65 is_httpserv_alive
66 }
68 ########################### kill_httpserv ##############################
69 # local shell function to kill the httpserver after the tests are done
70 ########################################################################
71 kill_httpserv()
72 {
73 if [ "${OS_ARCH}" = "WINNT" ] && \
74 [ "$OS_NAME" = "CYGWIN_NT" -o "$OS_NAME" = "MINGW32_NT" ]; then
75 PID=${SHELL_HTTPPID}
76 else
77 PID=`cat ${HTTPPID}`
78 fi
80 echo "trying to kill httpserv with PID ${PID} at `date`"
82 if [ "${OS_ARCH}" = "WINNT" -o "${OS_ARCH}" = "WIN95" -o "${OS_ARCH}" = "OS2" ]; then
83 echo "${KILL} ${PID}"
84 ${KILL} ${PID}
85 else
86 echo "${KILL} -USR1 ${PID}"
87 ${KILL} -USR1 ${PID}
88 fi
89 wait ${PID}
91 # On Linux httpserv needs up to 30 seconds to fully die and free
92 # the port. Wait until the port is free. (Bug 129701)
93 if [ "${OS_ARCH}" = "Linux" ]; then
94 echo "httpserv -b -p ${NSS_AIA_PORT} 2>/dev/null;"
95 until ${BINDIR}/httpserv -b -p ${NSS_AIA_PORT} 2>/dev/null; do
96 echo "RETRY: httpserv -b -p ${NSS_AIA_PORT} 2>/dev/null;"
97 sleep 1
98 done
99 fi
101 echo "httpserv with PID ${PID} killed at `date`"
103 rm ${HTTPPID}
104 html_detect_core "kill_httpserv core detection step"
105 }
107 ########################### start_httpserv #############################
108 # local shell function to start the httpserver with the parameters required
109 # for this test and log information (parameters, start time)
110 # also: wait until the server is up and running
111 ########################################################################
112 start_httpserv()
113 {
114 HTTP_METHOD=$1
116 if [ -n "$testname" ] ; then
117 echo "$SCRIPTNAME: $testname ----"
118 fi
119 echo "httpserv starting at `date`"
120 ODDIR="${HOSTDIR}/chains/OCSPD"
121 echo "httpserv -D -p ${NSS_AIA_PORT} ${SERVER_OPTIONS} \\"
122 echo " -A OCSPRoot -C ${ODDIR}/OCSPRoot.crl -A OCSPCA1 -C ${ODDIR}/OCSPCA1.crl \\"
123 echo " -A OCSPCA2 -C ${ODDIR}/OCSPCA2.crl -A OCSPCA3 -C ${ODDIR}/OCSPCA3.crl \\"
124 echo " -O ${HTTP_METHOD} -d ${ODDIR}/ServerDB/ -f ${ODDIR}/ServerDB/dbpasswd \\"
125 echo " -i ${HTTPPID} $verbose &"
126 ${PROFTOOL} ${BINDIR}/httpserv -D -p ${NSS_AIA_PORT} ${SERVER_OPTIONS} \
127 -A OCSPRoot -C ${ODDIR}/OCSPRoot.crl -A OCSPCA1 -C ${ODDIR}/OCSPCA1.crl \
128 -A OCSPCA2 -C ${ODDIR}/OCSPCA2.crl -A OCSPCA3 -C ${ODDIR}/OCSPCA3.crl \
129 -O ${HTTP_METHOD} -d ${ODDIR}/ServerDB/ -f ${ODDIR}/ServerDB/dbpasswd \
130 -i ${HTTPPID} $verbose &
131 RET=$?
133 # The PID $! returned by the MKS or Cygwin shell is not the PID of
134 # the real background process, but rather the PID of a helper
135 # process (sh.exe). MKS's kill command has a bug: invoking kill
136 # on the helper process does not terminate the real background
137 # process. Our workaround has been to have httpserv save its PID
138 # in the ${HTTPPID} file and "kill" that PID instead. But this
139 # doesn't work under Cygwin; its kill command doesn't recognize
140 # the PID of the real background process, but it does work on the
141 # PID of the helper process. So we save the value of $! in the
142 # SHELL_HTTPPID variable, and use it instead of the ${HTTPPID}
143 # file under Cygwin. (In fact, this should work in any shell
144 # other than the MKS shell.)
145 SHELL_HTTPPID=$!
146 wait_for_httpserv
148 if [ "${OS_ARCH}" = "WINNT" ] && \
149 [ "$OS_NAME" = "CYGWIN_NT" -o "$OS_NAME" = "MINGW32_NT" ]; then
150 PID=${SHELL_HTTPPID}
151 else
152 PID=`cat ${HTTPPID}`
153 fi
155 echo "httpserv with PID ${PID} started at `date`"
156 }
158 ############################# chains_init ##############################
159 # local shell function to initialize this script
160 ########################################################################
161 chains_init()
162 {
163 if [ -z "${CLEANUP}" ] ; then # if nobody else is responsible for
164 CLEANUP="${SCRIPTNAME}" # cleaning this script will do it
165 fi
166 if [ -z "${INIT_SOURCED}" ] ; then
167 cd ../common
168 . ./init.sh
169 fi
171 SCRIPTNAME="chains.sh"
173 CHAINS_DIR="${HOSTDIR}/chains"
174 mkdir -p ${CHAINS_DIR}
175 cd ${CHAINS_DIR}
177 CHAINS_SCENARIOS="${QADIR}/chains/scenarios/scenarios"
179 CERT_SN_CNT=$(date '+%m%d%H%M%S' | sed "s/^0*//")
180 CERT_SN_FIX=$(expr ${CERT_SN_CNT} - 1000)
182 PK7_NONCE=${CERT_SN_CNT}
183 SCEN_CNT=${CERT_SN_CNT}
185 AIA_FILES="${HOSTDIR}/aiafiles"
187 CU_DATA=${HOSTDIR}/cu_data
188 CRL_DATA=${HOSTDIR}/crl_data
190 DEFAULT_AIA_BASE_PORT=$(expr ${PORT:-8631} + 10)
191 NSS_AIA_PORT=${NSS_AIA_PORT:-$DEFAULT_AIA_BASE_PORT}
192 DEFAULT_UNUSED_PORT=$(expr ${PORT:-8631} + 11)
193 NSS_UNUSED_PORT=${NSS_UNUSED_PORT:-$DEFAULT_UNUSED_PORT}
194 NSS_AIA_HTTP=${NSS_AIA_HTTP:-"http://${HOSTADDR}:${NSS_AIA_PORT}"}
195 NSS_AIA_PATH=${NSS_AIA_PATH:-$HOSTDIR/aiahttp}
196 NSS_AIA_OCSP=${NSS_AIA_OCSP:-$NSS_AIA_HTTP/ocsp}
197 NSS_OCSP_UNUSED=${NSS_AIA_OCSP_UNUSED:-"http://${HOSTADDR}:${NSS_UNUSED_PORT}"}
199 html_head "Certificate Chains Tests"
200 }
202 chains_run_httpserv()
203 {
204 HTTP_METHOD=$1
206 if [ -n "${NSS_AIA_PATH}" ]; then
207 HTTPPID=${NSS_AIA_PATH}/http_pid.$$
208 mkdir -p "${NSS_AIA_PATH}"
209 SAVEPWD=`pwd`
210 cd "${NSS_AIA_PATH}"
211 # Start_httpserv sets environment variables, which are required for
212 # correct cleanup. (Running it in a subshell doesn't work, the
213 # value of $SHELL_HTTPPID wouldn't arrive in this scope.)
214 start_httpserv ${HTTP_METHOD}
215 cd "${SAVEPWD}"
216 fi
217 }
219 chains_stop_httpserv()
220 {
221 if [ -n "${NSS_AIA_PATH}" ]; then
222 kill_httpserv
223 fi
224 }
226 ############################ chains_cleanup ############################
227 # local shell function to finish this script (no exit since it might be
228 # sourced)
229 ########################################################################
230 chains_cleanup()
231 {
232 html "</TABLE><BR>"
233 cd ${QADIR}
234 . common/cleanup.sh
235 }
237 ############################ print_cu_data #############################
238 # local shell function to print certutil input data
239 ########################################################################
240 print_cu_data()
241 {
242 echo "=== Certutil input data ==="
243 cat ${CU_DATA}
244 echo "==="
245 }
247 set_cert_sn()
248 {
249 if [ -z "${SERIAL}" ]; then
250 CERT_SN_CNT=$(expr ${CERT_SN_CNT} + 1)
251 CERT_SN=${CERT_SN_CNT}
252 else
253 echo ${SERIAL} | cut -b 1 | grep '+' > /dev/null
254 if [ $? -eq 0 ]; then
255 CERT_SN=$(echo ${SERIAL} | cut -b 2-)
256 CERT_SN=$(expr ${CERT_SN_FIX} + ${CERT_SN})
257 else
258 CERT_SN=${SERIAL}
259 fi
260 fi
261 }
263 ############################# create_db ################################
264 # local shell function to create certificate database
265 ########################################################################
266 create_db()
267 {
268 DB=$1
270 [ -d "${DB}" ] && rm -rf ${DB}
271 mkdir -p ${DB}
273 echo "${DB}passwd" > ${DB}/dbpasswd
275 TESTNAME="Creating DB ${DB}"
276 echo "${SCRIPTNAME}: ${TESTNAME}"
277 echo "certutil -N -d ${DB} -f ${DB}/dbpasswd"
278 ${BINDIR}/certutil -N -d ${DB} -f ${DB}/dbpasswd
279 html_msg $? 0 "${SCENARIO}${TESTNAME}"
280 }
282 ########################### create_root_ca #############################
283 # local shell function to generate self-signed root certificate
284 ########################################################################
285 create_root_ca()
286 {
287 ENTITY=$1
288 ENTITY_DB=${ENTITY}DB
290 set_cert_sn
291 date >> ${NOISE_FILE} 2>&1
293 CTYPE_OPT=
294 if [ -n "${CTYPE}" ]; then
295 CTYPE_OPT="-k ${CTYPE}"
296 fi
298 echo "5
299 6
300 9
301 n
302 y
303 -1
304 n
305 5
306 6
307 7
308 9
309 n
310 " > ${CU_DATA}
312 TESTNAME="Creating Root CA ${ENTITY}"
313 echo "${SCRIPTNAME}: ${TESTNAME}"
314 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}"
315 print_cu_data
316 ${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}
317 html_msg $? 0 "${SCENARIO}${TESTNAME}"
319 TESTNAME="Exporting Root CA ${ENTITY}.der"
320 echo "${SCRIPTNAME}: ${TESTNAME}"
321 echo "certutil -L -d ${ENTITY_DB} -r -n ${ENTITY} -o ${ENTITY}.der"
322 ${BINDIR}/certutil -L -d ${ENTITY_DB} -r -n ${ENTITY} -o ${ENTITY}.der
323 html_msg $? 0 "${SCENARIO}${TESTNAME}"
324 }
326 ########################### create_cert_req ############################
327 # local shell function to generate certificate sign request
328 ########################################################################
329 create_cert_req()
330 {
331 ENTITY=$1
332 TYPE=$2
334 ENTITY_DB=${ENTITY}DB
336 REQ=${ENTITY}Req.der
338 date >> ${NOISE_FILE} 2>&1
340 CTYPE_OPT=
341 if [ -n "${CTYPE}" ]; then
342 CTYPE_OPT="-k ${CTYPE}"
343 fi
345 CA_FLAG=
346 EXT_DATA=
347 OPTIONS=
349 if [ "${TYPE}" != "EE" ]; then
350 CA_FLAG="-2"
351 EXT_DATA="y
352 -1
353 y
354 "
355 fi
357 process_crldp
359 echo "${EXT_DATA}" > ${CU_DATA}
361 TESTNAME="Creating ${TYPE} certifiate request ${REQ}"
362 echo "${SCRIPTNAME}: ${TESTNAME}"
363 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}"
364 print_cu_data
365 ${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}
366 html_msg $? 0 "${SCENARIO}${TESTNAME}"
367 }
369 ############################ create_entity #############################
370 # local shell function to create certificate chain entity
371 ########################################################################
372 create_entity()
373 {
374 ENTITY=$1
375 TYPE=$2
377 if [ -z "${ENTITY}" ]; then
378 echo "Configuration error: Unnamed entity"
379 exit 1
380 fi
382 DB=${ENTITY}DB
383 ENTITY_DB=${ENTITY}DB
385 case "${TYPE}" in
386 "Root")
387 create_db "${DB}"
388 create_root_ca "${ENTITY}"
389 ;;
390 "Intermediate" | "Bridge" | "EE")
391 create_db "${DB}"
392 create_cert_req "${ENTITY}" "${TYPE}"
393 ;;
394 "*")
395 echo "Configuration error: Unknown type ${TYPE}"
396 exit 1
397 ;;
398 esac
399 }
401 ########################################################################
402 # List of global variables related to certificate extensions processing:
403 #
404 # Generated by process_extensions and functions called from it:
405 # OPTIONS - list of command line policy extensions
406 # DATA - list of inpud data related to policy extensions
407 #
408 # Generated by parse_config:
409 # POLICY - list of certificate policies
410 # MAPPING - list of policy mappings
411 # INHIBIT - inhibit flag
412 # AIA - AIA list
413 ########################################################################
415 ############################ process_policy ############################
416 # local shell function to process policy extension parameters and
417 # generate input for certutil
418 ########################################################################
419 process_policy()
420 {
421 if [ -n "${POLICY}" ]; then
422 OPTIONS="${OPTIONS} --extCP"
424 NEXT=
425 for ITEM in ${POLICY}; do
426 if [ -n "${NEXT}" ]; then
427 DATA="${DATA}y
428 "
429 fi
431 NEXT=1
432 DATA="${DATA}${ITEM}
433 1
435 n
436 "
437 done
439 DATA="${DATA}n
440 n
441 "
442 fi
443 }
445 ########################### process_mapping ############################
446 # local shell function to process policy mapping parameters and
447 # generate input for certutil
448 ########################################################################
449 process_mapping()
450 {
451 if [ -n "${MAPPING}" ]; then
452 OPTIONS="${OPTIONS} --extPM"
454 NEXT=
455 for ITEM in ${MAPPING}; do
456 if [ -n "${NEXT}" ]; then
457 DATA="${DATA}y
458 "
459 fi
461 NEXT=1
462 IDP=`echo ${ITEM} | cut -d: -f1`
463 SDP=`echo ${ITEM} | cut -d: -f2`
464 DATA="${DATA}${IDP}
465 ${SDP}
466 "
467 done
469 DATA="${DATA}n
470 n
471 "
472 fi
473 }
475 ########################### process_inhibit#############################
476 # local shell function to process inhibit extension and generate input
477 # for certutil
478 ########################################################################
479 process_inhibit()
480 {
481 if [ -n "${INHIBIT}" ]; then
482 OPTIONS="${OPTIONS} --extIA"
484 DATA="${DATA}${INHIBIT}
485 n
486 "
487 fi
488 }
490 ############################# process_aia ##############################
491 # local shell function to process AIA extension parameters and
492 # generate input for certutil
493 ########################################################################
494 process_aia()
495 {
496 if [ -n "${AIA}" ]; then
497 OPTIONS="${OPTIONS} --extAIA"
499 DATA="${DATA}1
500 "
502 for ITEM in ${AIA}; do
503 PK7_NONCE=`expr $PK7_NONCE + 1`
505 echo ${ITEM} | grep ":" > /dev/null
506 if [ $? -eq 0 ]; then
507 CERT_NICK=`echo ${ITEM} | cut -d: -f1`
508 CERT_ISSUER=`echo ${ITEM} | cut -d: -f2`
509 CERT_LOCAL="${CERT_NICK}${CERT_ISSUER}.der"
510 CERT_PUBLIC="${HOST}-$$-${CERT_NICK}${CERT_ISSUER}-${PK7_NONCE}.der"
511 else
512 CERT_LOCAL="${ITEM}.p7"
513 CERT_PUBLIC="${HOST}-$$-${ITEM}-${PK7_NONCE}.p7"
514 fi
516 DATA="${DATA}7
517 ${NSS_AIA_HTTP}/${CERT_PUBLIC}
518 "
520 if [ -n "${NSS_AIA_PATH}" ]; then
521 cp ${CERT_LOCAL} ${NSS_AIA_PATH}/${CERT_PUBLIC} 2> /dev/null
522 chmod a+r ${NSS_AIA_PATH}/${CERT_PUBLIC}
523 echo ${NSS_AIA_PATH}/${CERT_PUBLIC} >> ${AIA_FILES}
524 fi
525 done
527 DATA="${DATA}0
528 n
529 n"
530 fi
531 }
533 process_ocsp()
534 {
535 if [ -n "${OCSP}" ]; then
536 OPTIONS="${OPTIONS} --extAIA"
538 if [ "${OCSP}" = "offline" ]; then
539 MY_OCSP_URL=${NSS_OCSP_UNUSED}
540 else
541 MY_OCSP_URL=${NSS_AIA_OCSP}
542 fi
544 DATA="${DATA}2
545 7
546 ${MY_OCSP_URL}
547 0
548 n
549 n
550 "
551 fi
552 }
554 process_crldp()
555 {
556 if [ -n "${CRLDP}" ]; then
557 OPTIONS="${OPTIONS} -4"
559 EXT_DATA="${EXT_DATA}1
560 "
562 for ITEM in ${CRLDP}; do
563 CRL_PUBLIC="${HOST}-$$-${ITEM}-${SCEN_CNT}.crl"
565 EXT_DATA="${EXT_DATA}7
566 ${NSS_AIA_HTTP}/${CRL_PUBLIC}
567 "
568 done
570 EXT_DATA="${EXT_DATA}-1
571 -1
572 -1
573 n
574 n
575 "
576 fi
577 }
579 process_ku_ns_eku()
580 {
581 if [ -n "${EXT_KU}" ]; then
582 OPTIONS="${OPTIONS} --keyUsage ${EXT_KU}"
583 fi
584 if [ -n "${EXT_NS}" ]; then
585 EXT_NS_KEY=$(echo ${EXT_NS} | cut -d: -f1)
586 EXT_NS_CODE=$(echo ${EXT_NS} | cut -d: -f2)
588 OPTIONS="${OPTIONS} --nsCertType ${EXT_NS_KEY}"
589 DATA="${DATA}${EXT_NS_CODE}
590 -1
591 n
592 "
593 fi
594 if [ -n "${EXT_EKU}" ]; then
595 OPTIONS="${OPTIONS} --extKeyUsage ${EXT_EKU}"
596 fi
597 }
599 copy_crl()
601 {
602 if [ -z "${NSS_AIA_PATH}" ]; then
603 return;
604 fi
606 CRL_LOCAL="${COPYCRL}.crl"
607 CRL_PUBLIC="${HOST}-$$-${COPYCRL}-${SCEN_CNT}.crl"
609 cp ${CRL_LOCAL} ${NSS_AIA_PATH}/${CRL_PUBLIC} 2> /dev/null
610 chmod a+r ${NSS_AIA_PATH}/${CRL_PUBLIC}
611 echo ${NSS_AIA_PATH}/${CRL_PUBLIC} >> ${AIA_FILES}
612 }
614 ########################## process_extension ###########################
615 # local shell function to process entity extension parameters and
616 # generate input for certutil
617 ########################################################################
618 process_extensions()
619 {
620 OPTIONS=
621 DATA=
623 process_policy
624 process_mapping
625 process_inhibit
626 process_aia
627 process_ocsp
628 process_ku_ns_eku
629 }
631 ############################## sign_cert ###############################
632 # local shell function to sign certificate sign reuqest
633 ########################################################################
634 sign_cert()
635 {
636 ENTITY=$1
637 ISSUER=$2
638 TYPE=$3
640 [ -z "${ISSUER}" ] && return
642 ENTITY_DB=${ENTITY}DB
643 ISSUER_DB=${ISSUER}DB
644 REQ=${ENTITY}Req.der
645 CERT=${ENTITY}${ISSUER}.der
647 set_cert_sn
649 EMAIL_OPT=
650 if [ "${TYPE}" = "Bridge" ]; then
651 EMAIL_OPT="-7 ${ENTITY}@${ISSUER}"
653 [ -n "${EMAILS}" ] && EMAILS="${EMAILS},"
654 EMAILS="${EMAILS}${ENTITY}@${ISSUER}"
655 fi
657 process_extensions
659 echo "${DATA}" > ${CU_DATA}
661 TESTNAME="Creating certficate ${CERT} signed by ${ISSUER}"
662 echo "${SCRIPTNAME}: ${TESTNAME}"
663 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}"
664 print_cu_data
665 ${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}
666 html_msg $? 0 "${SCENARIO}${TESTNAME}"
668 TESTNAME="Importing certificate ${CERT} to ${ENTITY_DB} database"
669 echo "${SCRIPTNAME}: ${TESTNAME}"
670 echo "certutil -A -n ${ENTITY} -t u,u,u -d ${ENTITY_DB} -f ${ENTITY_DB}/dbpasswd -i ${CERT}"
671 ${BINDIR}/certutil -A -n ${ENTITY} -t u,u,u -d ${ENTITY_DB} -f ${ENTITY_DB}/dbpasswd -i ${CERT}
672 html_msg $? 0 "${SCENARIO}${TESTNAME}"
673 }
675 ############################# create_pkcs7##############################
676 # local shell function to package bridge certificates into pkcs7
677 # package
678 ########################################################################
679 create_pkcs7()
680 {
681 ENTITY=$1
682 ENTITY_DB=${ENTITY}DB
684 TESTNAME="Generating PKCS7 package from ${ENTITY_DB} database"
685 echo "${SCRIPTNAME}: ${TESTNAME}"
686 echo "cmsutil -O -r \"${EMAILS}\" -d ${ENTITY_DB} > ${ENTITY}.p7"
687 ${BINDIR}/cmsutil -O -r "${EMAILS}" -d ${ENTITY_DB} > ${ENTITY}.p7
688 html_msg $? 0 "${SCENARIO}${TESTNAME}"
689 }
691 ############################# import_key ###############################
692 # local shell function to import private key + cert into database
693 ########################################################################
694 import_key()
695 {
696 KEY_NAME=$1.p12
697 DB=$2
699 KEY_FILE=../OCSPD/${KEY_NAME}
701 TESTNAME="Importing p12 key ${KEY_NAME} to ${DB} database"
702 echo "${SCRIPTNAME}: ${TESTNAME}"
703 echo "${BINDIR}/pk12util -d ${DB} -i ${KEY_FILE} -k ${DB}/dbpasswd -W nssnss"
704 ${BINDIR}/pk12util -d ${DB} -i ${KEY_FILE} -k ${DB}/dbpasswd -W nssnss
705 html_msg $? 0 "${SCENARIO}${TESTNAME}"
706 }
708 export_key()
709 {
710 KEY_NAME=$1.p12
711 DB=$2
713 TESTNAME="Exporting $1 as ${KEY_NAME} from ${DB} database"
714 echo "${SCRIPTNAME}: ${TESTNAME}"
715 echo "${BINDIR}/pk12util -d ${DB} -o ${KEY_NAME} -n $1 -k ${DB}/dbpasswd -W nssnss"
716 ${BINDIR}/pk12util -d ${DB} -o ${KEY_NAME} -n $1 -k ${DB}/dbpasswd -W nssnss
717 html_msg $? 0 "${SCENARIO}${TESTNAME}"
718 }
720 ############################# import_cert ##############################
721 # local shell function to import certificate into database
722 ########################################################################
723 import_cert()
724 {
725 IMPORT=$1
726 DB=$2
728 CERT_NICK=`echo ${IMPORT} | cut -d: -f1`
729 CERT_ISSUER=`echo ${IMPORT} | cut -d: -f2`
730 CERT_TRUST=`echo ${IMPORT} | cut -d: -f3`
732 if [ "${CERT_ISSUER}" = "x" ]; then
733 CERT_ISSUER=
734 CERT=${CERT_NICK}.cert
735 CERT_FILE="${QADIR}/libpkix/certs/${CERT}"
736 elif [ "${CERT_ISSUER}" = "d" ]; then
737 CERT_ISSUER=
738 CERT=${CERT_NICK}.der
739 CERT_FILE="../OCSPD/${CERT}"
740 else
741 CERT=${CERT_NICK}${CERT_ISSUER}.der
742 CERT_FILE=${CERT}
743 fi
745 IS_ASCII=`grep -c -- "-----BEGIN CERTIFICATE-----" ${CERT_FILE}`
747 ASCII_OPT=
748 if [ "${IS_ASCII}" -gt 0 ]; then
749 ASCII_OPT="-a"
750 fi
752 TESTNAME="Importing certificate ${CERT} to ${DB} database"
753 echo "${SCRIPTNAME}: ${TESTNAME}"
754 echo "certutil -A -n ${CERT_NICK} ${ASCII_OPT} -t \"${CERT_TRUST}\" -d ${DB} -f ${DB}/dbpasswd -i ${CERT_FILE}"
755 ${BINDIR}/certutil -A -n ${CERT_NICK} ${ASCII_OPT} -t "${CERT_TRUST}" -d ${DB} -f ${DB}/dbpasswd -i ${CERT_FILE}
756 html_msg $? 0 "${SCENARIO}${TESTNAME}"
757 }
759 import_crl()
760 {
761 IMPORT=$1
762 DB=$2
764 CRL_NICK=`echo ${IMPORT} | cut -d: -f1`
765 CRL_FILE=${CRL_NICK}.crl
767 if [ ! -f "${CRL_FILE}" ]; then
768 return
769 fi
771 TESTNAME="Importing CRL ${CRL_FILE} to ${DB} database"
772 echo "${SCRIPTNAME}: ${TESTNAME}"
773 echo "crlutil -I -d ${DB} -f ${DB}/dbpasswd -i ${CRL_FILE}"
774 ${BINDIR}/crlutil -I -d ${DB} -f ${DB}/dbpasswd -i ${CRL_FILE}
775 html_msg $? 0 "${SCENARIO}${TESTNAME}"
776 }
778 create_crl()
779 {
780 ISSUER=$1
781 ISSUER_DB=${ISSUER}DB
783 CRL=${ISSUER}.crl
785 DATE=$(date -u '+%Y%m%d%H%M%SZ')
786 DATE_LAST="${DATE}"
788 UPDATE=$(expr $(date -u '+%Y') + 1)$(date -u '+%m%d%H%M%SZ')
790 echo "update=${DATE}" > ${CRL_DATA}
791 echo "nextupdate=${UPDATE}" >> ${CRL_DATA}
793 TESTNAME="Create CRL for ${ISSUER_DB}"
794 echo "${SCRIPTNAME}: ${TESTNAME}"
795 echo "crlutil -G -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL}"
796 echo "=== Crlutil input data ==="
797 cat ${CRL_DATA}
798 echo "==="
799 ${BINDIR}/crlutil -G -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL} < ${CRL_DATA}
800 html_msg $? 0 "${SCENARIO}${TESTNAME}"
801 }
803 revoke_cert()
804 {
805 ISSUER=$1
806 ISSUER_DB=${ISSUER}DB
808 CRL=${ISSUER}.crl
810 set_cert_sn
812 DATE=$(date -u '+%Y%m%d%H%M%SZ')
813 while [ "${DATE}" = "${DATE_LAST}" ]; do
814 sleep 1
815 DATE=$(date -u '+%Y%m%d%H%M%SZ')
816 done
817 DATE_LAST="${DATE}"
819 echo "update=${DATE}" > ${CRL_DATA}
820 echo "addcert ${CERT_SN} ${DATE}" >> ${CRL_DATA}
822 TESTNAME="Revoking certificate with SN ${CERT_SN} issued by ${ISSUER}"
823 echo "${SCRIPTNAME}: ${TESTNAME}"
824 echo "crlutil -M -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL}"
825 echo "=== Crlutil input data ==="
826 cat ${CRL_DATA}
827 echo "==="
828 ${BINDIR}/crlutil -M -d ${ISSUER_DB} -n ${ISSUER} -f ${ISSUER_DB}/dbpasswd -o ${CRL} < ${CRL_DATA}
829 html_msg $? 0 "${SCENARIO}${TESTNAME}"
830 }
832 ########################################################################
833 # List of global variables related to certificate verification:
834 #
835 # Generated by parse_config:
836 # DB - DB used for testing
837 # FETCH - fetch flag (used with AIA extension)
838 # POLICY - list of policies
839 # TRUST - trust anchor
840 # TRUST_AND_DB - Examine both trust anchors and the cert db for trust
841 # VERIFY - list of certificates to use as vfychain parameters
842 # EXP_RESULT - expected result
843 # REV_OPTS - revocation options
844 ########################################################################
846 ############################# verify_cert ##############################
847 # local shell function to verify certificate validity
848 ########################################################################
849 verify_cert()
850 {
851 ENGINE=$1
853 DB_OPT=
854 FETCH_OPT=
855 POLICY_OPT=
856 TRUST_OPT=
857 VFY_CERTS=
858 VFY_LIST=
859 TRUST_AND_DB_OPT=
861 if [ -n "${DB}" ]; then
862 DB_OPT="-d ${DB}"
863 fi
865 if [ -n "${FETCH}" ]; then
866 FETCH_OPT="-f"
867 if [ -z "${NSS_AIA_HTTP}" ]; then
868 echo "${SCRIPTNAME} Skipping test using AIA fetching, NSS_AIA_HTTP not defined"
869 return
870 fi
871 fi
873 if [ -n "${TRUST_AND_DB}" ]; then
874 TRUST_AND_DB_OPT="-T"
875 fi
877 for ITEM in ${POLICY}; do
878 POLICY_OPT="${POLICY_OPT} -o ${ITEM}"
879 done
881 for ITEM in ${TRUST}; do
882 echo ${ITEM} | grep ":" > /dev/null
883 if [ $? -eq 0 ]; then
884 CERT_NICK=`echo ${ITEM} | cut -d: -f1`
885 CERT_ISSUER=`echo ${ITEM} | cut -d: -f2`
886 CERT=${CERT_NICK}${CERT_ISSUER}.der
888 TRUST_OPT="${TRUST_OPT} -t ${CERT}"
889 else
890 TRUST_OPT="${TRUST_OPT} -t ${ITEM}"
891 fi
892 done
894 for ITEM in ${VERIFY}; do
895 CERT_NICK=`echo ${ITEM} | cut -d: -f1`
896 CERT_ISSUER=`echo ${ITEM} | cut -d: -f2`
898 if [ "${CERT_ISSUER}" = "x" ]; then
899 CERT="${QADIR}/libpkix/certs/${CERT_NICK}.cert"
900 VFY_CERTS="${VFY_CERTS} ${CERT}"
901 VFY_LIST="${VFY_LIST} ${CERT_NICK}.cert"
902 elif [ "${CERT_ISSUER}" = "d" ]; then
903 CERT="../OCSPD/${CERT_NICK}.der"
904 VFY_CERTS="${VFY_CERTS} ${CERT}"
905 VFY_LIST="${VFY_LIST} ${CERT_NICK}.cert"
906 else
907 CERT=${CERT_NICK}${CERT_ISSUER}.der
908 VFY_CERTS="${VFY_CERTS} ${CERT}"
909 VFY_LIST="${VFY_LIST} ${CERT}"
910 fi
911 done
913 VFY_OPTS_TNAME="${DB_OPT} ${ENGINE} ${TRUST_AND_DB_OPT} ${REV_OPTS} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${TRUST_OPT}"
914 VFY_OPTS_ALL="${DB_OPT} ${ENGINE} -vv ${TRUST_AND_DB_OPT} ${REV_OPTS} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${VFY_CERTS} ${TRUST_OPT}"
916 TESTNAME="Verifying certificate(s) ${VFY_LIST} with flags ${VFY_OPTS_TNAME}"
917 echo "${SCRIPTNAME}: ${TESTNAME}"
918 echo "vfychain ${VFY_OPTS_ALL}"
920 if [ -z "${MEMLEAK_DBG}" ]; then
921 VFY_OUT=$(${BINDIR}/vfychain ${VFY_OPTS_ALL} 2>&1)
922 RESULT=$?
923 echo "${VFY_OUT}"
924 else
925 VFY_OUT=$(${RUN_COMMAND_DBG} ${BINDIR}/vfychain ${VFY_OPTS_ALL} 2>> ${LOGFILE})
926 RESULT=$?
927 echo "${VFY_OUT}"
928 fi
930 echo "${VFY_OUT}" | grep "ERROR -5990: I/O operation timed out" > /dev/null
931 E5990=$?
932 echo "${VFY_OUT}" | grep "ERROR -8030: Server returned bad HTTP response" > /dev/null
933 E8030=$?
935 if [ $E5990 -eq 0 -o $E8030 -eq 0 ]; then
936 echo "Result of this test is not valid due to network time out."
937 html_unknown "${SCENARIO}${TESTNAME}"
938 return
939 fi
941 echo "Returned value is ${RESULT}, expected result is ${EXP_RESULT}"
943 if [ "${EXP_RESULT}" = "pass" -a ${RESULT} -eq 0 ]; then
944 html_passed "${SCENARIO}${TESTNAME}"
945 elif [ "${EXP_RESULT}" = "fail" -a ${RESULT} -ne 0 ]; then
946 html_passed "${SCENARIO}${TESTNAME}"
947 else
948 html_failed "${SCENARIO}${TESTNAME}"
949 fi
950 }
952 check_ocsp()
953 {
954 OCSP_CERT=$1
956 CERT_NICK=`echo ${OCSP_CERT} | cut -d: -f1`
957 CERT_ISSUER=`echo ${OCSP_CERT} | cut -d: -f2`
959 if [ "${CERT_ISSUER}" = "x" ]; then
960 CERT_ISSUER=
961 CERT=${CERT_NICK}.cert
962 CERT_FILE="${QADIR}/libpkix/certs/${CERT}"
963 elif [ "${CERT_ISSUER}" = "d" ]; then
964 CERT_ISSUER=
965 CERT=${CERT_NICK}.der
966 CERT_FILE="../OCSPD/${CERT}"
967 else
968 CERT=${CERT_NICK}${CERT_ISSUER}.der
969 CERT_FILE=${CERT}
970 fi
972 # sample line:
973 # URI: "http://ocsp.server:2601"
974 OCSP_HOST=$(${BINDIR}/pp -w -t certificate -i ${CERT_FILE} | grep URI | sed "s/.*:\/\///" | sed "s/:.*//")
975 OCSP_PORT=$(${BINDIR}/pp -w -t certificate -i ${CERT_FILE} | grep URI | sed "s/^.*:.*:\/\/.*:\([0-9]*\).*$/\1/")
977 echo "tstclnt -h ${OCSP_HOST} -p ${OCSP_PORT} -q -t 20"
978 tstclnt -h ${OCSP_HOST} -p ${OCSP_PORT} -q -t 20
979 return $?
980 }
982 ############################ parse_result ##############################
983 # local shell function to process expected result value
984 # this function was created for case that expected result depends on
985 # some conditions - in our case type of cert DB
986 #
987 # default results are pass and fail
988 # this function added parsable values in format:
989 # type1:value1 type2:value2 .... typex:valuex
990 #
991 # allowed types are dbm, sql, all (all means all other cases)
992 # allowed values are pass and fail
993 #
994 # if this format is not used, EXP_RESULT will stay unchanged (this also
995 # covers pass and fail states)
996 ########################################################################
997 parse_result()
998 {
999 for RES in ${EXP_RESULT}
1000 do
1001 RESTYPE=$(echo ${RES} | cut -d: -f1)
1002 RESSTAT=$(echo ${RES} | cut -d: -f2)
1004 if [ "${RESTYPE}" = "${NSS_DEFAULT_DB_TYPE}" -o "${RESTYPE}" = "all" ]; then
1005 EXP_RESULT=${RESSTAT}
1006 break
1007 fi
1008 done
1009 }
1011 ############################ parse_config ##############################
1012 # local shell function to parse and process file containing certificate
1013 # chain configuration and list of tests
1014 ########################################################################
1015 parse_config()
1016 {
1017 SCENARIO=
1018 LOGNAME=
1020 while read KEY VALUE
1021 do
1022 case "${KEY}" in
1023 "entity")
1024 ENTITY="${VALUE}"
1025 TYPE=
1026 ISSUER=
1027 CTYPE=
1028 POLICY=
1029 MAPPING=
1030 INHIBIT=
1031 AIA=
1032 CRLDP=
1033 OCSP=
1034 DB=
1035 EMAILS=
1036 EXT_KU=
1037 EXT_NS=
1038 EXT_EKU=
1039 SERIAL=
1040 EXPORT_KEY=
1041 ;;
1042 "type")
1043 TYPE="${VALUE}"
1044 ;;
1045 "issuer")
1046 if [ -n "${ISSUER}" ]; then
1047 if [ -z "${DB}" ]; then
1048 create_entity "${ENTITY}" "${TYPE}"
1049 fi
1050 sign_cert "${ENTITY}" "${ISSUER}" "${TYPE}"
1051 fi
1053 ISSUER="${VALUE}"
1054 POLICY=
1055 MAPPING=
1056 INHIBIT=
1057 AIA=
1058 EXT_KU=
1059 EXT_NS=
1060 EXT_EKU=
1061 ;;
1062 "ctype")
1063 CTYPE="${VALUE}"
1064 ;;
1065 "policy")
1066 POLICY="${POLICY} ${VALUE}"
1067 ;;
1068 "mapping")
1069 MAPPING="${MAPPING} ${VALUE}"
1070 ;;
1071 "inhibit")
1072 INHIBIT="${VALUE}"
1073 ;;
1074 "aia")
1075 AIA="${AIA} ${VALUE}"
1076 ;;
1077 "crldp")
1078 CRLDP="${CRLDP} ${VALUE}"
1079 ;;
1080 "ocsp")
1081 OCSP="${VALUE}"
1082 ;;
1083 "db")
1084 DB="${VALUE}DB"
1085 create_db "${DB}"
1086 ;;
1087 "import")
1088 IMPORT="${VALUE}"
1089 import_cert "${IMPORT}" "${DB}"
1090 import_crl "${IMPORT}" "${DB}"
1091 ;;
1092 "import_key")
1093 IMPORT="${VALUE}"
1094 import_key "${IMPORT}" "${DB}"
1095 ;;
1096 "crl")
1097 ISSUER="${VALUE}"
1098 create_crl "${ISSUER}"
1099 ;;
1100 "revoke")
1101 REVOKE="${VALUE}"
1102 ;;
1103 "serial")
1104 SERIAL="${VALUE}"
1105 ;;
1106 "export_key")
1107 EXPORT_KEY=1
1108 ;;
1109 "copycrl")
1110 COPYCRL="${VALUE}"
1111 copy_crl "${COPYCRL}"
1112 ;;
1113 "verify")
1114 VERIFY="${VALUE}"
1115 TRUST=
1116 TRUST_AND_DB=
1117 POLICY=
1118 FETCH=
1119 EXP_RESULT=
1120 REV_OPTS=
1121 USAGE_OPT=
1122 ;;
1123 "cert")
1124 VERIFY="${VERIFY} ${VALUE}"
1125 ;;
1126 "testdb")
1127 if [ -n "${VALUE}" ]; then
1128 DB="${VALUE}DB"
1129 else
1130 DB=
1131 fi
1132 ;;
1133 "trust")
1134 TRUST="${TRUST} ${VALUE}"
1135 ;;
1136 "trust_and_db")
1137 TRUST_AND_DB=1
1138 ;;
1139 "fetch")
1140 FETCH=1
1141 ;;
1142 "result")
1143 EXP_RESULT="${VALUE}"
1144 parse_result
1145 ;;
1146 "rev_type")
1147 REV_OPTS="${REV_OPTS} -g ${VALUE}"
1148 ;;
1149 "rev_flags")
1150 REV_OPTS="${REV_OPTS} -h ${VALUE}"
1151 ;;
1152 "rev_mtype")
1153 REV_OPTS="${REV_OPTS} -m ${VALUE}"
1154 ;;
1155 "rev_mflags")
1156 REV_OPTS="${REV_OPTS} -s ${VALUE}"
1157 ;;
1158 "scenario")
1159 SCENARIO="${VALUE}: "
1161 CHAINS_DIR="${HOSTDIR}/chains/${VALUE}"
1162 mkdir -p ${CHAINS_DIR}
1163 cd ${CHAINS_DIR}
1165 if [ -n "${MEMLEAK_DBG}" ]; then
1166 LOGNAME="libpkix-${VALUE}"
1167 LOGFILE="${LOGDIR}/${LOGNAME}"
1168 fi
1170 SCEN_CNT=$(expr ${SCEN_CNT} + 1)
1171 ;;
1172 "sleep")
1173 sleep ${VALUE}
1174 ;;
1175 "break")
1176 break
1177 ;;
1178 "check_ocsp")
1179 TESTNAME="Test that OCSP server is reachable"
1180 check_ocsp ${VALUE}
1181 if [ $? -ne 0 ]; then
1182 html_failed "$TESTNAME"
1183 break;
1184 else
1185 html_passed "$TESTNAME"
1186 fi
1187 ;;
1188 "ku")
1189 EXT_KU="${VALUE}"
1190 ;;
1191 "ns")
1192 EXT_NS="${VALUE}"
1193 ;;
1194 "eku")
1195 EXT_EKU="${VALUE}"
1196 ;;
1197 "usage")
1198 USAGE_OPT="-u ${VALUE}"
1199 ;;
1200 "")
1201 if [ -n "${ENTITY}" ]; then
1202 if [ -z "${DB}" ]; then
1203 create_entity "${ENTITY}" "${TYPE}"
1204 fi
1205 sign_cert "${ENTITY}" "${ISSUER}" "${TYPE}"
1206 if [ "${TYPE}" = "Bridge" ]; then
1207 create_pkcs7 "${ENTITY}"
1208 fi
1209 if [ -n "${EXPORT_KEY}" ]; then
1210 export_key "${ENTITY}" "${DB}"
1211 fi
1212 ENTITY=
1213 fi
1215 if [ -n "${VERIFY}" ]; then
1216 verify_cert "-pp"
1217 if [ -n "${VERIFY_CLASSIC_ENGINE_TOO}" ]; then
1218 verify_cert ""
1219 verify_cert "-p"
1220 fi
1221 VERIFY=
1222 fi
1224 if [ -n "${REVOKE}" ]; then
1225 revoke_cert "${REVOKE}" "${DB}"
1226 REVOKE=
1227 fi
1228 ;;
1229 *)
1230 if [ `echo ${KEY} | cut -b 1` != "#" ]; then
1231 echo "Configuration error: Unknown keyword ${KEY}"
1232 exit 1
1233 fi
1234 ;;
1235 esac
1236 done
1238 if [ -n "${MEMLEAK_DBG}" ]; then
1239 log_parse
1240 html_msg $? 0 "${SCENARIO}Memory leak checking"
1241 fi
1242 }
1244 process_scenario()
1245 {
1246 SCENARIO_FILE=$1
1248 > ${AIA_FILES}
1250 parse_config < "${QADIR}/chains/scenarios/${SCENARIO_FILE}"
1252 while read AIA_FILE
1253 do
1254 rm ${AIA_FILE} 2> /dev/null
1255 done < ${AIA_FILES}
1256 rm ${AIA_FILES}
1257 }
1259 # process ocspd.cfg separately
1260 chains_ocspd()
1261 {
1262 process_scenario "ocspd.cfg"
1263 }
1265 # process ocsp.cfg separately
1266 chains_method()
1267 {
1268 process_scenario "method.cfg"
1269 }
1271 ############################# chains_main ##############################
1272 # local shell function to process all testing scenarios
1273 ########################################################################
1274 chains_main()
1275 {
1276 while read LINE
1277 do
1278 [ `echo ${LINE} | cut -b 1` != "#" ] || continue
1280 [ ${LINE} != 'ocspd.cfg' ] || continue
1281 [ ${LINE} != 'method.cfg' ] || continue
1283 process_scenario ${LINE}
1284 done < "${CHAINS_SCENARIOS}"
1285 }
1287 ################################ main ##################################
1289 chains_init
1290 VERIFY_CLASSIC_ENGINE_TOO=
1291 chains_ocspd
1292 VERIFY_CLASSIC_ENGINE_TOO=1
1293 chains_run_httpserv get
1294 chains_method
1295 chains_stop_httpserv
1296 chains_run_httpserv post
1297 chains_method
1298 chains_stop_httpserv
1299 VERIFY_CLASSIC_ENGINE_TOO=
1300 chains_run_httpserv random
1301 chains_main
1302 chains_stop_httpserv
1303 chains_run_httpserv get-unknown
1304 chains_main
1305 chains_stop_httpserv
1306 chains_cleanup