From c1ca5a641b08ec4c13207595ccdf1a41f0134b90 Mon Sep 17 00:00:00 2001 From: Dirk Date: Fri, 13 Mar 2015 12:20:19 +0100 Subject: [PATCH 01/26] - FIX garbled output for servers with a TLS reply on SSLv2 socket call --- testssl.sh | 81 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/testssl.sh b/testssl.sh index 5cda096..59f5acb 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1446,7 +1446,7 @@ sockread_serverhello() { [[ "x$2" = "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 ret=0 - SOCK_REPLY_FILE=`mktemp /tmp/ddreply.XXXXXX` || exit 7 + SOCK_REPLY_FILE=`mktemp $TEMPDIR/ddreply.XXXXXX` || exit 7 dd bs=$1 of=$SOCK_REPLY_FILE count=1 <&5 2>/dev/null & pid=$! @@ -1487,27 +1487,32 @@ display_sslv2serverhello() { v2_hello_ascii=`hexdump -v -e '16/1 "%02X"' $1` [[ "$DEBUG" -ge 4 ]] && echo $v2_hello_ascii # one line without any blanks - [[ -z $v2_hello_ascii ]] && return 0 # no server hello received + if [[ -z $v2_hello_ascii ]] ; then + ret=0 # no server hello received + debugme echo "server hello empty" + else + # now scrape two bytes out of the reply per byte + v2_hello_initbyte="${v2_hello_ascii:0:1}" # normally this belongs to the next, should be 8! + v2_hello_length="${v2_hello_ascii:1:3}" # + 0x8000 see above + v2_hello_handshake="${v2_hello_ascii:4:2}" + v2_hello_cert_length="${v2_hello_ascii:14:4}" + v2_hello_cipherspec_length="${v2_hello_ascii:18:4}" - # now scrape two bytes out of the reply per byte - v2_hello_initbyte="${v2_hello_ascii:0:1}" # normally this belongs to the next, should be 8! - v2_hello_length="${v2_hello_ascii:1:3}" # + 0x8000 see above - v2_hello_handshake="${v2_hello_ascii:4:2}" - v2_hello_cert_length="${v2_hello_ascii:14:4}" - v2_hello_cipherspec_length="${v2_hello_ascii:18:4}" - V2_HELLO_CIPHERSPEC_LENGTH=`printf "%d\n" "0x$v2_hello_cipherspec_length"` + if [[ $v2_hello_initbyte != "8" ]] || [[ $v2_hello_handshake != "04" ]]; then + [[ $DEBUG -ge 2 ]] && echo "$v2_hello_initbyte / $v2_hello_handshake" + ret=1 + fi - if [[ $v2_hello_initbyte != "8" ]] || [[ $v2_hello_handshake != "04" ]]; then - [[ $DEBUG -ge 2 ]] && echo "$v2_hello_initbyte / $v2_hello_handshake" - return 1 + if [[ $DEBUG -ge 3 ]]; then + echo "SSLv2 server hello length: 0x0$v2_hello_length" + echo "SSLv2 certificate length: 0x$v2_hello_cert_length" + echo "SSLv2 cipher spec length: 0x$v2_hello_cipherspec_length" + fi + + V2_HELLO_CIPHERSPEC_LENGTH=`printf "%d\n" "0x$v2_hello_cipherspec_length" 2>/dev/null` + [ $? -ne 0 ] && ret=7 fi - - if [[ $DEBUG -ge 3 ]]; then - echo "SSLv2 server hello length: 0x0$v2_hello_length" - echo "SSLv2 certificate length: 0x$v2_hello_cert_length" - echo "SSLv2 cipher spec length: 0x$v2_hello_cipherspec_length" - fi - return 0 + return $ret } @@ -1634,22 +1639,28 @@ sslv2_sockets() { fi display_sslv2serverhello "$SOCK_REPLY_FILE" - - # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL - lines=`cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l` - [[ "$DEBUG" -ge 2 ]] && out " ($lines lines) " - - if [[ "$lines" -gt 1 ]] ;then - ciphers_detected=$(($V2_HELLO_CIPHERSPEC_LENGTH / 3 )) - if [ 0 -eq $ciphers_detected ] ; then - pr_litered "supported but couldn't detect a cipher"; outln "(may need debugging)" - else - pr_red "offered (NOT ok)"; outln " -- $ciphers_detected ciphers" - fi - ret=1 + if [ $? -eq 7 ]; then + # strange reply + pr_litemagenta "strange v2 reply " + outln " (rerun with DEBUG=2)" + [[ $DEBUG -ge 2 ]] && hexdump -C $SOCK_REPLY_FILE | head -1 else - pr_greenln "not offered (OK)" - ret=0 + # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL + lines=`cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l` + [[ "$DEBUG" -ge 2 ]] && out " ($lines lines) " + + if [[ "$lines" -gt 1 ]] ;then + ciphers_detected=$(($V2_HELLO_CIPHERSPEC_LENGTH / 3 )) + if [ 0 -eq $ciphers_detected ] ; then + pr_litered "supported but couldn't detect a cipher"; outln "(may need debugging)" + else + pr_red "offered (NOT ok)"; outln " -- $ciphers_detected ciphers" + fi + ret=1 + else + pr_greenln "not offered (OK)" + ret=0 + fi fi pr_off @@ -2978,6 +2989,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.201 2015/03/09 07:07:40 dirkw Exp $ +# $Id: testssl.sh,v 1.203 2015/03/13 11:20:18 dirkw Exp $ # vim:ts=5:sw=5 From b5a568da62dfd5f04abd4d58591c1a34906fe811 Mon Sep 17 00:00:00 2001 From: Dirk Date: Fri, 13 Mar 2015 12:21:06 +0100 Subject: [PATCH 02/26] - @feld --- CREDITS.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 00a613a..855588c 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -8,19 +8,22 @@ * Olivier Paroz * conversion xxd --> hexdump stuff +* Rechi + - initial MX stuff + +* Mark Felder + - minor cleanups + +* Peter Mosmans + - cleanups + * Markus Manzke: - Fix for HSTS + subdomains - LibreSSL patch -* Rechi - - initial MX stuff - * @nvsofts (NV) - LibreSSL patch for GOST -* Peter Mosmans - - cleanups - * Dmitri S - inspiration & help for Darwin port From 305fcca2aea51ef007475371ec5390906f76f9bc Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 09:52:39 -0500 Subject: [PATCH 03/26] Replace backticks with $(..) https://github.com/koalaman/shellcheck/wiki/SC2006 --- testssl.sh | 410 ++++++++++++++++++++++++++--------------------------- 1 file changed, 205 insertions(+), 205 deletions(-) diff --git a/testssl.sh b/testssl.sh index 59f5acb..81a7e2e 100755 --- a/testssl.sh +++ b/testssl.sh @@ -74,7 +74,7 @@ DAYS2WARN2=30 # days to warn before cert expires, threshold 2 # more global vars, here just declared ECHO="/usr/bin/printf --" # works under Linux, BSD, MacOS. NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1" -RUN_DIR=`dirname $0` +RUN_DIR=$(dirname $0) TEMPDIR="" TLS_PROTO_OFFERED="" SOCKREPLY="" @@ -274,7 +274,7 @@ wait_kill(){ return 0 # didn't reach maxsleep yet fi sleep 1 - maxsleep=`expr $maxsleep - 1` + maxsleep=$(expr $maxsleep - 1) test $maxsleep -eq 0 && break done # needs to be killed: kill $pid >&2 2>/dev/null @@ -311,8 +311,8 @@ EOF ) &>$HEADERFILE_BREACH & pid=$! if wait_kill $pid $HEADER_MAXSLEEP; then - result=`cat $HEADERFILE_BREACH | grep -a '^Content-Encoding' | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g'` - result=`echo $result | tr -cd '\40-\176'` + result=$(cat $HEADERFILE_BREACH | grep -a '^Content-Encoding' | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g') + result=$(echo $result | tr -cd '\40-\176') if [ -z $result ]; then pr_green "no HTTP compression (OK) " ret=0 @@ -407,7 +407,7 @@ EOF ret=3 fi if egrep -awq "301|302|^Location" $HEADERFILE; then - redir2=`grep -a '^Location' $HEADERFILE | sed 's/Location: //' | tr -d '\r\n'` + redir2=$(grep -a '^Location' $HEADERFILE | sed 's/Location: //' | tr -d '\r\n') outln " (got 30x to $redir2, may be better try this URL?)\n" fi [[ $DEBUG -eq 0 ]] && rm $HEADERFILE.2 2>/dev/null @@ -438,7 +438,7 @@ hsts() { grep -iaw '^Strict-Transport-Security' $HEADERFILE >$TMPFILE if [ $? -eq 0 ]; then grep -aciw '^Strict-Transport-Security' $HEADERFILE | egrep -wq "1" || out "(two HSTS header, using 1st one) " - hsts_age_sec=`sed -e 's/[^0-9]*//g' $TMPFILE | head -1` + hsts_age_sec=$(sed -e 's/[^0-9]*//g' $TMPFILE | head -1) hsts_age_days=$(( hsts_age_sec / 86400)) if [ $hsts_age_days -gt $HSTS_MIN ]; then pr_litegreen "$hsts_age_days days \c" ; out "($hsts_age_sec s)" @@ -468,10 +468,10 @@ hpkp() { if [ $? -eq 0 ]; then egrep -aciw '^Public-Key-Pins|Public-Key-Pins-Report-Only' $HEADERFILE | egrep -wq "1" || out "(two HPKP header, using 1st one) " # dirty trick so that grep -c really counts occurances and not lines w/ occurances: - if [ `sed 's/pin-sha/pin-sha\n/g' < $TMPFILE | grep -c pin-sha` -eq 1 ]; then + if [ $(sed 's/pin-sha/pin-sha\n/g' < $TMPFILE | grep -c pin-sha) -eq 1 ]; then pr_brown "One key is not sufficent, " fi - hpkp_age_sec=`sed -e 's/\r//g' -e 's/^.*max-age=//' -e 's/;.*//' $TMPFILE` + hpkp_age_sec=$(sed -e 's/\r//g' -e 's/^.*max-age=//' -e 's/;.*//' $TMPFILE) hpkp_age_days=$((hpkp_age_sec / 86400)) if [ $hpkp_age_days -ge $HPKP_MIN ]; then pr_litegreen "$hpkp_age_days days \c" ; out "= $hpkp_age_sec s" @@ -505,7 +505,7 @@ serverbanner() { pr_bold " Server " grep -ai '^Server' $HEADERFILE >$TMPFILE if [ $? -eq 0 ]; then - serverbanner=`cat $TMPFILE | sed -e 's/^Server: //' -e 's/^server: //'` + serverbanner=$(cat $TMPFILE | sed -e 's/^Server: //' -e 's/^server: //') if [ x"$serverbanner" == "x\n" -o x"$serverbanner" == "x\n\r" -o x"$serverbanner" == "x" ]; then outln "banner exists but empty string" else @@ -553,19 +553,19 @@ cookieflags() { # ARG1: Path, ARG2: path pr_bold " Cookie(s) " grep -ai '^Set-Cookie' $HEADERFILE >$TMPFILE if [ $? -eq 0 ]; then - nr_cookies=`cat $TMPFILE | wc -l` + nr_cookies=$(cat $TMPFILE | wc -l) out "$nr_cookies issued: " if [ $nr_cookies -gt 1 ] ; then negative_word="NONE" else negative_word="NOT" fi - nr_secure=`grep -iac secure $TMPFILE` + nr_secure=$(grep -iac secure $TMPFILE) case $nr_secure in 0) out "$negative_word secure, " ;; [123456789]) pr_litegreen "$nr_secure/$nr_cookies"; out "secure, ";; esac - nr_httponly=`grep -cai httponly $TMPFILE` + nr_httponly=$(grep -cai httponly $TMPFILE) case $nr_httponly in 0) out "$negative_word HttpOnly" ;; [123456789]) pr_litegreen "$nr_httponly/$nr_cookies"; out "HttpOnly" ;; @@ -584,19 +584,19 @@ cookieflags() { # ARG1: Path, ARG2: path # #1: string with 2 opensssl codes, HEXC= same in NSS/ssllab terminology normalize_ciphercode() { - part1=`echo "$1" | awk -F',' '{ print $1 }'` - part2=`echo "$1" | awk -F',' '{ print $2 }'` - part3=`echo "$1" | awk -F',' '{ print $3 }'` + part1=$(echo "$1" | awk -F',' '{ print $1 }') + part2=$(echo "$1" | awk -F',' '{ print $2 }') + part3=$(echo "$1" | awk -F',' '{ print $3 }') if [ "$part1" == "0x00" ] ; then # leading 0x00 HEXC=$part2 else - part2=`echo $part2 | sed 's/0x//g'` + part2=$(echo $part2 | sed 's/0x//g') if [ -n "$part3" ] ; then # a SSLv2 cipher has three parts - part3=`echo $part3 | sed 's/0x//g'` + part3=$(echo $part3 | sed 's/0x//g') fi HEXC="$part1$part2$part3" fi - HEXC=`echo $HEXC | tr 'A-Z' 'a-z' | sed 's/0x/x/'` #tolower + strip leading 0 + HEXC=$(echo $HEXC | tr 'A-Z' 'a-z' | sed 's/0x/x/') #tolower + strip leading 0 return 0 } @@ -615,7 +615,7 @@ prettyprint_local() { neat_list $HEXC $ciph $kx $enc | strings done else - for arg in `echo $@ | sed 's/,/ /g'`; do + for arg in $(echo $@ | sed 's/,/ /g'); do $OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode dash ciph sslvers kx auth enc mac export ; do normalize_ciphercode $hexcode neat_list $HEXC $ciph $kx $enc | strings | grep -wai "$arg" @@ -672,7 +672,7 @@ std_cipherlists() { esac tmpfile_handle $FUNCNAME.txt else - singlespaces=`echo "$2" | sed -e 's/ \+/ /g' -e 's/^ //' -e 's/ $//g' -e 's/ //g'` + singlespaces=$(echo "$2" | sed -e 's/ \+/ /g' -e 's/^ //' -e 's/ $//g' -e 's/ //g') pr_magentaln "Local problem: No $singlespaces configured in $OPENSSL" fi # we need lf in those cases: @@ -686,7 +686,7 @@ std_cipherlists() { # ARG2: sleep socksend() { # the following works under BSD and Linux, which is quite tricky. So don't mess with it unless you're really sure what you do - data=`echo "$1" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\\/g' | tr -d '\n'` + data=$(echo "$1" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\\/g' | tr -d '\n') [[ $DEBUG -ge 4 ]] && echo "\"$data\"" printf -- "$data" >&5 2>/dev/null & sleep $2 @@ -697,7 +697,7 @@ sockread() { [ "x$2" = "x" ] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 ret=0 - ddreply=`mktemp /tmp/ddreply.XXXXXX` || exit 7 + ddreply=$(mktemp /tmp/ddreply.XXXXXX) || exit 7 dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null & pid=$! @@ -707,7 +707,7 @@ sockread() { kill $pid >&2 2>/dev/null fi sleep 1 - maxsleep=`expr $maxsleep - 1` + maxsleep=$(expr $maxsleep - 1) test $maxsleep -eq 0 && break done #FIXME: cleanup, we have extra function for this now @@ -718,7 +718,7 @@ sockread() { wait $pid 2>/dev/null ret=3 # means killed fi - SOCKREPLY=`cat $ddreply` + SOCKREPLY=$(cat $ddreply) rm $ddreply return $ret @@ -727,7 +727,7 @@ sockread() { show_rfc_style(){ [ ! -r "$MAP_RFC_FNAME" ] && return 1 - RFCname=`grep -iw $1 "$MAP_RFC_FNAME" | sed -e 's/^.*TLS/TLS/' -e 's/^.*SSL/SSL/'` + RFCname=$(grep -iw $1 "$MAP_RFC_FNAME" | sed -e 's/^.*TLS/TLS/' -e 's/^.*SSL/SSL/') [[ -n "$RFCname" ]] && out "$RFCname" return 0 } @@ -738,11 +738,11 @@ neat_header(){ } neat_list(){ - kx=`echo $3 | sed 's/Kx=//g'` - enc=`echo $4 | sed 's/Enc=//g'` - strength=`echo $enc | sed -e 's/.*(//' -e 's/)//'` # strength = encryption bits - strength=`echo $strength | sed -e 's/ChaCha20-Poly1305/ly1305/g'` # workaround for empty bits ChaCha20-Poly1305 - enc=`echo $enc | sed -e 's/(.*)//g' -e 's/ChaCha20-Poly1305/ChaCha20-Po/g'` # workaround for empty bits ChaCha20-Poly1305 + kx=$(echo $3 | sed 's/Kx=//g') + enc=$(echo $4 | sed 's/Enc=//g') + strength=$(echo $enc | sed -e 's/.*(//' -e 's/)//') # strength = encryption bits + strength=$(echo $strength | sed -e 's/ChaCha20-Poly1305/ly1305/g') # workaround for empty bits ChaCha20-Poly1305 + enc=$(echo $enc | sed -e 's/(.*)//g' -e 's/ChaCha20-Poly1305/ChaCha20-Po/g') # workaround for empty bits ChaCha20-Poly1305 echo "$export" | grep -iq export && strength="$strength,export" if [ -r "$MAP_RFC_FNAME" ]; then printf -- " %-7s %-30s %-10s %-11s%-11s${MAP_RFC_FNAME:+ %-48s}${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength" "$(show_rfc_style $HEXC)" @@ -754,7 +754,7 @@ neat_list(){ test_just_one(){ pr_blue "--> Testing single cipher with word pattern "\"$1\"" (ignore case)"; outln "\n" neat_header - for arg in `echo $@ | sed 's/,/ /g'`; do + for arg in $(echo $@ | sed 's/,/ /g'); do # 1st check whether openssl has cipher or not $OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode dash ciph sslvers kx auth enc mac export ; do normalize_ciphercode $hexcode @@ -782,7 +782,7 @@ test_just_one(){ # test for all ciphers locally configured (w/o distinguishing whether they are good or bad allciphers(){ - nr_ciphers=`$OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' | sed 's/:/ /g' | wc -w` + nr_ciphers=$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' | sed 's/:/ /g' | wc -w) pr_blue "--> Testing all locally available $nr_ciphers ciphers against the server"; outln "\n" neat_header @@ -969,10 +969,10 @@ server_preference() { openssl_error ret=6 else - cipher1=`grep -w Cipher $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'` - list2=`echo $list1 | tr ':' '\n' | sort -r | tr '\n' ':'` # pr_reverse the list + cipher1=$(grep -w Cipher $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') + list2=$(echo $list1 | tr ':' '\n' | sort -r | tr '\n' ':') # pr_reverse the list $OPENSSL s_client $STARTTLS -cipher $list2 -connect $NODEIP:$PORT $SNI /dev/null >$TMPFILE - cipher2=`grep -w Cipher $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'` + cipher2=$(grep -w Cipher $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') out " Has server cipher order? " if [[ "$cipher1" != "$cipher2" ]]; then @@ -987,7 +987,7 @@ server_preference() { $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $SNI /dev/null >$TMPFILE out " Negotiated protocol " - default_proto=`grep -w "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g'` + default_proto=$(grep -w "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') case "$default_proto" in *TLSv1.2) pr_greenln $default_proto ;; *TLSv1.1) pr_litegreenln $default_proto ;; @@ -998,7 +998,7 @@ server_preference() { esac out " Negotiated cipher " - default_cipher=`grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g'` + default_cipher=$(grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') case "$default_cipher" in *NULL*|*EXP*) pr_red "$default_cipher" ;; *RC4*) pr_litered "$default_cipher" ;; @@ -1016,25 +1016,25 @@ server_preference() { # proto-check b4! $OPENSSL s_client $STARTTLS -"$p" -connect $NODEIP:$PORT $SNI /dev/null >$TMPFILE if [ $ret -eq 0 ]; then - proto[i]=`grep -w "Protocol" $TMPFILE | sed -e 's/^ \+Protocol \+://' -e 's/ //g'` - cipher[i]=`grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'` + proto[i]=$(grep -w "Protocol" $TMPFILE | sed -e 's/^ \+Protocol \+://' -e 's/ //g') + cipher[i]=$(grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') [[ ${cipher[i]} == "0000" ]] && cipher[i]="" # Hack! [[ $DEBUG -ge 2 ]] && outln "Default cipher for ${proto[i]}: ${cipher[i]}" else proto[i]="" cipher[i]="" fi - i=`expr $i + 1` + i=$(expr $i + 1) done if spdy_pre ; then # is NPN/SPDY supported and is this no STARTTLS? $OPENSSL s_client -host $NODE -port $PORT -nextprotoneg "$NPN_PROTOs" /dev/null >$TMPFILE if [ $? -eq 0 ]; then - proto[i]=`grep -aw "Next protocol" $TMPFILE | sed -e 's/^Next protocol://' -e 's/(.)//' -e 's/ //g'` + proto[i]=$(grep -aw "Next protocol" $TMPFILE | sed -e 's/^Next protocol://' -e 's/(.)//' -e 's/ //g') if [ -z "${proto[i]}" ]; then cipher[i]="" else - cipher[i]=`grep -aw "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'` + cipher[i]=$(grep -aw "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') [[ $DEBUG -ge 2 ]] && outln "Default cipher for ${proto[i]}: ${cipher[i]}" fi fi @@ -1066,7 +1066,7 @@ server_preference() { server_defaults() { outln pr_blue "--> Testing server defaults (Server Hello)"; outln "\n" - localtime=`date "+%s"` + localtime=$(date "+%s") # throwing every cipher/protocol at the server and displaying its pick $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $SNI -tlsextdebug -status /dev/null >$TMPFILE @@ -1077,7 +1077,7 @@ server_defaults() { ret=6 else out " TLS server extensions " - extensions=`grep -w "^TLS server extension" $TMPFILE | sed -e 's/^TLS server extension \"//' -e 's/\".*$/,/g'` + extensions=$(grep -w "^TLS server extension" $TMPFILE | sed -e 's/^TLS server extension \"//' -e 's/\".*$/,/g') if [ -z "$extensions" ]; then outln "(none)" else @@ -1085,17 +1085,17 @@ server_defaults() { fi out " Session Tickets RFC 5077 " - sessticket_str=`grep -w "session ticket" $TMPFILE | grep lifetime` + sessticket_str=$(grep -w "session ticket" $TMPFILE | grep lifetime) if [ -z "$sessticket_str" ]; then outln "(none)" else - lifetime=`echo $sessticket_str | grep lifetime | sed 's/[A-Za-z:() ]//g'` - unit=`echo $sessticket_str | grep lifetime | sed -e 's/^.*'"$lifetime"'//' -e 's/[ ()]//g'` + lifetime=$(echo $sessticket_str | grep lifetime | sed 's/[A-Za-z:() ]//g') + unit=$(echo $sessticket_str | grep lifetime | sed -e 's/^.*'"$lifetime"'//' -e 's/[ ()]//g') outln "$lifetime $unit" fi out " Server key size " - keysize=`grep -w "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //'` + keysize=$(grep -w "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //') if [ -z "$keysize" ]; then outln "(couldn't determine)" else @@ -1109,7 +1109,7 @@ server_defaults() { # google seems to have EC keys which displays as 256 Bit out " Signature Algorithm " - algo=`$OPENSSL x509 -in $HOSTCERT -noout -text | grep "Signature Algorithm" | sed 's/^.*Signature Algorithm: //' | sort -u ` + algo=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep "Signature Algorithm" | sed 's/^.*Signature Algorithm: //' | sort -u ) case $algo in sha1WithRSAEncryption) pr_brownln "SHA1withRSA" ;; sha256WithRSAEncryption) pr_litegreenln "SHA256withRSA" ;; @@ -1124,11 +1124,11 @@ server_defaults() { outln " $($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256 | sed 's/Fingerprint=//' | sed 's/://g' )" out " Common Name (CN) " - CN=`$OPENSSL x509 -in $HOSTCERT -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//'` + CN=$($OPENSSL x509 -in $HOSTCERT -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//') out "$CN" - CN_nosni=`$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT 2>/dev/null /dev/null //g'` + SAN=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ + sed -e 's/DNS://g' -e 's/ //g' -e 's/,/\n/g' -e 's/othername://g') # ^^^ CACert - [ x"$SAN" != "x" ] && SAN=`echo "$SAN" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'` && outln " subjectAltName (SAN) $SAN" + [ x"$SAN" != "x" ] && SAN=$(echo "$SAN" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g) && outln " subjectAltName (SAN) $SAN" # replace line feed by " " out " Issuer " - issuer=`$OPENSSL x509 -in $HOSTCERT -noout -issuer | sed -e 's/^.*CN=//g' -e 's/\/.*$//g'` - issuer_o=`$OPENSSL x509 -in $HOSTCERT -noout -issuer | sed 's/^.*O=//g' | sed 's/\/.*$//g'` + issuer=$($OPENSSL x509 -in $HOSTCERT -noout -issuer | sed -e 's/^.*CN=//g' -e 's/\/.*$//g') + issuer_o=$($OPENSSL x509 -in $HOSTCERT -noout -issuer | sed 's/^.*O=//g' | sed 's/\/.*$//g') if $OPENSSL x509 -in $HOSTCERT -noout -issuer | grep -q 'C=' ; then - issuer_c=`$OPENSSL x509 -in $HOSTCERT -noout -issuer | sed 's/^.*C=//g' | sed 's/\/.*$//g'` + issuer_c=$($OPENSSL x509 -in $HOSTCERT -noout -issuer | sed 's/^.*C=//g' | sed 's/\/.*$//g') else issuer_c="" # CACert would have 'issuer= ' here otherwise fi @@ -1159,15 +1159,15 @@ server_defaults() { fi out " Certificate Expiration " - expire=`$OPENSSL x509 -in $HOSTCERT -checkend 0` + expire=$($OPENSSL x509 -in $HOSTCERT -checkend 0) if ! echo $expire | grep -qw not; then pr_red "expired!" else - SECS2WARN=`expr 24 \* 60 \* 60 \* $DAYS2WARN2` # low threshold first - expire=`$OPENSSL x509 -in $HOSTCERT -checkend $SECS2WARN` + SECS2WARN=$(expr 24 \* 60 \* 60 \* $DAYS2WARN2) # low threshold first + expire=$($OPENSSL x509 -in $HOSTCERT -checkend $SECS2WARN) if echo "$expire" | grep -qw not; then - SECS2WARN=`expr 24 \* 60 \* 60 \* $DAYS2WARN2` - expire=`$OPENSSL x509 -in $HOSTCERT -checkend $SECS2WARN` + SECS2WARN=$(expr 24 \* 60 \* 60 \* $DAYS2WARN2) + expire=$($OPENSSL x509 -in $HOSTCERT -checkend $SECS2WARN) if echo "$expire" | grep -qw not; then pr_litegreen ">= $DAYS2WARN1 days" else @@ -1177,23 +1177,23 @@ server_defaults() { pr_litered "expires < $DAYS2WARN2 days!" fi fi - enddate=`date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z"` - startdate=`date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M"` + enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") + startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") outln " ($startdate --> $enddate)" - savedir=`pwd`; cd $TEMPDIR + savedir=$(pwd); cd $TEMPDIR $OPENSSL s_client -showcerts $STARTTLS -connect $NODEIP:$PORT $SNI 2>/dev/null ("level" c ".crt")} /---END CERTIFICATE-----/{inc=0}' - nrsaved=`ls $TEMPDIR/level?.crt 2>/dev/null | wc -w` + nrsaved=$(ls $TEMPDIR/level?.crt 2>/dev/null | wc -w) outln " # of certificates provided $nrsaved" cd $savedir out " Certificate Revocation List " - crl=`$OPENSSL x509 -in $HOSTCERT -noout -text | grep -A 4 "CRL Distribution" | grep URI | sed 's/^.*URI://'` + crl=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep -A 4 "CRL Distribution" | grep URI | sed 's/^.*URI://') [ x"$crl" == "x" ] && pr_literedln "--" || echo "$crl" out " OCSP URI " - ocsp_uri=`$OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri` + ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri) [ x"$ocsp_uri" == "x" ] && pr_literedln "--" || echo "$ocsp_uri" out " OCSP stapling " @@ -1213,10 +1213,10 @@ server_defaults() { #gmt_unix_time, removed since 1.0.1f # - #remotetime=`grep -w "Start Time" $TMPFILE | sed 's/[A-Za-z:() ]//g'` + #remotetime=$(grep -w "Start Time" $TMPFILE | sed 's/[A-Za-z:() ]//g') #if [ ! -z "$remotetime" ]; then - # remotetime_stdformat=`date --date="@$remotetime" "+%Y-%m-%d %r"` - # difftime=`expr $localtime - $remotetime` + # remotetime_stdformat=$(date --date="@$remotetime" "+%Y-%m-%d %r") + # difftime=$(expr $localtime - $remotetime) # [ $difftime -gt 0 ] && difftime="+"$difftime # difftime=$difftime" s" # outln " remotetime? : $remotetime ($difftime) = $remotetime_stdformat" @@ -1251,7 +1251,7 @@ pfs() { $OPENSSL ciphers -V "$PFSOK" >$TMPFILE 2>/dev/null if [ $? -ne 0 ] ; then - number_pfs=`wc -l $TMPFILE | awk '{ print $1 }'` + number_pfs=$(wc -l $TMPFILE | awk '{ print $1 }') if [ "$number_pfs" -le "$CLIENT_MIN_PFS" ] ; then outln pr_magentaln " Local problem: you have only $number_pfs client side PFS ciphers " @@ -1260,13 +1260,13 @@ pfs() { return 1 fi fi - savedciphers=`cat $TMPFILE` - [ $SHOW_LOC_CIPH = "1" ] && echo "local ciphers available for testing PFS:" && echo `cat $TMPFILE` + savedciphers=$(cat $TMPFILE) + [ $SHOW_LOC_CIPH = "1" ] && echo "local ciphers available for testing PFS:" && echo $(cat $TMPFILE) $OPENSSL s_client -cipher 'ECDH:DH' $STARTTLS -connect $NODEIP:$PORT $SNI &>$TMPFILE Checking RC4 Ciphers" ; outln $OPENSSL ciphers -V 'RC4:@STRENGTH' >$TMPFILE - [ $SHOW_LOC_CIPH = "1" ] && echo "local ciphers available for testing RC4:" && echo `cat $TMPFILE` - $OPENSSL s_client -cipher `$OPENSSL ciphers RC4` $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null /dev/null /dev/null >$TMPFILE if [ $? -eq 0 ]; then # we need -a here - tmpstr=`grep -a '^Protocols' $TMPFILE | sed 's/Protocols.*: //'` + tmpstr=$(grep -a '^Protocols' $TMPFILE | sed 's/Protocols.*: //') if [ -z "$tmpstr" -o "$tmpstr" = " " ] ; then out "not offered" ret=1 @@ -1417,7 +1417,7 @@ spdy() { fd_socket() { # arg doesn't work here if ! exec 5<> /dev/tcp/$NODEIP/$PORT; then - pr_magenta "`basename $0`: unable to open a socket to $NODEIP:$PORT" + pr_magenta "$(basename $0): unable to open a socket to $NODEIP:$PORT" return 6 fi return 0 @@ -1436,7 +1436,7 @@ close_socket(){ socksend_clienthello() { code2network "$SSLv2_CLIENT_HELLO" - data=`echo $NW_STR` + data=$(echo $NW_STR) [[ "$DEBUG" -ge 3 ]] && echo "\"$data\"" printf -- "$data" >&5 2>/dev/null & sleep $USLEEP_SND @@ -1446,7 +1446,7 @@ sockread_serverhello() { [[ "x$2" = "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 ret=0 - SOCK_REPLY_FILE=`mktemp $TEMPDIR/ddreply.XXXXXX` || exit 7 + SOCK_REPLY_FILE=$(mktemp $TEMPDIR/ddreply.XXXXXX) || exit 7 dd bs=$1 of=$SOCK_REPLY_FILE count=1 <&5 2>/dev/null & pid=$! @@ -1485,7 +1485,7 @@ display_sslv2serverhello() { # [certificate length] ==> certificate # [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY! - v2_hello_ascii=`hexdump -v -e '16/1 "%02X"' $1` + v2_hello_ascii=$(hexdump -v -e '16/1 "%02X"' $1) [[ "$DEBUG" -ge 4 ]] && echo $v2_hello_ascii # one line without any blanks if [[ -z $v2_hello_ascii ]] ; then ret=0 # no server hello received @@ -1509,7 +1509,7 @@ display_sslv2serverhello() { echo "SSLv2 cipher spec length: 0x$v2_hello_cipherspec_length" fi - V2_HELLO_CIPHERSPEC_LENGTH=`printf "%d\n" "0x$v2_hello_cipherspec_length" 2>/dev/null` + V2_HELLO_CIPHERSPEC_LENGTH=$(printf "%d\n" "0x$v2_hello_cipherspec_length" 2>/dev/null) [ $? -ne 0 ] && ret=7 fi return $ret @@ -1532,14 +1532,14 @@ display_tls_serverhello() { # byte 46+sid-len: compression method: 00: none, 01: deflate # byte 47+48+sid-len: extension length - tls_hello_ascii=`hexdump -v -e '16/1 "%02X"' $1` + tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' $1) [[ "$DEBUG" -eq 5 ]] && echo $tls_hello_ascii # one line without any blanks [[ -z $tls_hello_ascii ]] && return 0 # no server hello received # now scrape two bytes out of the reply per byte tls_hello_initbyte="${tls_hello_ascii:0:2}" # normally this is x16 tls_hello_protocol="${tls_hello_ascii:2:4}" - tls_len_all=`printf "%d\n" ${tls_hello_ascii:6:4}` + tls_len_all=$(printf "%d\n" ${tls_hello_ascii:6:4}) if [[ $tls_hello_initbyte != "16" ]] ; then [[ $DEBUG -ge 1 ]] && echo "tls_hello_initbyte: 0x$tls_hello_initbyte" @@ -1557,9 +1557,9 @@ display_tls_serverhello() { tls_hello="${tls_hello_ascii:10:2}" # normally this is x02 tls_hello_protocol2="${tls_hello_ascii:18:4}" tls_hello_time="${tls_hello_ascii:22:8}" - tls_time=`printf "%d\n" 0x$tls_hello_time` - tls_time=`date --date="@$tls_time" "+%Y-%m-%d %r"` - tls_sid_len=`printf "%d\n" 0x${tls_hello_ascii:86:2}` + tls_time=$(printf "%d\n" 0x$tls_hello_time) + tls_time=$(date --date="@$tls_time" "+%Y-%m-%d %r") + tls_sid_len=$(printf "%d\n" 0x${tls_hello_ascii:86:2}) let sid_offset=88+$tls_sid_len*2 tls_cipher_suite="${tls_hello_ascii:$sid_offset:4}" let sid_offset=92+$tls_sid_len*2 @@ -1587,14 +1587,14 @@ display_tls_serverhello() { # helper function for protocol checks # arg1: formatted string here in the code code2network() { - NW_STR=`echo "$1" | sed -e 's/,/\\\x/g' | sed -e 's/# .*$//g' -e 's/ //g' -e '/^$/d' | tr -d '\n' | tr -d '\t'` + NW_STR=$(echo "$1" | sed -e 's/,/\\\x/g' | sed -e 's/# .*$//g' -e 's/ //g' -e '/^$/d' | tr -d '\n' | tr -d '\t') } len2twobytes() { - len_arg1=`echo ${#1}` - [[ $len_arg1 -le 2 ]] && LEN_STR=`printf "00, %02s \n" $1` - [[ $len_arg1 -eq 3 ]] && LEN_STR=`printf "%02s, %02s \n" ${1:0:1} ${1:1:2}` - [[ $len_arg1 -eq 4 ]] && LEN_STR=`printf "%02s, %02s \n" ${1:0:2} ${1:2:2}` + len_arg1=$(echo ${#1}) + [[ $len_arg1 -le 2 ]] && LEN_STR=$(printf "00, %02s \n" $1) + [[ $len_arg1 -eq 3 ]] && LEN_STR=$(printf "%02s, %02s \n" ${1:0:1} ${1:1:2}) + [[ $len_arg1 -eq 4 ]] && LEN_STR=$(printf "%02s, %02s \n" ${1:0:2} ${1:2:2}) } @@ -1646,7 +1646,7 @@ sslv2_sockets() { [[ $DEBUG -ge 2 ]] && hexdump -C $SOCK_REPLY_FILE | head -1 else # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL - lines=`cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l` + lines=$(cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l) [[ "$DEBUG" -ge 2 ]] && out " ($lines lines) " if [[ "$lines" -gt 1 ]] ;then @@ -1732,34 +1732,34 @@ tls_sockets() { # arg3: SERVERNAME # ??? more extensions? - len_sni=`echo ${#3}` + len_sni=$(echo ${#3}) #tls_ver=printf "%02x\n" $1" code2network "$2" cipher_suites="$NW_STR" # we don't have the leading \x here so string length is two byte less, see next # convert length's from dec to hex: - hex_len_sn_hex=`printf "%02x\n" $LEN_SN_HEX` - hex_len_sn_hex3=`printf "%02x\n" $((LEN_SN_HEX+3))` - hex_len_sn_hex5=`printf "%02x\n" $((LEN_SN_HEX+5))` - hex_len_extention=`printf "%02x\n" $((LEN_SN_HEX+9))` + hex_len_sn_hex=$(printf "%02x\n" $LEN_SN_HEX) + hex_len_sn_hex3=$(printf "%02x\n" $((LEN_SN_HEX+3))) + hex_len_sn_hex5=$(printf "%02x\n" $((LEN_SN_HEX+5))) + hex_len_extention=$(printf "%02x\n" $((LEN_SN_HEX+9))) - len_ciph_suites_byte=`echo ${#cipher_suites}` + len_ciph_suites_byte=$(echo ${#cipher_suites}) let "len_ciph_suites_byte += 2" # we have additional 2 chars \x in each 2 byte string and 2 byte ciphers, so we need to divide by 4: - len_ciph_suites=`printf "%02x\n" $(($len_ciph_suites_byte / 4 ))` + len_ciph_suites=$(printf "%02x\n" $(($len_ciph_suites_byte / 4 ))) len2twobytes "$len_ciph_suites" len_ciph_suites_word="$LEN_STR" [[ $DEBUG -ge 4 ]] && echo $len_ciph_suites_word - len2twobytes `printf "%02x\n" $((0x$len_ciph_suites + 0x27 + 0x$hex_len_extention + 0x2))` - #len2twobytes `printf "%02x\n" $((0x$len_ciph_suites + 0x27))` + len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x27 + 0x$hex_len_extention + 0x2))) + #len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x27))) len_c_hello_word="$LEN_STR" [[ $DEBUG -ge 4 ]] && echo $len_c_hello_word - len2twobytes `printf "%02x\n" $((0x$len_ciph_suites + 0x2b + 0x$hex_len_extention + 0x2))` - #len2twobytes `printf "%02x\n" $((0x$len_ciph_suites + 0x2b))` + len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x2b + 0x$hex_len_extention + 0x2))) + #len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x2b))) len_all_word="$LEN_STR" [[ $DEBUG -ge 4 ]] && echo $len_all_word @@ -1796,7 +1796,7 @@ tls_sockets() { code2network "$TLS_CLIENT_HELLO$EXTENSION_CONTAINING_SNI" #code2network "$TLS_CLIENT_HELLO" - data=`echo $NW_STR` + data=$(echo $NW_STR) [[ "$DEBUG" -ge 2 ]] && printf "sending client hello..." if [[ "$tls_low_byte" == "03" ]] ; then @@ -1816,7 +1816,7 @@ tls_sockets() { ret=$? # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL - lines=`cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l` + lines=$(cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l) [[ "$DEBUG" -ge 2 ]] && out " (returned $lines lines) " # case $tls_low_byte in @@ -1864,8 +1864,8 @@ ccs_injection(){ $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT &>$TMPFILE $TMPFILE &1 &1 $TMPFILE if grep Compression $TMPFILE | grep -q NONE >/dev/null; then pr_green "not vulnerable (OK)" @@ -2168,13 +2168,13 @@ crime() { # echo # pr_bold "CRIME Vulnerability, SPDY \c" ; outln "(CVE-2012-4929): \c" -# STR=`grep Compression $TMPFILE ` +# STR=$(grep Compression $TMPFILE ) # if echo $STR | grep -q NONE >/dev/null; then # pr_green "not vulnerable (OK)" -# ret=`expr $ret + 0` +# ret=$(expr $ret + 0) # else # pr_red "VULNERABLE (NOT ok)" -# ret=`expr $ret + 1` +# ret=$(expr $ret + 1) # fi # fi # fi @@ -2199,7 +2199,7 @@ ssl_poodle() { local cbc_ciphers pr_bold " POODLE, SSL"; out " (CVE-2014-3566), experimental " - cbc_ciphers=`$OPENSSL ciphers -v 'ALL:eNULL' | awk '/CBC/ { print $1 }' | tr '\n' ':'` + cbc_ciphers=$($OPENSSL ciphers -v 'ALL:eNULL' | awk '/CBC/ { print $1 }' | tr '\n' ':') debugme echo $cbc_ciphers $OPENSSL s_client -ssl3 $STARTTLS -cipher $cbc_ciphers -connect $NODEIP:$PORT $SNI &>$TMPFILE Testing specific vulnerabilities" ; outln "\n" #FIXME: heartbleed + CCS won't work this way yet -# heartbleed ; ret=`expr $? + $ret` -# ccs_injection ; ret=`expr $? + $ret` - renego ; ret=`expr $? + $ret` - crime ; ret=`expr $? + $ret` - ssl_poodle ; ret=`expr $? + $ret` - freak ; ret=`expr $? + $ret` - beast ; ret=`expr $? + $ret` +# heartbleed ; ret=$(expr $? + $ret) +# ccs_injection ; ret=$(expr $? + $ret) + renego ; ret=$(expr $? + $ret) + crime ; ret=$(expr $? + $ret) + ssl_poodle ; ret=$(expr $? + $ret) + freak ; ret=$(expr $? + $ret) + beast ; ret=$(expr $? + $ret) - rc4 ; ret=`expr $? + $ret` - pfs ; ret=`expr $? + $ret` + rc4 ; ret=$(expr $? + $ret) + pfs ; ret=$(expr $? + $ret) outln - #cipher_per_proto ; ret=`expr $? + $ret` - allciphers ; ret=`expr $? + $ret` + #cipher_per_proto ; ret=$(expr $? + $ret) + allciphers ; ret=$(expr $? + $ret) fi ;; *) pr_litemagentaln "momentarily only ftp, smtp, pop3, imap, xmpp and telnet, ldap allowed" >&2 @@ -2426,7 +2426,7 @@ starttls() { help() { - PRG=`basename $0` + PRG=$(basename $0) cat << EOF $PRG @@ -2476,15 +2476,15 @@ EOF mybanner() { - me=`basename $0` - osslver=`$OPENSSL version` - osslpath=`which $OPENSSL` - nr_ciphers=`$OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' | sed 's/:/ /g' | wc -w` - hn=`hostname` + me=$(basename $0) + osslver=$($OPENSSL version) + osslpath=$(which $OPENSSL) + nr_ciphers=$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' | sed 's/:/ /g' | wc -w) + hn=$(hostname) #poor man's ident (nowadays ident not neccessarily installed) - idtag=`grep '\$Id' $0 | grep -w [E]xp | sed -e 's/^# //' -e 's/\$ $/\$/'` + idtag=$(grep '\$Id' $0 | grep -w [E]xp | sed -e 's/^# //' -e 's/\$ $/\$/') [ "$COLOR" -ne 0 ] && idtag="\033[1;30m$idtag\033[m\033[1m" - bb=`cat < / + URL_PATH=$(echo $1 | sed 's/.*'"${NODE}"'//' | sed 's/.*'"${PORT}"'//') # remove protocol and node part and port + URL_PATH=$(echo $URL_PATH | sed 's/\/\//\//g') # we rather want // -> / # now get NODEIP get_dns_entries @@ -2678,7 +2678,7 @@ parse_hn_port() { get_dns_entries() { - test4iponly=`printf $NODE | sed -e 's/[0-9]//g' -e 's/\.//g'` + test4iponly=$(printf $NODE | sed -e 's/[0-9]//g' -e 's/\.//g') if [ "x$test4iponly" == "x" ]; then # only an IPv4 address was supplied IP4=$NODE SNI="" # override this as we test the IP only @@ -2688,14 +2688,14 @@ get_dns_entries() { getent ahostsv4 $NODE 2>/dev/null >/dev/null if [ $? -eq 0 ]; then # Linux: - IP4=`getent ahostsv4 $NODE 2>/dev/null | grep -v ':' | awk '/STREAM/ { print $1}' | uniq` + IP4=$(getent ahostsv4 $NODE 2>/dev/null | grep -v ':' | awk '/STREAM/ { print $1}' | uniq) #else - # IP4=`getent hosts $NODE 2>/dev/null | grep -v ':' | awk '{ print $1}' | uniq` + # IP4=$(getent hosts $NODE 2>/dev/null | grep -v ':' | awk '{ print $1}' | uniq) #FIXME: FreeBSD returns only one entry fi fi if [ -z "$IP4" ] ; then # getent returned nothing: - IP4=`host -t a $NODE 2>/dev/null | grep -v alias | sed 's/^.*address //'` + IP4=$(host -t a $NODE 2>/dev/null | grep -v alias | sed 's/^.*address //') if echo "$IP4" | grep -q NXDOMAIN || echo "$IP4" | grep -q "no A record"; then pr_magenta "Can't proceed: No IP address for \"$NODE\" available"; outln "\n" exit 1 @@ -2703,40 +2703,40 @@ get_dns_entries() { fi # MSYS2 has no host or getent, so we do this if [ -z "$IP4" ] ; then - IP4=`nslookup $NODE 2>/dev/null | grep -A10 Name | grep -v Name | sed 's/^Address.*: .//'` + IP4=$(nslookup $NODE 2>/dev/null | grep -A10 Name | grep -v Name | sed 's/^Address.*: .//') fi # for IPv6 we often get this :ffff:IPV4 address which isn't of any use - #which getent 2>&1 >/dev/null && IP6=`getent ahostsv6 $NODE | grep $NODE | awk '{ print $1}' | grep -v '::ffff' | uniq` + #which getent 2>&1 >/dev/null && IP6=$(getent ahostsv6 $NODE | grep $NODE | awk '{ print $1}' | grep -v '::ffff' | uniq) if [ -z "$IP6" ] ; then if host -t aaaa $NODE &>/dev/null ; then - IP6=`host -t aaaa $NODE | grep -v alias | grep -v "no AAAA record" | sed 's/^.*address //'` + IP6=$(host -t aaaa $NODE | grep -v alias | grep -v "no AAAA record" | sed 's/^.*address //') else IP6="" fi fi # MSYS2 has no host or getent, so we do this if [ -z "$IP6" ] ; then - IP6=`nslookup -type=aaaa $NODE 2>/dev/null | grep -A10 Name | grep -v Name | sed 's/^Address.*: .//'` + IP6=$(nslookup -type=aaaa $NODE 2>/dev/null | grep -A10 Name | grep -v Name | sed 's/^Address.*: .//') fi fi # test4iponly - IPADDRs=`echo $IP4` - [ ! -z "$IP6" ] && IPADDRs=`echo $IP4`" "`echo $IP6` + IPADDRs=$(echo $IP4) + [ ! -z "$IP6" ] && IPADDRs=$(echo $IP4)" "$(echo $IP6) # FIXME: we could/should test more than one IPv4 addresses if available, same IPv6. For now we test the first IPv4: - NODEIP=`echo "$IP4" | head -1` + NODEIP=$(echo "$IP4" | head -1) # we can't do this as some checks and even openssl are not yet IPv6 safe. BTW: bash sockets do IPv6 transparently! - #NODEIP=`echo "$IP6" | head -1` - rDNS=`host -t PTR $NODEIP 2>/dev/null | grep -v "is an alias for" | sed -e 's/^.*pointer //' -e 's/\.$//'` + #NODEIP=$(echo "$IP6" | head -1) + rDNS=$(host -t PTR $NODEIP 2>/dev/null | grep -v "is an alias for" | sed -e 's/^.*pointer //' -e 's/\.$//') echo $rDNS | grep -q NXDOMAIN && rDNS=" - " } display_rdns_etc() { - if [ `printf "$IPADDRs" | wc -w` -gt 1 ]; then + if [ $(printf "$IPADDRs" | wc -w) -gt 1 ]; then out " further IP addresses: " for i in $IPADDRs; do [ "$i" == "$NODEIP" ] && continue @@ -2750,7 +2750,7 @@ display_rdns_etc() { } datebanner() { - tojour=`date +%F`" "`date +%R` + tojour=$(date +%F)" "$(date +%R) outln pr_reverse "$1 now ($tojour) ---> $NODEIP:$PORT ($NODE) <---"; outln "\n" if [ "$1" = "Testing" ] ; then @@ -2800,12 +2800,12 @@ find_openssl_binary mybanner #PATH_TO_TESTSSL="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")" -PATH_TO_TESTSSL=`readlink "$BASH_SOURCE"` 2>/dev/null +PATH_TO_TESTSSL=$(readlink "$BASH_SOURCE") 2>/dev/null [ -z $PATH_TO_TESTSSL ] && PATH_TO_TESTSSL="." # # next file provides a pair "keycode/ RFC style name", see the RFCs, cipher(1) and # https://www.carbonwind.net/TLS_Cipher_Suites_Project/tls_ssl_cipher_suites_simple_table_all.htm -[ -r "$(dirname $PATH_TO_TESTSSL)/mapping-rfc.txt" ] && MAP_RFC_FNAME=`dirname $PATH_TO_TESTSSL`"/mapping-rfc.txt" +[ -r "$(dirname $PATH_TO_TESTSSL)/mapping-rfc.txt" ] && MAP_RFC_FNAME=$(dirname $PATH_TO_TESTSSL)"/mapping-rfc.txt" #FIXME: I know this sucks and getoptS is better @@ -2846,7 +2846,7 @@ case "$1" in maketempf parse_hn_port "$2" runprotocols ; ret=$? - spdy ; ret=`expr $? + $ret` + spdy ; ret=$(expr $? + $ret) exit $ret ;; -f|--ciphers) maketempf @@ -2903,7 +2903,7 @@ case "$1" in breach "$URL_PATH" ret=$? fi - ret=`expr $? + $ret` + ret=$(expr $? + $ret) exit $ret ;; -O|--ssl_poodle|poodle) maketempf @@ -2941,11 +2941,11 @@ case "$1" in hpkp "$URL_PATH" ret=$? serverbanner "$URL_PATH" - ret=`expr $? + $ret` + ret=$(expr $? + $ret) applicationbanner "$URL_PATH" - ret=`expr $? + $ret` + ret=$(expr $? + $ret) cookieflags "$URL_PATH" - ret=`expr $? + $ret` + ret=$(expr $? + $ret) else pr_litemagentaln " Wrong usage: You're not targetting a HTTP service" ret=2 @@ -2958,34 +2958,34 @@ case "$1" in outln runprotocols ; ret=$? - spdy ; ret=`expr $? + $ret` - run_std_cipherlists ; ret=`expr $? + $ret` - server_preference ; ret=`expr $? + $ret` - server_defaults ; ret=`expr $? + $ret` + spdy ; ret=$(expr $? + $ret) + run_std_cipherlists ; ret=$(expr $? + $ret) + server_preference ; ret=$(expr $? + $ret) + server_defaults ; ret=$(expr $? + $ret) if [[ $SERVICE == "HTTP" ]]; then outln; pr_blue "--> Testing HTTP Header response" outln "\n" - hsts "$URL_PATH" ; ret=`expr $? + $ret` - hpkp "$URL_PATH" ; ret=`expr $? + $ret` - serverbanner "$URL_PATH" ; ret=`expr $? + $ret` - applicationbanner "$URL_PATH" ; ret=`expr $? + $ret` - cookieflags "$URL_PATH" ; ret=`expr $? + $ret` + hsts "$URL_PATH" ; ret=$(expr $? + $ret) + hpkp "$URL_PATH" ; ret=$(expr $? + $ret) + serverbanner "$URL_PATH" ; ret=$(expr $? + $ret) + applicationbanner "$URL_PATH" ; ret=$(expr $? + $ret) + cookieflags "$URL_PATH" ; ret=$(expr $? + $ret) fi outln; pr_blue "--> Testing specific vulnerabilities" outln "\n" - heartbleed ; ret=`expr $? + $ret` - ccs_injection ; ret=`expr $? + $ret` - renego ; ret=`expr $? + $ret` - crime ; ret=`expr $? + $ret` - [[ $SERVICE == "HTTP" ]] && breach "$URL_PATH" ; ret=`expr $? + $ret` - ssl_poodle ; ret=`expr $? + $ret` - freak ; ret=`expr $? + $ret` - beast ; ret=`expr $? + $ret` + heartbleed ; ret=$(expr $? + $ret) + ccs_injection ; ret=$(expr $? + $ret) + renego ; ret=$(expr $? + $ret) + crime ; ret=$(expr $? + $ret) + [[ $SERVICE == "HTTP" ]] && breach "$URL_PATH" ; ret=$(expr $? + $ret) + ssl_poodle ; ret=$(expr $? + $ret) + freak ; ret=$(expr $? + $ret) + beast ; ret=$(expr $? + $ret) - rc4 ; ret=`expr $? + $ret` - pfs ; ret=`expr $? + $ret` + rc4 ; ret=$(expr $? + $ret) + pfs ; ret=$(expr $? + $ret) exit $ret ;; esac From b7b88a03e71df6a2de0d076849bb0951d5391b8e Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 10:00:14 -0500 Subject: [PATCH 04/26] Fix order of the redirect https://github.com/koalaman/shellcheck/wiki/SC2069 --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 81a7e2e..0b02f67 100755 --- a/testssl.sh +++ b/testssl.sh @@ -270,7 +270,7 @@ wait_kill(){ pid=$1 maxsleep=$2 while true; do - if ! ps $pid 2>&1 >/dev/null; then + if ! ps $pid >/dev/null 2>&1; then return 0 # didn't reach maxsleep yet fi sleep 1 @@ -702,7 +702,7 @@ sockread() { pid=$! while true; do - if ! ps $pid 2>&1 >/dev/null; then + if ! ps $pid >/dev/null 2>&1; then break # didn't reach maxsleep yet kill $pid >&2 2>/dev/null fi @@ -712,7 +712,7 @@ sockread() { done #FIXME: cleanup, we have extra function for this now - if ps $pid 2>&1 >/dev/null; then + if ps $pid >/dev/null 2&>1; then # time's up and dd is still alive --> timeout kill $pid wait $pid 2>/dev/null @@ -1460,7 +1460,7 @@ sockread_serverhello() { [[ $maxsleep -le 0 ]] && break done - if ps $pid 2>&1 >/dev/null; then + if ps $pid >/dev/null 2>&1; then # time's up and dd is still alive --> timeout kill $pid >&2 2>/dev/null wait $pid 2>/dev/null From 73202da2fd6778728d36b45caaa9bbdde64fafa8 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 14:26:02 -0500 Subject: [PATCH 05/26] Fix missing single quote --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index 0b02f67..2762276 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1139,7 +1139,7 @@ server_defaults() { SAN=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ sed -e 's/DNS://g' -e 's/ //g' -e 's/,/\n/g' -e 's/othername://g') # ^^^ CACert - [ x"$SAN" != "x" ] && SAN=$(echo "$SAN" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g) && outln " subjectAltName (SAN) $SAN" + [ x"$SAN" != "x" ] && SAN=$(echo "$SAN" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g') && outln " subjectAltName (SAN) $SAN" # replace line feed by " " out " Issuer " From 59ed025f36f716eb9ff7b6dd0bbb51880a8dd57c Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 14:54:36 -0500 Subject: [PATCH 06/26] Replace expr with $(( )) https://github.com/koalaman/shellcheck/wiki/SC2003 --- testssl.sh | 96 +++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/testssl.sh b/testssl.sh index 2762276..b62b164 100755 --- a/testssl.sh +++ b/testssl.sh @@ -274,7 +274,7 @@ wait_kill(){ return 0 # didn't reach maxsleep yet fi sleep 1 - maxsleep=$(expr $maxsleep - 1) + maxsleep=$(($maxsleep - 1)) test $maxsleep -eq 0 && break done # needs to be killed: kill $pid >&2 2>/dev/null @@ -686,7 +686,7 @@ std_cipherlists() { # ARG2: sleep socksend() { # the following works under BSD and Linux, which is quite tricky. So don't mess with it unless you're really sure what you do - data=$(echo "$1" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\\/g' | tr -d '\n') + data=$(echo "$1" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\/g' | tr -d '\n') [[ $DEBUG -ge 4 ]] && echo "\"$data\"" printf -- "$data" >&5 2>/dev/null & sleep $2 @@ -707,7 +707,7 @@ sockread() { kill $pid >&2 2>/dev/null fi sleep 1 - maxsleep=$(expr $maxsleep - 1) + maxsleep=$(($maxsleep - 1)) test $maxsleep -eq 0 && break done #FIXME: cleanup, we have extra function for this now @@ -1024,7 +1024,7 @@ server_preference() { proto[i]="" cipher[i]="" fi - i=$(expr $i + 1) + i=$(($i + 1)) done if spdy_pre ; then # is NPN/SPDY supported and is this no STARTTLS? @@ -1163,10 +1163,10 @@ server_defaults() { if ! echo $expire | grep -qw not; then pr_red "expired!" else - SECS2WARN=$(expr 24 \* 60 \* 60 \* $DAYS2WARN2) # low threshold first + SECS2WARN=$((24 * 60 * 60 * $DAYS2WARN2)) # low threshold first expire=$($OPENSSL x509 -in $HOSTCERT -checkend $SECS2WARN) if echo "$expire" | grep -qw not; then - SECS2WARN=$(expr 24 \* 60 \* 60 \* $DAYS2WARN2) + SECS2WARN=$((24 * 60 * 60 * $DAYS2WARN2)) expire=$($OPENSSL x509 -in $HOSTCERT -checkend $SECS2WARN) if echo "$expire" | grep -qw not; then pr_litegreen ">= $DAYS2WARN1 days" @@ -1216,7 +1216,7 @@ server_defaults() { #remotetime=$(grep -w "Start Time" $TMPFILE | sed 's/[A-Za-z:() ]//g') #if [ ! -z "$remotetime" ]; then # remotetime_stdformat=$(date --date="@$remotetime" "+%Y-%m-%d %r") - # difftime=$(expr $localtime - $remotetime) + # difftime=$(($localtime - $remotetime)) # [ $difftime -gt 0 ] && difftime="+"$difftime # difftime=$difftime" s" # outln " remotetime? : $remotetime ($difftime) = $remotetime_stdformat" @@ -2171,10 +2171,10 @@ crime() { # STR=$(grep Compression $TMPFILE ) # if echo $STR | grep -q NONE >/dev/null; then # pr_green "not vulnerable (OK)" -# ret=$(expr $ret + 0) +# ret=$(($ret + 0)) # else # pr_red "VULNERABLE (NOT ok)" -# ret=$(expr $ret + 1) +# ret=$(($ret + 1)) # fi # fi # fi @@ -2393,27 +2393,27 @@ starttls() { # of the cmdline e.g. with getopts. STARTTLS="-starttls $protocol" export STARTTLS - runprotocols ; ret=$(expr $? + $ret) - run_std_cipherlists ; ret=$(expr $? + $ret) - server_preference ; ret=$(expr $? + $ret) - server_defaults ; ret=$(expr $? + $ret) + runprotocols ; ret=$(($? + $ret)) + run_std_cipherlists ; ret=$(($? + $ret)) + server_preference ; ret=$(($? + $ret)) + server_defaults ; ret=$(($? + $ret)) outln; pr_blue "--> Testing specific vulnerabilities" ; outln "\n" #FIXME: heartbleed + CCS won't work this way yet -# heartbleed ; ret=$(expr $? + $ret) -# ccs_injection ; ret=$(expr $? + $ret) - renego ; ret=$(expr $? + $ret) - crime ; ret=$(expr $? + $ret) - ssl_poodle ; ret=$(expr $? + $ret) - freak ; ret=$(expr $? + $ret) - beast ; ret=$(expr $? + $ret) +# heartbleed ; ret=$(($? + $ret)) +# ccs_injection ; ret=$(($? + $ret)) + renego ; ret=$(($? + $ret)) + crime ; ret=$(($? + $ret)) + ssl_poodle ; ret=$(($? + $ret)) + freak ; ret=$(($? + $ret)) + beast ; ret=$(($? + $ret)) - rc4 ; ret=$(expr $? + $ret) - pfs ; ret=$(expr $? + $ret) + rc4 ; ret=$(($? + $ret)) + pfs ; ret=$(($? + $ret)) outln - #cipher_per_proto ; ret=$(expr $? + $ret) - allciphers ; ret=$(expr $? + $ret) + #cipher_per_proto ; ret=$(($? + $ret)) + allciphers ; ret=$(($? + $ret)) fi ;; *) pr_litemagentaln "momentarily only ftp, smtp, pop3, imap, xmpp and telnet, ldap allowed" >&2 @@ -2846,7 +2846,7 @@ case "$1" in maketempf parse_hn_port "$2" runprotocols ; ret=$? - spdy ; ret=$(expr $? + $ret) + spdy ; ret=$(($? + $ret)) exit $ret ;; -f|--ciphers) maketempf @@ -2903,7 +2903,7 @@ case "$1" in breach "$URL_PATH" ret=$? fi - ret=$(expr $? + $ret) + ret=$(($? + $ret)) exit $ret ;; -O|--ssl_poodle|poodle) maketempf @@ -2941,11 +2941,11 @@ case "$1" in hpkp "$URL_PATH" ret=$? serverbanner "$URL_PATH" - ret=$(expr $? + $ret) + ret=$(($? + $ret)) applicationbanner "$URL_PATH" - ret=$(expr $? + $ret) + ret=$(($? + $ret)) cookieflags "$URL_PATH" - ret=$(expr $? + $ret) + ret=$(($? + $ret)) else pr_litemagentaln " Wrong usage: You're not targetting a HTTP service" ret=2 @@ -2958,34 +2958,34 @@ case "$1" in outln runprotocols ; ret=$? - spdy ; ret=$(expr $? + $ret) - run_std_cipherlists ; ret=$(expr $? + $ret) - server_preference ; ret=$(expr $? + $ret) - server_defaults ; ret=$(expr $? + $ret) + spdy ; ret=$(($? + $ret)) + run_std_cipherlists ; ret=$(($? + $ret)) + server_preference ; ret=$(($? + $ret)) + server_defaults ; ret=$(($? + $ret)) if [[ $SERVICE == "HTTP" ]]; then outln; pr_blue "--> Testing HTTP Header response" outln "\n" - hsts "$URL_PATH" ; ret=$(expr $? + $ret) - hpkp "$URL_PATH" ; ret=$(expr $? + $ret) - serverbanner "$URL_PATH" ; ret=$(expr $? + $ret) - applicationbanner "$URL_PATH" ; ret=$(expr $? + $ret) - cookieflags "$URL_PATH" ; ret=$(expr $? + $ret) + hsts "$URL_PATH" ; ret=$(($? + $ret)) + hpkp "$URL_PATH" ; ret=$(($? + $ret)) + serverbanner "$URL_PATH" ; ret=$(($? + $ret)) + applicationbanner "$URL_PATH" ; ret=$(($? + $ret)) + cookieflags "$URL_PATH" ; ret=$(($? + $ret)) fi outln; pr_blue "--> Testing specific vulnerabilities" outln "\n" - heartbleed ; ret=$(expr $? + $ret) - ccs_injection ; ret=$(expr $? + $ret) - renego ; ret=$(expr $? + $ret) - crime ; ret=$(expr $? + $ret) - [[ $SERVICE == "HTTP" ]] && breach "$URL_PATH" ; ret=$(expr $? + $ret) - ssl_poodle ; ret=$(expr $? + $ret) - freak ; ret=$(expr $? + $ret) - beast ; ret=$(expr $? + $ret) + heartbleed ; ret=$(($? + $ret)) + ccs_injection ; ret=$(($? + $ret)) + renego ; ret=$(($? + $ret)) + crime ; ret=$(($? + $ret)) + [[ $SERVICE == "HTTP" ]] && breach "$URL_PATH" ; ret=$(($? + $ret)) + ssl_poodle ; ret=$(($? + $ret)) + freak ; ret=$(($? + $ret)) + beast ; ret=$(($? + $ret)) - rc4 ; ret=$(expr $? + $ret) - pfs ; ret=$(expr $? + $ret) + rc4 ; ret=$(($? + $ret)) + pfs ; ret=$(($? + $ret)) exit $ret ;; esac From 4cdc89aa61f932d186ea5c52f3138d3bd2711314 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 14:56:30 -0500 Subject: [PATCH 07/26] Revert to 2>&1 > /dev/null order because it isn't behaving correctly. --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index b62b164..1972aaa 100755 --- a/testssl.sh +++ b/testssl.sh @@ -270,7 +270,7 @@ wait_kill(){ pid=$1 maxsleep=$2 while true; do - if ! ps $pid >/dev/null 2>&1; then + if ! ps $pid 2>&1 >/dev/null ; then return 0 # didn't reach maxsleep yet fi sleep 1 @@ -702,7 +702,7 @@ sockread() { pid=$! while true; do - if ! ps $pid >/dev/null 2>&1; then + if ! ps $pid 2>&1 >/dev/null ; then break # didn't reach maxsleep yet kill $pid >&2 2>/dev/null fi @@ -712,7 +712,7 @@ sockread() { done #FIXME: cleanup, we have extra function for this now - if ps $pid >/dev/null 2&>1; then + if ps $pid 2&>1 >/dev/null ; then # time's up and dd is still alive --> timeout kill $pid wait $pid 2>/dev/null @@ -1460,7 +1460,7 @@ sockread_serverhello() { [[ $maxsleep -le 0 ]] && break done - if ps $pid >/dev/null 2>&1; then + if ps $pid 2>&1 >/dev/null ; then # time's up and dd is still alive --> timeout kill $pid >&2 2>/dev/null wait $pid 2>/dev/null From 8ad1cca0ab170b2b7881343e2258d902ffd953c7 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 15:10:36 -0500 Subject: [PATCH 08/26] Remove useless kittens --- testssl.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index 0b02f67..43f77a6 100755 --- a/testssl.sh +++ b/testssl.sh @@ -505,7 +505,7 @@ serverbanner() { pr_bold " Server " grep -ai '^Server' $HEADERFILE >$TMPFILE if [ $? -eq 0 ]; then - serverbanner=$(cat $TMPFILE | sed -e 's/^Server: //' -e 's/^server: //') + serverbanner=$(sed -e 's/^Server: //' -e 's/^server: //' $TMPFILE) if [ x"$serverbanner" == "x\n" -o x"$serverbanner" == "x\n\r" -o x"$serverbanner" == "x" ]; then outln "banner exists but empty string" else @@ -553,7 +553,7 @@ cookieflags() { # ARG1: Path, ARG2: path pr_bold " Cookie(s) " grep -ai '^Set-Cookie' $HEADERFILE >$TMPFILE if [ $? -eq 0 ]; then - nr_cookies=$(cat $TMPFILE | wc -l) + nr_cookies=$(wc -l $TMPFILE) out "$nr_cookies issued: " if [ $nr_cookies -gt 1 ] ; then negative_word="NONE" @@ -645,7 +645,7 @@ listciphers() { std_cipherlists() { out "$2 "; if listciphers $1; then # is that locally available?? - [ $SHOW_LOC_CIPH = "1" ] && out "local ciphers are: " && cat $TMPFILE | sed 's/:/, /g' + [ $SHOW_LOC_CIPH = "1" ] && out "local ciphers are: " && sed 's/:/, /g' $TMPFILE $OPENSSL s_client -cipher "$1" $STARTTLS -connect $NODEIP:$PORT $SNI 2>$TMPFILE >/dev/null $TMPFILE $TMPFILE Date: Fri, 13 Mar 2015 15:16:21 -0500 Subject: [PATCH 09/26] Remove 2>&1 for the ps $pid lines; it's unnecessary --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 4c7a759..8e0c4b1 100755 --- a/testssl.sh +++ b/testssl.sh @@ -270,7 +270,7 @@ wait_kill(){ pid=$1 maxsleep=$2 while true; do - if ! ps $pid 2>&1 >/dev/null ; then + if ! ps $pid >/dev/null ; then return 0 # didn't reach maxsleep yet fi sleep 1 @@ -702,7 +702,7 @@ sockread() { pid=$! while true; do - if ! ps $pid 2>&1 >/dev/null ; then + if ! ps $pid >/dev/null ; then break # didn't reach maxsleep yet kill $pid >&2 2>/dev/null fi @@ -712,7 +712,7 @@ sockread() { done #FIXME: cleanup, we have extra function for this now - if ps $pid 2&>1 >/dev/null ; then + if ps $pid >/dev/null ; then # time's up and dd is still alive --> timeout kill $pid wait $pid 2>/dev/null @@ -1460,7 +1460,7 @@ sockread_serverhello() { [[ $maxsleep -le 0 ]] && break done - if ps $pid 2>&1 >/dev/null ; then + if ps $pid >/dev/null ; then # time's up and dd is still alive --> timeout kill $pid >&2 2>/dev/null wait $pid 2>/dev/null From 8d965f7c713d2f05eaa5aa0473f47dc3772ddc4c Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 15:19:47 -0500 Subject: [PATCH 10/26] More useless cat --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 1972aaa..55a47af 100755 --- a/testssl.sh +++ b/testssl.sh @@ -311,7 +311,7 @@ EOF ) &>$HEADERFILE_BREACH & pid=$! if wait_kill $pid $HEADER_MAXSLEEP; then - result=$(cat $HEADERFILE_BREACH | grep -a '^Content-Encoding' | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g') + result=$(grep -a '^Content-Encoding' $HEADERFILE_BREACH | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g') result=$(echo $result | tr -cd '\40-\176') if [ -z $result ]; then pr_green "no HTTP compression (OK) " @@ -392,7 +392,7 @@ EOF pid=$! if wait_kill $pid $HEADER_MAXSLEEP; then if ! egrep -iq "XML|HTML|DOCTYPE|HTTP|Connection" $HEADERFILE; then - pr_litemagenta "likely HTTP header requests failed (#lines: $(cat $HEADERFILE | wc -l))." + pr_litemagenta "likely HTTP header requests failed (#lines: $(wc -l $HEADERFILE))." outln "Rerun with DEBUG=1 and inspect \"http_header.txt\"\n" debugme cat $HEADERFILE ret=7 From 8cdd516ad1c5434d3bee608d8d547b8d87093765 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 13 Mar 2015 15:24:16 -0500 Subject: [PATCH 11/26] more ps >/dev/null fixes more useless cat --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 55a47af..985ee51 100755 --- a/testssl.sh +++ b/testssl.sh @@ -270,7 +270,7 @@ wait_kill(){ pid=$1 maxsleep=$2 while true; do - if ! ps $pid 2>&1 >/dev/null ; then + if ! ps $pid >/dev/null ; then return 0 # didn't reach maxsleep yet fi sleep 1 @@ -702,7 +702,7 @@ sockread() { pid=$! while true; do - if ! ps $pid 2>&1 >/dev/null ; then + if ! ps $pid >/dev/null ; then break # didn't reach maxsleep yet kill $pid >&2 2>/dev/null fi @@ -2203,7 +2203,7 @@ ssl_poodle() { debugme echo $cbc_ciphers $OPENSSL s_client -ssl3 $STARTTLS -cipher $cbc_ciphers -connect $NODEIP:$PORT $SNI &>$TMPFILE $TMPFILE Date: Fri, 13 Mar 2015 15:51:50 -0500 Subject: [PATCH 12/26] Make date command work with both Linux and FreeBSD --- testssl.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index a0f468f..d66656e 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1177,8 +1177,16 @@ server_defaults() { pr_litered "expires < $DAYS2WARN2 days!" fi fi - enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") - startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") + case $(uname -s) in + Linux) + enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") + startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") + ;; + FreeBSD) + enddate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") + startdate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") + ;; + esac outln " ($startdate --> $enddate)" savedir=$(pwd); cd $TEMPDIR From 5cd4b8f73e40fc0d3c3af849febb2d326e662b28 Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 15 Mar 2015 09:04:49 +0100 Subject: [PATCH 13/26] - Shellcheck static analysis by Mark --- CREDITS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CREDITS.md b/CREDITS.md index 855588c..1cc5879 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -12,7 +12,8 @@ - initial MX stuff * Mark Felder - - minor cleanups + - lots of cleanups + - Shellcheck static analysis * Peter Mosmans - cleanups From fbd383f345eff52fbd5d9d557a05a18f74fd3bfe Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 15 Mar 2015 10:18:37 +0100 Subject: [PATCH 14/26] - prework for checking hpkp fingerprints --- testssl.sh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index d66656e..b891517 100755 --- a/testssl.sh +++ b/testssl.sh @@ -90,8 +90,6 @@ NODEIP="" IPS="" SERVICE="" # is the server running an HTTP server, SMTP, POP or IMAP? -BLA="" - # make sure that temporary files are cleaned up after use trap "cleanup" QUIT EXIT @@ -459,6 +457,8 @@ hsts() { hpkp() { local hpkp_age_sec local hpkp_age_days + local hpkp_nr_keys + local hpkp_key if [ ! -s $HEADERFILE ] ; then http_header "$1" || return 3 @@ -468,7 +468,8 @@ hpkp() { if [ $? -eq 0 ]; then egrep -aciw '^Public-Key-Pins|Public-Key-Pins-Report-Only' $HEADERFILE | egrep -wq "1" || out "(two HPKP header, using 1st one) " # dirty trick so that grep -c really counts occurances and not lines w/ occurances: - if [ $(sed 's/pin-sha/pin-sha\n/g' < $TMPFILE | grep -c pin-sha) -eq 1 ]; then + hpkp_nr_keys=$(sed 's/pin-sha/pin-sha\n/g' < $TMPFILE | grep -c pin-sha) + if [ $hpkp_nr_keys -eq 1 ]; then pr_brown "One key is not sufficent, " fi hpkp_age_sec=$(sed -e 's/\r//g' -e 's/^.*max-age=//' -e 's/;.*//' $TMPFILE) @@ -481,6 +482,15 @@ hpkp() { includeSubDomains "$TMPFILE" preload "$TMPFILE" + + # get the key fingerprints: + sed -i -e 's/Public-Key-Pins://g' -e s'/Public-Key-Pins-Report-Only://' $TMPFILE + while read hpkp_key; do + #FIXME: to be checked against level0.crt + # like openssl x509 -in level0.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl base64 -d + debugme echo "$hpkp_key=" + done < <(sed -e 's/;/\n/g' -e 's/ //g' $TMPFILE | awk -F'=' '/pin.*=/ { print $2 }') + out " (fingerprints not checked)" else out "--" @@ -2336,7 +2346,7 @@ old_fart() { find_openssl_binary() { # 0. check environment variable whether it's executable if [ ! -z "$OPENSSL" ] && [ ! -x "$OPENSSL" ]; then - pr_redln "\ncannot execute specified ($OPENSSL) openssl binary." + pr_redln "\ncannot find (\$OPENSSL=$OPENSSL) binary." outln "continuing ..." fi if [ -x "$OPENSSL" ]; then @@ -2997,6 +3007,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.203 2015/03/13 11:20:18 dirkw Exp $ +# $Id: testssl.sh,v 1.205 2015/03/15 09:18:36 dirkw Exp $ # vim:ts=5:sw=5 From 655944bd4d31e1509bbeb5f3e60ce215f9ace428 Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 15 Mar 2015 14:41:34 +0100 Subject: [PATCH 15/26] - FIX: regression for wc -l w/o cat (3x) - removal of unneccessary waitpid, inline --- testssl.sh | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/testssl.sh b/testssl.sh index b891517..596ae44 100755 --- a/testssl.sh +++ b/testssl.sh @@ -390,7 +390,7 @@ EOF pid=$! if wait_kill $pid $HEADER_MAXSLEEP; then if ! egrep -iq "XML|HTML|DOCTYPE|HTTP|Connection" $HEADERFILE; then - pr_litemagenta "likely HTTP header requests failed (#lines: $(wc -l $HEADERFILE))." + pr_litemagenta "likely HTTP header requests failed (#lines: $(wc -l < $HEADERFILE))." outln "Rerun with DEBUG=1 and inspect \"http_header.txt\"\n" debugme cat $HEADERFILE ret=7 @@ -563,7 +563,7 @@ cookieflags() { # ARG1: Path, ARG2: path pr_bold " Cookie(s) " grep -ai '^Set-Cookie' $HEADERFILE >$TMPFILE if [ $? -eq 0 ]; then - nr_cookies=$(wc -l $TMPFILE) + nr_cookies=$(wc -l < $TMPFILE) out "$nr_cookies issued: " if [ $nr_cookies -gt 1 ] ; then negative_word="NONE" @@ -710,24 +710,10 @@ sockread() { ddreply=$(mktemp /tmp/ddreply.XXXXXX) || exit 7 dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null & pid=$! - - while true; do - if ! ps $pid >/dev/null ; then - break # didn't reach maxsleep yet - kill $pid >&2 2>/dev/null - fi - sleep 1 - maxsleep=$(($maxsleep - 1)) - test $maxsleep -eq 0 && break - done -#FIXME: cleanup, we have extra function for this now - if ps $pid >/dev/null ; then - # time's up and dd is still alive --> timeout - kill $pid - wait $pid 2>/dev/null - ret=3 # means killed - fi + wait_kill $pid $maxsleep + ret=$? + SOCKREPLY=$(cat $ddreply) rm $ddreply @@ -1269,7 +1255,7 @@ pfs() { $OPENSSL ciphers -V "$PFSOK" >$TMPFILE 2>/dev/null if [ $? -ne 0 ] ; then - number_pfs=$(wc -l $TMPFILE | awk '{ print $1 }') + number_pfs=$(wc -l < $TMPFILE) if [ "$number_pfs" -le "$CLIENT_MIN_PFS" ] ; then outln pr_magentaln " Local problem: you have only $number_pfs client side PFS ciphers " @@ -3007,6 +2993,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.205 2015/03/15 09:18:36 dirkw Exp $ +# $Id: testssl.sh,v 1.206 2015/03/15 13:41:33 dirkw Exp $ # vim:ts=5:sw=5 From 68695bbad3faec5218e1b78639a0c44c0c9c115d Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 15 Mar 2015 16:10:14 +0100 Subject: [PATCH 16/26] FIX #74 for sed BSD: doesn't like inline \n headline for BEAST was missing --- testssl.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 596ae44..c19dfd7 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2267,6 +2267,7 @@ beast(){ local higher_proto_supported="" local -i ret=0 local spaces=" " + local cr=$'\n' pr_bold " BEAST"; out " (CVE-2011-3389) " @@ -2290,7 +2291,7 @@ beast(){ if [ -z "$detected_cbc_cipher" ]; then pr_litegreenln "no CBC ciphers for $(echo $proto | tr '[a-z]' '[A-Z]') (OK)" else - detected_cbc_cipher=$(echo "$detected_cbc_cipher" | sed -e 's/ /\n '"${spaces}"'/9' -e 's/ /\n '"${spaces}"'/6' -e 's/ /\n '"${spaces}"'/3') + detected_cbc_cipher=$(echo "$detected_cbc_cipher" | sed -e "s/ /\\${cr} ${spaces}/9" -e "s/ /\\${cr} ${spaces}/6" -e "s/ /\\${cr} ${spaces}/3") [ $ret -eq 1 ] && out "$spaces" out "$(echo $proto | tr '[a-z]' '[A-Z]'):"; pr_brownln "$detected_cbc_cipher" ret=1 @@ -2934,6 +2935,7 @@ case "$1" in -A|--beast) maketempf parse_hn_port "$2" + outln; pr_blue "--> Testing for BEAST vulnerability"; outln "\n" beast exit $? ;; -H|--header|--headers) @@ -2993,6 +2995,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.206 2015/03/15 13:41:33 dirkw Exp $ +# $Id: testssl.sh,v 1.207 2015/03/15 15:10:13 dirkw Exp $ # vim:ts=5:sw=5 From 4556108a726dd51398de0b608dd28895acf57120 Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 15 Mar 2015 16:59:29 +0100 Subject: [PATCH 17/26] further improvements through shellcheck --- testssl.sh | 111 ++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/testssl.sh b/testssl.sh index c19dfd7..b2036fb 100755 --- a/testssl.sh +++ b/testssl.sh @@ -272,7 +272,7 @@ wait_kill(){ return 0 # didn't reach maxsleep yet fi sleep 1 - maxsleep=$(($maxsleep - 1)) + maxsleep=$((maxsleep - 1)) test $maxsleep -eq 0 && break done # needs to be killed: kill $pid >&2 2>/dev/null @@ -713,7 +713,6 @@ sockread() { wait_kill $pid $maxsleep ret=$? - SOCKREPLY=$(cat $ddreply) rm $ddreply @@ -1421,7 +1420,7 @@ spdy() { fd_socket() { # arg doesn't work here if ! exec 5<> /dev/tcp/$NODEIP/$PORT; then - pr_magenta "$(basename $0): unable to open a socket to $NODEIP:$PORT" + pr_magenta "$(basename "$0"): unable to open a socket to $NODEIP:$PORT" return 6 fi return 0 @@ -1455,12 +1454,12 @@ sockread_serverhello() { pid=$! while true; do - if ! ps ax | grep -v grep | grep -q $pid; then + if ! ps $pid >/dev/null; then break # didn't reach maxsleep yet kill $pid >&2 2>/dev/null fi sleep $USLEEP_REC - maxsleep=$(($maxsleep - 1)) + maxsleep=$((maxsleep - 1)) [[ $maxsleep -le 0 ]] && break done @@ -2398,27 +2397,27 @@ starttls() { # of the cmdline e.g. with getopts. STARTTLS="-starttls $protocol" export STARTTLS - runprotocols ; ret=$(($? + $ret)) - run_std_cipherlists ; ret=$(($? + $ret)) - server_preference ; ret=$(($? + $ret)) - server_defaults ; ret=$(($? + $ret)) + runprotocols ; ret=$(($? + ret)) + run_std_cipherlists ; ret=$(($? + ret)) + server_preference ; ret=$(($? + ret)) + server_defaults ; ret=$(($? + ret)) outln; pr_blue "--> Testing specific vulnerabilities" ; outln "\n" #FIXME: heartbleed + CCS won't work this way yet -# heartbleed ; ret=$(($? + $ret)) -# ccs_injection ; ret=$(($? + $ret)) - renego ; ret=$(($? + $ret)) - crime ; ret=$(($? + $ret)) - ssl_poodle ; ret=$(($? + $ret)) - freak ; ret=$(($? + $ret)) - beast ; ret=$(($? + $ret)) +# heartbleed ; ret=$(($? + ret)) +# ccs_injection ; ret=$(($? + ret)) + renego ; ret=$(($? + ret)) + crime ; ret=$(($? + ret)) + ssl_poodle ; ret=$(($? + ret)) + freak ; ret=$(($? + ret)) + beast ; ret=$(($? + ret)) - rc4 ; ret=$(($? + $ret)) - pfs ; ret=$(($? + $ret)) + rc4 ; ret=$(($? + ret)) + pfs ; ret=$(($? + ret)) outln - #cipher_per_proto ; ret=$(($? + $ret)) - allciphers ; ret=$(($? + $ret)) + #cipher_per_proto ; ret=$(($? + ret)) + allciphers ; ret=$(($? + ret)) fi ;; *) pr_litemagentaln "momentarily only ftp, smtp, pop3, imap, xmpp and telnet, ldap allowed" >&2 @@ -2431,7 +2430,7 @@ starttls() { help() { - PRG=$(basename $0) + PRG=$(basename "$0") cat << EOF $PRG @@ -2481,13 +2480,13 @@ EOF mybanner() { - me=$(basename $0) + me=$(basename "$0") osslver=$($OPENSSL version) osslpath=$(which $OPENSSL) nr_ciphers=$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' | sed 's/:/ /g' | wc -w) hn=$(hostname) #poor man's ident (nowadays ident not neccessarily installed) - idtag=$(grep '\$Id' $0 | grep -w [E]xp | sed -e 's/^# //' -e 's/\$ $/\$/') + idtag=$(grep '\$Id' $0 | grep -w "[E]xp" | sed -e 's/^# //' -e 's/\$ $/\$/') [ "$COLOR" -ne 0 ] && idtag="\033[1;30m$idtag\033[m\033[1m" bb=$(cat < /dev/null; then - MXs=$(dig +short -t MX $1) + MXs=$(dig +short -t MX "$1") elif which host &> /dev/null; then - MXs=$(host -t MX $1 | grep 'handled by' | sed -e 's/^.*by //' -e 's/\.$//') + MXs=$(host -t MX "$1" | grep 'handled by' | sed -e 's/^.*by //' -e 's/\.$//') elif which nslookup &> /dev/null; then - MXs=$(nslookup -type=MX $1 2> /dev/null | grep 'mail exchanger = ' | sed 's/^.*mail exchanger = //g') + MXs=$(nslookup -type=MX "$1" 2> /dev/null | grep 'mail exchanger = ' | sed 's/^.*mail exchanger = //g') else pr_magentaln 'No dig, host or nslookup' exit 3 @@ -2806,7 +2805,7 @@ mybanner #PATH_TO_TESTSSL="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")" PATH_TO_TESTSSL=$(readlink "$BASH_SOURCE") 2>/dev/null -[ -z $PATH_TO_TESTSSL ] && PATH_TO_TESTSSL="." +[ -z "$PATH_TO_TESTSSL" ] && PATH_TO_TESTSSL="." # # next file provides a pair "keycode/ RFC style name", see the RFCs, cipher(1) and # https://www.carbonwind.net/TLS_Cipher_Suites_Project/tls_ssl_cipher_suites_simple_table_all.htm @@ -2820,7 +2819,7 @@ case "$1" in exit 0 ;; --mx) - mx_allentries $2 + mx_allentries "$2" exit $? ;; -V|--local) @@ -2851,7 +2850,7 @@ case "$1" in maketempf parse_hn_port "$2" runprotocols ; ret=$? - spdy ; ret=$(($? + $ret)) + spdy ; ret=$(($? + ret)) exit $ret ;; -f|--ciphers) maketempf @@ -2908,7 +2907,7 @@ case "$1" in breach "$URL_PATH" ret=$? fi - ret=$(($? + $ret)) + ret=$(($? + ret)) exit $ret ;; -O|--ssl_poodle|poodle) maketempf @@ -2947,11 +2946,11 @@ case "$1" in hpkp "$URL_PATH" ret=$? serverbanner "$URL_PATH" - ret=$(($? + $ret)) + ret=$(($? + ret)) applicationbanner "$URL_PATH" - ret=$(($? + $ret)) + ret=$(($? + ret)) cookieflags "$URL_PATH" - ret=$(($? + $ret)) + ret=$(($? + ret)) else pr_litemagentaln " Wrong usage: You're not targetting a HTTP service" ret=2 @@ -2964,37 +2963,37 @@ case "$1" in outln runprotocols ; ret=$? - spdy ; ret=$(($? + $ret)) - run_std_cipherlists ; ret=$(($? + $ret)) - server_preference ; ret=$(($? + $ret)) - server_defaults ; ret=$(($? + $ret)) + spdy ; ret=$(($? + ret)) + run_std_cipherlists ; ret=$(($? + ret)) + server_preference ; ret=$(($? + ret)) + server_defaults ; ret=$(($? + ret)) if [[ $SERVICE == "HTTP" ]]; then outln; pr_blue "--> Testing HTTP Header response" outln "\n" - hsts "$URL_PATH" ; ret=$(($? + $ret)) - hpkp "$URL_PATH" ; ret=$(($? + $ret)) - serverbanner "$URL_PATH" ; ret=$(($? + $ret)) - applicationbanner "$URL_PATH" ; ret=$(($? + $ret)) - cookieflags "$URL_PATH" ; ret=$(($? + $ret)) + hsts "$URL_PATH" ; ret=$(($? + ret)) + hpkp "$URL_PATH" ; ret=$(($? + ret)) + serverbanner "$URL_PATH" ; ret=$(($? + ret)) + applicationbanner "$URL_PATH" ; ret=$(($? + ret)) + cookieflags "$URL_PATH" ; ret=$(($? + ret)) fi outln; pr_blue "--> Testing specific vulnerabilities" outln "\n" - heartbleed ; ret=$(($? + $ret)) - ccs_injection ; ret=$(($? + $ret)) - renego ; ret=$(($? + $ret)) - crime ; ret=$(($? + $ret)) - [[ $SERVICE == "HTTP" ]] && breach "$URL_PATH" ; ret=$(($? + $ret)) - ssl_poodle ; ret=$(($? + $ret)) - freak ; ret=$(($? + $ret)) - beast ; ret=$(($? + $ret)) + heartbleed ; ret=$(($? + ret)) + ccs_injection ; ret=$(($? + ret)) + renego ; ret=$(($? + ret)) + crime ; ret=$(($? + ret)) + [[ $SERVICE == "HTTP" ]] && breach "$URL_PATH" ; ret=$(($? + ret)) + ssl_poodle ; ret=$(($? + ret)) + freak ; ret=$(($? + ret)) + beast ; ret=$(($? + ret)) - rc4 ; ret=$(($? + $ret)) - pfs ; ret=$(($? + $ret)) + rc4 ; ret=$(($? + ret)) + pfs ; ret=$(($? + ret)) exit $ret ;; esac -# $Id: testssl.sh,v 1.207 2015/03/15 15:10:13 dirkw Exp $ +# $Id: testssl.sh,v 1.208 2015/03/15 15:59:28 dirkw Exp $ # vim:ts=5:sw=5 From f8ba69f9fbacf275bc139a95a005dc212a03df99 Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 16 Mar 2015 00:22:51 +0100 Subject: [PATCH 18/26] - some internal code internal cleanups - minor cosmetic output corrections - preparation for bash sockets for SSLv3 to TLS 1.2 --- testssl.sh | 483 +++++++++++++++++++++++++++-------------------------- 1 file changed, 244 insertions(+), 239 deletions(-) diff --git a/testssl.sh b/testssl.sh index b2036fb..2721a84 100755 --- a/testssl.sh +++ b/testssl.sh @@ -49,27 +49,28 @@ SWCONTACT="dirk aet testssl dot sh" # following variables make use of $ENV, e.g. OPENSSL= ./testssl.sh COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all SHOW_LOC_CIPH=${SHOW_LOC_CIPH:-0} # determines whether the client side ciphers are displayed at all (makes no sense normally) -VERBERR=${VERBERR:-1} # 0 means to be more verbose (some like the errors to be dispayed so that one can tell better - # whether handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1 -LOCERR=${LOCERR:-0} # displays the local error SHOW_EACH_C=${SHOW_EACH_C:-0} # where individual ciphers are tested show just the positively ones tested SNEAKY=${SNEAKY:-1} # if zero: the referer and useragent we leave while checking the http header is just usual -HEADER_MAXSLEEP=${HEADER_MAXSLEEP:-3} # we wait this long before killing the process to retrieve a service banner / http header SSL_NATIVE=${SSL_NATIVE:-0} # we do per default bash sockets! ASSUMING_HTTP=${ASSUMING_HTTP:-0} # in seldom cases (WAF, old servers/grumpy SSL) the service detection fails. Set to 1 for HTTP +DEBUG=${DEBUG:-0} # if 1 the temp files won't be erased. 2: list more what's going on (formerly: eq VERBOSE=1), + # 3: slight hexdumps and other info, 4: the whole nine yards of output + #FIXME: still to be filled with (more) sense or following to be included: +LOCERR=${LOCERR:-0} # displays the local error +VERBERR=${VERBERR:-1} # 0 means to be more verbose (some like the errors to be dispayed so that one can tell better + # whether handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1 -#FIXME: still to be filled with (more) sense: -DEBUG=${DEBUG:-0} # if 1 the temp files won't be erased. 2: list more what's going on (formerly: eq VERBOSE=1), 3: slight hexdumps - # and other info, 4: the whole nine yards of output -PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' +HEADER_MAXSLEEP=${HEADER_MAXSLEEP:-3} # we wait this long before killing the process to retrieve a service banner / http header +MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply +USLEEP_SND=${USLEEP_SND:-0.1} # sleep time for general socket send +USLEEP_REC=${USLEEP_REC:-0.2} # sleep time for general socket receive CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet. FC has only a CA bundle per default, ==> openssl version -d -HSTS_MIN=180 # >180 days is ok for HSTS -HPKP_MIN=30 # >=30 days should be ok for HPKP_MIN, practical hints? -MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply -CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS -DAYS2WARN1=60 # days to warn before cert expires, threshold 1 -DAYS2WARN2=30 # days to warn before cert expires, threshold 2 +HSTS_MIN=180 # >180 days is ok for HSTS +HPKP_MIN=30 # >=30 days should be ok for HPKP_MIN, practical hints? +CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS +DAYS2WARN1=60 # days to warn before cert expires, threshold 1 +DAYS2WARN2=30 # days to warn before cert expires, threshold 2 # more global vars, here just declared ECHO="/usr/bin/printf --" # works under Linux, BSD, MacOS. @@ -77,8 +78,12 @@ NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1" RUN_DIR=$(dirname $0) TEMPDIR="" TLS_PROTO_OFFERED="" +DETECTED_TLS_VERSION="" SOCKREPLY="" +SOCK_REPLY_FILE="" HEXC="" +NW_STR="" +LEN_STR="" SNI="" IP4="" IP6="" @@ -91,15 +96,76 @@ IPS="" SERVICE="" # is the server running an HTTP server, SMTP, POP or IMAP? +# debugging help: +PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' + # make sure that temporary files are cleaned up after use trap "cleanup" QUIT EXIT + # The various hexdump commands we need to replace xxd (BSD compatability)) HEXDUMPVIEW=(hexdump -C) # This is used in verbose mode to see what's going on HEXDUMP=(hexdump -ve '16/1 "%02x " " \n"') # This is used to analyse the reply HEXDUMPPLAIN=(hexdump -ve '1/1 "%.2x"') # Replaces both xxd -p and tr -cd '[:print:]' + + +###### some hexbytes for bash network sockets ###### + +# 133 standard cipher for TLS 1.2 and SPDY/NPN +TLS12_CIPHER=" +cc, 14, cc, 13, cc, 15, c0, 30, c0, 2c, c0, 28, c0, 24, c0, 14, +c0, 0a, c0, 22, c0, 21, c0, 20, 00, a5, 00, a3, 00, a1, 00, 9f, +00, 6b, 00, 6a, 00, 69, 00, 68, 00, 39, 00, 38, 00, 37, 00, 36, +c0, 77, c0, 73, 00, c4, 00, c3, 00, c2, 00, c1, 00, 88, 00, 87, +00, 86, 00, 85, c0, 32, c0, 2e, c0, 2a, c0, 26, c0, 0f, c0, 05, +c0, 79, c0, 75, 00, 9d, 00, 3d, 00, 35, 00, c0, 00, 84, c0, 2f, +c0, 2b, c0, 27, c0, 23, c0, 13, c0, 09, c0, 1f, c0, 1e, c0, 1d, +00, a4, 00, a2, 00, a0, 00, 9e, 00, 67, 00, 40, 00, 3f, 00, 3e, +00, 33, 00, 32, 00, 31, 00, 30, c0, 76, c0, 72, 00, be, 00, bd, +00, bc, 00, bb, 00, 9a, 00, 99, 00, 98, 00, 97, 00, 45, 00, 44, +00, 43, 00, 42, c0, 31, c0, 2d, c0, 29, c0, 25, c0, 0e, c0, 04, +c0, 78, c0, 74, 00, 9c, 00, 3c, 00, 2f, 00, ba, 00, 96, 00, 41, +00, 07, c0, 11, c0, 07, 00, 66, c0, 0c, c0, 02, 00, 05, 00, 04, +c0, 12, c0, 08, c0, 1c, c0, 1b, c0, 1a, 00, 16, 00, 13, 00, 10, +00, 0d, c0, 0d, c0, 03, 00, 0a, 00, 63, 00, 15, 00, 12, 00, 0f, +00, 0c, 00, 62, 00, 09, 00, 65, 00, 64, 00, 14, 00, 11, 00, 0e, +00, 0b, 00, 08, 00, 06, 00, 03, 00, ff" + +# 76 standard cipher for SSLv3, TLS 1, TLS 1.1 +TLS_CIPHER=" +c0, 14, c0, 0a, c0, 22, c0, 21, c0, 20, 00, 39, 00, 38, 00, 37, +00, 36, 00, 88, 00, 87, 00, 86, 00, 85, c0, 0f, c0, 05, 00, 35, +00, 84, c0, 13, c0, 09, c0, 1f, c0, 1e, c0, 1d, 00, 33, 00, 32, +00, 31, 00, 30, 00, 9a, 00, 99, 00, 98, 00, 97, 00, 45, 00, 44, +00, 43, 00, 42, c0, 0e, c0, 04, 00, 2f, 00, 96, 00, 41, 00, 07, +c0, 11, c0, 07, 00, 66, c0, 0c, c0, 02, 00, 05, 00, 04, c0, 12, +c0, 08, c0, 1c, c0, 1b, c0, 1a, 00, 16, 00, 13, 00, 10, 00, 0d, +c0, 0d, c0, 03, 00, 0a, 00, 63, 00, 15, 00, 12, 00, 0f, 00, 0c, +00, 62, 00, 09, 00, 65, 00, 64, 00, 14, 00, 11, 00, 0e, 00, 0b, +00, 08, 00, 06, 00, 03, 00, ff" + +SSLv2_CLIENT_HELLO=" +,80,34 # length (here: 52) +,01 # Client Hello +,00,02 # SSLv2 +,00,1b # cipher spec length (here: 27 ) +,00,00 # session ID length +,00,10 # challenge length +,05,00,80 # 1st cipher 9 cipher specs, only classical V2 ciphers are used here, see http://max.euston.net/d/tip_sslciphers.html +,03,00,80 # 2nd there are v3 in v2!!! : https://tools.ietf.org/html/rfc6101#appendix-E +,01,00,80 # 3rd Cipher specifications introduced in version 3.0 can be included in version 2.0 client hello messages using +,07,00,c0 # 4th the syntax below. [..] # V2CipherSpec (see Version 3.0 name) = { 0x00, CipherSuite }; !!!! +,08,00,80 # 5th +,06,00,40 # 6th +,04,00,80 # 7th +,02,00,80 # 8th +,00,00,00 # 9th +,29,22,be,b3,5a,01,8b,04,fe,5f,80,03,a0,13,eb,c4" # Challenge + + +###### output functions ###### -out() { +out() { $ECHO "$1" } outln() { @@ -107,8 +173,7 @@ outln() { $ECHO "\n" } -# http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html -#### color print functions +# color print functions, see also http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html pr_off() { [[ "$COLOR" -ne 0 ]] && out "\033[m\c" @@ -220,7 +285,7 @@ if [[ "$COLOR" -ge 1 ]]; then fi -###### function definitions +###### helper function definitions ###### debugme() { if [[ $DEBUG -ge 2 ]]; then @@ -280,53 +345,8 @@ wait_kill(){ return 3 # killed } -# in a nutshell: It's HTTP-level compression & an attack which works against any cipher suite and -# is agnostic to the version of TLS/SSL, more: http://www.breachattack.com/ -# foreign referers are the important thing here! -breach() { - pr_bold " BREACH"; out " (CVE-2013-3587) =HTTP Compression " - url="$1" - [ -z "$url" ] && url="/" - if [ $SNEAKY -eq 0 ] ; then - referer="Referer: http://google.com/" # see https://community.qualys.com/message/20360 - useragent="User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" - else - referer="Referer: TLS/SSL-Tester from $SWURL" - useragent="User-Agent: Mozilla/4.0 (X11; Linux x86_64; rv:42.0) Gecko/19700101 Firefox/42.0" - fi - ( - $OPENSSL s_client -quiet -connect $NODEIP:$PORT $SNI << EOF -GET $url HTTP/1.1 -Host: $NODE -$useragent -Accept: text/* -Accept-Language: en-US,en -Accept-encoding: gzip,deflate,compress -$referer -Connection: close - -EOF -) &>$HEADERFILE_BREACH & - pid=$! - if wait_kill $pid $HEADER_MAXSLEEP; then - result=$(grep -a '^Content-Encoding' $HEADERFILE_BREACH | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g') - result=$(echo $result | tr -cd '\40-\176') - if [ -z $result ]; then - pr_green "no HTTP compression (OK) " - ret=0 - else - pr_litered "NOT ok, uses $result compression " - ret=1 - fi - # Catch: any URL can be vulnerable. I am testing now only the root. URL! - outln "(only \"$url\" tested)" - else - pr_litemagentaln "failed (HTTP header request stalled)" - ret=3 - fi - return $ret -} +###### check code starts here ###### # determines whether the port has an HTTP service running or not (plain TLS, no STARTTLS) runs_HTTP() { @@ -444,7 +464,9 @@ hsts() { pr_brown "$hsts_age_days days (<$HSTS_MIN is not good enough)" fi includeSubDomains "$TMPFILE" - preload "$TMPFILE" #FIXME: To be checked against: e.g. https://dxr.mozilla.org/mozilla-central/source/security/manager/boot/src/nsSTSPreloadList.inc and https://chromium.googlesource.com/chromium/src/+/master/net/http/transport_security_state_static.json + preload "$TMPFILE" + #FIXME: To be checked against e.g. https://dxr.mozilla.org/mozilla-central/source/security/manager/boot/src/nsSTSPreloadList.inc + # and https://chromium.googlesource.com/chromium/src/+/master/net/http/transport_security_state_static.json else out "--" fi @@ -925,21 +947,13 @@ runprotocols() { run_std_cipherlists() { outln pr_blue "--> Testing standard cipher lists"; outln "\n" -# see man ciphers +# see ciphers(1ssl) std_cipherlists NULL:eNULL " Null Cipher " 1 std_cipherlists aNULL " Anonymous NULL Cipher " 1 std_cipherlists ADH " Anonymous DH Cipher " 1 - #if [[ "$OSSL_VER" = *chacha* ]]; then - #out " 40 Bit encryption "; pr_magentaln "Local problem: $OPENSSL has a bug here" - #else - std_cipherlists EXPORT40 " 40 Bit encryption " 1 - #fi + std_cipherlists EXPORT40 " 40 Bit encryption " 1 std_cipherlists EXPORT56 " 56 Bit encryption " 1 - #if [[ "$OSSL_VER" = *chacha* ]]; then - # out " Export Cipher (general) "; pr_magentaln "Local problem: $OPENSSL has a bug here" - #else - std_cipherlists EXPORT " Export Cipher (general) " 1 - #fi + std_cipherlists EXPORT " Export Cipher (general) " 1 std_cipherlists LOW " Low (<=64 Bit) " 1 std_cipherlists DES " DES Cipher " 1 std_cipherlists 3DES " Triple DES Cipher " 2 @@ -1101,7 +1115,7 @@ server_defaults() { *) outln "$keysize" ;; esac fi -# google seems to have EC keys which displays as 256 Bit +#FIXME: google seems to have EC keys which displays as 256 Bit out " Signature Algorithm " algo=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep "Signature Algorithm" | sed 's/^.*Signature Algorithm: //' | sort -u ) @@ -1173,14 +1187,14 @@ server_defaults() { fi fi case $(uname -s) in - Linux) - enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") - startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") - ;; - FreeBSD) + FreeBSD|Mac*) enddate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") startdate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") ;; + *) + enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") + startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") + ;; esac outln " ($startdate --> $enddate)" @@ -1242,17 +1256,17 @@ pfs() { local none local number_pfs local hexcode n ciph sslvers kx auth enc mac + local pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' + # ^^^ the exclusing via ! doesn't work with libressl. + # https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy + + # pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH' + # this catches also ECDHE-ECDSA-NULL-SHA or ECDHE-RSA-RC4-SHA outln pr_blue "--> Testing (Perfect) Forward Secrecy (P)FS)"; outln " -- omitting 3DES, RC4 and Null Encryption here" -# https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy - PFSOK='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' -# ^^^ remark: the exclusing via ! doesn't work with libressl. -# -# PFSOK='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH' -# this catches also ECDHE-ECDSA-NULL-SHA or ECDHE-RSA-RC4-SHA - $OPENSSL ciphers -V "$PFSOK" >$TMPFILE 2>/dev/null + $OPENSSL ciphers -V "$pfs_ciphers" >$TMPFILE 2>/dev/null if [ $? -ne 0 ] ; then number_pfs=$(wc -l < $TMPFILE) if [ "$number_pfs" -le "$CLIENT_MIN_PFS" ] ; then @@ -1279,22 +1293,21 @@ pfs() { while read hexcode n ciph sslvers kx auth enc mac; do $OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null /dev/null ret=$? - if [ $ret -ne 0 ] && [ "$SHOW_EACH_C" -eq 0 ] ; then + if [[ $ret -ne 0 ]] && [[ "$SHOW_EACH_C" -eq 0 ]] ; then continue # no successful connect AND not verbose displaying each cipher fi normalize_ciphercode $hexcode neat_list $HEXC $ciph $kx $enc $strength - if [ "$SHOW_EACH_C" -ne 0 ]; then - if [ $ret -eq 0 ]; then + if [[ "$SHOW_EACH_C" -ne 0 ]]; then + if [[ $ret -eq 0 ]]; then pr_litered "available" else out "not a/v" @@ -1362,6 +1375,55 @@ rc4() { # good start to read: http://en.wikipedia.org/wiki/Transport_Layer_Security#Attacks_against_TLS.2FSSL +# in a nutshell: It's HTTP-level compression & an attack which works against any cipher suite and +# is agnostic to the version of TLS/SSL, more: http://www.breachattack.com/ +# foreign referers are the important thing here! +breach() { + pr_bold " BREACH"; out " (CVE-2013-3587) =HTTP Compression " + url="$1" + [ -z "$url" ] && url="/" + if [ $SNEAKY -eq 0 ] ; then + referer="Referer: http://google.com/" # see https://community.qualys.com/message/20360 + useragent="User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" + else + referer="Referer: TLS/SSL-Tester from $SWURL" + useragent="User-Agent: Mozilla/4.0 (X11; Linux x86_64; rv:42.0) Gecko/19700101 Firefox/42.0" + fi + ( + $OPENSSL s_client -quiet -connect $NODEIP:$PORT $SNI << EOF +GET $url HTTP/1.1 +Host: $NODE +$useragent +Accept: text/* +Accept-Language: en-US,en +Accept-encoding: gzip,deflate,compress +$referer +Connection: close + +EOF +) &>$HEADERFILE_BREACH & + pid=$! + if wait_kill $pid $HEADER_MAXSLEEP; then + result=$(grep -a '^Content-Encoding' $HEADERFILE_BREACH | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g') + result=$(echo $result | tr -cd '\40-\176') + if [ -z $result ]; then + pr_green "no HTTP compression (OK) " + ret=0 + else + pr_litered "NOT ok, uses $result compression " + ret=1 + fi + # Catch: any URL can be vulnerable. I am testing now only the root. URL! + outln "(only \"$url\" tested)" + else + pr_litemagentaln "failed (HTTP header request stalled)" + ret=3 + fi + return $ret +} + + + lucky13() { #FIXME: to do # CVE-2013-0169 @@ -1435,9 +1497,23 @@ close_socket(){ ## old network code ^^^^^^ -### new funcs for network follow +###### new funcs for network follow -socksend_clienthello() { +# first: helper function for protocol checks + +code2network() { + # arg1: formatted string here in the code + NW_STR=$(echo "$1" | sed -e 's/,/\\\x/g' | sed -e 's/# .*$//g' -e 's/ //g' -e '/^$/d' | tr -d '\n' | tr -d '\t') +} + +len2twobytes() { + len_arg1=$(echo ${#1}) + [[ $len_arg1 -le 2 ]] && LEN_STR=$(printf "00, %02s \n" $1) + [[ $len_arg1 -eq 3 ]] && LEN_STR=$(printf "%02s, %02s \n" ${1:0:1} ${1:1:2}) + [[ $len_arg1 -eq 4 ]] && LEN_STR=$(printf "%02s, %02s \n" ${1:0:2} ${1:2:2}) +} + +socksend_sslv2_clienthello() { code2network "$SSLv2_CLIENT_HELLO" data=$(echo $NW_STR) [[ "$DEBUG" -ge 3 ]] && echo "\"$data\"" @@ -1445,6 +1521,7 @@ socksend_clienthello() { sleep $USLEEP_SND } +# for SSLv2 to TLS 1.2: sockread_serverhello() { [[ "x$2" = "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 ret=0 @@ -1463,6 +1540,7 @@ sockread_serverhello() { [[ $maxsleep -le 0 ]] && break done + #FIXME: wait_kill if ps $pid >/dev/null ; then # time's up and dd is still alive --> timeout kill $pid >&2 2>/dev/null @@ -1474,19 +1552,19 @@ sockread_serverhello() { } # arg1: name of file with socket reply -display_sslv2serverhello() { -# server hello: in hex representation, see below -# byte 1+2: length of server hello 0123 -# 3: 04=Handshake message, server hello 45 -# 4: session id hit or not (boolean: 00=false, this 67 -# is the normal case) -# 5: certificate type, 01 = x509 89 -# 6+7 version (00 02 = SSLv2) 10-13 -# 8+9 certificate length 14-17 -# 10+11 cipher spec length 17-20 -# 12+13 connection id length -# [certificate length] ==> certificate -# [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY! +display_sslv2_serverhello() { + # server hello: in hex representation, see below + # byte 1+2: length of server hello 0123 + # 3: 04=Handshake message, server hello 45 + # 4: session id hit or not (boolean: 00=false, this 67 + # is the normal case) + # 5: certificate type, 01 = x509 89 + # 6+7 version (00 02 = SSLv2) 10-13 + # 8+9 certificate length 14-17 + # 10+11 cipher spec length 17-20 + # 12+13 connection id length + # [certificate length] ==> certificate + # [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY! v2_hello_ascii=$(hexdump -v -e '16/1 "%02X"' $1) [[ "$DEBUG" -ge 4 ]] && echo $v2_hello_ascii # one line without any blanks @@ -1587,52 +1665,13 @@ display_tls_serverhello() { } -# helper function for protocol checks -# arg1: formatted string here in the code -code2network() { - NW_STR=$(echo "$1" | sed -e 's/,/\\\x/g' | sed -e 's/# .*$//g' -e 's/ //g' -e '/^$/d' | tr -d '\n' | tr -d '\t') -} - -len2twobytes() { - len_arg1=$(echo ${#1}) - [[ $len_arg1 -le 2 ]] && LEN_STR=$(printf "00, %02s \n" $1) - [[ $len_arg1 -eq 3 ]] && LEN_STR=$(printf "%02s, %02s \n" ${1:0:1} ${1:1:2}) - [[ $len_arg1 -eq 4 ]] && LEN_STR=$(printf "%02s, %02s \n" ${1:0:2} ${1:2:2}) -} - - sslv2_sockets() { - V2_HELLO_CIPHERSPEC_LENGTH=0 # initialize - USLEEP_REC=${USLEEP_REC:-0.2} - USLEEP_SND=${USLEEP_SND:-0.1} # 1 second wait until otherwise specified - SOCK_REPLY_FILE="" # we do this with a file here. At a certain point heartbleed and ccs needs to be changed and make use of code2network - NW_STR="" - out " SSLv2 "; - # SSLV2 chello: - SSLv2_CLIENT_HELLO=" - ,80,34 # length (here: 52) - ,01 # Client Hello - ,00,02 # SSLv2 - ,00,1b # cipher spec length (here: 27 ) - ,00,00 # session ID length - ,00,10 # challenge length - ,05,00,80 # 1st cipher 9 cipher specs, only classical V2 ciphers are used here, see http://max.euston.net/d/tip_sslciphers.html - ,03,00,80 # 2nd there are v3 in v2!!! : https://tools.ietf.org/html/rfc6101#appendix-E - ,01,00,80 # 3rd Cipher specifications introduced in version 3.0 can be included in version 2.0 client hello messages using - ,07,00,c0 # 4th the syntax below. [..] # V2CipherSpec (see Version 3.0 name) = { 0x00, CipherSuite }; !!!! - ,08,00,80 # 5th - ,06,00,40 # 6th - ,04,00,80 # 7th - ,02,00,80 # 8th - ,00,00,00 # 9th - ,29,22,be,b3,5a,01,8b,04,fe,5f,80,03,a0,13,eb,c4" # Challenge - fd_socket 5 || return 6 [[ "$DEBUG" -ge 2 ]] && out "sending client hello... " - socksend_clienthello + socksend_sslv2_clienthello sockread_serverhello 32768 0 [[ "$DEBUG" -ge 2 ]] && out "reading server hello... " @@ -1641,7 +1680,7 @@ sslv2_sockets() { outln fi - display_sslv2serverhello "$SOCK_REPLY_FILE" + display_sslv2_serverhello "$SOCK_REPLY_FILE" if [ $? -eq 7 ]; then # strange reply pr_litemagenta "strange v2 reply " @@ -1649,7 +1688,7 @@ sslv2_sockets() { [[ $DEBUG -ge 2 ]] && hexdump -C $SOCK_REPLY_FILE | head -1 else # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL - lines=$(cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l) + lines=$(hexdump -C "$SOCK_REPLY_FILE" 2>/dev/null | wc -l) [[ "$DEBUG" -ge 2 ]] && out " ($lines lines) " if [[ "$lines" -gt 1 ]] ;then @@ -1674,79 +1713,40 @@ sslv2_sockets() { } -#for tls_low_byte in "00" "01" "02" "03"; do -tls_sockets() { - SN_HEX="" - LEN_SN_HEX=0 - COL_WIDTH=32 - USLEEP_REC=${USLEEP_REC:-0.2} - USLEEP_SND=${USLEEP_SND:-0.1} # 1 second wait until otherwise specified - MAX_WAITSOCK=2 - SOCK_REPLY_FILE="" - NW_STR="" - LEN_STR="" - DETECTED_TLS_VERSION="" +# ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) +# ARG2: CIPHER_SUITES string +socksend_tls_clienthello() { + local len_sni + local tls_low_byte + local tls_low_byte + local len_servername + local hexdump_format_str + local servername_hexstr - # 133 cipher: spdy, TLS 1.2 - TLS12_CIPHER=" - cc, 14, cc, 13, cc, 15, c0, 30, c0, 2c, c0, 28, c0, 24, c0, 14, - c0, 0a, c0, 22, c0, 21, c0, 20, 00, a5, 00, a3, 00, a1, 00, 9f, - 00, 6b, 00, 6a, 00, 69, 00, 68, 00, 39, 00, 38, 00, 37, 00, 36, - c0, 77, c0, 73, 00, c4, 00, c3, 00, c2, 00, c1, 00, 88, 00, 87, - 00, 86, 00, 85, c0, 32, c0, 2e, c0, 2a, c0, 26, c0, 0f, c0, 05, - c0, 79, c0, 75, 00, 9d, 00, 3d, 00, 35, 00, c0, 00, 84, c0, 2f, - c0, 2b, c0, 27, c0, 23, c0, 13, c0, 09, c0, 1f, c0, 1e, c0, 1d, - 00, a4, 00, a2, 00, a0, 00, 9e, 00, 67, 00, 40, 00, 3f, 00, 3e, - 00, 33, 00, 32, 00, 31, 00, 30, c0, 76, c0, 72, 00, be, 00, bd, - 00, bc, 00, bb, 00, 9a, 00, 99, 00, 98, 00, 97, 00, 45, 00, 44, - 00, 43, 00, 42, c0, 31, c0, 2d, c0, 29, c0, 25, c0, 0e, c0, 04, - c0, 78, c0, 74, 00, 9c, 00, 3c, 00, 2f, 00, ba, 00, 96, 00, 41, - 00, 07, c0, 11, c0, 07, 00, 66, c0, 0c, c0, 02, 00, 05, 00, 04, - c0, 12, c0, 08, c0, 1c, c0, 1b, c0, 1a, 00, 16, 00, 13, 00, 10, - 00, 0d, c0, 0d, c0, 03, 00, 0a, 00, 63, 00, 15, 00, 12, 00, 0f, - 00, 0c, 00, 62, 00, 09, 00, 65, 00, 64, 00, 14, 00, 11, 00, 0e, - 00, 0b, 00, 08, 00, 06, 00, 03, 00, ff" + tls_low_byte=$1 + len_servername=$(echo ${#NODE}) + hexdump_format_str="$len_servername/1 \"%02x,\"" + servername_hexstr=$(printf $NODE | hexdump -v -e "${hexdump_format_str}" | sed 's/,$//') + len_sni=$(echo ${#3}) - # 76 cipher for SSLv3, TLS 1, TLS 1.1: - TLS_CIPHER=" - c0, 14, c0, 0a, c0, 22, c0, 21, c0, 20, 00, 39, 00, 38, 00, 37, - 00, 36, 00, 88, 00, 87, 00, 86, 00, 85, c0, 0f, c0, 05, 00, 35, - 00, 84, c0, 13, c0, 09, c0, 1f, c0, 1e, c0, 1d, 00, 33, 00, 32, - 00, 31, 00, 30, 00, 9a, 00, 99, 00, 98, 00, 97, 00, 45, 00, 44, - 00, 43, 00, 42, c0, 0e, c0, 04, 00, 2f, 00, 96, 00, 41, 00, 07, - c0, 11, c0, 07, 00, 66, c0, 0c, c0, 02, 00, 05, 00, 04, c0, 12, - c0, 08, c0, 1c, c0, 1b, c0, 1a, 00, 16, 00, 13, 00, 10, 00, 0d, - c0, 0d, c0, 03, 00, 0a, 00, 63, 00, 15, 00, 12, 00, 0f, 00, 0c, - 00, 62, 00, 09, 00, 65, 00, 64, 00, 14, 00, 11, 00, 0e, 00, 0b, - 00, 08, 00, 06, 00, 03, 00, ff" + code2network "$2" # CIPHER_SUITES + cipher_suites="$NW_STR" # we don't have the leading \x here so string length is two byte less, see next #formatted example for SNI -#00 00 # extention server_name +#00 00 # extension server_name #00 1a # length = the following +2 = server_name length + 5 #00 18 # server_name list_length = server_name length +3 #00 # server_name type (hostname) #00 15 # server_name length #66 66 66 66 66 66 2e 66 66 66 66 66 66 66 66 66 66 2e 66 66 66 target.mydomain1.tld # server_name target - - -# arg1: TLS_VER_LSB -# arg2: CIPHER_SUITES string -# arg3: SERVERNAME -# ??? more extensions? - - len_sni=$(echo ${#3}) - #tls_ver=printf "%02x\n" $1" - - code2network "$2" - cipher_suites="$NW_STR" # we don't have the leading \x here so string length is two byte less, see next - # convert length's from dec to hex: - hex_len_sn_hex=$(printf "%02x\n" $LEN_SN_HEX) - hex_len_sn_hex3=$(printf "%02x\n" $((LEN_SN_HEX+3))) - hex_len_sn_hex5=$(printf "%02x\n" $((LEN_SN_HEX+5))) - hex_len_extention=$(printf "%02x\n" $((LEN_SN_HEX+9))) - + hex_len_sn_hex=$(printf "%02x\n" $len_servername) + hex_len_sn_hex3=$(printf "%02x\n" $((len_servername+3))) + hex_len_sn_hex5=$(printf "%02x\n" $((len_servername+5))) + hex_len_extention=$(printf "%02x\n" $((len_servername+9))) + +### continue here len_ciph_suites_byte=$(echo ${#cipher_suites}) let "len_ciph_suites_byte += 2" @@ -1757,34 +1757,32 @@ tls_sockets() { [[ $DEBUG -ge 4 ]] && echo $len_ciph_suites_word len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x27 + 0x$hex_len_extention + 0x2))) - #len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x27))) len_c_hello_word="$LEN_STR" [[ $DEBUG -ge 4 ]] && echo $len_c_hello_word len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x2b + 0x$hex_len_extention + 0x2))) - #len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x2b))) len_all_word="$LEN_STR" [[ $DEBUG -ge 4 ]] && echo $len_all_word TLS_CLIENT_HELLO=" # TLS header ( 5 bytes) - ,16, 03, $1 # TLS Version - ,$len_all_word # Length <--- + ,16, 03, $tls_low_byte # TLS Version + ,$len_all_word # Length <--- # Handshake header: - ,01 # Type (x01 for ClientHello) - ,00, $len_c_hello_word # Length ClientHello - ,03, $1 # TLS Version (again) - ,54, 51, 1e, 7a # Unix time since see www.moserware.com/2009/06/first-few-milliseconds-of-https.html - ,de, ad, be, ef # Random 28 bytes + ,01 # Type (x01 for ClientHello) + ,00, $len_c_hello_word # Length ClientHello + ,03, $tls_low_byte # TLS Version (again) + ,54, 51, 1e, 7a # Unix time since see www.moserware.com/2009/06/first-few-milliseconds-of-https.html + ,de, ad, be, ef # Random 28 bytes ,31, 33, 07, 00, 00, 00, 00, 00 ,cf, bd, 39, 04, cc, 16, 0a, 85 ,03, 90, 9f, 77, 04, 33, d4, de - ,00 # Session ID length - ,$len_ciph_suites_word # Cipher suites length + ,00 # Session ID length + ,$len_ciph_suites_word # Cipher suites length # Cipher suites ,$cipher_suites - ,01 # Compression methods length - ,00" # Compression method (x00 for NULL) + ,01 # Compression methods length + ,00" # Compression method (x00 for NULL) EXTENSION_CONTAINING_SNI=" ,00, $hex_len_extention # first the len of all (here: 1) extentions. We assume len(hostname) < FF - 9 @@ -1793,19 +1791,25 @@ tls_sockets() { ,00, $hex_len_sn_hex3 # server_name list_length ,00 # server_name type (hostname) ,00, $hex_len_sn_hex # server_name length - ,$SN_HEX" # server_name target + ,$servername_hexstr" # server_name target fd_socket 5 || return 6 code2network "$TLS_CLIENT_HELLO$EXTENSION_CONTAINING_SNI" - #code2network "$TLS_CLIENT_HELLO" data=$(echo $NW_STR) + [[ "$DEBUG" -ge 4 ]] && echo "\"$data\"" + printf -- "$data" >&5 2>/dev/null & + sleep $USLEEP_SND - [[ "$DEBUG" -ge 2 ]] && printf "sending client hello..." + return 0 +} + +tls_sockets() { + [[ "$DEBUG" -ge 2 ]] && echo "sending client hello..." if [[ "$tls_low_byte" == "03" ]] ; then - socksend_clienthello $tls_low_byte "$TLS12_CIPHER" $SNIHEX + socksend_tls_clienthello $tls_low_byte "$TLS12_CIPHER" else - socksend_clienthello $tls_low_byte "$TLS_CIPHER" $SNIHEX + socksend_tls_clienthello $tls_low_byte "$TLS_CIPHER" fi sockread_serverhello 32768 0 @@ -1819,7 +1823,7 @@ tls_sockets() { ret=$? # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL - lines=$(cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l) + lines=$(hexdump -C "$SOCK_REPLY_FILE" 2>/dev/null | wc -l) [[ "$DEBUG" -ge 2 ]] && out " (returned $lines lines) " # case $tls_low_byte in @@ -1845,7 +1849,6 @@ tls_sockets() { fi fi - close_socket TMPFILE=$SOCK_REPLY_FILE tmpfile_handle $FUNCNAME.dd @@ -1853,6 +1856,7 @@ tls_sockets() { } +###### ccs, heartbleed ok_ids(){ greenln "\n ok -- something resetted our ccs packets" @@ -1860,6 +1864,7 @@ ok_ids(){ } +#FIXME: At a certain point heartbleed and ccs needs to be changed and make use of code2network using a file, then tls_sockets ccs_injection(){ # see https://www.openssl.org/news/secadv_20140605.txt # mainly adapted from Ramon de C Valle's C code from https://gist.github.com/rcvalle/71f4b027d61a78c42607 @@ -2048,7 +2053,7 @@ heartbleed(){ lines_returned=$(echo "$SOCKREPLY" | "${HEXDUMP[@]}" | wc -l) if [ $lines_returned -gt 1 ]; then - pr_red "VULNERABLE" + pr_red "VULNERABLE (NOT ok)" ret=1 else pr_green "not vulnerable (OK)" @@ -2306,7 +2311,7 @@ beast(){ fi done if [ $ret -eq 1 ] ; then - [ ! -z "$higher_proto_supported" ] && outln "$spaces but also supports higher protocols (possible mitigation):$higher_proto_supported" + [ ! -z "$higher_proto_supported" ] && outln "${spaces}but also supports higher protocols (possible mitigation):$higher_proto_supported" fi # printf "For a full individual test of each CBC cipher suites support by your $OPENSSL run \"$0 -x CBC $NODE\"\n" @@ -2994,6 +2999,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.208 2015/03/15 15:59:28 dirkw Exp $ +# $Id: testssl.sh,v 1.209 2015/03/15 23:22:50 dirkw Exp $ # vim:ts=5:sw=5 From 263535520f048139bca248ebc6981460dfb10dab Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 17 Mar 2015 12:22:21 +0100 Subject: [PATCH 19/26] - FIX for date --> applied to other BSD systems too - FIX for SNI output as it doensn';t make sense for non HTTP servives - lines for RC4 and PFS shortenedA - display all MX records to test before testing - removed LOCERR, added CCS_MAX_WAITSOCK, HEARTBLEED_MAX_WAITSOCK --- testssl.sh | 85 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/testssl.sh b/testssl.sh index 2721a84..1da8222 100755 --- a/testssl.sh +++ b/testssl.sh @@ -56,12 +56,13 @@ ASSUMING_HTTP=${ASSUMING_HTTP:-0} # in seldom cases (WAF, old servers/grumpy SS DEBUG=${DEBUG:-0} # if 1 the temp files won't be erased. 2: list more what's going on (formerly: eq VERBOSE=1), # 3: slight hexdumps and other info, 4: the whole nine yards of output #FIXME: still to be filled with (more) sense or following to be included: -LOCERR=${LOCERR:-0} # displays the local error -VERBERR=${VERBERR:-1} # 0 means to be more verbose (some like the errors to be dispayed so that one can tell better +VERBERR=${VERBERR:-1} # 0 means/to be more verbose (some like the errors to be dispayed so that one can tell better # whether handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1 HEADER_MAXSLEEP=${HEADER_MAXSLEEP:-3} # we wait this long before killing the process to retrieve a service banner / http header -MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply +MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply +CCS_MAX_WAITSOCK=5 # for the two CCS payload (each) +HEARTBLEED_MAX_WAITSOCK=8 # for the heartbleed payload USLEEP_SND=${USLEEP_SND:-0.1} # sleep time for general socket send USLEEP_REC=${USLEEP_REC:-0.2} # sleep time for general socket receive @@ -289,7 +290,7 @@ fi debugme() { if [[ $DEBUG -ge 2 ]]; then - echo "$@" + #echo "$@" "$@" else : @@ -664,7 +665,7 @@ prettyprint_local() { listciphers() { $OPENSSL ciphers $1 &>$TMPFILE ret=$? - [[ $LOCERR -eq 1 ]] && cat $TMPFILE + debugme cat $TMPFILE tmpfile_handle $FUNCNAME.txt return $ret @@ -708,7 +709,6 @@ std_cipherlists() { pr_magentaln "Local problem: No $singlespaces configured in $OPENSSL" fi # we need lf in those cases: - [[ $LOCERR -eq 1 ]] && echo [[ $DEBUG -ge 2 ]] && echo } @@ -1025,6 +1025,7 @@ server_preference() { # proto-check b4! $OPENSSL s_client $STARTTLS -"$p" -connect $NODEIP:$PORT $SNI /dev/null >$TMPFILE if [ $ret -eq 0 ]; then + #FIXME: BSD output is not so fine proto[i]=$(grep -w "Protocol" $TMPFILE | sed -e 's/^ \+Protocol \+://' -e 's/ //g') cipher[i]=$(grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') [[ ${cipher[i]} == "0000" ]] && cipher[i]="" # Hack! @@ -1140,9 +1141,17 @@ server_defaults() { $OPENSSL x509 -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//') [[ $DEBUG -ge 2 ]] && out "$NODE | $CN | $CN_nosni" if [[ $NODE == $CN_nosni ]]; then - outln " (works w/o SNI)" + if [[ $SERVICE != "HTTP" ]] ; then + outln " (matches certificate directly)" + else + outln " (works w/o SNI)" + fi else - outln " (CN response to request w/o SNI: '$CN_nosni')" + if [[ $SERVICE != "HTTP" ]] ; then + pr_brownln " (CN doesn't match but for non-HTTP services it might be ok)" + else + outln " (CN response to request w/o SNI: '$CN_nosni')" + fi fi SAN=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ @@ -1187,7 +1196,7 @@ server_defaults() { fi fi case $(uname -s) in - FreeBSD|Mac*) + *BSD|Mac*) enddate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") startdate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") ;; @@ -1257,7 +1266,7 @@ pfs() { local number_pfs local hexcode n ciph sslvers kx auth enc mac local pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' - # ^^^ the exclusing via ! doesn't work with libressl. + # ^^^ the exclusion via ! doesn't work with libressl. # https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy # pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH' @@ -1284,10 +1293,10 @@ pfs() { ret=$? outln if [ $ret -ne 0 ] || [ $(grep -c "BEGIN CERTIFICATE" $TMPFILE) -eq 0 ]; then - pr_brown "No PFS available" + pr_brownln "Not OK: No ciphers supporting Forward Secrecy offered" else - pr_litegreenln "In general PFS is offered. Now testing specific ciphers ..."; - outln "(it depends on the browser/client whether one of them will be used)\n" + pr_litegreen "OK: PFS is offered. "; + outln "Client/browser support is important here. Offered PFS server ciphers follow... \n" none=0 neat_header while read hexcode n ciph sslvers kx auth enc mac; do @@ -1309,7 +1318,6 @@ pfs() { outln done < <($OPENSSL ciphers -V "$pfs_ciphers") # ^^^^^ posix redirect as shopt will either segfault or doesn't work with old bash versions - outln debugme echo $none if [ "$none" -eq 0 ] ; then @@ -1319,6 +1327,8 @@ pfs() { ret=0 fi fi + outln + tmpfile_handle $FUNCNAME.txt return $ret } @@ -1334,9 +1344,9 @@ rc4() { [ $SHOW_LOC_CIPH = "1" ] && echo "local ciphers available for testing RC4:" && echo $(cat $TMPFILE) $OPENSSL s_client -cipher $($OPENSSL ciphers RC4) $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null /dev/null @@ -1353,7 +1363,7 @@ rc4() { out "not a/v" fi else - bad=1 + rc4_offered=1 out fi outln @@ -1363,11 +1373,11 @@ rc4() { else outln pr_litegreenln "no RC4 ciphers detected (OK)" - bad=0 + rc4_offered=0 fi tmpfile_handle $FUNCNAME.txt - return $bad + return $rc4_offered } @@ -1410,7 +1420,7 @@ EOF pr_green "no HTTP compression (OK) " ret=0 else - pr_litered "NOT ok, uses $result compression " + pr_litered "NOT ok: uses $result compression " ret=1 fi # Catch: any URL can be vulnerable. I am testing now only the root. URL! @@ -1926,7 +1936,7 @@ ccs_injection(){ fi socksend "$ccs_message" 1 || ok_ids - sockread 2048 5 # 5 seconds + sockread 2048 $CCS_MAX_WAITSOCK if [[ $DEBUG -ge 3 ]]; then outln "\n1st reply: " out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20 @@ -1936,7 +1946,7 @@ ccs_injection(){ fi socksend "$ccs_message" 2 || ok_ids - sockread 2048 5 + sockread 2048 $CCS_MAX_WAITSOCK retval=$? if [[ $DEBUG -ge 3 ]]; then @@ -1954,7 +1964,7 @@ ccs_injection(){ pr_green "not vulnerable (OK)" ret=0 else - pr_red "VULNERABLE (not OK)" + pr_red "VULNERABLE (NOT ok)" ret=1 fi [ $retval -eq 3 ] && out "(timed out)" @@ -2042,7 +2052,7 @@ heartbleed(){ fi socksend "$heartbleed_payload" 1 - sockread 16384 + sockread 16384 $HEARTBLEED_MAX_WAITSOCK retval=$? if [[ $DEBUG -ge 3 ]]; then @@ -2543,19 +2553,22 @@ CAPATH: $CAPATH ECHO: $ECHO COLOR: $COLOR SHOW_LOC_CIPH: $SHOW_LOC_CIPH -VERBERR: $VERBERR -LOCERR: $LOCERR -SHOW_EACH_C: $SHOW_EACH_C +SSL_NATIVE: $SSL_NATIVE +ASSUMING_HTTP $ASSUMING_HTTP SNEAKY: $SNEAKY + +VERBERR: $VERBERR +SHOW_EACH_C: $SHOW_EACH_C DEBUG: $DEBUG HSTS_MIN: $HSTS_MIN HPKP_MIN: $HPKP_MIN MAX_WAITSOCK: $MAX_WAITSOCK -HEADER_MAXSLEEP: $HEADER_MAXSLEEP -CLIENT_MIN_PFS: $CLIENT_MIN_PFS -DAYS2WARN1: $DAYS2WARN1 -DAYS2WARN2: $DAYS2WARN2 +CCS_MAX_WAITSOCK: $CCS_MAX_WAITSOCK +HEARTBLEED_MAX_WAITSOCK: $HEARTBLEED_MAX_WAITSOCK + +USLEEP_SND $USLEEP_SND +USLEEP_REC $USLEEP_REC EOF $OPENSSL ciphers -V $1 &>$TEMPDIR/all_local_ciphers.txt @@ -2673,7 +2686,7 @@ parse_hn_port() { $OPENSSL s_client -connect "$NODE:$PORT" $SNI /dev/null 2>&1 if [ $? -ne 0 ]; then pr_boldln "$NODE:$PORT doesn't seem a TLS/SSL enabled server or it requires a certificate"; - ignore_no_or_lame "Proceed (note that the results might look ok but they are nonsense) ? " + ignore_no_or_lame "Note that the results might look ok but they are nonsense. Proceed ? " [ $? -ne 0 ] && exit 3 fi fi @@ -2681,6 +2694,7 @@ parse_hn_port() { datebanner "Testing" [[ -z "$2" ]] && runs_HTTP # for starttls we don't check the protocol as it is supplied on the cmd line initialize_engine + outln return 0 } @@ -2782,9 +2796,10 @@ mx_allentries() { fi # test first higher priority servers - MXs=$(echo "$MXs" | sort -n | sed -e 's/^.* //' -e 's/\.$//') + MXs=$(echo "$MXs" | sort -n | sed -e 's/^.* //' -e 's/\.$//' | tr '\n' ' ') if [ -n "$MXs" ] ; then + pr_bold "Testing now all MX records (on port 25): "; outln "$MXs" for MX in $MXs; do parse_hn_port "$MX:25" 'smtp' && starttls 'smtp' done @@ -2999,6 +3014,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.209 2015/03/15 23:22:50 dirkw Exp $ +# $Id: testssl.sh,v 1.210 2015/03/17 11:22:20 dirkw Exp $ # vim:ts=5:sw=5 From c159af7f420c6de0913046b5a56d6e621f37a5da Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 17 Mar 2015 15:14:58 +0100 Subject: [PATCH 20/26] - check whether openssl is executable - spaces to tabs - adding hint to "aha" in help --- testssl.sh | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index 1da8222..8089609 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2366,6 +2366,12 @@ find_openssl_binary() { fi fi + if ! $OPENSSL version -a 2>&1 >/dev/null; then + outln + pr_magentaln "FATAL: cannot exec $OPENSSL" + exit -1 + fi + # http://www.openssl.org/news/openssl-notes.html OSSL_VER=$($OPENSSL version | awk -F' ' '{ print $2 }') OSSL_VER_MAJOR=$(echo "$OSSL_VER" | sed 's/\..*$//') @@ -2489,6 +2495,11 @@ partly mandatory parameters: protocol is one of ftp,smtp,pop3,imap,xmpp,telnet,ldap (for the latter two you need e.g. the supplied openssl) +For HTML output you need to pipe through "aha" (Ansi HTML Adapter: github.com/theZiz/aha) like + + "$PRG | aha >output.html" + + EOF return $? } @@ -2835,7 +2846,7 @@ PATH_TO_TESTSSL=$(readlink "$BASH_SOURCE") 2>/dev/null #FIXME: I know this sucks and getoptS is better case "$1" in - -b|--banner|-banner|-v|--version|-version) + -b|--banner|-banner|-v|--version|-version) exit 0 ;; --mx) @@ -2877,12 +2888,12 @@ case "$1" in parse_hn_port "$2" run_std_cipherlists exit $? ;; - -S|--server_defaults) + -S|--server_defaults) maketempf parse_hn_port "$2" server_defaults exit $? ;; - -P|--server_preference) + -P|--server_preference) maketempf parse_hn_port "$2" server_preference @@ -3014,6 +3025,6 @@ case "$1" in exit $ret ;; esac -# $Id: testssl.sh,v 1.210 2015/03/17 11:22:20 dirkw Exp $ -# vim:ts=5:sw=5 +# $Id: testssl.sh,v 1.211 2015/03/17 14:14:57 dirkw Exp $ +# vim:ts=5:sw=5 From 2faad9de9a1c3464dc36edbbd4339741f0fbc68a Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 17 Mar 2015 18:11:18 +0100 Subject: [PATCH 21/26] - working tls handshake with bash sockets (not yet in production, hint: see option "-q" in the bottom) --- testssl.sh | 79 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/testssl.sh b/testssl.sh index 8089609..54a663b 100755 --- a/testssl.sh +++ b/testssl.sh @@ -54,7 +54,7 @@ SNEAKY=${SNEAKY:-1} # if zero: the referer and useragent we leave while chec SSL_NATIVE=${SSL_NATIVE:-0} # we do per default bash sockets! ASSUMING_HTTP=${ASSUMING_HTTP:-0} # in seldom cases (WAF, old servers/grumpy SSL) the service detection fails. Set to 1 for HTTP DEBUG=${DEBUG:-0} # if 1 the temp files won't be erased. 2: list more what's going on (formerly: eq VERBOSE=1), - # 3: slight hexdumps and other info, 4: the whole nine yards of output + # 3: slight hexdumps + other info, 4: send bytes via sockets, 5: received, 6: whole 9 yards #FIXME: still to be filled with (more) sense or following to be included: VERBERR=${VERBERR:-1} # 0 means/to be more verbose (some like the errors to be dispayed so that one can tell better # whether handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1 @@ -729,7 +729,7 @@ sockread() { [ "x$2" = "x" ] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 ret=0 - ddreply=$(mktemp /tmp/ddreply.XXXXXX) || exit 7 + ddreply=$(mktemp /tmp/ddreply.XXXXXX) || return 7 dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null & pid=$! @@ -1536,7 +1536,7 @@ sockread_serverhello() { [[ "x$2" = "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 ret=0 - SOCK_REPLY_FILE=$(mktemp $TEMPDIR/ddreply.XXXXXX) || exit 7 + SOCK_REPLY_FILE=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7 dd bs=$1 of=$SOCK_REPLY_FILE count=1 <&5 2>/dev/null & pid=$! @@ -1550,7 +1550,7 @@ sockread_serverhello() { [[ $maxsleep -le 0 ]] && break done - #FIXME: wait_kill +#FIXME: wait_kill $pid $maxsleep if ps $pid >/dev/null ; then # time's up and dd is still alive --> timeout kill $pid >&2 2>/dev/null @@ -1726,20 +1726,19 @@ sslv2_sockets() { # ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) # ARG2: CIPHER_SUITES string socksend_tls_clienthello() { - local len_sni local tls_low_byte - local tls_low_byte - local len_servername + local servername_hexstr len_servername len_servername_hex local hexdump_format_str - local servername_hexstr + local len_sni_listlen len_sni_ext len_extension_hex + local cipher_suites len_ciph_suites len_ciph_suites_word + local len_client_hello_word len_all_word - tls_low_byte=$1 + tls_low_byte="$1" len_servername=$(echo ${#NODE}) hexdump_format_str="$len_servername/1 \"%02x,\"" servername_hexstr=$(printf $NODE | hexdump -v -e "${hexdump_format_str}" | sed 's/,$//') - len_sni=$(echo ${#3}) - code2network "$2" # CIPHER_SUITES + code2network "$2" # CIPHER_SUITES cipher_suites="$NW_STR" # we don't have the leading \x here so string length is two byte less, see next #formatted example for SNI @@ -1750,13 +1749,12 @@ socksend_tls_clienthello() { #00 15 # server_name length #66 66 66 66 66 66 2e 66 66 66 66 66 66 66 66 66 66 2e 66 66 66 target.mydomain1.tld # server_name target - # convert length's from dec to hex: - hex_len_sn_hex=$(printf "%02x\n" $len_servername) - hex_len_sn_hex3=$(printf "%02x\n" $((len_servername+3))) - hex_len_sn_hex5=$(printf "%02x\n" $((len_servername+5))) - hex_len_extention=$(printf "%02x\n" $((len_servername+9))) + # convert lengths we need to fill in from dec to hex: + len_servername_hex=$(printf "%02x\n" $len_servername) + len_sni_listlen=$(printf "%02x\n" $((len_servername+3))) + len_sni_ext=$(printf "%02x\n" $((len_servername+5))) + len_extension_hex=$(printf "%02x\n" $((len_servername+9))) -### continue here len_ciph_suites_byte=$(echo ${#cipher_suites}) let "len_ciph_suites_byte += 2" @@ -1764,15 +1762,15 @@ socksend_tls_clienthello() { len_ciph_suites=$(printf "%02x\n" $(($len_ciph_suites_byte / 4 ))) len2twobytes "$len_ciph_suites" len_ciph_suites_word="$LEN_STR" - [[ $DEBUG -ge 4 ]] && echo $len_ciph_suites_word + [[ $DEBUG -ge 3 ]] && echo $len_ciph_suites_word - len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x27 + 0x$hex_len_extention + 0x2))) - len_c_hello_word="$LEN_STR" - [[ $DEBUG -ge 4 ]] && echo $len_c_hello_word + len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x27 + 0x$len_extension_hex + 0x2))) + len_client_hello_word="$LEN_STR" + [[ $DEBUG -ge 3 ]] && echo $len_client_hello_word - len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x2b + 0x$hex_len_extention + 0x2))) + len2twobytes $(printf "%02x\n" $((0x$len_ciph_suites + 0x2b + 0x$len_extension_hex + 0x2))) len_all_word="$LEN_STR" - [[ $DEBUG -ge 4 ]] && echo $len_all_word + [[ $DEBUG -ge 3 ]] && echo $len_all_word TLS_CLIENT_HELLO=" # TLS header ( 5 bytes) @@ -1780,7 +1778,7 @@ socksend_tls_clienthello() { ,$len_all_word # Length <--- # Handshake header: ,01 # Type (x01 for ClientHello) - ,00, $len_c_hello_word # Length ClientHello + ,00, $len_client_hello_word # Length ClientHello ,03, $tls_low_byte # TLS Version (again) ,54, 51, 1e, 7a # Unix time since see www.moserware.com/2009/06/first-few-milliseconds-of-https.html ,de, ad, be, ef # Random 28 bytes @@ -1789,18 +1787,17 @@ socksend_tls_clienthello() { ,03, 90, 9f, 77, 04, 33, d4, de ,00 # Session ID length ,$len_ciph_suites_word # Cipher suites length - # Cipher suites ,$cipher_suites ,01 # Compression methods length ,00" # Compression method (x00 for NULL) EXTENSION_CONTAINING_SNI=" - ,00, $hex_len_extention # first the len of all (here: 1) extentions. We assume len(hostname) < FF - 9 - ,00, 00 # extention server_name - ,00, $hex_len_sn_hex5 # length SNI EXT - ,00, $hex_len_sn_hex3 # server_name list_length + ,00, $len_extension_hex # first the len of all (here: 1) extentions. We assume len(hostname) < FF - 9 + ,00, 00 # extension server_name + ,00, $len_sni_ext # length SNI EXT + ,00, $len_sni_listlen # server_name list_length ,00 # server_name type (hostname) - ,00, $hex_len_sn_hex # server_name length + ,00, $len_servername_hex # server_name length ,$servername_hexstr" # server_name target fd_socket 5 || return 6 @@ -1814,7 +1811,15 @@ socksend_tls_clienthello() { return 0 } +# ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) tls_sockets() { + + tls_low_byte="$1" + if [ ! -z "$2" ] ; then + TLS_CIPHER="$2" + TLS12_CIPHER="$2" + fi + [[ "$DEBUG" -ge 2 ]] && echo "sending client hello..." if [[ "$tls_low_byte" == "03" ]] ; then socksend_tls_clienthello $tls_low_byte "$TLS12_CIPHER" @@ -2987,6 +2992,16 @@ case "$1" in ret=2 fi exit $ret ;; + +### following is a development feature and will disappear: + -q) + maketempf + parse_hn_port "$2" + tls_sockets "$3" "$4" + exit $? +# DEBUG=3 ./testssl.sh -q google.de 03 "cc, 13, c0, 13" +# DEBUG=3 ./testssl.sh -q yandex.ru 01 + ;; -*) help ;; # wrong argument *) maketempf @@ -3005,7 +3020,7 @@ case "$1" in hsts "$URL_PATH" ; ret=$(($? + ret)) hpkp "$URL_PATH" ; ret=$(($? + ret)) serverbanner "$URL_PATH" ; ret=$(($? + ret)) - applicationbanner "$URL_PATH" ; ret=$(($? + ret)) + applicationbanner "$URL_PATH" ; ret=$(($? + ret)) cookieflags "$URL_PATH" ; ret=$(($? + ret)) fi @@ -3026,5 +3041,5 @@ case "$1" in esac -# $Id: testssl.sh,v 1.211 2015/03/17 14:14:57 dirkw Exp $ +# $Id: testssl.sh,v 1.212 2015/03/17 17:11:17 dirkw Exp $ # vim:ts=5:sw=5 From ca6ca5d47efe2c2abd4979aaaa3bcae3b4b88d20 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 17 Mar 2015 22:02:23 +0100 Subject: [PATCH 22/26] - added two pairs of ciphers to server preference (thx Dilian) --- testssl.sh | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/testssl.sh b/testssl.sh index 54a663b..3d82b2e 100755 --- a/testssl.sh +++ b/testssl.sh @@ -962,20 +962,17 @@ run_std_cipherlists() { return 0 } -openssl_error() { - pr_magenta "$OPENSSL returned an error. This shouldn't happen. " - outln "continuing anyway" - return 0 -} - server_preference() { - list1="DES-CBC3-SHA:RC4-MD5:DES-CBC-SHA:RC4-SHA:AES128-SHA:AES128-SHA:AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-RSA-AES128-SHA:ECDH-RSA-AES256-SHA:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-DSS-AES256-GCM-SHA384" + list1="DES-CBC3-SHA:RC4-MD5:DES-CBC-SHA:RC4-SHA:AES128-SHA:AES128-SHA256:AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-RSA-AES128-SHA:ECDH-RSA-AES256-SHA:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:AES256-SHA256" outln; pr_blue "--> Testing server preferences"; outln "\n" + out " Has server cipher order? " $OPENSSL s_client $STARTTLS -cipher $list1 -connect $NODEIP:$PORT $SNI /dev/null >$TMPFILE if [ $? -ne 0 ]; then - openssl_error + pr_magenta "no matching cipher in list found" + outln "$list1" + outln "Please report this" ret=6 else cipher1=$(grep -w Cipher $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') @@ -983,7 +980,6 @@ server_preference() { $OPENSSL s_client $STARTTLS -cipher $list2 -connect $NODEIP:$PORT $SNI /dev/null >$TMPFILE cipher2=$(grep -w Cipher $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') - out " Has server cipher order? " if [[ "$cipher1" != "$cipher2" ]]; then pr_litered "nope (NOT ok)" remark4default_cipher=" (limited sense as client will pick)" @@ -3041,5 +3037,5 @@ case "$1" in esac -# $Id: testssl.sh,v 1.212 2015/03/17 17:11:17 dirkw Exp $ +# $Id: testssl.sh,v 1.213 2015/03/17 21:02:22 dirkw Exp $ # vim:ts=5:sw=5 From 2d0bfca34379f9f4db0bd421119c2269ea4ccaaf Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 17 Mar 2015 22:12:25 +0100 Subject: [PATCH 23/26] =?UTF-8?q?-=20FIX=20for=203des=20cipher=20report=20?= =?UTF-8?q?(thx=20=D0=94=D0=B8=D0=BB=D1=8F=D0=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 3d82b2e..45d9aa2 100755 --- a/testssl.sh +++ b/testssl.sh @@ -693,7 +693,7 @@ std_cipherlists() { if [[ $ret -eq 0 ]]; then ok 2 0 # offered in normal else - ok 2 0 # not offered also in normal + ok 0 1 # not offered also in normal fi;; *) # the ugly rest if [[ $ret -eq 0 ]]; then @@ -3037,5 +3037,5 @@ case "$1" in esac -# $Id: testssl.sh,v 1.213 2015/03/17 21:02:22 dirkw Exp $ +# $Id: testssl.sh,v 1.214 2015/03/17 21:12:24 dirkw Exp $ # vim:ts=5:sw=5 From 0d3b7f343f37f88b5f47cbdc3c5f9cd227c290ee Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 17 Mar 2015 22:14:05 +0100 Subject: [PATCH 24/26] =?UTF-8?q?=D0=94=D0=B8=D0=BB=D1=8F=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CREDITS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index 1cc5879..27657d2 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -22,6 +22,9 @@ - Fix for HSTS + subdomains - LibreSSL patch +* Дилян Палаузов + - bug fix for 3des report + * @nvsofts (NV) - LibreSSL patch for GOST From 63a1df1fe28c2e18f87657b2a03c172a5e4f4dd3 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sun, 15 Mar 2015 09:02:05 -0500 Subject: [PATCH 25/26] Using square brackets in tr results in trying to match/replace them --- testssl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index 596ae44..02621fa 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2288,11 +2288,11 @@ beast(){ #detected_cbc_cipher=$(echo $detected_cbc_cipher | sed 's/ //g') if [ -z "$detected_cbc_cipher" ]; then - pr_litegreenln "no CBC ciphers for $(echo $proto | tr '[a-z]' '[A-Z]') (OK)" + pr_litegreenln "no CBC ciphers for $(echo $proto | tr 'a-z' 'A-Z') (OK)" else detected_cbc_cipher=$(echo "$detected_cbc_cipher" | sed -e 's/ /\n '"${spaces}"'/9' -e 's/ /\n '"${spaces}"'/6' -e 's/ /\n '"${spaces}"'/3') [ $ret -eq 1 ] && out "$spaces" - out "$(echo $proto | tr '[a-z]' '[A-Z]'):"; pr_brownln "$detected_cbc_cipher" + out "$(echo $proto | tr 'a-z' 'A-Z'):"; pr_brownln "$detected_cbc_cipher" ret=1 detected_cbc_cipher="" fi @@ -2385,7 +2385,7 @@ starttls() { protocol=$(echo "$1" | sed 's/s$//') # strip trailing s in ftp(s), smtp(s), pop3(s), imap(s), ldap(s), telnet(s) case "$1" in ftp|smtp|pop3|imap|xmpp|telnet|ldap) - outln " Trying STARTTLS via $(echo $protocol| tr '[a-z]' '[A-Z]')\n" + outln " Trying STARTTLS via $(echo $protocol| tr 'a-z' 'A-Z')\n" $OPENSSL s_client -connect $NODEIP:$PORT $SNI -starttls $protocol $TMPFILE 2>&1 ret=$? if [ $ret -ne 0 ]; then From 819e6e6163e9d08129c61bab1f09132b78d25d88 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sun, 15 Mar 2015 09:18:01 -0500 Subject: [PATCH 26/26] Fix variable directly referenced in printf --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index 596ae44..77985d1 100755 --- a/testssl.sh +++ b/testssl.sh @@ -331,7 +331,7 @@ EOF # determines whether the port has an HTTP service running or not (plain TLS, no STARTTLS) runs_HTTP() { # SNI is nonsense for !HTTP but fortunately SMTP and friends don't care - printf "GET / HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\nAccept: text/*\r\n\r\n" | $OPENSSL s_client -quiet -connect $NODE:$PORT $SNI &>$TMPFILE & + printf "GET / HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\nAccept: text/*\r\n\r\n" "$NODE" | $OPENSSL s_client -quiet -connect $NODE:$PORT $SNI &>$TMPFILE & wait_kill $! $HEADER_MAXSLEEP head $TMPFILE | grep -q ^HTTP && SERVICE=HTTP head $TMPFILE | grep -q SMTP && SERVICE=SMTP