#!/usr/bin/env bash # Define test functions. # See numerous configuration variables later on in this file that you can set # in the environment or the site.sh file. The definitions in the site.sh file # override # # Create working dir as variable "dir" # The functions are somewhat wildgrown, a little too many: # - expectpart # - expecteof # - expecteof_netconf # - expecteofx # - expecteofeq # - expecteof_file # - expectwait # - expectmatch #set -e # : ${A=B} vs : ${A:=B} # colon also checks for NULL # Testfile (not including path) : ${testfile:=$(basename $0)} # SKIPLIST lists the filenames of the test files that you do *not* want to run. # The format is a whitespace separated list of filenames. Specify the SKIPLIST # either in the shell environment or in the site.sh file. Any SKIPLIST specified # in site.sh overrides a SKIPLIST specified in the environment. If not specified # in either the environment or the site.sh, then the default SKIPLIST is empty. : ${SKIPLIST:=""} >&2 echo "Running $testfile" # Generated config file from autotools / configure if [ -f ./config.sh ]; then . ./config.sh if [ $? -ne 0 ]; then return -1 # error fi fi # Test number from start : ${testnr:=0} # Test number in this test testi=0 # Single test. Set by "new" testname= # Valgind memory leak check. # The values are: # 0: No valgrind check # 1: Start valgrind at every new testcase. Check result every next new # 2: Start valgrind every new backend start. Check when backend stops # 3: Start valgrind every new restconf start. Check when restconf stops # 4: Start valgrind every new snmp start. Check when snmp stops # : ${valgrindtest=0} # If set to 0, override starting of clixon_backend in test (you bring your own) : ${BE:=1} # If BE is set, some tests have a user timeout to show which params to set # for starting a backend : ${BETIMEOUT:=10} # If set, enable debugging (of backend and restconf daemons) : ${DBG:=0} # If set to 0, override starting of clixon_restconf in test (you bring your own) : ${RC:=1} # Where to log restconf. Some systems may not have syslog, # eg logging to a file: RCLOG="-l f/www-data/restconf.log" : ${RCLOG:=} # If set to 0, override starting of clixon_snmp in test (you bring your own) : ${CS:=1} # Namespace: netconf base BASENS='urn:ietf:params:xml:ns:netconf:base:1.0' # Namespace: Clixon config CONFNS='xmlns="http://clicon.org/config"' # Namespace: Clixon lib LIBNS='xmlns="http://clicon.org/lib"' # Namespace: Clixon restconf RESTCONFNS='xmlns="http://clicon.org/restconf"' # Default netconf namespace statement, typically as placed on top-level urn:ietf:params:netconf:base:1.0urn:ietf:params:netconf:base:1.1]]>]]>" # XXX cannot get this to work for all combinations of nc/netcat fcgi/native # But leave it here for debugging where netcat works properly if [ -n "$(type netcat 2> /dev/null)" ]; then netcat="netcat -w 1" # -N does not work on fcgi # nc on freebsd does not work either #elif [ -n "$(type nc 2> /dev/null)" ]; then # netcat=nc else netcat= fi # SSL serv cert common name XXX should use DNS resolve : ${SSLCN:="localhost"} # Options passed to curl calls # -s : silent # -S : show error # -i : Include HTTP response headers # -k : insecure : ${CURLOPTS:="-Ssik"} # Set HTTP version 1.1 or 2 if ${HAVE_LIBNGHTTP2}; then : ${HVER:=2} else : ${HVER:=1.1} fi if [ ${HVER} = 2 ]; then if ${HAVE_HTTP1}; then # This is if http/1 is enabled (unset proto=HTTP_2 in restconf_accept_client) CURLOPTS="${CURLOPTS} --http2" else # This is if http/1 is disabled (set proto=HTTP_2 in restconf_accept_client) CURLOPTS="${CURLOPTS} --http2-prior-knowledge" fi else CURLOPTS="${CURLOPTS} --http1.1" fi # Wait after daemons (backend/restconf) start. See mem.sh for valgrind if [ "$(uname -m)" = "armv7l" ]; then : ${DEMWAIT:=8} else : ${DEMWAIT:=2} fi # Multiplication factor to sleep less than whole seconds DEMSLEEP=0.2 # Some sleep implementations cannot handle sub-seconds, change to 1s sleep $DEMSLEEP || DEMSLEEP=1 # DEMWAIT is expressed in seconds, but really * DEMSLEEP let DEMLOOP=5*DEMWAIT # RESTCONF protocol, eg http or https if [ "${WITH_RESTCONF}" = "fcgi" ]; then : ${RCPROTO:=http} else : ${RCPROTO:=https} fi # www user (on linux typically www-data, freebsd www) # Start restconf user, can be root which is dropped to wwwuser : ${wwwstartuser:=root} # Some restconf tests can run IPv6, but its complicated because: # - docker by default does not run IPv6 : ${IPv6:=false} # Backend user BUSER=clicon # If set, unknown XML is treated as ANYDATA # This would only happen if you set option YANG_UNKNOWN_ANYDATA to something else than default : ${YANG_UNKNOWN_ANYDATA:=false} # Follow the binary programs that can be parametrized (eg with valgrind) : ${clixon_cli:=clixon_cli} : ${clixon_netconf:=$(which clixon_netconf)} : ${clixon_restconf:=clixon_restconf} : ${clixon_backend:=clixon_backend} : ${clixon_snmp:=$(type -p clixon_snmp)} : ${clixon_snmp_pidfile:="/var/tmp/clixon_snmp.pid"} # Source the site-specific definitions for test script variables, if site.sh # exists. The variables defined in site.sh override any variables of the same # names in the environment in the current execution. if [ -f ./site.sh ]; then . ./site.sh if [ $? -ne 0 ]; then return -1 # skip fi # test skiplist. for f in $SKIPLIST; do if [ "$testfile" = "$f" ]; then echo "...skipped (see site.sh)" return -1 # skip fi done fi # Standard IETF RFC yang files. if [ ! -z ${YANG_STANDARD_DIR} ]; then : ${IETFRFC=$YANG_STANDARD_DIR/ietf/RFC} fi : ${SNMPCHECK:=true} if $SNMPCHECK; then snmpget="$(type -p snmpget) -On -c public -v2c localhost " snmpset="$(type -p snmpset) -On -c public -v2c localhost " snmpgetstr="$(type -p snmpget) -c public -v2c localhost " snmpgetnext="$(type -p snmpgetnext) -On -c public -v2c localhost " snmpgetnextstr="$(type -p snmpgetnext) -c public -v2c localhost " snmptable="$(type -p snmptable) -c public -v2c localhost " snmptranslate="$(type -p snmptranslate) " if [ "${ENABLE_NETSNMP}" == "yes" ]; then pgrep snmpd > /dev/null if [ $? != 0 ]; then echo -e "\e[31m\nenable-netsnmp set but snmpd not running, start with:" echo "systemctl start snmpd" echo "" echo "snmpd must be configured to use a Unix socket for agent communication" echo "and have a rwcommunity configured, make sure the following lines are" echo "added to /etc/snmp/snmpd.conf:" echo "" echo " rwcommunity public localhost" echo " agentXSocket unix:/var/run/snmp.sock" echo " agentxperms 777 777" echo "" echo "If you don't rely on systemd you can configure the lines above" echo "and start snmpd manually with 'snmpd -Lo -p /var/run/snmpd.pid'." echo -e "\e[0m" exit -1 fi fi function validate_oid(){ oid=$1 oid2=$2 type=$3 value=$4 name="$($snmptranslate $oid)" name2="$($snmptranslate $oid2)" if [ $oid == $oid2 ]; then new "Validating numerical OID: $oid2 = $type: $value" expectpart "$($snmpget $oid)" 0 "$oid2 = $type: $value" new "Validating textual OID: $name2 = $type: $value" expectpart "$($snmpgetstr $name)" 0 "$name2 = $type: $value" else new "Validating numerical next OID: $oid2 = $type: $value" expectpart "$($snmpgetnext $oid)" 0 "$oid2 = $type: $value" new "Validating textual next OID: $name2 = $type: $value" expectpart "$($snmpgetnextstr $name)" 0 "$name2 = $type: $value" fi } function validate_set(){ oid=$1 type=$2 value=$3 case $type in "INTEGER") set_type="i" ;; "STRING") set_type="s" ;; esac if [ $type == "INTEGER" ]; then set_type="i" fi new "Setting value $value to OID $oid with type $set_type" if [ $type == "STRING" ]; then expectpart "$($snmpset $oid $set_type "$value")" 0 "$type: \"$value\"" else expectpart "$($snmpset $oid $set_type "$value")" 0 "$type: $value" fi } fi # Check sanity between --with-restconf setting and if nginx is started by systemd or not # This check is optional because some installs, such as vagrant make a non-systemd/direct # start : ${NGINXCHECK:=false} # Sanity nginx running on systemd platforms if $NGINXCHECK; then if systemctl > /dev/null 2>&1 ; then # even if systemd exists, nginx may be started in other ways nginxactive=$(systemctl show nginx |grep ActiveState=active) if [ "${WITH_RESTCONF}" = "fcgi" ]; then if [ -z "$nginxactive" -a ! -f /var/run/nginx.pid ]; then echo -e "\e[31m\nwith-restconf=fcgi set but nginx not running, start with:" echo "systemctl start nginx" echo -e "\e[0m" exit -1 fi else if [ -n "$nginxactive" -o -f /var/run/nginx.pid ]; then echo -e "\e[31m\nwith-restconf=fcgi not set but nginx running, stop with:" echo "systemctl stop nginx" echo -e "\e[0m" exit -1 fi fi fi # systemctl fi dir=/var/tmp/$0 if [ ! -d $dir ]; then mkdir $dir fi # Default restconf configuration: IPv4 # Can be placed in clixon-config # Note that https clause assumes there exists certs and keys in /etc/ssl,... # Args: # 1: auth-type (one of none, client-cert, user) # 2: pretty (if true pretty-print restconf return values) # [3: proto: http or https] # [4: http_data: true or false] # Note feature http-data must be enabled # Note, if AUTH=none then FEATURE clixon-restconf:allow-auth-none must be enabled # Note if https, check if server cert/key exists, if not generate them function restconf_config() { AUTH=$1 PRETTY=$2 # Change this to fixed parameters if [ $# -gt 2 ]; then myproto=$3 else myproto=$RCPROTO fi if [ $# -gt 3 ]; then myhttpdata=$4 else myhttpdata=false fi echo -n "clixon-restconf:fcgi" if [ $myproto = http ]; then echo -n "true" if ${myhttpdata}; then echo -n "true" fi echo "$AUTH$PRETTY$DBGdefault
0.0.0.0
80false
" else certdir=$dir/certs if [ ! -f ${dir}/clixon-server-crt.pem ]; then certdir=$dir/certs test -d $certdir || mkdir $certdir srvcert=${certdir}/clixon-server-crt.pem srvkey=${certdir}/clixon-server-key.pem cacert=${certdir}/clixon-ca-crt.pem cakey=${certdir}/clixon-ca-key.pem cacerts $cakey $cacert servercerts $cakey $cacert $srvkey $srvcert fi echo -n "true" if ${myhttpdata}; then echo -n "true" fi echo "$AUTH$PRETTY${certdir}/clixon-server-crt.pem${certdir}/clixon-server-key.pem${certdir}/clixon-ca-crt.pem$DBGdefault
0.0.0.0
443true
" fi } # Default autocli configuration # Can be placed in clixon-config # Exclude all modules instead as defined by arg1 # Args: # 1: modname module name pattern to be included # 2: list-keyword # 3: treerefstate function autocli_config() { modname=$1 listkw=$2 state=$3 TMP=$(cat < false $listkw $state include $modname enable $modname EOF ) echo "${TMP}" } # Some tests may set owner of testdir to something strange and quit, need # to reset to me if [ ! -G $dir ]; then u=$(whoami) sudo chown $u $dir sudo chgrp $u $dir fi # If you bring your own backend BE=0 (it is already started), the backend may # have created some files (eg unix socket) in $dir and therefore cannot # be deleted. # Same with RC=0 if [ $BE -ne 0 -a $RC -ne 0 ]; then rm -rf $dir/* fi # error and exit, # arg1: expected # arg2: errmsg[optional] # Assumes: $dir and $expect are set # see err1 function err(){ echo -e "\e[31m\nError in Test$testnr [$testname]:" if [ $# -gt 0 ]; then echo "Expected: $1" echo fi if [ $# -gt 1 ]; then echo "Received: $2" fi echo -e "\e[0m" echo "Diff between Expected and Received:" diff <(echo "$ret"| od -t c) <(echo "$expect"| od -t c) exit -1 #$testnr } # Dont print diffs function err1(){ echo -e "\e[31m\nError in Test$testnr [$testname]:" if [ $# -gt 0 ]; then echo "Expected: $1" echo fi if [ $# -gt 1 ]; then echo "Received: $2" fi echo -e "\e[0m" exit -1 #$testnr } # Test is previous test had valgrind errors if so quit function checkvalgrind(){ if [ -f $valgrindfile ]; then res=$(cat $valgrindfile | grep -e "Invalid" |awk '{print $4}' | grep -v '^0$') if [ -n "$res" ]; then >&2 cat $valgrindfile sudo rm -f $valgrindfile exit -1 fi res=$(cat $valgrindfile | grep -e "reachable" -e "lost:"|awk '{print $4}' | grep -v '^0$') if [ -n "$res" ]; then >&2 cat $valgrindfile sudo rm -f $valgrindfile exit -1 fi sudo rm -f $valgrindfile fi } # Check if two RFC6242 NETCONF frames are equal # Since they use \n you cannot just use = function chunked_equal() { echo "1:$1" echo "2:$2" if [ "$1" == "$2" ]; then return 0 else return 255 fi } # Given a string, add RFC6242 chunked franing around it # Args: # 0: string function chunked_framing() { str=$1 length=${#str} printf "\n#%s\n%s\n##\n" ${length} "${str}" } # Start clixon_snmp function start_snmp(){ cfg=$1 rm -f ${clixon_snmp_pidfile} $clixon_snmp -f $cfg -D $DBG & if [ $? -ne 0 ]; then err fi } # Stop clixon_snmp and Valgrind if needed function stop_snmp(){ if [ $valgrindtest -eq 4 ]; then pkill -f clixon_snmp sleep 1 checkvalgrind else killall -q clixon_snmp fi rm -f ${clixon_snmp_pidfile} } # Start backend with all varargs. # If valgrindtest == 2, start valgrind function start_backend(){ if [ $valgrindtest -eq 2 ]; then # Start in background since daemon version creates two traces: parent, # child. If background then only the single relevant. sudo $clixon_backend -F -D $DBG $* & else sudo $clixon_backend -D $DBG $* fi if [ $? -ne 0 ]; then err fi } function stop_backend(){ sudo clixon_backend -z $* if [ $? -ne 0 ]; then err "kill backend" fi if [ $valgrindtest -eq 2 ]; then sleep 1 checkvalgrind fi sudo pkill -f clixon_backend # extra ($BUSER?) } # Wait for restconf to stop sending 502 Bad Gateway function wait_backend(){ freq=$(chunked_framing "") reply=$(echo "$freq" | $clixon_netconf -q1ef $cfg) # freply=$(chunked_framing "") # chunked_equal "$reply" "$freply" let i=0; while [[ $reply != *"
]]>]]>" | clixon_netconf -qef $cfg 2> /dev/null) # echo "reply:$reply" let i++; # echo "wait_backend $i" if [ $i -ge $DEMLOOP ]; then err "backend timeout $DEMWAIT seconds" fi done } # Start restconf daemon # @see wait_restconf function start_restconf(){ # Start in background echo "sudo -u $wwwstartuser -s $clixon_restconf $RCLOG -D $DBG $*" sudo -u $wwwstartuser -s $clixon_restconf $RCLOG -D $DBG $* & if [ $? -ne 0 ]; then err1 "expected 0" "$?" fi } # Stop restconf daemon before test function stop_restconf_pre(){ sudo pkill -f clixon_restconf } # Stop restconf daemon after test # Some problems with pkill: # 1) Dont use $clixon_restconf (dont work in valgrind) # 2) Dont use -u $WWWUSER since clixon_restconf may drop privileges. # 3) After fork, it seems to take some time before name is right function stop_restconf(){ sudo pkill -f clixon_restconf if [ $valgrindtest -eq 3 ]; then sleep 1 checkvalgrind fi } # Wait for restconf to stop sending 502 Bad Gateway # @see start_restconf # Reasons for not working: if you run native is nginx running? # @note assumes port=80 if RCPROTO=http and port=443 if RCPROTO=https # Args: # 1: (optional) override RCPROTO with http or https function wait_restconf(){ if [ $# = 1 ]; then myproto=$1 else myproto=${RCPROTO} fi # echo "curl $CURLOPTS -X GET $myproto://localhost/restconf" hdr=$(curl $CURLOPTS -X GET $myproto://localhost/restconf 2> /dev/null) # echo "hdr:\"$hdr\"" let i=0; while [[ "$hdr" != *"200"* ]]; do # echo "wait_restconf $i" if [ $i -ge $DEMLOOP ]; then err1 "restconf timeout $DEMWAIT seconds" fi sleep $DEMSLEEP # echo "curl $CURLOPTS -X GET $myproto://localhost/restconf" hdr=$(curl $CURLOPTS -X GET $myproto://localhost/restconf 2> /dev/null) # echo "hdr:\"$hdr\"" let i++; done if [ $valgrindtest -eq 3 ]; then sleep 2 # some problems with valgrind fi } # Wait for restconf to stop # @note assumes port=80 if RCPROTO=http and port=443 if RCPROTO=https # @see wait_restconf function wait_restconf_stopped(){ # echo "curl $CURLOPTS $* $RCPROTO://localhost/restconf" hdr=$(curl $CURLOPTS $* $RCPROTO://localhost/restconf 2> /dev/null) # echo "hdr:\"$hdr\"" let i=0; while [[ $hdr = *"200 OK"* ]]; do # echo "wait_restconf_stopped $i" if [ $i -ge $DEMLOOP ]; then err1 "restconf timeout $DEMWAIT seconds" fi sleep $DEMSLEEP hdr=$(curl $CURLOPTS $* $RCPROTO://localhost/restconf 2> /dev/null) # echo "hdr:\"$hdr\"" let i++; done if [ $valgrindtest -eq 3 ]; then sleep 2 # some problems with valgrind fi } # Use pidfile to check snmp started. pidfile is created after init in clixon_snmp function wait_snmp() { let i=0; while [ ! -f ${clixon_snmp_pidfile} ]; do if [ $i -ge $DEMLOOP ]; then err1 "snmp timeout $DEMWAIT seconds" fi sleep $DEMSLEEP let i++; done } # End of test, final tests before normal exit of test # Note this is a single test started by new, not a total test suite function endtest() { if [ $valgrindtest -eq 1 ]; then checkvalgrind fi } # Increment test number and print a nice string function new(){ endtest # finalize previous test testnr=`expr $testnr + 1` testi=`expr $testi + 1` testname=$1 >&2 echo "Test $testi($testnr) [$1]" } # End of complete test-suite, eg a test file function endsuite() { unset CURLOPTS } # Evaluate and return # Example: expectpart $(fn arg) 0 "my return" -- "foo" # - evaluated expression # - expected command return value (0 if OK) or list of values, eg "55 56" # - expected stdout outcome* # - the token "--not--" # - not expected stdout outcome* # Example: # expectpart "$(a-shell-cmd arg)" 0 'expected match 1' 'expected match 2' --not-- 'not expected 1' # @note need to escape \[\] function expectpart(){ r=$? ret=$1 retval=$2 expect=$3 # echo "r:$r" # echo "ret:\"$ret\"" # echo "retval:$retval" # echo "expect:\"$expect\"" if [ "$retval" -eq "$retval" 2> /dev/null ] ; then # single retval if [ $r != $retval ]; then echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:" echo -e "\e[0m:" exit -1 fi else # List of retvals found=0 for rv in $retval; do if [ $r == $rv ]; then found=1 fi done if [ $found -eq 0 ]; then echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:" echo -e "\e[0m:" exit -1 fi fi if [ -z "$ret" -a -z "$expect" ]; then return fi # Loop over all variable args expect strings (skip first two args) # note that "expect" var is never actually used # Then test positive for strings, if the token --not-- is detected, then test negative for the rest positive=true; let i=0; for exp in "$@"; do if [ $i -gt 1 ]; then if [ "$exp" == "--not--" ]; then positive=false; else # echo "echo \"$ret\" | grep --null -o \"$exp"\" match=$(echo "$ret" | grep --null -i -o "$exp") #-i ignore case XXX -EZo: -E cant handle {} r=$? if $positive; then if [ $r != 0 ]; then err "$exp" "$ret" fi else if [ $r == 0 ]; then err "not $exp" "$ret" fi fi fi fi let i++; done # if [[ "$ret" != "$expect" ]]; then # err "$expect" "$ret" # fi } # Pipe stdin to command # Arguments: # - Command # - expected command return value (0 if OK) XXX SHOULD SWITCH w next # - stdin input # - expected stdout outcome # - expected stderr outcome (can be null) # Use this if you want regex eg ^foo$ function expecteof(){ cmd=$1 retval=$2 input=$3 expect=$4 if [ $# -gt 4 ]; then errfile=$(mktemp) expecterr=$5 # Do while read stuff ret=$($cmd 2> $errfile < $dir/expectwaitresult ret="" sleep $wait | cat <(echo "$input1$inputenc") -| $cmd | while [ 1 ] ; do read -t 20 r # echo "r:<$r>" if [ -z "$r" ]; then sleep 1 continue fi # Append $r to $ret ret="$ret$r" # echo "ret:$ret" let i=0; positive=true; let ok=0 let fail=0 for exp in "$@"; do if [ $i -gt 4 ]; then # echo "i:$i" # echo "exp:$exp" if [ "$exp" == "--not--" ]; then positive=false; else match=$(echo "$ret" | grep --null -i -o "$exp") # match=$(echo "$ret" | grep -Eo "$exp"); r=$? if $positive; then if [ $r != 0 ]; then # echo "fail: $exp" let fail++ break fi else if [ $r == 0 ]; then # echo "fail: $exp" let fail++ break fi fi fi fi let i++; done # for exp # echo "fail:$fail" if [ $fail -eq 0 ]; then # echo ok echo ok > $dir/expectwaitresult # break exit 0 fi done # cat $dir/expectwaitresult if [ $(cat $dir/expectwaitresult) != "ok" ]; then err "ok" "$(cat $dir/expectwaitresult)" cat $dir/expectwaitresult exit -1 fi } function expectmatch(){ ret=$1 r=$2 expret=$3 expect=$4 # echo "ret:$ret" # echo "ret:$r" # echo "expret:$expret" # echo "expect:$expect" if [ $r != $expret ]; then echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:" echo -e "\e[0m:" exit -1 fi if [ -z "$ret" -a -z "$expect" ]; then echo > /dev/null else match=$(echo "$ret" | grep -Eo "$expect") if [ -z "$match" ]; then err "$expect" "$ret" fi if [ -n "$expect2" ]; then match=`echo "$ret" | grep --null -Eo "$expect2"` if [ -z "$match" ]; then err $expect "$ret" fi fi fi } # Create CA certs # Output variables set as filenames on entry, set as cert/keys on exit: # Vars: # 1: cakey filename # 2: cacert filename function cacerts() { if [ $# -ne 2 ]; then echo "cacerts function: Expected: cakey cacert" exit 1 fi local cakey=$1 local cacert=$2 tmpdir=$dir/tmpcertdir test -d $tmpdir || mkdir $tmpdir # 1. CA cat< $tmpdir/ca.cnf [ ca ] default_ca = CA_default [ CA_default ] serial = ca-serial crl = ca-crl.pem database = ca-database.txt name_opt = CA_default cert_opt = CA_default default_crl_days = 9999 default_md = md5 [ req ] default_bits = ${CERTKEYLEN} days = 1 distinguished_name = req_distinguished_name attributes = req_attributes prompt = no output_password = password [ req_distinguished_name ] C = SE L = Stockholm O = Clixon OU = clixon CN = ca emailAddress = olof@hagsand.se [ req_attributes ] challengePassword = test EOF # Generate CA cert openssl req -x509 -days 1 -config $tmpdir/ca.cnf -keyout $cakey -out $cacert || err "Generate CA cert" rm -rf $tmpdir } # Create server certs # Output variables set as filenames on entry, set as cert/keys on exit: # Vars: # 1: cakey filename (input) # 2: cacert filename (input) # 3: srvkey filename (output) # 4: srvcert filename (output) function servercerts() { if [ $# -ne 4 ]; then echo "servercerts function: Expected: cakey cacert srvkey srvcert" exit 1 fi cakey=$1 cacert=$2 srvkey=$3 srvcert=$4 tmpdir=$dir/tmpcertdir test -d $tmpdir || mkdir $tmpdir cat< $tmpdir/srv.cnf [req] prompt = no distinguished_name = dn req_extensions = ext [dn] CN = ${SSLCN} # localhost emailAddress = olof@hagsand.se O = Clixon L = Stockholm C = SE [ext] subjectAltName = DNS:clicon.org EOF # Generate server key openssl genpkey -algorithm RSA -out $srvkey || err "Generate server key" # Generate CSR (signing request) openssl req -new -config $tmpdir/srv.cnf -key $srvkey -out $tmpdir/srv_csr.pem || err "Generate signing request" # Sign server cert by CA openssl x509 -req -extfile $tmpdir/srv.cnf -days 1 -passin "pass:password" -in $tmpdir/srv_csr.pem -CA $cacert -CAkey $cakey -CAcreateserial -out $srvcert || err "Sign server cert" rm -rf $tmpdir }